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

# Payment flows

# Payment Flows

PayChain supports several payment and treasury flows. Choose the simplest flow that matches the business outcome. Most merchants should start with fixed amount invoices, then add payout routing, dynamic recipients, or programmatic withdrawals only when the workflow needs it.

<Info>
  **Important note:** Invoice state is the source of truth for customer payment fulfillment. Balances and transactions are useful for reconciliation, but they should not replace verified invoice status.
</Info>

## Flow overview

| Flow                      | Best for                                                          | Key API surface                                       | Fund movement                                                                             |
| ------------------------- | ----------------------------------------------------------------- | ----------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| Fixed amount invoice      | Checkout, one-off payment links, SaaS invoices, order payments    | Customers, invoices, webhooks                         | Customer pays invoice. Merchant later withdraws or settles.                               |
| Auto-detected payment     | Repeat payer addresses, fintech deposits, wallet-style funding    | Customer addresses, auto-generated invoices, webhooks | PayChain detects qualifying deposits and creates invoice records.                         |
| Payout route invoice      | Repeated split patterns, marketplace seller splits, revenue share | Invoice with `payoutRouteId`                          | PayChain creates payout withdrawals after full settlement.                                |
| Dynamic payout recipients | On/off-ramp orders, one-time marketplace receivers                | Invoice with `payoutRecipients`                       | PayChain creates payout withdrawals to invoice-specific recipients after full settlement. |
| Programmatic withdrawal   | Treasury payout automation, off-platform settlement               | Withdrawal quote and create                           | Backend creates a withdrawal using a payout API key.                                      |

<Warning>
  **Key separation note:** Standard API keys are for collection, invoices, reads, balances, transactions, networks, tokens, and webhooks. Programmatic fund movement requires a payout API key.
</Warning>

<Info>
  **Plan note:** Payout API withdrawals are plan-priced. Free plan businesses have no included payout API quota, so programmatic withdrawals can still be created with a payout API key, but the Free payout API fee applies from the first withdrawal.
</Info>

## Fixed amount invoice

Use this when the customer should pay a known amount for an order, subscription, invoice, top-up, or checkout session.

### What happens

1. Your backend creates or finds a customer.
2. Your backend creates an invoice with amount, token, chain, and network.
3. The customer pays the invoice address.
4. PayChain detects and confirms settlement.
5. PayChain sends an invoice webhook.
6. Your backend verifies the webhook and fetches the invoice.
7. Your system fulfills the order.

### SDK example

```ts theme={null}
const invoice = await paychain.invoices.create(
  {
    amount: '100.00',
    token: 'USDC',
    chain: 'evm',
    networkId: 'base-mainnet',
    customerId: 'customer_123',
    metadata: {
      orderId: 'order_123'
    }
  },
  { idempotencyKey: 'order_123_invoice' }
);
```

### REST equivalent

```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",
    "customerId": "customer_123",
    "metadata": {
      "orderId": "order_123"
    }
  }'
```

<Tip>
  **Best first flow:** Fixed amount invoices are the cleanest first integration because the customer, amount, asset, network, webhook, and fulfillment state are explicit.
</Tip>

## Auto-detected payment

Use this when repeat users deposit to a reusable customer address and you do not want to pre-create every invoice.

### What happens

1. The customer has a reusable PayChain deposit address.
2. A supported transfer arrives on that address.
3. PayChain applies strict asset matching, dust protection, and operational-transfer exclusions.
4. PayChain creates an auto-generated invoice record for a qualifying deposit.
5. PayChain sends the normal invoice webhook.

<Warning>
  **Dust protection note:** Auto-detected deposits below configured thresholds, non-positive observations, sponsored-gas activity, and PayChain operational wallet transfers should not become customer revenue.
</Warning>

### Use cases

* Fintech wallet funding.
* Recurring customer deposit addresses.
* Gaming deposits.
* On/off-ramp user funding.

### API surfaces

* Create or fetch customer.
* Read customer deposit addresses where available.
* Listen for `invoice.*` webhooks.
* Fetch the canonical invoice after webhook verification.

<Info>
  **REST note:** Auto-detection is usually configured around customer deposit addresses and backend webhooks. The important REST action is not creating every invoice manually; it is reconciling the auto-generated invoice PayChain creates after a qualifying deposit.
</Info>

## Payout route invoice

Use this when the same split pattern repeats across many invoices, such as marketplace seller splits or partner revenue share.

### What happens

1. An authorized team member creates and approves a payout route template in the dashboard.
2. Your backend creates an invoice with `payoutRouteId`.
3. The customer fully pays or overpays the invoice.
4. PayChain calculates net business amount after fees.
5. PayChain creates one withdrawal per route recipient.
6. Each recipient leg counts as one payout API withdrawal for quota and fee purposes.

### SDK example

```ts theme={null}
await paychain.invoices.create(
  {
    amount: '250.00',
    token: 'USDC',
    chain: 'evm',
    networkId: 'base-mainnet',
    payoutRouteId: 'route_marketplace_seller_split'
  },
  { idempotencyKey: 'order_456_invoice' }
);
```

### REST equivalent

```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_456_invoice" \
  -d '{
    "amount": "250.00",
    "token": "USDC",
    "chain": "evm",
    "networkId": "base-mainnet",
    "payoutRouteId": "route_marketplace_seller_split"
  }'
```

