A mobile wallet payment is not settled when our API responds to you. The customer still has to
approve it on their handset — by entering their MPIN in a USSD prompt or approving in their wallet
app — and that can take seconds or minutes.So a successful response to POST /Payment/deposit means the request was accepted, not that
money moved. The status you receive is Processing. The terminal outcome arrives later, and the
webhook is how you learn it.
Do not treat a successful HTTP response as a completed payment. Fulfil orders on the webhook, or on
a status query — never on the accept response alone.
Register an HTTPS endpoint in the merchant portal. You will be shown a signing secret beginning
whsec_ exactly once — store it somewhere your application can read it, and treat it like a
password.
Every delivery carries a signature computed with HMAC-SHA256 over your endpoint’s secret. Always
verify it before acting on a webhook. An unverified webhook endpoint is a URL anyone can post
payment notifications to.
We recommend rejecting deliveries whose timestamp is more than 300 seconds from your own clock.
The timestamp is part of the signed string, so an attacker cannot move it forward without
invalidating the signature.
The legacy X-Swich-Signature header contains only an HMAC over the payload, with no timestamp — so
a captured request replays indefinitely. Both headers are sent during the transition period.Migrate to X-Swich-Signature-V2. The legacy header will be withdrawn on a date we will announce
in advance. Until then, no action is required for existing integrations to keep working.
It identifies the server-side operation that produced the delivery. If a webhook looks wrong to you,
send us the TraceId — it is the fastest route to the exact processing trace on our side. The same
identifier appears as traceId on synchronous API responses and on status-inquiry results, so a
single payment can be followed end to end.
data field names are PascalCase (CurrentStatus, TraceId), while the envelope around it is
lowercase (id, type, created, livemode). A parser configured for camelCase will silently read
nulls out of data.
Return a 2xx status as soon as you have stored the event. Do the work afterwards, out of band.If you return a non-2xx or time out, we retry with exponential backoff. Retries reuse the same
X-Swich-Event-Id.
You will occasionally receive the same event twice. That is a normal property of at-least-once
delivery, not a fault. A network failure after you responded — but before we recorded it — produces a
redelivery.Deduplicate on X-Swich-Event-Id. Record the ids you have processed and ignore repeats. Crediting a
customer twice because a webhook arrived twice is the failure mode this prevents.
Deliveries are not ordered. A completed event can arrive before a pending one for the same
transaction.Always treat the transaction status inside the payload as authoritative, and never move a transaction
backwards out of a terminal state.Order by the envelope’s created field (Unix seconds) and keep the newest. Discard any delivery whose
created is older than the one you have already applied.
The webhook is authoritative over the synchronous API response, not the other way round. A payout
can be confirmed by the provider while the original POST /Payment/withdraw call is still open, so a
later webhook saying Completed supersedes a synchronous response that said Failed or Processing.
If the two ever disagree, believe the webhook — or confirm with status inquiry.
Webhooks are a notification mechanism, not a guarantee. Endpoints go down, DNS breaks, and deploys
happen mid-delivery.For any transaction where you have not received a terminal event within a few minutes, query
GET /Transaction/{reference} and use that answer. Reconcile on a schedule rather than assuming
delivery.