POST to each URL you subscribe with Create a Webhook. Payout events cover payouts your backend sends and cash outs from the widget, in both products. Transaction events cover value moving inside ZBD, for programs where ZBD holds balances.
Payout events
Transaction events
The payload carries
transaction_id, type, reference_id, project_id, and the transaction’s movements, in the same shape as Get a Transaction. It’s signed the same way as payout events.
Payout payload
string
Unique ID for the event. Deduplicate on it, since a retry can deliver the same event twice.
string
Which event this is, from the table above.
string
When it happened, as an ISO 8601 timestamp.
string
The payout the event is about.
string
api for payouts your backend sent and widget for cash outs.string
The user being paid.
string | null
The payout’s project, if it has one.
string | null
Your own ID for the payout, if you sent one. Use it to match the event to your records.
integer
The payout amount, in the currency’s smallest unit.
string
Currency code for the amounts.
integer
The fee for the payment method, in the smallest unit. By default it comes out of
amount.integer
What the user receives, in the smallest unit. By default this is
amount minus fee_amount.string
Why the payout failed or came back. Only on
FAILED and RETURNED.string
A readable version of
reason_code. Only on FAILED and RETURNED.boolean
true once the amount is back in your funding account. Only on FAILED and RETURNED.Verifying a webhook
Every webhook is signed. TheX-ZBD-Signature header carries the signature, and X-ZBD-Signature-Key-Id names the key that signed it.
- Fetch ZBD’s public keys from
GET /api/v1/webhooks/jwks.jsonand cache them. - Pick the key that matches
X-ZBD-Signature-Key-Id. - Check the signature over the raw request body before you act on the event.
Handling deliveries
- Respond quickly with a
2xx. Do the work after you respond. ZBD retries deliveries that fail or time out. - Deduplicate on
event_id. A retry can deliver the same event more than once. - Don’t rely on order. Use
occurred_at, and the payout’s current status from Get a Payout if you need to be sure.