<Info>
  **Routing note:** Payout routing triggers only after full settlement. It should not run for tolerated underpayments, failed invoices, or wrong-asset payments.
</Info>

## Dynamic payout recipients

Use this when the receiver changes on each invoice, such as on-ramp, off-ramp, or marketplace orders with one-time sellers.

### What happens

1. Your trusted backend validates the receiver and order.
2. Your backend creates an invoice with `payoutRecipients`.
3. The customer fully pays or overpays the invoice.
4. PayChain splits the net amount by percentage.
5. PayChain creates payout withdrawals after settlement.

### SDK example

```ts theme={null}
await paychain.invoices.create(
  {
    amount: '500.00',
    token: 'USDC',
    chain: 'evm',
    networkId: 'base-mainnet',
    payoutRecipients: [
      {
        label: 'Receiver',
        destinationAddress: '0x0000000000000000000000000000000000000000',
        percentage: 98
      },
      {
        label: 'Platform fee',
        destinationAddress: '0x0000000000000000000000000000000000000000',
        percentage: 2
      }
    ]
  },
  { idempotencyKey: 'order_789_invoice' }
);
```

### REST equivalent

```bash theme={null}
curl -X POST "$PAYCHAIN_API_URL/businesses/$PAYCHAIN_BUSINESS_ID/invoices" \
  -H "x-api-key: $PAYCHAIN_PAYOUT_API_KEY" \
  -H "content-type: application/json" \
  -H "Idempotency-Key: order_789_invoice" \
  -d '{
    "amount": "500.00",
    "token": "USDC",
    "chain": "evm",
    "networkId": "base-mainnet",
    "payoutRecipients": [
      {
        "label": "Receiver",
        "destinationAddress": "0x0000000000000000000000000000000000000000",
        "shareBps": 9800
      },
      {
        "label": "Platform fee",
        "destinationAddress": "0x0000000000000000000000000000000000000000",
        "shareBps": 200
      }
    ]
  }'
```

<Warning>
  **Security note:** Do not trust payout destinations submitted directly by a browser or mobile app. Validate receivers, order status, limits, and fraud rules in your backend before creating the invoice.
</Warning>

## Programmatic withdrawal

Use this when your backend needs to move business treasury funds after your own business logic approves the payout.

<Warning>
  **Free plan behavior:** Free plan includes `0` payout API withdrawals as free quota, not as a withdrawal ban. A Free plan payout API key can create programmatic withdrawals when policy and balance checks pass, and the Free payout API fee is deducted from the requested amount.
</Warning>

### What happens

1. Your backend calculates the payout.
2. Your backend requests a withdrawal quote.
3. Your backend creates the withdrawal with a payout API key.
4. PayChain queues the withdrawal and checks withdrawable treasury capacity.
5. If recent invoice funds are still sweeping into treasury, PayChain can hold the withdrawal in `pending_funds` until those sweepable funds are available.
6. PayChain processes the withdrawal through the normal lifecycle.
7. PayChain sends withdrawal webhooks.

### SDK example

```ts theme={null}
const quote = await paychain.withdrawals.quote({
  token: 'USDC',
  chain: 'evm',
  networkId: 'base-mainnet',
  amount: '100.00',
  destinationAddress: '0x0000000000000000000000000000000000000000'
});

const withdrawal = await paychain.withdrawals.create(
  {
    quoteId: quote.id,
    clientReference: 'payout_123'
  },
  { idempotencyKey: 'payout_123' }
);
```

### REST equivalent

```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 '{
    "token": "USDC",
    "chain": "evm",
    "networkId": "base-mainnet",
    "amount": "100.00",
    "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" \
  -d '{
    "quoteId": "quote_123",
    "clientReference": "payout_123"
  }'
```

<Warning>
  **Gas credit note:** If PayChain sponsors network cost for a withdrawal, the operation can consume included or prepaid gas credits. If credits are insufficient, the withdrawal may become gas-blocked until top-up.
</Warning>

<Info>
  **Immediate payout note:** For webhook-driven payouts, create withdrawals with idempotency keys and then follow withdrawal state. A valid withdrawal may be accepted as `pending_funds` while PayChain finishes sweeping newly settled invoice funds. A true over-withdrawal or non-sweepable legacy source balance can still be rejected.
</Info>

## Which flow should I choose?

| If you need...                                     | Choose                    |
| -------------------------------------------------- | ------------------------- |
| A customer pays a known amount                     | Fixed amount invoice      |
| Repeat payer deposits without pre-created invoices | Auto-detected payment     |
| Same split template across many invoices           | Payout route invoice      |
| One-time receiver per invoice                      | Dynamic payout recipients |
| Backend-controlled treasury movement               | Programmatic withdrawal   |

## Common mistakes

* Using auto-detection when the payment amount and order should be exact.
* Using dynamic payout recipients without server-side receiver validation.
* Treating a payout route as active before the invoice is fully settled.
* Using a standard API key for programmatic withdrawals.
* Fulfillment based only on transaction history instead of canonical invoice state.
* Retrying payout or withdrawal creation without an idempotency key.
* Treating `totalHeld` or recovery-required balance as immediately withdrawable. Use the withdrawal quote or `amounts.total` for withdrawable capacity.
