Core concepts
Payouts
Payouts move merchant balance out to destinations you control. Use destination availability and idempotency for safe execution.
Create payout
POST
/v1/payoutsCreate payout request| Field | Type | Description |
|---|---|---|
| assetrequired | string | Settlement token, or token:chain. Chain must match the operator-configured treasury withdrawal rail for that token (see GET /v1/payouts/withdrawal-rail). |
| amountrequired | string | Amount in base units for selected asset. |
| railrequired | string | Destination rail (for example crypto or fiat). |
| destination_address | string | Destination wallet/account detail when required. |
| totp_code | string | Console only (user JWT): payout authenticator code. Not used with API key auth. |
| email_otp_code | string | Console only: email OTP when enabled. |
curl "$XPEND_BASE_URL/v1/payouts" \
-H "Authorization: Bearer $XPEND_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: payout_req_4021" \
-d '{
"asset": "usdc:ethereum",
"amount": "125000000",
"rail": "crypto",
"destination_address": "0x1234..."
}'Check availability first
GET
/v1/payouts/withdrawal-railCanonical chain + withdrawal gates per tokenGET
/v1/payouts/destination-availabilityOperator-enabled payout networksGET
/v1/payouts/fiat-availabilityOperator-enabled fiat corridorsBalance reservation
Creating a payout reserves the payout amount from
available_balance into reserved_balance until the withdrawal completes or is cancelled. Spendable balance for new payouts is available_balance only. A fixed USDT processing fee may apply on withdrawal (ledger debit only — no on-chain fee transfer).Operator-enabled withdrawal rails only
Payout create is rejected unless the settlement chain is enabled for withdrawals in your environment. For crypto, operators configure the canonical treasury chain per token (
TreasuryLiquidityPolicy) and which destination networks accept payouts (PlatformPayoutEnabledChain allowlist and blocks). Merchants cannot pick an arbitrary chain — call GET /v1/payouts/withdrawal-rail?token=usdc and GET /v1/payouts/destination-availability before building payout UI or automation. Fiat bank withdrawals must use a corridor from GET /v1/payouts/fiat-availability.For crypto, combine withdrawal rail (per-token canonical chain and treasury gates) with destination availability (platform-enabled networks). For fiat, use fiat availability and optionally institutions / beneficiary resolve before create.
Fiat bank payout
POST
/v1/payouts/fiat/institutionsList banks for a corridorPOST
/v1/payouts/fiat/beneficiary/resolveResolve account namecurl "$XPEND_BASE_URL/v1/payouts" \
-H "Authorization: Bearer $XPEND_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: payout_fiat_4021" \
-d '{
"rail": "fiat",
"asset": "usdc:ethereum",
"amount": "2000000",
"fiat": {
"method": "BANK_TRANSFER",
"bank_code": "058",
"account_number": "0123456789",
"receive_currency": "NGN"
}
}'Fiat beneficiary fields
For local bank payouts, send
fiat.bank_code and fiat.account_number plus receive_currency. The platform resolves the account holder name (and bank label when available) automatically — you do not need beneficiary_name or bank_name unless you want to supply them explicitly. Use POST /v1/payouts/fiat/beneficiary/resolve to preview resolution before create.Read and cancel
GET
/v1/payoutsList payoutsGET
/v1/payouts/{id}Get payout status/detailsPOST
/v1/payouts/{id}/cancelCancel payout if still cancellableOperational model
- Create payout once with a stable idempotency key.
- Persist payout ID and show status to operators.
- Consume webhook events for status transitions.
- Allow cancel only while payout is not terminal/executed.
Security posture
Payouts authenticated with an API key do not require
totp_code — the key itself is the automation credential. Merchant console (user JWT) withdrawals still require step-up verification via payout authenticator or email OTP. See /business/docs/security.See endpoint-level details in /business/reference/payouts.