Webhook Delivery Guarantees
Most webhook systems promise at-least-once delivery — which quietly means you must be ready for more than once.
What you'll learn
- Define the three common delivery guarantee levels
- Explain why at-least-once is the usual webhook promise
- Show how idempotency turns at-least-once into effectively-once
- Reason about what a provider does and does not guarantee
6 min read
Three levels of guarantee
Messaging systems describe their reliability using three standard phrases, and it is worth knowing all three. At-most-once means an event may be lost but will never be duplicated. At-least-once means an event will never be lost but may be duplicated. Exactly-once means each event is delivered precisely a single time — the most appealing of the three on paper, but genuinely very hard to achieve across independent systems separated by an unreliable network.
These are not merely jargon to memorise; each one tells you concretely which failures you must be prepared to handle in your own code. Knowing your provider's actual guarantee level lets you design a receiver that copes with that specific set of weaknesses, rather than quietly hoping for stronger behaviour the provider never actually promised you.
Why at-least-once dominates
The great majority of webhook providers offer at-least-once delivery, and there is a sound reason behind that near-universal choice. To avoid ever losing an event, a provider must retry until it positively sees a 2xx from you. But because a response can be lost in transit just like a request can, the provider will sometimes retry an event you had already received and processed — and that retry produces a duplicate. Choosing never to lose events inherently risks delivering some of them more than once.
True exactly-once delivery across a network is largely impractical to guarantee, so providers very sensibly favour never losing an event over never duplicating one. As the consumer on the receiving end, you inherit the duplicates that this choice creates and must handle them gracefully — which, with the right design, is entirely manageable and not a cause for concern.
From at-least-once to effectively-once
The genuinely good news is that you can achieve exactly-once effects on top of at-least-once delivery, and the technique is one you already know: make your processing idempotent. Deduplicate on the unique event id so that handling a duplicate delivery changes nothing at all, and the practical, observable result becomes exactly as if each event had been processed precisely once, no more and no less.
if (processed.has(event.id)) return respond(200);
handle(event);
processed.add(event.id);This is the standard recipe, and it is covered in full in webhook idempotency. It is precisely why at-least-once delivery, despite sounding alarming when you first meet the duplicates, is perfectly workable and indeed pleasant to build on in practice.
Know your provider's promise
Guarantees vary meaningfully from one provider to the next, so always read the fine print rather than assuming. Find out clearly whether deliveries can be duplicated (the answer is almost always yes), whether ordering is preserved across deliveries (very often it is not), and how long retries persist before an undelivered event is finally dropped for good. Each of those answers shapes a concrete design decision somewhere in your receiver.
Above all, do not build on a stronger guarantee than the documentation actually states, because designing against an imagined promise leads directly to brittle systems that fail in surprising ways. The specific delivery behaviour that Merion's webhooks provide is described in the API documentation, which is the single authoritative source to design against.
Key takeaways
- Guarantees come as at-most-once, at-least-once, or exactly-once
- Webhooks almost always use at-least-once, so expect duplicates
- Idempotent processing yields exactly-once effects in practice
- Confirm duplication, ordering, and retry duration from the docs
FAQ
Do webhooks guarantee exactly-once delivery?
Rarely. Most providers offer at-least-once, meaning events are never lost but can be duplicated. You achieve exactly-once effects yourself through idempotent processing.
Why does at-least-once cause duplicates?
To avoid losing events, the provider retries until it sees a 2xx. If your acknowledgement is lost, it retries one you already received, delivering it again.
How do I cope with at-least-once delivery?
Make processing idempotent. Deduplicate on the event id so a repeated delivery has no extra effect, turning at-least-once delivery into effectively-once processing.
Ready to build?
Read the API reference, grab the OpenAPI spec, and ship a resilient integration.