Skip to main content
All events share one envelope. See Webhooks for registration, signature verification, and retries.

Payout events

All eight fire today. payout.successful, payout.failed, and payout.expired are terminal — nothing further arrives for that payout, except payout.refunded and the refund.* family after a failure.

Refund events

All four fire today.
Refund events carry a payout snapshot. data.object is "payout" and data.id is the payout ID, not the refund ID. There is no refund object in the payload and no refund amount in it.Distinguish them by event_type, then call GET /v1/payouts/{data.id}/refunds for the amounts, the destination, and the refund’s own status. Do not read data.status as the refund’s status — it is the payout’s.

Not currently emitted

These types are defined in the contract and reserved, but nothing emits them yet. Do not build logic that waits on one: inflow.received, inflow.matched, outflow.dispatched, outflow.successful, outflow.failed The information is available on the payout events and by reading /v1/inflows and /v1/payouts/{id}/outflows directly.

Payload

The snapshot is the same for every event type — only status and the timestamps differ.
payment_instruction is the payout’s current instruction, carried on every event that has one — so payout.pending_payment alone is enough to show the sender where to pay, with no follow-up call. It is null only on payout.created, before the instruction has been generated. account_unique inside payment_instruction is our receiving address or virtual account — where the merchant settles — not the beneficiary’s account. After settlement the same object records what was paid: payment_status becomes PAID and paid_at is set. The beneficiary appears as destination_account_name plus destination_account_unique_masked (last 4 only). Once name enquiry is enabled, the name is the bank-confirmed one, which can differ from the name you supplied — that difference is worth logging on your side.

What the payload does not contain

Only destination_account_unique_masked is sent — the last 4 digits, enough to recognise the beneficiary in an alert or a support thread, not enough to pay them.Every payload is stored verbatim in the delivery log, which is readable via GET /v1/webhooks/deliveries and kept indefinitely. A full account number there would be unprotected PII at rest, so it stays out. You already hold the full value from your own create request — correlate on data.id or merchant_reference.
Not included. Read status_timeline from GET /v1/payouts/{id} when you need the history rather than the current state.
Not included, even on refund.* events. Use GET /v1/payouts/{id}/refunds.

Handling them well

Ignore unrecognised event_type values rather than erroring. New types ship without a version bump, and a handler that throws on the unfamiliar starts failing deliveries — and burning retries — the day one appears.
Deliveries can arrive out of order. Treat data.status as the truth and ignore an event that would move your record backwards from where it already is.