Safeguard
Developer Tools•

How should a webhook sender schedule retries with backoff and jitter?

Retry failed webhooks with exponential backoff and jitter over several days, keep the same event id, and avoid retry storms on recovering receivers.

Safeguard Security Team
3 min read

Retry failed webhook deliveries on a schedule that spans multiple days, with exponential backoff and random jitter, treat any response other than 2xx as a failure, and send the same webhook id on every attempt. That is the guidance in the Standard Webhooks specification.

Definition

A retry schedule is the set of delays between delivery attempts. Exponential backoff means each delay is longer than the last. Jitter adds a random amount to each delay so that many failed deliveries do not all retry at the same instant.

Why jitter matters

Picture a customer endpoint that goes down for ten minutes. Thousands of your queued events fail together. If every one retries after exactly one minute, then two, they arrive as synchronized waves. A receiver that has just recovered gets flattened again, which keeps it down. Jitter spreads attempts out so a recovering service sees a ramp, not a wall.

This is also a defense for you. Retry traffic from your own workers competes with fresh events. A schedule without randomness creates predictable spikes in your own queue.

What the spec says

According to the spec: retry on a schedule that spans multiple days, with exponential backoff and random jitter; use webhook-id as an idempotency key, for example by storing ids to block duplicates; treat any response other than 2xx as a failure; and treat 410 Gone as a signal to disable the endpoint. A timeout of roughly 15 to 30 seconds is recommended per attempt.

An example schedule

This is an illustration, not a prescribed schedule.

AttemptBase delayWith jitter
1ImmediateNone
2About 30 secondsAdd a random share of the base
3About 5 minutesSame
4About 30 minutesSame
5About 2 hoursSame
6 and laterSeveral hours, wideningSame, until the end of your window

Pick your own numbers, publish them, and apply them consistently.

Steps

  1. Choose a retry window and a maximum number of attempts and document them for customers.
  2. Implement backoff with jitter in the delivery worker, not in each integration.
  3. Keep webhook-id constant across attempts so receivers can deduplicate. See duplicate event handling.
  4. Cap concurrency per destination so one slow endpoint cannot use up your worker pool.
  5. Pause retries when an endpoint is clearly down and resume with a ramp.
  6. At the end of the window, mark the delivery failed, surface it in a dashboard, and follow your disable policy.

Per destination limits

One customer's broken endpoint should not delay events for everyone else. Use separate queues or concurrency caps per destination. That isolation is a reliability control and a security one, since hostile URLs can otherwise be used to stall delivery for others.

Where Safeguard fits

Safeguard's dependency scanning covers the queueing and HTTP client libraries behind your delivery workers, and its policy gates help keep reviews in your release flow. The free scan is at https://gold.safeguard.sh/scan.

Quick check

Why add randomness to a delay I can already compute?

Without it, many failed events retry in sync and can overwhelm a recovering receiver. Jitter spreads the load.

Should retries use a new event id?

No. Keep the same id so receivers can detect and ignore duplicates.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.