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

# Workflows

# Workflow Guides

Workflow pages connect API actions, webhook behavior, settlement state, pricing impact, and troubleshooting. Use this page when you want the full operating sequence instead of only endpoint examples.

<Info>
  **Developer note:** For SDK/API examples across fixed amount invoices, auto-detected payments, payout routes, dynamic payout recipients, and programmatic withdrawals, see [Payment flows](payment-flows).
</Info>

## Receive payments

Use this workflow when the payer should pay a specific amount for an order, checkout session, invoice, top-up, or service.

### Before you begin

* Confirm the business is in the correct environment: sandbox or live.
* Confirm the token and `networkId` are supported.
* Store API keys only on your backend.
* Configure webhook URL and signing secret.
* Decide what your system should do after `paid` or `overpaid`.

### What you do

1. Create or find a customer.
2. Create an invoice with `amount`, `token`, `chain`, `networkId`, and your own order metadata.
3. Show the hosted invoice link or render the payment address in your own checkout.
4. Wait for PayChain to detect and confirm the transfer.
5. Verify the webhook signature with the raw request body.
6. Fetch the canonical invoice.
7. Fulfill the order only after the canonical invoice is `paid` or `overpaid`.
8. Store the PayChain invoice ID, transaction hash, and your order reference together.

### Expected result

* The invoice moves from `pending` to `confirming` when payment is observed.
* The invoice moves to `paid` after settlement confirmation.
* Eligible funds are swept or made available for treasury movement according to the supported rail and business policy.
* Your backend receives a signed webhook.
* Your own order moves to fulfilled once your handler verifies and fetches the invoice.

### Stellar invoices

For Stellar mainnet, PayChain returns the business Stellar treasury address plus a required numeric Stellar Memo ID by default. The payer must send the exact asset to `depositAddress` and include the returned memo.

The invoice response includes:

```json theme={null}
{
  "chain": "stellar",
  "networkId": "stellar-mainnet",
  "depositAddress": "G...",
  "receiveMode": "memo_required",
  "memoId": "123456789",
  "memo": {
    "type": "id",
    "value": "123456789"
  }
}
```

After PayChain confirms the transfer with the correct asset and Memo ID, it emits the normal `invoice.paid` webhook. A Stellar payment with a missing memo, wrong memo, wrong asset, or wrong issuer is recorded for review and does not automatically fulfill the invoice.

### Stellar issued asset invoices

For Stellar issued assets such as USDC, the asset identity must include the issuer. PayChain matches Stellar issued assets by `assetCode`, `issuerAddress`, and `canonicalAssetId`, not by the display symbol alone.

Use this shape when creating a Stellar USDC invoice:

```json theme={null}
{
  "chain": "stellar",
  "networkId": "stellar-mainnet",
  "token": "USDC",
  "assetCode": "USDC",
  "issuerAddress": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
  "canonicalAssetId": "stellar:USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
}
```

PayChain only settles issued-asset invoices for assets registered in the supported-token catalog. A payment with the wrong issuer, an unsupported asset, or only a symbol match will not settle the invoice.

For default Stellar receive, PayChain prepares the business treasury for memo-based receive and ensures the treasury has the required issued-asset trustline. PayChain does not create or activate a new Stellar account for each invoice.

If you explicitly create a Stellar invoice with `receiveMode: "dedicated_address"`, the invoice uses the legacy dedicated-address flow. Dedicated-address Stellar issued-asset invoices require the receiver account and trustline to be ready before the address is shown.

### Pricing or gas impact

* The invoice fee applies when the invoice settles.
* Inbound payment detection does not consume gas credits.
* Automatic settlement or sponsored outbound movement after payment may consume gas credits.

### Troubleshooting

| Issue                      | What to check                                                              |
| -------------------------- | -------------------------------------------------------------------------- |
| Invoice stays `pending`    | Confirm the payer used the exact network, token, and address.              |
| Invoice stays `confirming` | Wait for required network settlement confirmations.                        |
| Webhook did not arrive     | Check webhook URL, delivery logs, retry state, and endpoint response code. |
| Customer paid wrong asset  | Do not fulfill unless PayChain marks the invoice settled.                  |
| Customer underpaid         | Wait for completion or follow your underpayment policy.                    |

## Auto-detect payments

Use auto-detection when repeat payers deposit to reusable customer addresses and you do not want to pre-create every invoice.

