The verdict in three sentences
An unverified payment webhook can be spoofed: anyone sends a fake callback and your orders flip to "paid" for free. Two controls shut the door: HMAC signature verification (with a 5-minute replay window) and an idempotency key that blocks double-credit despite retry storms. In Lagos as in Dakar in 2026, trusting the raw callback is the most common and costliest flaw.
The threat surface
A webhook endpoint is public by nature: the operator must be able to call it. With no controls, that open door becomes a hole.
| Threat | Mechanism | Impact | Defense |
|---|---|---|---|
| Fake callback | Forged "paid" request | Order shipped unpaid | HMAC signature |
| Replay | Resending a captured callback | Account double-credited | 5-min window + nonce |
| Double credit | Operator retries (up to 5x) | Balance/order duplicated | Idempotency key |
| Payload injection | Tampered fields | Faked amount | Verify amount server-side |
| Endpoint leak | Guessed URL | Malicious probing | Secret + rate limit |
Mobile-money operators resend a webhook up to 5 times until they get a 2xx. Without idempotency, each retry re-credits the order.
Hardening checklist
Securing a webhook comes down to a handful of rules applied every time.
| Control | 2026 rule | Why |
|---|---|---|
| HMAC signature | Recompute and compare the hash | Proves origin |
| Replay window | Reject timestamp > 5 min | Blocks replay |
| Idempotency key | Process each event exactly once | Stops double credit |
| 2xx-only ack | Ack only if processed | Avoids needless retries |
| Amount check | Compare to order amount | Counters injection |
| Log + alert | Log every mismatch | Early detection |
| Rate limit | Cap calls per IP | Slows probing |
Golden rule: never trust the raw body. Verify the signature, reject out-of-window, deduplicate by key, and only then update the order.
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
Ibrahim, developer of a Lagos store, received the operator webhook and marked orders paid without verifying the signature. An attacker sends 40 fake "paid" callbacks on 35,000 FCFA baskets: 1,400,000 FCFA of orders enter fulfillment unpaid. After the fix (HMAC + 5-min window + idempotency key), the 40 forged requests are rejected and a burst of 5 legitimate retries credits only once. Cost of the flaw before the fix: 1,400,000 FCFA of goods potentially lost; cost of the fix: half a day of dev work.
FAQ
What is an HMAC signature in practice? The operator signs the payload with a shared secret; your server recomputes the same hash and compares. If the two differ, the callback is fake and you reject it before any processing.
Why a 5-minute window? It limits replay: a captured callback resent later is refused because its timestamp is stale. Five minutes cover network latency without leaving a long attack window.
How does an idempotency key work? Each event carries a unique identifier that you store after processing. If the same identifier returns (up to 5 operator retries), you return 2xx without re-crediting.
Should I verify the amount in the webhook? Yes, always server-side. Compare the callback amount to the recorded order; a gap flags payload injection or an error and blocks validation.
What to do on a signature mismatch? Log the event, alert, and update nothing. A spike in mismatches reveals a spoofing attempt; the alert lets you react before damage.
Let's talk about your project. We audit and harden your Wave and Orange Money webhooks (signature, idempotency, alerts) before you go live. 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.

