> ## Documentation Index
> Fetch the complete documentation index at: https://docs.paychainhq.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Rest api guide

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

<Info>
  **API positioning:** PayChain is SDK-first for speed, but API-complete for teams that need direct HTTP access or non-TypeScript environments.
</Info>

For exact schemas, query parameters, and endpoint paths, use [OpenAPI reference](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. |

<Warning>
  **Environment note:** Keep sandbox and live API keys, webhook secrets, and webhook URLs separate.
</Warning>

## Required headers

```http theme={null}
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.                        | Account administration, billing changes, or broad dashboard access. |

<Warning>
  **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.
</Warning>

<Warning>
  **Security note:** API keys must stay on your backend. Never expose them in frontend JavaScript, mobile apps, public repositories, browser extensions, or analytics logs.
</Warning>

## Common REST request pattern

```bash theme={null}
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

```bash theme={null}
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. Send the exact `chain` and `networkId`, then verify the returned `address.chainFamily` and `address.networkId` before showing the address to the payer.

Solana and Stellar use the same ensure pattern: call the customer address ensure endpoint for the exact rail and never fall back to an EVM `0x...` address when a non-EVM address is expected.

The ensure endpoint:

* Returns the existing customer address when the customer already has one for the requested rail.
* Provisions a missing address when the business is configured for that rail.
* Returns `created` and address metadata so your backend can verify the rail before displaying payment instructions.

Call this endpoint before showing a reusable address, not only when the customer is first created. This keeps existing customers compatible when PayChain enables a new network, because older customers may not have an address for that rail until your integration asks PayChain to ensure it.

```bash theme={null}
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"
  }'
```

```bash theme={null}
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_stellar_address" \
  -d '{
    "chain": "stellar",
    "networkId": "stellar-mainnet",
    "token": "XLM"
  }'
```

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 the returned rail matches the requested rail, such as `address.chainFamily: "sol"` with `address.networkId: "sol-mainnet"` or `address.chainFamily: "stellar"` with `address.networkId: "stellar-mainnet"`.

<Info>
  **Lazy provisioning note:** If `networkId` is omitted and only one active network matches the requested rail, PayChain may infer it. Production integrations should still send `networkId` explicitly so the address-selection pattern stays consistent across Solana, Stellar, and future rails.
</Info>

### Get an invoice after a webhook

```bash theme={null}
curl "$PAYCHAIN_API_URL/businesses/invoices/inv_123" \
  -H "x-api-key: $PAYCHAIN_API_KEY"
```

### Poll invoice confirmation progress

```bash theme={null}
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

```bash theme={null}
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

```bash theme={null}
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

```bash theme={null}
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

```bash theme={null}
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

```bash theme={null}
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.

<Warning>
  **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.
</Warning>

## Webhooks

REST integrations should still use signed webhooks for real-time lifecycle changes.

```http theme={null}
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](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](supported-networks-tokens) before hardcoding any network or token assumptions.

## Production checklist

* API keys stored in protected server-side secret storage.
* 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.