Before showing a reusable customer address, ensure the customer has an address for the exact rail you are about to display. Use this pattern for reusable-address rails:

* For Solana mainnet, call `POST /api/v1/businesses/:businessId/customers/:customerId/addresses/ensure` or `paychain.customers.ensureAddress(...)` with `chain: "sol"` and `networkId: "sol-mainnet"`.
* For Stellar mainnet, default invoice and Auto Deposit Intent receive uses the business treasury address plus a required Memo ID, so `ensureAddress` is not required unless you explicitly opt into `receiveMode: "dedicated_address"`.

<Info>
  **Reusable-address rail note:** PayChain can lazily provision a missing customer address for supported reusable-address rails. Call the ensure endpoint before displaying those addresses, including for existing customers after PayChain enables a new network. Integrations should still send `networkId` explicitly and must verify the returned `address.chainFamily` and `address.networkId` before displaying it. If the expected address is not returned, fail setup instead of falling back to an EVM `0x...` address or another reusable address.
</Info>

### What PayChain does

1. Watches supported customer deposit addresses.
2. Ignores non-positive observations.
3. Ignores PayChain operational transfers.
4. Applies auto-invoice minimum and dust thresholds.
5. Creates an auto-generated invoice for a qualifying deposit.
6. Emits the normal invoice webhook.

### Auto Deposit Intents

Use an Auto Deposit Intent when a customer deposit represents a specific off-ramp, on-ramp, wallet-funding, or provider-payout order. On Stellar, the default intent returns the business treasury address plus a required Memo ID. On reusable-address rails such as Solana, the intent uses the customer deposit address.

For each `business + customer + token + network`, PayChain keeps one active intent. Creating a new same-rail intent replaces the older active intent. A deposit is assigned to an order only when exactly one active intent exists and the received amount is within the configured tolerance.

Auto-detect assignment has two business modes:

| Mode              | Behavior                                                                                                                     |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `intent_required` | Deposits can attach to an order only through a matching active Auto Deposit Intent.                                          |
| `ledger_only`     | Deposits create paid auto-generated invoices for reconciliation, but never attach order identity or provider payout routing. |

### Order-aware reusable address flow

1. Create the customer or fetch the existing customer.
2. Create an Auto Deposit Intent with `externalOrderId`, `chain`, `networkId`, `token`, `expectedAmount`, and optional payout route or payout recipients.
3. Show the returned payment instructions to the payer. For Stellar, show both `depositAddress` and `memo.value`.
4. Verify the `invoice.paid` webhook.
5. Fetch the canonical invoice.
6. Fulfill only when `autoDepositAssignmentStatus` is `matched` and `externalOrderId` matches the order you are about to release.
7. Route provider payout only from a matched invoice.

If there is no active intent, more than one active intent, or the amount is outside tolerance, PayChain still records the paid auto-generated invoice for reconciliation, but marks it for review and does not attach provider payout routing.

### Dust and minimum rules

Auto-detected deposits use plan and network guardrails so tiny or operational transfers do not become customer revenue.

| Rule                       | Applies to                 | Behavior                                                               |
| -------------------------- | -------------------------- | ---------------------------------------------------------------------- |
| `dustThresholdUsd`         | Auto-detected observations | Below-threshold observations are ignored.                              |
| `autoInvoiceMinUsd`        | Auto-generated invoices    | Deposits below the auto-invoice minimum do not create revenue records. |
| Explicit invoice economics | Merchant-created invoices  | Small invoices can be created if expected merchant net is positive.    |

<Warning>
  **Dust protection note:** Auto-detected dust protection does not mean customers cannot pay small explicit invoices. Explicit invoices are safer for exact small payments because the expected amount, asset, and network are known up front.
</Warning>

## Settlement confirmation

PayChain separates “observed” from “settled.” A transfer can be seen before it is safe to treat as final.

| Stage      | Meaning                                                           | Fulfillment guidance                                    |
| ---------- | ----------------------------------------------------------------- | ------------------------------------------------------- |
| Observed   | A matching transfer was detected.                                 | Do not fulfill yet.                                     |
| Confirming | PayChain is waiting for required finality.                        | Keep showing pending/confirming.                        |
| Settled    | Required confirmation/finality rules passed.                      | Fulfill after webhook verification and canonical fetch. |
| Rejected   | Wrong asset, wrong network, invalid amount, or failed validation. | Do not fulfill.                                         |

