Skip to content

Event catalogue

Every event Wajub emits, what triggers it, and what arrives with it.

Konsole offers 60 event types to subscribe to. 57 of them actually reach an endpoint, and the three that do not are named at the bottom of this page. They all arrive in the same envelope, described in Webhooks; only data changes from one to the next, and data is always the full resource, identical to what the REST endpoint for that resource returns.

This page is the complete list, grouped by what the event is about, with the thing worth doing when it lands.

How an endpoint decides to fire

Subscription matching is a plain string comparison against the events array you registered. Three cases, and no fourth.

Your events arrayWhat you receive
["payment.succeeded", "refund.failed"]Exactly those two types
["*"]Every payment, refund, transfer, customer, dispute, invoice, link, account, balance, fee and endpoint event
[]The same as ["*"]

Prefix wildcards do not exist. payment.* is a literal string that no event is ever equal to. If you want everything under one resource, list its types.

How the names are built

resource.verb, verb in the past tense, both lowercase. The verbs are stable across resources, which makes the list shorter to remember than it looks.

VerbMeaning
createdThe resource now exists
updatedA field changed
deletedThe resource was removed, or anonymised
processingHanded to a provider, outcome unknown
succeededTerminal, it worked
failedTerminal, it did not
cancelledTerminal, stopped on purpose
expiredTerminal, the window closed

Three spellings cost people an afternoon: it is succeeded, never completed or complete; it is cancelled with two l; and Sync uses deauthorized with a z while everything else in the platform is British spelling.

Payments

The six states a payment moves through. Only payment.succeeded means money.

EventFires whenWhat to do
payment.createdThe payment exists and is waiting for the payerNothing, record the id
payment.processingThe operator accepted the debit requestShow a pending state
payment.succeededThe funds are capturedFulfil the order here
payment.failedThe operator or the card issuer declinedRelease the reservation, tell the customer
payment.cancelledThe payer refused, or you called DELETE /payments/{id}Release the reservation
payment.expiredThe payment window closed before confirmationRelease the reservation

payment.failed carries failure_reason in data. The field is absent, not null, when there is no reason to give.

Payment splits

Emitted when a single payment is debited in several instalments, using split_count or split_amounts on POST /payments.

EventFires when
payment.split.processingOne instalment was sent to the operator
payment.split.succeededThat instalment cleared
payment.split.failedThat instalment was declined

data is the full payment, plus a split object naming which instalment this was.

The split object added to the payment payload
"split": {
  "id": "splt_9mWvL2xR7tB5nY4hC6dF",
  "split_number": 2,
  "amount": 500000,
  "currency": "XAF",
  "split_currency": "XAF",
  "status": "succeeded",
  "reference": "order-4172-2",
  "provider_reference": "MP260115.1032.B41209",
  "initiated_at": "2026-01-15T10:32:04+00:00",
  "succeeded_at": "2026-01-15T10:32:41+00:00"
}

The parent payment reaches payment.succeeded only once every instalment has succeeded. Counting payment.split.succeeded yourself to decide the order is complete is a way to ship an order that is half paid.

Refunds

EventFires whenWhat to do
refund.createdThe refund was accepted for processingRecord it, do not credit yet
refund.processingThe provider is executing itNothing
refund.succeededThe money left your balanceCredit the customer here
refund.failedThe provider rejected itRead failure_reason, decide manually
refund.cancelledThe refund was stopped before executionNothing

data.transaction is the id of the payment being refunded, as a string, not a nested object.

Transfers

Payouts out of your balance, whether to a mobile money wallet, a bank account or a card.

EventFires whenWhat to do
transfer.createdThe transfer was accepted and debited your available balanceRecord the id
transfer.processingHanded to the payout providerNothing
transfer.succeededThe beneficiary was paidMark the payout settled
transfer.failedThe provider could not payRead failure_reason, the amount returns to your balance

Customers

EventFires when
customer.createdA customer record was created, including implicitly by a payment
customer.updatedAny field on the customer changed
customer.deletedDELETE /customers/{id} ran, and the record was anonymised

The payload of customer.deleted is the customer after anonymisation: the name reads Deleted User <pseudonym>, and the email, phone and date of birth are gone. If you need the original values for your own records, you must have kept them.

Beneficiaries

EventFires when
beneficiary.createdA payout destination was saved
beneficiary.updatedIts details changed
beneficiary.deletedIt was removed
EventFires when
link.createdA payment link was created
link.updatedIts amount, expiry or state changed
link.deletedIt was deleted

A payment made through a link emits payment.*, not link.*. The link events are about the link object itself.

link.expired appears in the Konsole picker but belongs to the per link webhook system, not to your account endpoints. Subscribing to it on an account endpoint produces nothing.

Invoices

EventFires when
invoice.createdAn invoice was issued
invoice.updatedA line, a status or a due date changed
invoice.deletedIt was deleted

There is no `invoice.paid`

When an invoice is settled, what fires is payment.succeeded for the payment that settled it, followed by invoice.updated when the invoice status changes. Reconcile on the payment, and use the invoice reference you put in the payment metadata to connect the two.

Disputes

Chargebacks and complaints. These are the events with the shortest deadlines attached to them.

EventFires whenWhat to do
dispute.createdA dispute was opened against a paymentStart gathering evidence
dispute.updatedA field changed, or a message was addedRead data.messages
dispute.closedThe dispute ended without a winner being recordedNothing
dispute.wonThe decision went your wayKeep the funds
dispute.lostThe decision went against youThe amount is debited
dispute.deletedThe dispute record was removedNothing

Accounts, for Sync platforms

These describe a connected merchant on a Sync platform, not your own account.

