The verdict in three sentences
Wave replays webhooks until it receives a 200 response, which, unprotected, creates duplicate orders and payments counted twice. Without a safeguard, incident rates run around 0.3% — invisible at small scale, costly at large. Three measures suffice: an idempotency key, signature verification and a deduplicated transactions table.
Why a webhook arrives twice
A webhook is not a guarantee of single delivery. If your server responds slowly, returns a 500 error or exceeds the timeout, Wave treats the event as undelivered and replays it. Your code then receives the same payment twice.
| Duplicate cause | Relative frequency | Countermeasure |
|---|---|---|
| Retry after server timeout | High | Reply 200 fast + process async |
| Retry after 5xx error | Medium | Idempotency on transaction_id |
| Customer double-click at checkout | Medium | Request-side idempotency key |
| Malicious replay | Low | Signature verification |
| Concurrent race condition | Low | DB lock / unique constraint |
The golden rule: process each transaction_id exactly once, no matter how many times the event arrives.
Three safeguards and their dev cost
| Measure | Role | Dev effort (2026 ballpark) |
|---|---|---|
| Signature verification | Reject forged webhooks | 1–2 h |
| Idempotency key | Ignore an already-seen event | 2–3 h |
| Deduplicated table (unique) | Block duplicate insertion | 1–2 h |
| Fast 200 reply + queue | Avoid timeout retries | 1–2 h |
| Incident log | Audit and replay cleanly | 1 h |
All told, a robust Wave endpoint takes 4 to 8 hours to build. That is trivial against the cost of a dispute: an undetected phantom order causes an average loss of about 12,000 FCFA between refund, handling time and eroded trust.
Mini case study
Moussa sells event tickets online in Dakar, with 1,500 payments/month. Without idempotency, at a 0.3% incident rate, he suffers around 4 to 5 duplicates per month: customers charged twice, complaint emails, manual refunds. At 12,000 FCFA average loss per incident, that is ~54,000 FCFA/month and a bruised reputation. After adding an idempotency key and a unique constraint on transaction_id (6 hours of dev), his duplicate rate falls to zero.
Need a professional website?
Kolonell builds websites that attract clients, optimized for the Sénégalese market. Free quote in 2 minutes.
FAQ
What is an idempotency key in concrete terms?
It is a unique identifier attached to a payment operation. If your server receives the same key twice, it processes the first and ignores the second, guaranteeing a single charge.
Why verify the webhook signature?
It proves the call really comes from Wave and not an attacker faking a successful payment. It is the first line of defense, coded in 1 to 2 hours.
Is a unique DB constraint enough?
It blocks duplicate insertion at the database level, a robust safety net. Combined with an application-side idempotency key, it covers race conditions.
How long does Wave replay a webhook?
Wave retries within a retry window until it gets a 200 response. Hence the importance of replying 200 quickly and handling business logic asynchronously.
Let's talk about your project. We secure your Wave integration against double charges. 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.

