How reliable are webhooks?
A single webhook is one HTTP POST, so on its own it is exactly as reliable as one request across the internet: it fails whenever the receiver is deploying, slow, or unreachable. Webhook reliability comes from the machinery around that request, namely retries with backoff, a dead letter queue, and receivers that tolerate duplicates.
What actually goes wrong
Most failed deliveries are not exotic. The receiver is mid-deploy and refuses connections for thirty seconds. A load balancer returns a 502 while an instance rotates. A TLS handshake fails once. None of these mean the event should be lost, and all of them are fixed by trying again a moment later.
The next most common cause is self-inflicted: the receiver does real work before answering. Providers do not wait long. Stripe cuts a delivery off at 20 seconds, GitHub at 10, and Shopify at 5. A handler that calls two external APIs before returning 200 will trip a webhook timeout under load, and the sender will read that timeout as a failure even though the work completed.
Then there are the failures a retry cannot fix. A receiver returning 400 because of a schema mismatch will return 400 on every attempt. An endpoint whose owner deleted the service will never come back. A sender that cannot tell these apart from transient errors wastes its whole schedule on them.
What a reliable sender does
Four mechanisms carry most of the weight, and a provider either has them or does not.
- Retries with exponential backoff and jitter. Delays grow rather than staying fixed, so a struggling receiver gets room to recover, and jitter keeps a wave of failed deliveries from retrying in lockstep. Our retry best practices covers a concrete eight-attempt schedule spread over roughly 24 hours.
- A published schedule and clear success criteria. Receivers cannot reason about delivery unless they know the exact attempt timing and that only a
2xxcounts as success, redirects included. - A dead letter queue. When retries are exhausted the event moves to a dead letter queue rather than disappearing, with the payload, destination, and attempt history kept so it can be inspected and replayed.
- Failure isolation. Endpoints that have been failing for days get disabled so they stop consuming capacity, and per-endpoint concurrency limits keep one broken customer from delaying everyone else. Circuit breakers are the general form of this.
Together these change the delivery model from "one attempt, hope it lands" to at-least-once over a long window, which is the guarantee nearly every major provider offers. Webhook delivery guarantees explains what at-least-once does and does not promise.
What a reliable receiver does
At-least-once delivery pushes work onto the receiver, and two habits handle nearly all of it.
Answer immediately and process later. Verify the signature, write the event to a queue or a table, return 200, and do the real work in a background worker. This turns a handler that takes seconds into one that takes milliseconds, and it removes timeouts as a failure mode entirely.
Deduplicate on the event ID. Retries exist precisely because the sender cannot tell a lost response from a lost request, so the same event will arrive twice eventually. Storing processed IDs and skipping repeats makes that harmless, which is the whole subject of idempotency and deduplication. Do not assume ordering either: two events sent in sequence can arrive in either order after a retry.
The numbers to ask a provider for
When you are evaluating webhook reliability rather than building it, five answers tell you most of what you need: the delivery guarantee, the exact retry schedule and total retry window, the request timeout, how long events stay available for replay, and whether there is a delivery log you can search per endpoint. A provider that publishes all five has thought about failure. One that says "we retry a few times" has not.
For events you cannot afford to miss at all, pair webhooks with a periodic reconciliation pass against the provider's API. Webhooks give you latency measured in seconds; polling gives you a safety net that catches whatever a sustained outage on either side dropped.
When webhooks are the wrong reliability model
Webhooks fit server-to-server notification across a trust boundary, where the receiver is someone else's endpoint. They fit poorly when you need strict ordering, replay from an arbitrary offset, or millions of internal events per second. That is a log or a broker's job, and webhooks vs message queues walks through where the line sits.
Inside your own infrastructure, reach for a queue. On the boundary, the work is retries, signing, delivery logs, and the support load that follows when any of them misbehave. Svix provides that layer as a service, including the retry schedule, exhaustion notifications, and per-message delivery history, so reliability is configuration rather than a system you maintain.
Frequently asked questions
Can webhooks be lost?
Yes, if the sender does not retry. With retries over a long window and a dead letter queue for exhausted messages, loss requires the receiver to be unreachable for the entire retry period, commonly around 24 hours. Without retries, one failed request means the event is gone.
Are webhooks guaranteed to be delivered in order?
No. Most providers make no ordering guarantee, because a retried event can arrive after events created later. If order matters, include a sequence number or timestamp in the payload and reorder on the receiving side.
How many times should a failed webhook be retried?
A common default is around eight attempts spread across roughly 24 hours with exponential backoff, after which the message goes to a dead letter queue. The exact count matters less than publishing the schedule so receivers know how long they have to recover.
Why did my webhook fail even though my server processed it?
Almost always a timeout. The handler did its work but responded after the provider gave up, so the sender recorded a failure and retried. Return 2xx first and process asynchronously, and deduplicate on the event ID so the retry is harmless.