Payouts
The Payouts API allows you to convert crypto assets (BTC, USDT, USDC) into local fiat currencies (e.g., NGN, KES). The flow involves creating a quote, initializing the payout with beneficiary details, depositing funds, and finalizing the transaction.
Create quote → Initialize (with beneficiary) → Finalize. Use account-lookup, banks/:countryCode, and supported-countries/:country upstream to build a valid Initialize request.
Create Payouts Quote
Creates a quote for converting cryptocurrency to fiat. You can specify either amount (crypto amount) or settlement_amount (target fiat amount).
Create Payouts Quote Request
Crypto amount to convert, expressed as a decimal string in the source asset (e.g. '10' = 10 USDC). Takes priority over settlement_amount when both are provided.
Target fiat amount you want the beneficiary to receive. Ignored when amount is also provided.
Two-letter ISO 3166-1 alpha-2 country code for the destination (e.g. 'NG', 'KE', 'GH'). Must be one of the codes returned by GET /api/payouts/supported-countries.
Crypto asset you're debiting from your wallet: 'BTC', 'USDT', or 'USDC'.
Target fiat currency code the beneficiary will receive (e.g. 'NGN', 'KES', 'GHS'). Must be a currency supported on the chosen country.
Source of funds (lowercase). 'offchain' debits your Bitnob wallet balance directly; 'onchain' expects a blockchain deposit to cover the quote.
Blockchain network used when source is 'onchain' (e.g. 'BITCOIN', 'trc20', 'erc20'). Omit when source is 'offchain'.
Client-generated unique identifier for this quote. Reused on initialize and finalize for idempotency and reconciliation.
Provide either amount (crypto side) or settlement_amount (fiat side) — not both. When both are sent, amount takes priority and settlement_amount is ignored.
Create Payouts Quote Response
A globally unique identifier for the payout. Used to reference this payout in future requests.
An internal reference string for the quote, passed into subsequent payout endpoints.
The unique identifier of the company that created the quote.
The current state of the quote (e.g., 'QUOTE'). Changes as the payout progresses through its lifecycle.
The source of funds used for the payout (e.g., 'OFFCHAIN' for wallet balance, 'ONCHAIN' for blockchain deposit).
The crypto asset being converted (e.g., 'USDT', 'BTC', 'USDC').
The blockchain network for the transaction (e.g., 'CHAIN_TYPE_ETHEREUM', 'CHAIN_TYPE_BITCOIN').
The target fiat currency code (e.g., 'GHS', 'NGN').
The original crypto amount provided in the quote request.
The exact amount of fiat the recipient will receive after conversion.
The equivalent amount in satoshis for the requested crypto amount.
The equivalent BTC amount for the requested crypto amount.
The fee charged for this payout in the from_asset currency.
Contains the conversion rate details: 'rate' (crypto to fiat), 'btc_rate' (BTC to fiat), and 'currency'.
Your unique reference string for this quote.
Two-letter ISO country code for the destination.
Timestamp indicating when this quote expires. After this time, the quote must be re-generated.
Timestamp when the quote was created.
Initialize Payout
Locks the quote, attaches a beneficiary, and moves the payout to INITIATED. The beneficiary object varies by destination_type and country — call GET /api/payouts/supported-countries/:country (and, for bank rails, GET /api/payouts/banks/:countryCode + Account Lookup) to build a valid shape.
Initialize Payout - Path Parameters
The ID of the quote returned by Create Payouts Quote (e.g. 'QT_100003'). Must not be expired.
Initialize Payout - Request Body
The quote you're initializing. Must match the :quoteId path parameter.
Client-generated unique identifier for this payout. Reused on Finalize for idempotency and reconciliation.
Short reason code for the payment (e.g. 'salary', 'vendor_payment', 'family_support'). Some corridors require a value from a fixed list — check Get Country Details.
HTTPS URL that will receive payout lifecycle webhooks (completed, failed).
Recipient details. Shape depends on destination_type (bank, mobile_money, swift). For SWIFT, populate the bank fields, a nested beneficiary address, and a nested sender identity.
Rail selector: 'bank', 'mobile_money', or 'swift'.
Two-letter ISO country code of the destination account.
Name on the destination account. Use the value returned by Account Lookup when available.
Bank account number (or IBAN for SWIFT corridors).
Provider code from Get Banks. Required for 'bank' and 'mobile_money' destination types.
BIC/SWIFT code of the destination bank. Required when destination_type is 'swift'.
Display name of the destination bank. Required for SWIFT.
Physical address of the destination bank branch. All required for SWIFT.
Regulator-visible reason code (e.g. 'salary_payment', 'family_support'). Required for SWIFT.
Physical address of the recipient (country, city, post_code, address). Required for SWIFT.
Identity of the sender. type is 'business' or 'individual'. Business senders provide registration_number; individual senders provide date_of_birth and country_of_birth.
Initialize Payout - Response
Top-level flag indicating whether the request was processed successfully.
Human-readable status message.
The initialized payout record.
Unique identifier for this payout. Pass it as :id to GET /api/payouts/:id or as the path param on Finalize is keyed off quote_id (see Finalize).
The quote that was locked (echoed from the request).
Lifecycle state. 'INITIATED' after a successful initialize; transitions through processing states to 'COMPLETED' or 'FAILED' after Finalize.
Source of funds (from the original quote). 'SOURCE_UNSET' when source was not explicitly set.
Crypto asset being debited (e.g. 'USDT', 'USDC', 'BTC').
Destination fiat currency (e.g. 'GHS', 'NGN').
Crypto amount being sent, as a decimal string in from_asset units.
Fiat amount the beneficiary will receive after conversion.
Equivalent amount expressed in BTC for internal pricing.
Equivalent amount expressed in satoshis.
Total fees applied to the payout, as a decimal string in the source asset.
Total fees expressed in cents / smallest fiat unit.
Locked FX details: rate (from_asset → to_currency), btc_rate (for BTC pricing), currency (display).
The full beneficiary object echoed back from the request for auditability.
Reason code provided on the request.
Reference provided on the request.
RFC 3339 / ISO 8601 timestamp. Call Finalize before this time or re-request a quote.
Set once the payout is fully persisted downstream. May be null immediately after initialize.
Request identifier for log correlation and support.
Top-level RFC 3339 / ISO 8601 server timestamp of when the response was generated (UTC).
Initialize returns data.payout.expires_at. You must call POST /api/payouts/:quoteId/finalize before that timestamp — if it passes, re-run the quote and initialize flow to lock a fresh rate.
Finalize Payout
Finalizes a payout after the deposit has been confirmed. No request body is required — simply call this endpoint with the quoteId path parameter.
Finalize Payout - Path Parameters
The ID of the quote to finalize.
Finalize Payout Response
The response echoes the same data.payout shape as Initialize, with a few settlement-specific additions once the rail has accepted the transfer.
Transitions from 'INITIATED' to 'PENDING' on finalize, then on to 'COMPLETED' or 'FAILED' once the rail settles. Watch the webhook for the terminal state.
Populated from the quote (e.g. 'OFFCHAIN', 'ONCHAIN'). 'SOURCE_UNSET' is replaced with the real source at finalize.
The company the payout is debited from (populated at finalize).
Settlement amount in cents / smallest fiat unit.
Echoed from the initialize request — URL that will receive lifecycle webhooks.
Identifier returned by the downstream rail (e.g. SWIFT provider / bank). Use it for reconciliation with the provider.
Destination country (populated at finalize, e.g. 'GH').
Timestamps of each milestone in the payout's journey: quote_at, initialized_at, and (on completion) finalized_at.
When the quote was created.
When the beneficiary was attached and the payout was initialized.
Now populated (not null) — the payout has been persisted through the finalize pipeline.
All other fields (id, quote_id, from_asset, to_currency, amount, settlement_amount, btc_amount, sat_amount, fees, cent_fees, nested exchange_rate, echoed beneficiary, reference, payment_reason, expires_at) use the same shape as the Initialize response — refer to that section for per-field explanations.