First off — thank you for taking the time to contribute. 🎉
Paya is community-built. Every merged pull request, reported bug, and piece of documentation makes a real difference. This guide will help you understand how to contribute effectively, regardless of your skill level.
- Contributing to Paya
- Table of Contents
- Code of Conduct
- How to Contribute
- Project Structure
- Development Setup
- Picking an Issue
- Issue Labels
- Branch Naming
- Commit Message Format
- Pull Request Process
- Smart Contract Contributions
- Backend Contributions
- Frontend Contributions
- Testing Requirements
- Documentation
- Getting Help
- Recognition
By participating in this project, you agree to uphold our Code of Conduct:
- Be respectful. Disagreements happen. Debate ideas, not people.
- Be inclusive. Contributions from all backgrounds are welcome.
- Be constructive. Give feedback that helps people improve.
- Be patient. Maintainers are volunteers. Reviews take time.
Violations may result in a warning or removal from the project.
There are many ways to contribute to Paya:
| Type | What This Means |
|---|---|
| 🐛 Bug Reports | Found something broken? Open an issue |
| 💡 Feature Requests | Have an idea? Open a discussion |
| 🔨 Code | Fix bugs, implement features from open issues |
| 📝 Documentation | Improve READMEs, add examples, fix typos |
| 🧪 Tests | Add missing tests for contracts, APIs, or UI |
| 🎨 Design | Improve the checkout UI or dashboard |
Paya/
├── contracts/ ← Soroban smart contracts (Rust)
├── backend/ ← NestJS backend services (TypeScript)
├── frontend/ ← Next.js app (TypeScript)
└── docs/ ← Project documentation
Each directory is largely independent. You do not need to understand the entire codebase to contribute. Pick a module that matches your skills.
| Tool | Version | Purpose |
|---|---|---|
| Node.js | >= 18 | Backend & Frontend |
| pnpm | >= 8 | Package manager |
| Rust | latest stable | Smart contracts |
| Soroban CLI | latest | Deploy & test contracts |
| Docker | >= 20 | Local database & services |
| Git | any recent | Version control |
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
# Add WASM target
rustup target add wasm32-unknown-unknown
# Install Soroban CLI
cargo install --locked soroban-cli# Fork the repo first, then:
git clone https://github.com/<your-username>/Paya.git
cd Paya
# Add upstream remote
git remote add upstream https://github.com/your-org/Paya.git
# Install frontend dependencies
cd frontend && pnpm install && cd ..
# Install backend dependencies
cd backend && pnpm install && cd ..# Copy env file
cp .env.example .env
# Start Postgres + Redis via Docker
docker-compose up -d postgres redis
# Start backend
cd backend && pnpm start:dev
# Start frontend (separate terminal)
cd frontend && pnpm dev- Browse open issues
- Look for issues labeled
good first issueif you are new - Leave a comment: "I'd like to work on this"
- A maintainer will assign it to you
- Do not submit a PR for an unassigned issue — two people may end up doing the same work
Look for the good first issue label. These are small, well-scoped, and have enough context to get started without deep knowledge of the codebase.
| Label | Meaning |
|---|---|
good first issue |
Small, beginner-friendly task |
help wanted |
Maintainers need community help |
contract |
Soroban / Rust smart contract work |
backend |
NestJS backend service work |
frontend |
Next.js / React UI work |
bug |
Something is broken |
enhancement |
New feature or improvement |
documentation |
Docs only change |
testing |
Adding or improving tests |
blocked |
Waiting on another issue |
in progress |
Someone is actively working on this |
review needed |
PR is open and needs a review |
Use this format for your branch names:
<type>/<short-description>
| Type | When to Use |
|---|---|
feat |
New feature |
fix |
Bug fix |
docs |
Documentation only |
test |
Adding or fixing tests |
refactor |
Code restructure, no behavior change |
chore |
Tooling, config, dependencies |
contract |
Smart contract work |
feat/escrow-contract-logic
fix/payment-status-webhook
docs/add-soroban-deploy-guide
test/merchant-vault-unit-tests
contract/payment-split-initial
We follow the Conventional Commits standard.
<type>(scope): <short description>
[optional body]
[optional footer]
feat(contracts): implement escrow deposit function
Add create_escrow and deposit functions to escrow_contract.
Funds are locked until buyer approves or timeout occurs.
Closes #12
fix(backend): payment status not updating on webhook retry
The webhook retry worker was not re-fetching payment state.
Fixed by querying payment_service before sending webhook.
Fixes #47
docs(frontend): add checkout integration example to README
- Use present tense: "add feature" not "added feature"
- Keep subject line under 72 characters
- Reference the issue number in the footer:
Closes #<number> - Separate subject from body with a blank line
- Your branch is up to date with
main - All tests pass locally
- You've added tests for new functionality
- You've updated relevant documentation
- Your code follows the style conventions of the module
git fetch upstream
git rebase upstream/main- Push your branch:
git push origin feat/your-feature - Open a Pull Request against
main - Fill in the PR template completely
- Link the issue: "Closes #"
- Request a review if needed
Same as commit format:
feat(contracts): implement payment split contract
fix(backend): correct conversion rate calculation
docs: update README with deployment steps
- All PRs need at least 1 maintainer approval
- Complex contract PRs need 2 approvals
- Respond to review feedback within 7 days or the PR may be closed
- Maintainers may push small cleanup commits to your branch before merging
- Does the code do what the issue describes?
- Are there tests?
- Is there any security risk?
- Is the code readable and consistent with the rest of the module?
Smart contracts live in contracts/. Each is a standalone Rust crate.
contracts/<contract_name>/
├── src/
│ ├── lib.rs ← contract entry point and public functions
│ ├── types.rs ← data structures and enums
│ ├── storage.rs ← state read/write helpers
│ └── logic.rs ← business logic
└── Cargo.toml
- One contract = one responsibility. Do not add unrelated logic to an existing contract.
- Keep functions small. Extract helpers into
logic.rs. - Define all data types in
types.rs. - All storage reads/writes go through
storage.rs— never raw instance storage access inlib.rs. - Every public function must have a corresponding unit test.
- Use Soroban SDK events for any state-changing operations.
cd contracts/<contract_name>
cargo build --target wasm32-unknown-unknown --releasecd contracts/<contract_name>
cargo testBackend services live in backend/. The stack is NestJS + TypeScript.
- Each service is independent. Do not import directly from another service — use the API gateway.
- Use
class-validatorfor all request DTOs. - All database queries go through repository classes. No raw SQL in controllers or services.
- Errors must be thrown using NestJS
HttpExceptionor custom exception classes. - Every endpoint needs a corresponding unit test in
*.spec.ts. - Async functions must handle errors — use
try/catchand propagate properly.
cd backend/payment_service
pnpm start:dev# Unit tests
pnpm test
# E2E tests
pnpm test:e2e
# Coverage
pnpm test:covFrontend lives in frontend/. Stack is Next.js 14 + TypeScript + Tailwind CSS.
- Components go in
components/. Pages go inapp/. - Shared logic goes in
hooks/as custom React hooks. - API calls are centralized in
services/. Do not callfetchdirectly in components. - Use Tailwind utility classes only — no inline styles.
- Components must be accessible: use semantic HTML and ARIA attributes where needed.
- Every component should handle loading, error, and empty states.
cd frontend
npm devnpm test| Area | Minimum Requirement |
|---|---|
| Smart Contracts | Unit tests for every public function |
| Backend Services | Unit tests for service layer; e2e for critical flows |
| Frontend | Component tests for interactive components |
| APIs | Integration tests for all endpoints |
PRs without tests for new functionality will not be merged.
Good documentation is as valuable as code.
- Update the relevant
README.mdif your change affects setup or usage - Add inline code comments for complex logic — especially in contracts
- If you add a new API endpoint, document it in
docs/api.md - If you add a new contract function, add it to
docs/contracts.md
Stuck? Need clarification on an issue?
- Comment on the issue — maintainers check regularly
- Open a Discussion — for questions that don't fit an issue
- Tag a maintainer in your PR if it's been sitting without a review for more than 5 days
We want contributors to succeed. Don't hesitate to ask.
All contributors are recognized in:
- The
CONTRIBUTORS.mdfile (added automatically on first merged PR) - Release notes for the version their work ships in
Thank you for building Paya. 🚀