The verdict in three sentences
A payment webhook sent by CinetPay, Paystack or Flutterwave can arrive 3 to 8 times for a single transaction, because the aggregator retries until it receives a clean HTTP 200. Without an idempotency key stored in your database, each attempt recreates an order: double shipping, double email, double stock deduction. The fix rests on three blocks: HMAC signature verification, a deduplication table indexed on the transaction ID, and a persisted status (pending/success/failed).
Why a webhook arrives multiple times
Aggregators guarantee "at least once" delivery, never "exactly once". If your server responds in 6s, if the network drops, or if you return a 500, the PSP treats the event as undelivered and replays it. This is intentional: two notifications beat a lost transaction. Deduplication is therefore your code's responsibility.
| PSP (2026 order of magnitude) | Attempts in 24h | Retry window | Backoff |
|---|---|---|---|
| CinetPay | 3 to 5 | up to 24h | increasing |
| Paystack | 5 to 8 | up to 72h | exponential |
| Flutterwave | 3 to 6 | up to 48h | exponential |
| PayDunya | 3 to 5 | up to 24h | increasing |
| Wave (direct API) | 2 to 4 | up to 12h | increasing |
The lesson: design for at least 8 possible replays, even if the average is lower.
The real cost of a duplicate
A duplicate is not a cosmetic bug. On a physical order you lose 100% of the margin on the second shipment, plus return fees and support time.
| Duplicate impact | 2026 estimate | Comment |
|---|---|---|
| Lost margin (2nd shipment) | 100% of product | neither paid nor recoverable |
| Return shipping fees | 2,000 to 5,000 FCFA | if the customer returns |
| Support time | 15 to 30 min | per dispute |
| Non-refunded PSP fees | 1.5 to 3% | on the reprocessed amount |
| Negative review risk | high | 1-star reviews common |
The three technical blocks
1. Verify the HMAC signature. Each PSP signs the webhook body with your secret key. Recompute the HMAC-SHA256 and compare it with the received header. An improperly signed webhook is rejected before any processing: your first line of defense against fake payments.
Need a professional website?
Kolonell builds websites that attract clients, optimized for the Sénégalese market. Free quote in 2 minutes.
2. Deduplication table. Create a webhook_events(transaction_id UNIQUE, status, received_at) table. On receipt, attempt an INSERT. If the UNIQUE constraint fails, the event is already processed: return 200 and stop. That is your idempotency guarantee.
3. Respond fast, process later. Acknowledge (200) in under 2s, then run business logic in the background. Heavy synchronous processing causes timeouts... which cause replays.
Mini case study
Awa runs a cosmetics shop in Dakar, 900 orders/month via CinetPay. Before idempotency she saw about 2.5% duplicates, roughly 23 orders/month shipped twice. Average basket 18,000 FCFA, 40% margin: each duplicate cost her the margin (7,200 FCFA) plus 3,000 FCFA return, i.e. 10,200 FCFA. Total: 23 x 10,200 = 234,600 FCFA/month wasted. After adding a deduplication table (2 dev days), duplicates drop to near zero: the investment pays back in under two weeks.
FAQ
How many times can a webhook really arrive? Depending on the PSP, 2 to 8 attempts over a 12 to 72h window. Always design for the widest case, at least 8 replays.
Which key should I deduplicate on? The PSP transaction ID (not your order ID), set as a UNIQUE constraint. It is the only stable identifier across all replays of the same payment.
Should I return 200 even for a duplicate? Yes. Returning 200 in under 2s stops the retries. A 500 or a timeout restarts the full retry sequence.
Is the HMAC signature mandatory? Functionally no, but without it anyone can fake a successful payment. It is essential in production: the omission can cost 100% of the fraudulent basket.
How much does this hardening cost? Roughly 1 to 3 dev days for the dedup table, HMAC verification and async processing: negligible against the losses avoided.
Let's talk about your project. We integrate idempotent, signed webhooks for your mobile money aggregator, tested end to end. 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.

