Skip to main content
Learn how to listen for transactions that happen on your account A webhook is a URL on your server where we send payloads for transaction events. For example, if you implement webhooks, we will immediately notify your server with a deposit.success event once a Lightning payment is received. Whenever you receive a webhook notification from us, return a 200 OK to avoid resending the same event again from our server.
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.
  1. event (string) Webhook event name. ‘payouts.initialized’ indicates the payout was accepted for processing.
  2. event_id (uuid) Unique ID for this webhook delivery. Use it to de-duplicate events on retries.
  3. data.id (uuid) The payout’s internal identifier, the same id returned by Initialize / Finalize and accepted by GET /api/payouts/:id.
  4. data.quote_id (string) The quote this payout was created from, e.g. ‘QT2_21434949’.
  5. data.company_id (uuid) The UUID of the company that owns the payout.
  6. data.reference (string) Your reference for the payout, echoed back for reconciliation.
  7. data.status (string) Outcome carried by this event. On payouts.initialized this is ‘initiated’, or ‘pending_address_deposit’ for onchain funding.
  8. data.from_asset (string) The crypto asset debited, lowercase. For example, ‘btc’, ‘usdt’.
  9. data.to_currency (string) The fiat currency to be paid out, lowercase. For example, ‘ngn’.
  10. data.amount (string)
Amount debited in from_asset.
  1. data.settlement_amount (string)
Amount to be credited to the beneficiary in to_currency.
  1. data.fees (string)
Fee charged for processing the payout, in fee_currency.
  1. data.fee_currency (string)
Currency the fee is denominated in. For example, ‘USD’.
  1. data.source_fee (string)
The source fee for the payout.
  1. data.total_amount (string)
Total to be debited in from_asset.
  1. data.payment_reason (string)
The payment reason you sent on Initialize payout.
  1. data.beneficiary (object)
The destination the funds are headed to. Contains country, a masked account_number (e.g. ‘****6789’), and bank_code, bank_name, and account_name when they were set.
  1. data.created_at (timestamp)
When the payout record was created (ISO 8601, UTC).
  1. data.updated_at (timestamp)
When the payout record was last updated (ISO 8601, UTC).
  1. data.customer_id (uuid)
The customer linked to the payout. Present only when you set 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:
  1. data.status (string) ‘success’ on this event, rather than ‘initiated’.
  2. data.completed_at (timestamp)
When the payout reached its terminal state. Here, when settlement completed (ISO 8601, UTC). Absent while the payout is still in flight.

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:
  1. data.status (string) ‘expired’ on this event.
  2. data.completed_at (timestamp) When the payout reached its terminal state. Here, when it expired (ISO 8601, UTC).
  3. data.payment_reason (string)
The payment_reason you supplied on Initialize, echoed back. For example, ‘Crypto offramp’. Present when one was set.

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:
  1. data.status (string) Always failed.
  2. data.failure_reason (string) Why the payout failed, for example The 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.