Webhooks
Webhook Events
The full event catalogue, payload shapes, and when each event fires.
Every event delivers the same envelope:
{
"id": "01M2S18...",
"event_type": "payment.completed",
"event_key": "payment.completed:<transaction_id>",
"occurred_at": "2026-09-18T01:13:59Z",
"data": {}
}event_key is unique per event: dedupe on it, not id. data carries the
transaction payload at event time.
Event catalogue
| Event | Fires when | Key data fields |
|---|---|---|
payment.completed | A payment settles | transaction_id, amount_minor, currency, method, status |
payment.failed | A payment fails | + failure.code, failure.stage |
transfer.completed | A payout settles | transaction_id, amount_minor, currency, beneficiary_id, status |
transfer.failed | A payout fails | + failure.code, failure.stage |
exchange.completed | An exchange settles | transaction_id, from_amount_minor, to_amount_minor, from_currency, to_currency |
wallet.funded | An inbound funding credit posts to a wallet | transaction_id, wallet_id, amount_minor, currency, method |
transaction.updated | Any status transition on a transaction | transaction_id, status, previous_status |
Subscribing to events
Pass events when creating the subscription: an array of event types.
transaction.updated subscribes you to all transitions; the typed events
(payment.completed, transfer.failed, etc.) subscribe you to specific
outcomes.
Success payload
{
"id": "01M2S18...",
"event_type": "payment.completed",
"event_key": "payment.completed:01M2S17G4A0N9MDMXYSCCX8SPS",
"occurred_at": "2026-09-18T01:13:59Z",
"data": {
"transaction_id": "01M2S17G4A0N9MDMXYSCCX8SPS",
"status": "completed",
"amount_minor": 101000,
"currency": "NGN",
"method": "card",
"reference": "order-8842"
}
}Failure payload
Failed events include the failure details:
{
"id": "01M2S18...",
"event_type": "transfer.failed",
"event_key": "transfer.failed:01M2S18...",
"occurred_at": "2026-09-18T01:15:00Z",
"data": {
"transaction_id": "01M2S18...",
"status": "failed",
"failure": {
"code": "COMPLIANCE_DENIED",
"message": "This transfer is not permitted.",
"stage": "compliance"
}
}
}failure.code is machine-readable and stable. failure.stage tells you
where in the pipeline the transaction stopped.