Payout Webhook Events
Account-level webhook events for prefund payouts. Register a PAYOUT-type endpoint from the dashboard (Devtools → Webhooks).
Registration, signature verification, retries, and URL rules: Webhooks.
Events
| Event | Fires when |
|---|---|
payout.created | Payout created (INITIATED) |
payout.updated | Status changes (SETTLED, REVERSED, RETURNED) |
payout.prefund_completed | A prefund top-up settled and is spendable |
payout.prefund_reversed | The bank reversed a settled top-up |
payout.prefund_recredited | A reversed top-up was re-confirmed and credited back |
payout.deposit.updated | A deposit to a beneficiary's trigger address is credited, or is retried |
payout.withdrawal.updated | A transfer produced by such a deposit changes status |
The last two belong to paying a beneficiary from a deposit. They are the only notification for it, because you never create a request to start one. Transfers made this way do not appear in payout.created or payout.updated.
Envelope
{
"eventId": "payout.updated:b0e6c2f4-...:SETTLED",
"event": "payout.updated",
"webhookType": "PAYOUT",
"timestamp": "2026-07-16T09:31:05.000Z",
"data": {}
}| Field | Description |
|---|---|
eventId | Unique — use for idempotency |
event | Event name |
webhookType | PAYOUT for these events |
timestamp | ISO 8601 |
data | Event-specific payload |
Event data
payout.created / payout.updated
{
"payoutId": "b0e6c2f4-...",
"status": "SETTLED",
"type": "STANDARD",
"amount": "100000",
"fee": "1000",
"netAmount": "99000",
"beneficiaryId": "7c1a3e88-...",
"bankAccountId": null,
"idempotencyKey": "6f9619ff-8b86-d011-b42d-00cf4fc964ff",
"statusReason": null
}Fields match the REST Payout object, but data omits reference, createdAt, and submittedAt. Call GET /v1/payouts/{id} only when you need the full record or must reconcile a missed event.
payout.prefund_completed / payout.prefund_reversed / payout.prefund_recredited
{
"depositId": "3f8c1d20-...",
"amount": "5000000"
}| Field | Description |
|---|---|
depositId | The top-up this event is about |
amount | Credited (or reversed) amount, a string in sen |
amount is the movement, not the resulting balance. Read GET /v1/payout/prefund/balance after the event when you need the current balance.
payout.deposit.updated
{
"id": "5e9d0273-...",
"txHash": "0x5d5355...103ee3",
"logIndex": 12,
"chainId": 1,
"tokenId": "a71c4e08-...",
"amount": "100000",
"from": "0x9a3f7c21b8e04d6f5a19c2e70b48d3f61a5e9d02",
"status": "COMPLETED",
"confirmations": 24,
"triggerAddress": "0x7c1a3e889d2b4f618a441f0b6d3c9a5588ab01cd",
"destination": { "type": "BENEFICIARY", "id": "7c1a3e88-...", "name": "ADA LOVELACE" },
"result": { "status": "FAILED", "statusReason": "sender_not_allowed", "withdrawal": null },
"createdAt": "2026-08-07T09:30:44.000Z",
"updatedAt": "2026-08-07T09:34:22.000Z"
}Fields match the REST record — see GET /v1/payouts/deposits/{id} for the full table and the deposit status reason values.
The event arrives once the deposit is credited and the transfer it triggered has been decided, so one event tells you the tokens arrived and what happened next. A deposit refused for a reason you can fix says so here, and can be retried.
payout.withdrawal.updated
{
"withdrawalId": "c4a80f13-...",
"status": "COMPLETED",
"statusReason": null,
"amount": "100000",
"refId": "FW-20260807-0001",
"reference": "Invoice 4471",
"destination": { "type": "BENEFICIARY", "id": "7c1a3e88-...", "name": "ADA LOVELACE" },
"depositId": "5e9d0273-...",
"createdAt": "2026-08-07T09:31:05.000Z",
"updatedAt": "2026-08-07T09:34:22.000Z"
}| Field | Description |
|---|---|
withdrawalId | The transfer this event is about |
status | PENDING, PROCESSING, COMPLETED, REJECTED, FAILED, or CANCELLED |
statusReason | Set only on REJECTED, FAILED, and CANCELLED |
amount | A string in sen |
refId | Bank reference |
reference | Your own reference, where one was set |
destination | The beneficiary paid |
depositId | The deposit that triggered it — join the two events on this |
These transfers are separate from prefund payouts: withdrawalId is not a payoutId, and reading it with GET /v1/payouts/{id} returns 404.
payout.prefund_reversed is the one to alert on. A reversal the balance can't cover leaves you owing BLOX and suspends payouts on your account — every subsequent create returns 403 FEATURE_DISABLED until it is settled.
Each fires at most once per top-up, so eventId is <event>:<depositId>. A single top-up can legitimately produce all three, in that order, if the bank confirms it, reverses it, then re-confirms it.