How do you make a payment or WhatsApp webhook idempotent?
Share

In this article
Key every webhook on a unique ID from the sender, such as an order ID or message ID, and run its side effects once. A repeat delivery finds the ID already processed and does nothing. Publish the real work to a queue instead of doing it inline, so the sender is not kept waiting.
Why do webhooks arrive more than once?
Senders retry on timeouts, network blips and non-2xx responses, and they favour delivering twice over never delivering. Payment gateways and WhatsApp both do this. A handler that acts on every delivery will issue duplicate tickets, double-fire a booking confirmation or charge twice.
What should the idempotency key be?
Use the identifier the sender guarantees to be stable across retries: the order ID for payment webhooks, the message ID for WhatsApp. Store processed keys and check before acting. A key you generate yourself per delivery does not work, because each retry would look like a new event.
Why publish to a queue instead of doing the work in the handler?
Generating a ticket and sending an email inline makes the gateway wait on work it does not care about, which invites timeouts and more retries. Acknowledge fast, publish a payment-confirmed event to RabbitMQ, and let a consumer do the work. A repeated delivery publishes once; the second is a no-op.
Where is this used in production?
On FindYourVibe the payment webhook is idempotent on order ID and publishes to RabbitMQ before a consumer issues the ticket. On Trexind every WhatsApp webhook handler is idempotent on message ID, so a retried delivery updates state once instead of re-triggering booking or billing side effects.
How do you test that a webhook is idempotent?
Send the same payload twice, ideally concurrently, and assert the side effect happened once: one ticket, one booking, one charge. Then replay an old payload after the first has been fully processed. If any count is above one, the key check is racing or missing a unique constraint.
Originally published at sakshamjain.codes/blog/idempotent-payment-and-whatsapp-webhooks. Need this built? See my services on NexoRush or message me.