EventFires when
account.createdA merchant connected to your platform
account.updatedTheir details or pricing changed
account.deauthorizedThe connection ended, by deletion or by the merchant revoking it
account.payment_activatedThe merchant can now take live payments
account.payment_suspendedTheir ability to take payments was suspended

account.deauthorized fires for both deletion and revocation. There is no separate account.deleted.

Balance and fees

EventFires whenPayload
balance.updatedYour balance movedThe movement, not the new totals
fee.chargedWajub debited a fee from youThe fee
fee.receivedA Sync platform collected its fee on a connected merchantThe fee, plus account

balance.updated sends the movement itself, which is what you want for a ledger.

A balance.updated payload
{
"currency": "XAF",
"amount": 24250,
"direction": "credit",
"balance_type": "available",
"balance_before": 1840000,
"balance_after": 1864250,
"reason": "payment_settlement",
"sandbox": false
}

The eight figures GET /balance returns are not in this payload. Call the endpoint when you need the totals.

Compliance

Emitted while your account is being verified, and whenever your file changes state afterwards.

EventFires when
compliance.submittedYour verification file was submitted for review
compliance.verifiedThe account is verified, live money becomes possible
compliance.rejectedThe file was refused
compliance.changes_requestedA reviewer needs something else from you
compliance.inquiry.createdA specific question was raised on your file
compliance.inquiry.resolvedThat question was closed

For a platform onboarding merchants, compliance.verified is the signal that a connected account may start taking live payments. Do not infer it from anything else.

Providers

Emitted when the set of rails available to your account changes.

EventFires when
provider.activatedA provider was enabled on your account
provider.deactivatedA provider was disabled
provider.channel_activatedOne channel of a provider became available
provider.channel_deactivatedOne channel was withdrawn

Worth subscribing to if you cache the channel list rather than calling GET /channels on every checkout.

Webhook endpoints

EventFires when
webhook_endpoint.createdAn endpoint was registered
webhook_endpoint.updatedIts URL, subscriptions or state changed
webhook_endpoint.deletedIt was removed

Useful on a platform account where several people can change the configuration. Note that the endpoint receiving this event may be the one that was just changed.

What data actually contains

data is the resource serialised by the same code that serves the REST endpoint, with two consequences worth knowing.

Null fields are removed, not sent as null. A payment with no description has no description key at all. Read with a default, never assume the key exists.

The payload is always in the latest API version. Version pinning applies to your API calls, not to webhook deliveries: the envelope's api_version is the platform's current version at the moment the event was recorded, and the body is shaped for that version. Pinning your account to 2026-08-01 does not change what your endpoint receives.

A complete payment.succeeded delivery
{
"id": "evt_aio5DpN577tNU2vOxdmuZGhT",
"event": "payment.succeeded",
"livemode": true,
"created": "2026-01-15T10:32:41+00:00",
"api_version": "2026-09-01",
"pending_webhooks": 1,
"request": {
"id": null,
"idempotency_key": "idem_kZ3qP8mWvL2xR7tB5nY4hC6dF9jS1aG0"
},
"data": {
"id": "trx_CSUGajfv9xh0XQ5wu2lx",
"reference": "order-4172",
"amount": 25000,
"amount_paid": 25000,
"currency": "XAF",
"status": "succeeded",
"channel": "cm.mtn",
"payment_method": {
"channel": "cm.mtn",
"account": "+237670000000"
},
"customer": {
"id": "cus_4tRb3nP8sZcXvK2mQ9wL",
"name": "Amina Nkem",
"email": "amina@example.com",
"phone": "+237670000000"
},
"sandbox": false,
"credited_at": "2026-01-15T10:32:41+00:00",
"created_at": "2026-01-15T10:30:00+00:00",
"updated_at": "2026-01-15T10:32:41+00:00"
}
}

Events people look for and do not find

You expectedWhat actually exists
payment.refundedrefund.succeeded
payment.partially_refundedrefund.succeeded, compare data.amount to the payment
invoice.paidpayment.succeeded, then invoice.updated
transfer.reviewNothing. Read the transfer status
payout.*transfer.*, payouts are transfers in the API
subscription.*invoice.*, recurring billing emits invoice events
checkout.session.completedpayment.succeeded
account.deletedaccount.deauthorized
transaction.*Internal checkout telemetry. Never delivered, even to * subscribers

Three types you can subscribe to that never arrive

Konsole lets you tick them. Nothing is ever delivered.

TypeWhy
payment.checkout_page_openedRecorded in the Konsole event log, never dispatched to endpoints
payment.redirected_to_callbackSame, it is a checkout timeline entry
link.expiredEmitted by the per link webhook system, not by account endpoints

The first two are visible in Events, so you can still audit a checkout after the fact. You just cannot be notified of them.

Sandbox and live are separate streams

An endpoint belongs to one environment. A sandbox endpoint only ever receives sandbox events, and a live endpoint only live ones. Two things change in the payload:

  • livemode is false in sandbox and true in live.
  • Event ids are prefixed evt_test_ in sandbox and evt_ in live.

A handler that hardcodes an id length or slices a prefix off will break when it meets the other environment.

Sync platforms receive a copy

When a payment, refund or transfer belongs to a merchant connected through Sync, the event is delivered twice: once to the merchant's own endpoints, and once to the platform's, as a separate event with its own id. The platform's copy carries an extra account object so you know which connected merchant it came from.

What the platform copy adds to data
"account": {
  "id": "acc_7Yh2MpL4tRb3nP8sZcXv",
  "reference": "boutique-akwa"
}

Deduplicate on the event id, not on the payment id: the two copies describe the same payment and carry two different event ids, deliberately.

What did you think of this content?