Skip to main content
This walks a real payout end to end: 500 GHS to an MTN mobile money number in Ghana, settled in USDT. You need an approved account and a key with refunds:manage, identity:enquiry, rates:read, payouts:write, and payouts:read.

1. Register a refund destination

Do this once per settlement currency, before your first payout. We hold no balance for you. If a payout fails after your settlement has arrived, the money has to go somewhere — so we require the destination up front rather than asking for it at the worst possible moment.
Skip this and POST /v1/payouts returns 422 REFUND_DESTINATION_REQUIRED. The destination must match the settlement_currency of the payout — a USDT payout needs a USDT destination, not an NGN one.
Settling in NGN instead? Register a Nigerian bank account. We run name enquiry on it before saving, so a typo fails here rather than when a refund is already owed. See Refunds.

2. Find the provider code

The processor routes on a machine code, never on a display name. "MTN" is not a routing value — destination_provider_code is.
Each row’s provider_name and provider_code are named exactly as the payout request expects them, so you can pass them straight through.
Read the codes from this endpoint — do not hardcode them from this page. Codes are corridor-specific and set by the upstream institution directory, so they differ in format between countries and can change without a version bump on our side. Banks and mobile money providers are never mixed in one response; destination_type selects which list you get.

3. Confirm the beneficiary

Name enquiry tells you who actually holds the account, before you commit money to it.
Use the returned destination_account_name on the payout — it is what the institution holds, not what your user typed. This endpoint needs no Idempotency-Key; it writes nothing.

4. Price it

An indicative rate is live and non-binding — use it to show a price. A quote freezes the rate and fees for a short TTL.
Quotes expire in about 30 seconds. This step is optional — quoting is for showing a price to your user. Payout creation locks its own rate regardless. See Rates and quotes.

5. Create the payout

destination_amount is what the beneficiary receives. We derive what you owe.
The payout returns with status CREATED, settlement_amount: 0, and payment_instruction: null. All three change within seconds — the settlement amount is not known until the rate is locked.
Generate a fresh Idempotency-Key per payout and reuse it only when retrying that payout. Two different payouts sharing a key means the second silently returns the first one’s response and is never created.

6. Read the payment instruction

Instruction generation is kicked off immediately and swept every 30 seconds as a safety net. Wait for the payout.pending_payment webhook rather than polling.
A 404 PAYMENT_INSTRUCTION_NOT_FOUND here means the instruction does not exist yet — not that the payout is invalid. Retry, or wait for the webhook.

7. Settle it

Send exactly expected_amount to account_unique before expires_at.
  • Send less and the payout is held for review, not partially processed.
  • Send more and it proceeds; the excess comes back with any later refund.
  • Send nothing and the payout ends EXPIRED — terminal. Create a new one.
Crypto settlements also wait for network confirmations before advancing. See Settlement.

8. Track it

The response carries the current status and a status_timeline — every transition with the reason it happened and when. That timeline, not webhook arrival order, is the authoritative history.

Next steps

Set up webhooks

Stop polling. Every transition, pushed and signed.

Payout lifecycle

All seven statuses and what moves a payout between them.

Handle failures

What happens to your money when a payout fails.

Go live

The checklist before you point real volume at this.