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

{% hint style="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.
{% endhint %}

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

{% hint style="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.
{% endhint %}

### 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
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
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"
    }
  }'
```

{% hint style="success" %}
**Best first flow:** Fixed amount invoices are the cleanest first integration because the customer, amount, asset, network, webhook, and fulfillment state are explicit.
{% endhint %}

### 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 internal-transfer exclusions.
4. PayChain creates an auto-generated invoice record for a qualifying deposit.
5. PayChain sends the normal invoice webhook.

{% hint style="warning" %}
**Dust protection note:** Auto-detected deposits below configured thresholds, non-positive observations should not become customer revenue.
{% endhint %}

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

{% hint style="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.
{% endhint %}

### 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 operator 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
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
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"
  }'
```

{% hint style="info" %}
**Routing note:** Payout routing triggers only after full settlement. It should not run for tolerated underpayments, failed invoices, or wrong-asset payments.
{% endhint %}

### 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
await paychain.invoices.create(
  {
    amount: '500.00',
    token: 'USDC',
    chain: 'evm',
    networkId: 'base-mainnet',
    payoutRecipients: [
      {
        label: 'Receiver',
        destinationAddress: '0x0000000000000000000000000000000000000000',
        percentage: 98
      },
      {
        label: 'Operator fee',
        destinationAddress: '0x0000000000000000000000000000000000000000',
        percentage: 2
      }
    ]
  },
  { idempotencyKey: 'order_789_invoice' }
);
```

#### REST equivalent

```bash
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": "Operator fee",
        "destinationAddress": "0x0000000000000000000000000000000000000000",
        "shareBps": 200
      }
    ]
  }'
```

{% hint style="danger" %}
**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.
{% endhint %}

### Programmatic withdrawal

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

#### 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 processes the withdrawal through the normal lifecycle.
5. PayChain sends withdrawal webhooks.

#### SDK example

```ts
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
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"
  }'
```

{% hint style="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.
{% endhint %}

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.paychainhq.io/paychainhq-documentation-page/developer-quickstart/payment-flows.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
