The verdict in three sentences
The webhook is the only source of truth for a Wave payment: never validate an order on the browser return, always on the server event. Three mechanisms make it reliable: verifying the HMAC signature to authenticate Wave, an idempotency table indexed on event_id to process each event only once, and responding 200 immediately (< 10 s) then processing in a queue. Without these three pillars, you risk double-credits, fake confirmations and ghost orders.
The Wave webhook events to handle
Wave sends several event types; your handler must route them cleanly. 2026 orders of magnitude (estimate, check the Wave Business docs):
| Event | Status | Recommended action |
|---|---|---|
| checkout.session.completed | completed | Validate order, release delivery |
| checkout.session.failed | failed | Notify customer, offer another wallet |
| checkout.session.processing | processing | Wait, release nothing |
| refund.completed | refunded | Cancel order, update stock |
| refund.failed | failed | Alert support |
| balance.payout | settled | Mark T+1 settlement received |
Signature, idempotency and retries
Wave signs each payload (HMAC) and retries on failure. 2026 reference parameters:
| Mechanism | Reference value | Why |
|---|---|---|
| Signature algorithm | HMAC-SHA256 | Authenticate Wave origin |
| Signature header | Wave-Signature | Compare to local computation |
| Retry count | 5 attempts over 24 h | Tolerate a temporary outage |
| Backoff | Exponential (1m, 5m, 30m, 2h, 6h) | Avoid hammering |
| Expected timeout | 10 s max | Beyond this, Wave assumes failure |
| Expected response | Fast HTTP 200 | Confirms receipt |
The idempotency table stores each event_id with a uniqueness constraint: if the event arrives twice (retry after timeout), the insert fails and processing is skipped — the credit happens only once.
A robust Next.js handler
`ts
export async function POST(req: Request) {
const raw = await req.text();
const sig = req.headers.get("Wave-Signature");
if (!verifyHmac(raw, sig, process.env.WAVE_SECRET))
return new Response("invalid signature", { status: 401 });
const event = JSON.parse(raw);
const inserted = await db.insertIfAbsent("wave_events", event.id);
Need a professional website?
Kolonell builds websites that attract clients, optimized for the Sénégalese market. Free quote in 2 minutes.
// Respond 200 right away, then process in a queue
if (inserted) await queue.enqueue("wave", event);
return new Response("ok", { status: 200 });
}
`
The handler does three things and returns: verify the signature, deduplicate via insertIfAbsent, respond 200. All business logic (order validation, email, stock) goes to an async queue to stay under 10 s.
Mini case study
Ibrahim, a restaurateur in Dakar with delivery, was getting 2 % of orders paid but never confirmed because his handler validated on the browser return — cut off when the customer closed the app. On 1,500 orders/month at 6,500 FCFA, that meant 30 lost orders, i.e. 195,000 FCFA/month in disputes and manual refunds. After switching to a signed + idempotent webhook, the confirmation rate rose to 99.7 % and disputes nearly vanished.
FAQ
Why respond 200 before processing?
If your processing exceeds 10 s, Wave treats the delivery as failed and triggers a retry, creating duplicates. Responding 200 fast then queuing breaks that loop.
What if the signature doesn't match?
Return a 401 and process nothing: an improperly signed payload is not authenticated and could be a fraud attempt.
How long does Wave retry?
Generally 5 attempts spread over 24 h with exponential backoff (2026 estimate). Your idempotency table ensures none of these retries double-credit.
Should I store every event?
Yes, at minimum the event_id, status and timestamp. It's essential for accounting reconciliation and for replaying an event after a bug.
Let's talk about your project. We deliver signed, idempotent and monitored Wave webhooks, production-ready. 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.
