Signature verification, retries, source IPs, and local testing work the same way for every Bitnob Business API webhook. They’re covered once, on Webhooks.
Payout webhooks
Payout webhooks track a payout created through the payouts API (quote → initialize → finalize) as it moves toward settlement. Every event carries the payout record itself, so the field names match the payouts API response.Payout initialized
Fired when a payout has been initialized against a quote and accepted for processing. Settlement has not happened yet: wait for payouts.withdrawal.success before treating the funds as delivered.data.status on payout webhooks is the event outcome, lowercase (initiated, pending_address_deposit, processing, success, expired, failed). It is not the payout record’s lifecycle status returned by Get Payout, which is uppercase and uses a different vocabulary (QUOTE → INITIATED → PENDING → PROCESSING → SUCCESS / FAILED). Check the event field to decide how to handle each webhook, not data.status.-
event(string) Webhook event name. ‘payouts.initialized’ indicates the payout was accepted for processing. -
event_id(uuid) Unique ID for this webhook delivery. Use it to de-duplicate events on retries. -
data.id(uuid) The payout’s internal identifier, the same id returned by Initialize / Finalize and accepted by GET /api/payouts/:id. -
data.quote_id(string) The quote this payout was created from, e.g. ‘QT2_21434949’. -
data.company_id(uuid) The UUID of the company that owns the payout. -
data.reference(string) Your reference for the payout, echoed back for reconciliation. -
data.status(string) Outcome carried by this event. On payouts.initialized this is ‘initiated’, or ‘pending_address_deposit’ for onchain funding. -
data.from_asset(string) The crypto asset debited, lowercase. For example, ‘btc’, ‘usdt’. -
data.to_currency(string) The fiat currency to be paid out, lowercase. For example, ‘ngn’. -
data.amount(string)
data.settlement_amount(string)
data.fees(string)
fee_currency.
data.fee_currency(string)
data.source_fee(string)
data.total_amount(string)
data.payment_reason(string)
data.beneficiary(object)
country, a masked account_number (e.g. ‘****6789’), and bank_code, bank_name, and account_name when they were set.
data.created_at(timestamp)
data.updated_at(timestamp)
data.customer_id(uuid)
customer_id on Initialize payout.
Payout processing
Fired when Bitnob starts sending the payout to the settlement rail. This is an in-flight update, not a terminal state: wait for payouts.withdrawal.success before treating the funds as delivered. Same fields as Payout initialized. The payload carries the same fields as Payout initialized. Refer there for the per-field explanations. One difference:string
‘processing’ on this event.
Payout withdrawal successful
Fired when the payout has settled to the beneficiary. This is the event to act on when crediting an order or marking a transfer complete. Same fields as Payout initialized. The payload carries the same fields as Payout initialized. Refer there for the per-field explanations. Two differences:-
data.status(string) ‘success’ on this event, rather than ‘initiated’. -
data.completed_at(timestamp)
Payout withdrawal expired
Fired when a payout was not completed before its quote expired. No funds were settled to the beneficiary, to retry, create a fresh quote and initialize again. Same fields as Payout initialized. The payload carries the same fields as Payout initialized. Refer there for the per-field explanations. Differences:-
data.status(string) ‘expired’ on this event. -
data.completed_at(timestamp) When the payout reached its terminal state. Here, when it expired (ISO 8601, UTC). -
data.payment_reason(string)
Payout withdrawal failed
Fired when a payout fails. Event name:payouts.withdrawal.failed.
The payload carries the same fields as Payout initialized, with these differences:
-
data.status(string) Alwaysfailed. -
data.failure_reason(string) Why the payout failed, for exampleThe payout could not be delivered.The text can change, so show it to the user and don’t match on it. When we held funds for the payout, it also says they were returned.