What are webhook retries? How redelivery works

Webhook retries are repeat attempts a provider makes to deliver the same webhook after an earlier attempt failed. If your endpoint returns a non-2xx status, takes too long or can't be reached, the provider waits and sends the event again, usually with growing gaps (exponential backoff), until it gets a 2xx or its retry window runs out.

attempt 1  09:00:00  → 503 Service Unavailable
attempt 2  09:00:05  → timeout after 15s
attempt 3  09:05:05  → 502 Bad Gateway
attempt 4  09:35:05  → 200 OK   ✓ delivered

What triggers a retry

Your endpoint's responseWhat most providers do
2xxSuccess, no retry
3xx redirectUsually treated as a failure. Many senders don't follow redirects for POST.
4xxUsually retried, because the provider can't tell a bug from a transient problem
429 or 503Retried, often honouring Retry-After
410 GoneSome providers stop and disable the endpoint
500, 502, 504Retried
Timeout or connection errorRetried

The key point: only 2xx means "delivered". If you return 200 and then crash, the provider considers the event delivered and won't retry. If you return 500 after you already processed it, you'll get it again.

Retry policies vary a lot

  • Stripe retries with exponential backoff for up to about three days in live mode.
  • GitHub doesn't retry automatically. You redeliver failed deliveries by hand from the webhook settings or the API.
  • The Webhook Relay Outbound Gateway retries after 5 seconds, 5 minutes, 30 minutes, 2 hours, 5 hours, 10 hours and 10 hours, for up to 8 attempts within 48 hours, honours Retry-After on 429 and 503 (up to one hour), and stops and disables the endpoint on 410.
  • Many smaller providers try a few times over a few minutes, or not at all.

You can't change a provider's policy. If an outage outlasts it, the events are gone unless something in between stored them.

How to handle retries on the receiving side

  1. Acknowledge fast. Store or queue the event and return 200 within a few seconds. A handler that does all its work inline is the most common cause of retries for events that actually succeeded.
  2. Be idempotent. Retries mean duplicates. Record each event ID and skip ones you've seen. See idempotency.
  3. Return the right status. Return 2xx only once the event is safely stored. Return 5xx if you couldn't store it, so it's retried. Acknowledge event types you don't handle with 200 so they aren't retried forever.
  4. Don't depend on order. A retried event can arrive after a newer one. Compare timestamps or fetch current state from the provider.
  5. Watch for failures. A burst of retries usually means a deploy, a bad release or a full disk. Alert on them.

How to retry well when you're the sender

  • Use exponential backoff with jitter, so a recovering endpoint isn't flattened by every pending retry at once.
  • Keep the same event ID on every attempt so receivers can deduplicate.
  • Set a timeout per attempt (5 to 30 seconds is common).
  • Cap the total window, then move the event to a dead-letter queue or failed state where it can be replayed.
  • Honour Retry-After and back off on 429.

Adding a retry layer you control

Putting a webhook gateway between the provider and your endpoint means the provider's retry policy stops being the limit. Webhook Relay's durable retries persist each webhook before the first delivery attempt, run fast retries for a 15-minute handoff window by default, then keep retrying with exponential backoff on a schedule you choose per destination: about 25 minutes, about 16 hours, or up to 30 days. Waiting deliveries show as stalled in the logs with the time of the next attempt. Setup is in the durable webhooks docs, and the retries and idempotency guide goes deeper on receiver design.

Frequently asked questions

What are webhook retries?

Webhook retries are repeat attempts a provider makes to deliver the same webhook after an earlier attempt failed. A failure is usually any non-2xx response, a timeout or a connection error. The provider waits, typically longer each time, and sends the same event again until it succeeds or its retry window ends.

What triggers a webhook retry?

Most providers retry on any response that is not 2xx, on timeouts and on network errors such as DNS failures or refused connections. Some treat certain codes specially, for example honouring Retry-After on 429 and 503, or stopping and disabling the endpoint on 410 Gone.

How long do providers retry webhooks?

It varies widely. Stripe retries with exponential backoff for up to about three days in live mode. GitHub does not retry automatically, so failed deliveries must be redelivered by hand. Many smaller providers try a few times over minutes, or not at all.

How do I stop duplicate processing from retries?

Make the handler idempotent. Store each event ID with a unique constraint when you process it, and skip any event whose ID you have already seen. Also return 2xx quickly, because slow handlers that time out cause retries of events you actually processed.