Settlement rules can differ by network. Your integration should consume invoice status, not guess finality from a block explorer.

For networks that require multiple confirmations, poll `GET /api/v1/invoices/:invoiceId` or the authenticated invoice detail endpoint. The response includes `confirmationProgress.current`, `confirmationProgress.required`, `confirmationProgress.remaining`, `confirmationProgress.percent`, and `confirmationProgress.txHash` when a matching transaction is detected.

For Stellar mainnet XLM and registered issued assets, one successfully closed ledger is treated as settled. PayChain marks the invoice paid after it indexes the closed ledger.

If an on-chain Stellar payment is confirmed but the invoice remains pending longer than expected, keep fulfillment pending and contact PayChain support with the invoice ID, network, asset, amount, destination address, and transaction hash.

## Payout routes

A payout route is an approved template that tells PayChain how to split an invoice after it is fully paid. Use payout routes when the same split pattern repeats. Use dynamic payout recipients when each invoice has a one-time receiver, such as an on-ramp or marketplace order.

Each recipient leg counts as one payout API withdrawal for quota and fee purposes.

<Warning>
  **Payout route note:** Payout routing triggers after full invoice settlement. It should not run for tolerated underpayments, failed invoices, or payments that do not match the invoice asset.
</Warning>

## Withdraw funds

Withdrawals move business treasury funds to an external destination. Dashboard withdrawals are manual; payout API withdrawals are backend-driven.

<Warning>
  **Pricing note:** Programmatic withdrawals with payout API keys are allowed when policy and balance checks pass. Free plan businesses have `0` included payout API withdrawals, so the Free payout API fee applies from the first backend-created withdrawal.
</Warning>

### Withdrawal lifecycle

1. Quote the withdrawal.
2. Review amount, token, network, fee, and destination.
3. Create the withdrawal with a payout API key or dashboard action.
4. PayChain queues the withdrawal.
5. If the funds were just paid into an invoice or customer address, PayChain may wait for sweep completion before submitting the payout.
6. PayChain submits the network transaction where applicable.
7. PayChain sends withdrawal webhooks as the status changes.

For Stellar XLM withdrawals, use `chain: "stellar"`, `networkId: "stellar-mainnet"`, `token: "XLM"`, and a valid Stellar `G...` destination address. A withdrawal can include a Stellar memo when the destination requires one.

<Info>
  **Fresh-payment note:** If your backend creates a withdrawal immediately after an `invoice.paid` webhook, the withdrawal can enter `pending_funds` while PayChain finishes moving sweepable funds into withdrawable treasury capacity. Poll the withdrawal or listen for withdrawal webhooks instead of treating this as a failed payout.
</Info>

### Edge cases

| Case                          | Meaning                                                                                    | Recommended action                                                     |
| ----------------------------- | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------- |
| `pending_funds`               | Recent invoice funds appear eligible but are still sweeping into treasury capacity.        | Wait for the withdrawal to continue processing.                        |
| Insufficient balance          | Funds are not available, not sweepable, or below the requested amount after policy checks. | Lower amount, wait for settlement, or resolve recovery-required funds. |
| Funds reserved                | Another withdrawal already reserved the same funds.                                        | Wait for terminal state.                                               |
| `gas_blocked`                 | Sponsored network cost is not currently covered.                                           | Top up gas credits.                                                    |
| Destination rejected          | Destination failed policy or format checks.                                                | Correct destination or policy.                                         |
| Broadcasted but not completed | Network submission happened but final confirmation is pending.                             | Wait and track status.                                                 |

## Reconcile balances

Reconcile invoices, payments, balances, withdrawals, and transactions together. Raw wallet balance is not the same as invoice truth.

Use the balance fields intentionally:

* `amounts.total` is the merchant-facing withdrawable amount.
* `amounts.totalHeld` is the projected amount PayChain can see across active address rows.
* `amounts.requiresRecovery` is visible for reconciliation, but is not currently counted as withdrawable capacity.

See [Reconciliation](reconciliation) for examples.

## Webhook lifecycle

PayChain sends a webhook after important state changes. Your endpoint should verify, deduplicate, fetch the canonical resource, act once, and return a `2xx` quickly.

See [Webhooks](webhooks) for payload examples, retry behavior, and replay guidance.
