Skip to main content

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

EnvironmentBase URL
Livehttps://api.paychainhq.io/api/v1
SandboxUse 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.

Required headers

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 typeUse it forDo not use it for
Standard API keyCustomers, invoices, reads, balances, transactions, networks, tokens, webhooks.Programmatic withdrawals or fund movement.
Payout API keyProgrammatic 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.

Pagination

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 methodREST 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.