The verdict in three sentences
A payment webhook can arrive twice, late, or out of order — that is normal, and your system must assume it. The only reliable defense is an idempotency key (the provider transaction_id) stored in an event table, plus a daily reconciliation window that recovers lost callbacks. Without these two guardrails, you will eventually get a double debit or a validated order with no matching payment.
Why a webhook replays (and what it costs)
Paystack and mobile money gateways keep resending a callback until they receive a 200 OK from your server. A timeout on your side, a deploy mid-request, a load spike — and the same event fires again. Without deduplication, each redelivery re-runs your business logic: crediting the merchant balance, sending the SMS, validating the order.
| 2026 incident (order of magnitude) | Observed frequency | Consequence without idempotency |
|---|---|---|
| Webhook delivered twice | 0.3 to 1.5 % of payments | Double credit / double order |
| Late webhook (> 5 min) | 1 to 3 % | Order wrongly marked "unpaid" |
| Deferred redelivery | up to 24 h | End-of-day cash gap |
| Callback never received | 0.1 to 0.5 % | Payment taken, order stuck |
| Invalid / forged signature | rare but critical | Fraud if unchecked |
The typical gap found in daily reconciliation, before automation, sits between 0.2 and 0.8 % of volume — roughly 16,000 to 64,000 FCFA for 8,000,000 FCFA collected.
The technical pattern: signature + event table + retry
Three layers, in order. First, verify the HMAC signature in the header before any processing — an unsigned callback is dropped. Then, insert the event with transaction_id as a unique constraint: if the insert fails (duplicate), respond 200 without replaying the logic. Finally, an exponential retry on outbound actions (merchant payouts, notifications): 3 attempts, 5 s to 15 min.
| Parameter | Recommended 2026 value | Reason |
|---|---|---|
| Idempotency key | provider + transaction_id | Unique per provider |
| Success response | Immediate 200, async processing | Avoids re-trigger |
| Outbound retry attempts | 3 | Beyond that, manual alert |
| Backoff | 5 s → 1 min → 15 min | Absorbs short outages |
| Reconciliation window | Daily (T+1 morning) | Recovers lost callbacks |
| Event table retention | 90 days minimum | Audit and disputes |
Daily reconciliation calls each provider's getStatus API for any transaction still pending beyond 48 h, and compares it with the statement. That is what turns a silent incident into a corrected line.
Need a professional website?
Kolonell builds websites that attract clients, optimized for the Sénégalese market. Free quote in 2 minutes.
Mini case study
Fatou runs an online store in Accra, 900 orders per month, average basket 12,000 FCFA (about 190 GHS-equivalent). One Tuesday, a deploy causes a 4-minute timeout: 7 webhooks are redelivered. Without idempotency, 7 orders would have been credited twice on the merchant side — an 84,000 FCFA gap. With the unique constraint on transaction_id, all 7 redeliveries respond 200 with no effect, and the next-day reconciliation confirms zero gap. Cost of the fix: one indexed column and 20 lines of code.
FAQ
Do I really need to verify the webhook signature? Yes, no exception. An unsigned public endpoint can receive fake "payment success" callbacks. HMAC verification costs a few milliseconds and blocks that fraud entirely.
What about a payment collected whose webhook never arrives? That is reconciliation's job: query getStatus for every pending > 48 h. On 0.1 to 0.5 % of payments, this net recovers orders that would otherwise stay stuck.
Can retry cause a double debit for the customer? No, if retry only covers your outbound actions (merchant payout, SMS), not the customer debit already done by the provider. The debit is unique per transaction_id.
How long should I keep the event table? 90 days minimum, ideally 12 months for disputes. A contested transaction can surface weeks after collection.
Do all providers offer the same webhook reliability? The order of magnitude is comparable (0.3 to 1.5 % duplicates), but redelivery delays vary — up to 24 h under load. The same architecture covers them all.
Let's talk about your project. We set up idempotency, signature verification and daily reconciliation on your Paystack and mobile money store, with replay tests included. WhatsApp +221 77 596 93 33.
Mohamed Bah
Fondateur, Kolonell
Passionate about digital and entrepreneurship in Africa, Mohamed has been helping Sénégalese businesses with their digital transformation since 2020. Founder of Kolonell, he believes every SME deserves a professional and accessible online présence.
