Skip to main content
A payout moves money out of your balance to a beneficiary you have already registered. It is a single, idempotent, unattended call: no step-up authentication, no multi-call preview-then-confirm. There are two rails, and they behave the same way in every respect except where the money lands. Both take the same request body. The rail you call, and the beneficiary you name, decide everything else — there is no rail field, no network field and no token field to set. This page covers what the two rails share. The per-rail pages cover what differs.

You pay a beneficiary, not an address

You cannot send money to a raw account number or wallet address. You register a beneficiary first, and then pay out to its beneficiaryId.
A beneficiary is bound to one rail. A bank-rail beneficiary cannot receive a stablecoin payout and a wallet-rail beneficiary cannot receive a fiat one.
A wrong-rail beneficiary fails with 400, not 404. The beneficiary is yours, so it resolves; the call then fails on the rail details it does not carry — sending a bank-rail beneficiary to POST /v1/payouts/token returns 400 with errorKey: InvalidWalletAddress. A 404 here means the id is unknown or belongs to another partner, which is a different fix. Check rail on the beneficiary before you pay it.

Idempotency

Every payout requires an idempotencyKey, and it is the mechanism that makes a retry safe.
  • The key namespace is shared across both rails. A key used for a fiat payout cannot be reused for a stablecoin payout.
  • Replay detection hashes the mapped request, not the raw bytes. Whitespace or field ordering in your JSON cannot cause a spurious conflict.
  • Reusing a key with a different payload returns 409 with idempotency_key_reuse.
  • A blank key is treated as absent rather than as a value, so blanks do not collide with one another. Send a real key.
Generate the key from something stable in your own system — an invoice or order id — rather than a random value. A random key regenerated on retry defeats the protection entirely.

status is the outcome, not the HTTP code

A 201 means the payout was accepted, not that it settled. Treat status as an open set of strings, not a fixed enum — new values can be added without a breaking version change, so match on the values you know and handle the rest gracefully rather than failing closed.Settlement is asynchronous on both rails. The terminal state arrives by webhook, never in the response to the call that created the payout.

Errors

Tracking a payout

The reference on the response is the business reference. Use it to look the payout up in Transactions, and subscribe to transaction.status.changed to be told when it settles rather than polling. See Receiving webhooks.