REST API Guide
PayChain exposes the same core payment, payout, balance, transaction, network, token, billing, and webhook surfaces over HTTPS. The SDK is recommended for Node.js and TypeScript, but the REST API remains the source of truth for direct integrations.
API positioning: PayChain is SDK-first for speed, but API-complete for teams that need direct HTTP access or non-TypeScript environments.
For exact schemas, query parameters, and endpoint paths, use OpenAPI reference.
Base URLs
| Environment | Base URL |
|---|
| Live | https://api.paychainhq.io/api/v1 |
| Sandbox | Use the sandbox API URL provided in your dashboard or onboarding materials. |
Environment note: Keep sandbox and live API keys, webhook secrets, and webhook URLs separate.
x-api-key: $PAYCHAIN_API_KEY
content-type: application/json
Idempotency-Key: order_123_invoice
Use Idempotency-Key on mutating requests so retries do not create duplicate invoices, withdrawals, or payout actions.
API key types
| Key type | Use it for | Do not use it for |
|---|
| Standard API key | Customers, invoices, reads, balances, transactions, networks, tokens, webhooks. | Programmatic withdrawals or fund movement. |
| Payout API key | Programmatic withdrawals and approved payout automation. | Admin actions, dashboard-session actions, route-template mutation, billing controls. |
Pricing note: A payout API key is necessary for programmatic withdrawal creation, and the request must still pass policy, balance, and destination checks. Free plan businesses have 0 included payout API withdrawals, so the Free payout API fee applies from the first programmatic withdrawal.
Security note: API keys must stay on your backend. Never expose them in frontend JavaScript, mobile apps, public repositories, browser extensions, or analytics logs.
Common REST request pattern
curl -X POST "$PAYCHAIN_API_URL/businesses/$PAYCHAIN_BUSINESS_ID/invoices" \
-H "x-api-key: $PAYCHAIN_API_KEY" \
-H "content-type: application/json" \
-H "Idempotency-Key: order_123_invoice" \
-d '{
"amount": "100.00",
"token": "USDC",
"chain": "evm",
"networkId": "base-mainnet",
"metadata": {
"orderId": "order_123"
}
}'
Core REST examples
Create a customer
curl -X POST "$PAYCHAIN_API_URL/businesses/$PAYCHAIN_BUSINESS_ID/customers" \
-H "x-api-key: $PAYCHAIN_API_KEY" \
-H "content-type: application/json" \
-H "Idempotency-Key: customer_123_create" \
-d '{
"externalRef": "customer_123"
}'
Ensure a customer deposit address
Use this before displaying a reusable customer address for a specific rail. Solana flows should ensure chain: "sol" and networkId: "sol-mainnet" and must never fall back to an EVM 0x... address.
curl -X POST "$PAYCHAIN_API_URL/businesses/$PAYCHAIN_BUSINESS_ID/customers/$CUSTOMER_ID/addresses/ensure" \
-H "x-api-key: $PAYCHAIN_API_KEY" \
-H "content-type: application/json" \
-H "Idempotency-Key: customer_123_sol_address" \
-d '{
"chain": "sol",
"networkId": "sol-mainnet"
}'
The response returns created: true when PayChain provisioned a new address, or created: false when the address already existed. Use the returned address.address only when address.chainFamily is sol and address.networkId is sol-mainnet.
Get an invoice after a webhook
curl "$PAYCHAIN_API_URL/businesses/invoices/inv_123" \
-H "x-api-key: $PAYCHAIN_API_KEY"
Poll invoice confirmation progress
curl "$PAYCHAIN_API_URL/invoices/inv_123" \
-H "x-api-key: $PAYCHAIN_API_KEY"
When a payment is waiting for finality, invoice responses can include confirmationProgress.current, confirmationProgress.required, confirmationProgress.remaining, confirmationProgress.percent, and confirmationProgress.txHash.
List invoices for reconciliation
curl "$PAYCHAIN_API_URL/businesses/$PAYCHAIN_BUSINESS_ID/invoices?status=paid&limit=50" \
-H "x-api-key: $PAYCHAIN_API_KEY"
Quote and create a withdrawal
curl -X POST "$PAYCHAIN_API_URL/businesses/$PAYCHAIN_BUSINESS_ID/withdrawals/quote" \
-H "x-api-key: $PAYCHAIN_PAYOUT_API_KEY" \
-H "content-type: application/json" \
-H "Idempotency-Key: payout_123_quote" \
-d '{
"amount": "25.00",
"token": "USDC",
"chain": "evm",
"networkId": "base-mainnet",
"destinationAddress": "0x0000000000000000000000000000000000000000"
}'
curl -X POST "$PAYCHAIN_API_URL/businesses/$PAYCHAIN_BUSINESS_ID/withdrawals" \
-H "x-api-key: $PAYCHAIN_PAYOUT_API_KEY" \
-H "content-type: application/json" \
-H "Idempotency-Key: payout_123_create" \
-d '{
"quoteId": "quote_123",
"clientReference": "payout_123"
}'
Read balances and transactions
curl "$PAYCHAIN_API_URL/businesses/$PAYCHAIN_BUSINESS_ID/balances" \
-H "x-api-key: $PAYCHAIN_API_KEY"
curl "$PAYCHAIN_API_URL/businesses/$PAYCHAIN_BUSINESS_ID/transactions?limit=50" \
-H "x-api-key: $PAYCHAIN_API_KEY"
Balance responses separate amounts.total from amounts.totalHeld and amounts.requiresRecovery. Use amounts.total or withdrawal quotes for payout capacity.
Discover networks and tokens
curl "$PAYCHAIN_API_URL/networks" \
-H "x-api-key: $PAYCHAIN_API_KEY"
curl "$PAYCHAIN_API_URL/tokens?networkId=base-mainnet" \
-H "x-api-key: $PAYCHAIN_API_KEY"
Read billing and gas usage
curl "$PAYCHAIN_API_URL/billing/me" \
-H "x-api-key: $PAYCHAIN_API_KEY"
curl "$PAYCHAIN_API_URL/billing/usage" \
-H "x-api-key: $PAYCHAIN_API_KEY"
Response handling
Store these values when available:
- PayChain resource ID.
- Your own
clientReference or externalRef.
x-request-id.
- Status.
- Amount, token, chain, and network.
- Webhook delivery ID.
- Transaction hash after settlement or payout completion.
List endpoints may paginate. Keep pagination handling server-side and do not build business-critical reconciliation from a small client-side row limit.
Errors
Expect structured errors with:
- HTTP status.
- Machine-readable code.
- Message.
- Request ID.
- Details where available.
Error handling note: Do not retry validation errors, authentication errors, or policy rejections blindly. Retry only transient network failures, 408, 429, and 5xx responses, and only retry non-idempotent POST requests when an idempotency key is present.
Webhooks
REST integrations should still use signed webhooks for real-time lifecycle changes.
X-Webhook-Signature: ...
X-Webhook-Timestamp: ...
X-Webhook-ID: ...
Verify the signature with the raw request body, then fetch the canonical invoice or withdrawal before fulfillment.
See Webhooks for event handling, retries, replay, and common mistakes.
How REST maps to the SDK
| SDK method | REST concept |
|---|
paychain.customers.create() | Create customer endpoint |
paychain.invoices.create() | Create invoice endpoint |
paychain.invoices.get() | Get invoice endpoint |
paychain.withdrawals.quote() | Quote withdrawal endpoint |
paychain.withdrawals.create() | Create withdrawal endpoint |
paychain.balances.list() | List balances endpoint |
paychain.transactions.list() | List transactions endpoint |
paychain.networks.list() | List supported networks endpoint |
paychain.tokens.list() | List supported tokens endpoint |
See Supported networks and tokens before hardcoding any network or token assumptions.
Production checklist
- API keys stored in secret manager.
- Idempotency keys on mutating requests.
- Webhook signature verification uses raw body.
- Standard and payout API keys are separated.
- Request IDs are logged without secrets.
- Sandbox and live credentials are separate.
- Payout destinations are validated server-side.
- Billing, gas credits, and payout quota behavior are understood.