Skip to main content

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.
Developer note: For SDK/API examples across fixed amount invoices, auto-detected payments, payout routes, dynamic payout recipients, and programmatic withdrawals, see Payment flows.

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:
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:
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

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

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:

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

Settlement confirmation

PayChain separates “observed” from “settled.” A transfer can be seen before it is safe to treat as final. 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.
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.

Withdraw funds

Withdrawals move business treasury funds to an external destination. Dashboard withdrawals are manual; payout API withdrawals are backend-driven.
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.

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

Edge cases

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 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 for payload examples, retry behavior, and replay guidance.