Payout events notify you as each recipient's crypto payout moves through its lifecycle. They are emitted when a payout order has a callback_url (see Subscribing).
All payout events use the standard event envelope. This page documents the reference shared by every payout event: the identifier set, the status values, and the data snapshot shape. Each individual event is documented on its own page:
payout.quote_createdpayout.quote_confirmedpayout.quote_canceledpayout.status_changedpayout.terminal_state
Identifiers
Payout events carry these domain identifiers in the envelope:
| Field | Type | Value |
|---|---|---|
payout_order_uuid | String | UUID of the payout order this event belongs to. Stable across retries. |
recipient_email | String | Email of the recipient whose payout this event describes. |
external_send_id | String | Identifier for the underlying crypto send. A single recipient can produce multiple external_send_ids if a quote expires and is reopened — treat each one as a separate lifecycle. |
Status values
The envelope status field on a payout event is one of:
status | Meaning |
|---|---|
in_progress | The send request has been accepted. No funds have moved yet. |
processing | The send is being processed. An FX exchange may be in flight or the chain broadcast is pending. |
completed | The send is finalized. If tx_hash is present, funds are confirmed on chain. |
failed | The send did not go through. failure_reason carries the cause. |
expired | The send was not actioned within its lifetime window. |
canceled | The send was canceled. No funds moved. |
completed, failed, expired, and canceled are terminal — no further events fire for that external_send_id once a payout.terminal_state event has been sent.
data shape
data shapedata is present on payout.quote_* events and on payout.terminal_state events (it is omitted on payout.status_changed). It carries the full send-request snapshot at the moment the event was generated.
| Field | Type | Notes |
|---|---|---|
id | Integer | Send-request ID. Equals external_send_id parsed as integer. |
status | String | Current status of the underlying send. Mirrors the top-level status. |
purpose | String | Human-readable description of the payout. |
created_at | String | ISO-8601 timestamp when the send request was created. |
input_amount | String | Amount the recipient is sending, in input_currency. |
input_currency | Hash | See Currency object. |
sending_amount | String | Amount the recipient will receive, in sending_currency. |
sending_currency | Hash | See Currency object. |
input_to_sending_rate | String | FX rate used to convert input_amount to sending_amount. "1.0" for same-currency sends. |
balance_debit_amount | String | Amount debited from the merchant's ledger, in balance_debit_currency. |
balance_debit_currency | Hash | See Currency object. |
sending_to_balance_debit_rate | String | FX rate used to convert from sending_currency to balance_debit_currency. |
fees.service_fee | Hash | { amount, currency }. amount is a decimal string; currency follows the Currency object shape. |
fees.conversion_fee | Hash | { amount, currency }. Only present on cross-currency sends. |
ledger_account | Hash | { id, title, status, balance, account_type, currency }. The merchant ledger account funds were debited from. |
beneficiary_payout_setting | Hash | { id, beneficiary_id, created_at, currency, platform, crypto_address, crypto_address_metadata }. The destination wallet for this send. |
blockchain_transactions | Array | Empty [] until the chain broadcast lands. Once populated, each entry is { id, txid, amount, status, network_confirmations, currency }. The txid of the first entry is surfaced at the top level as tx_hash on payout.terminal_state. |
requires_2fa_confirmation | Boolean | Whether the recipient must complete 2FA before the send proceeds. |
Currency object
input_currency, sending_currency, balance_debit_currency, and the currency nested under fees.* / ledger_account / beneficiary_payout_setting all share the same shape:
| Field | Type | Notes |
|---|---|---|
id | Integer | Internal currency ID. |
kind | String | "fiat" or "crypto". |
title | String | Full currency name (e.g. "Ethereum", "USDC"). |
symbol | String | Ticker symbol (e.g. "ETH", "USDC"). |
enabled | Boolean | Whether the currency is currently enabled for new sends. |
disabled_message | String (optional) | Reason a disabled currency is unavailable. null when enabled: true. |
BlockchainTransaction object
Entries in data.blockchain_transactions[] describe individual on-chain transactions backing the send. The array is empty until the chain broadcast lands; once populated, the txid of the first entry is surfaced at the top level as tx_hash on payout.terminal_state.
| Field | Type | Notes |
|---|---|---|
id | Integer | Internal transaction ID. |
txid | String | On-chain transaction hash. |
amount | String | Decimal amount transferred in this transaction. |
status | String | Transaction status (e.g. "confirmed"). |
network_confirmations | Integer | Number of confirmations the transaction has received. |
currency | Hash | A thinner variant of the Currency object: { id, title, symbol, platform: { id, title } }. The nested platform identifies the chain the transaction was broadcast on (e.g. "Base", "Solana", "Ethereum"). |
Example:
{
"id": 7000001,
"txid": "0x1111111111111111111111111111111111111111111111111111111111111111",
"amount": "12.0",
"status": "confirmed",
"network_confirmations": 1,
"currency": {
"id": 113,
"title": "USDC",
"symbol": "USDC",
"platform": {
"id": 42,
"title": "Base"
}
}
}
Decimal amounts are stringsAll amounts are decimal strings — parse with your language's arbitrary-precision decimal type, not floats. Additional fields may appear in
data; treat unknown fields as informational.