Blog · · 5 min read

Stripe Webhooks: Retries, Ordering, Duplicates, Timeouts, and IPs

Stripe webhook retries, ordering, duplicates, timeouts and source IPs in one table, each linked to Stripe's docs, plus how to build a receiver around them.

Key points

  • In live mode Stripe retries failed webhook deliveries for up to three days with exponential backoff. In sandboxes it retries three times over a few hours.
  • Stripe does not guarantee ordering and may deliver the same event more than once. Deduplicate on the event ID and fetch current state from the API when order matters.
  • Stripe's docs do not publish the individual retry intervals or a timeout in seconds (as of 2026-09-27).

In live mode, Stripe retries webhook deliveries for up to three days using exponential backoff. In a sandbox, it retries three times over a few hours. Stripe does not guarantee that events arrive in the order they were created, and the same event can arrive more than once, so your receiver has to deduplicate on the event ID and, when order matters, fetch the current state from the API.

These details are spread across several pages of Stripe's docs. This post collects them in one table, checked against the official documentation on 2026-09-27, and marks anything Stripe doesn't publish as "not stated."

Stripe webhook behavior at a glance

Topic Behavior Source
Automatic retries (live) Exponential backoff for up to 3 days Webhooks
Automatic retries (sandbox) 3 times over a few hours Same
Individual intervals Not stated; the Dashboard shows the next scheduled attempt Same
Endpoint disabled or deleted during retries No further retries for that event; if you disable and re-enable before the next attempt, retries continue Same
Manual resend Dashboard: up to 15 days after the event was created. CLI (stripe events resend): up to 30 days Same
Effect of a manual resend A 2xx on a manual resend does not cancel automatic retries Same
Finding undelivered events List Events with delivery_success=false; only events from the last 30 days Process undelivered events
Ordering Not guaranteed Webhooks
Duplicates The same event can be delivered more than once Same
Timeout No number of seconds stated; timeouts count as failures Same
Success 2xx; redirects (3xx) are treated as failures Same
TLS TLS 1.2 and 1.3 Same
Signature Stripe-Signature with t= and v1=, HMAC-SHA256; a new timestamp and signature on every attempt Same
Source IPs Published list, also as ips_webhooks.json and .txt; changes announced on a mailing list 7 days ahead IP addresses
Failure notification In live mode Stripe emails you when webhooks are failing Subscriptions and webhooks
Endpoints per account Up to 16 Webhooks

Some third-party write-ups state specific numbers, such as "about 16 retries" or "a 20-second timeout." We could not find either in Stripe's official docs as of 2026-09-27. If your design depends on them, confirm the real behavior in your Dashboard's delivery log.

Retry behavior that catches people out

Processing an event yourself doesn't stop retries

After an outage you might list undelivered events and process them yourself. Stripe still considers them undelivered and keeps retrying. Stripe's guide says to detect events you've already handled, skip them and return a success response, which stops further retries. Your backfill script and Stripe's retries can run at the same time, so track "processing" as well as "processed."

// Express. Keep the body raw and verify before using it.
app.post('/webhooks/stripe', express.raw({ type: 'application/json' }), async (req, res) => {
  let event: Stripe.Event;
  try {
    event = stripe.webhooks.constructEvent(req.body, req.header('stripe-signature')!, endpointSecret);
  } catch {
    return res.status(400).end();
  }

  // Only the first delivery of an event ID gets through (unique constraint)
  const inserted = await db.query(
    'INSERT INTO stripe_events (id, status) VALUES ($1, $2) ON CONFLICT (id) DO NOTHING',
    [event.id, 'processing'],
  );
  if (inserted.rowCount === 0) return res.status(200).end(); // in progress or done

  await queue.add('stripe-event', { id: event.id }); // heavy work happens in the worker
  res.status(200).end();
});

Pausing your endpoint can drop events

If a scheduled retry comes due while your endpoint is disabled, Stripe stops retrying that event. If you disable the endpoint for maintenance, run List Events with delivery_success=false after you re-enable it. The recovering missed webhooks post covers reconciliation in detail.

Sandboxes can't show you day-three behavior

Three retries over a few hours means you'll never see, in a sandbox, a burst of days-old events arriving after a long outage. Test your deduplication and ordering logic by replaying events locally.

Ordering and duplicates

Stripe's docs use subscription creation as an example: it can produce customer.subscription.created, invoice.created, invoice.paid and charge.created, and Stripe doesn't guarantee they arrive in that order. Snapshot events record created in seconds, so different events can share a timestamp. Stripe says not to use created to order events or to decide whether you've processed one; track the event ID instead.

Three rules cover it:

  1. Deduplicate on the event ID. Record processed IDs under a unique constraint and skip any that are already there.
  2. Fetch state from the API. If invoice.paid arrives first, use the IDs inside it to retrieve the invoice, charge and subscription instead of waiting for the earlier events.
  3. Two separate events can describe the same change. Stripe notes that in some cases two Event objects are generated and sent separately; identify those by the data.object ID together with event.type.

We go deeper in handling duplicate webhooks and out-of-order webhooks.

Return 2xx before the heavy work

Stripe asks you to return a 2xx quickly, before any complex logic that could cause a timeout, for example before marking an invoice as paid in your accounting system. With no published timeout, keep the handler to "verify, record, enqueue, 200." Stripe also recommends processing events from an asynchronous queue so that spikes (such as the start of a month, when many subscriptions renew) don't overwhelm your server.

Allowlisting Stripe's IPs

Stripe publishes the IPs it sends webhooks from, also available at https://stripe.com/files/ips/ips_webhooks.json and .txt, and announces changes on its API announcements mailing list 7 days in advance. Stripe recommends using both an IP allowlist and signature verification. If you filter by IP, keep verifying signatures and refresh the list on a schedule. Our static IP post covers IP-based filtering more broadly.

When you are the one sending

Stripe's webhooks are a good reference if your own product needs to send them: a defined retry window with exponential backoff, a visible delivery log with the next attempt, manual resends, email when deliveries keep failing, and a fresh signature on every attempt. We covered choosing a schedule in designing webhook retries.

Webhook Admin handles retries, logs and alerts through an API. By default it retries immediately, then after 5 s, 5 min, 30 min, 2 h, 5 h, 10 h and 10 h (8 attempts, about 28 hours; you can choose the number of retries and the interval per endpoint), logs the status code and the first 1,024 bytes of every response, and lets you retry deliveries from the dashboard or the API. It alerts you (Slack, Teams, email or a webhook) when an endpoint has been failing for an hour, when retries run out, and when it disables an endpoint after five days of failures. The free plan includes 50,000 messages a month: https://app.webhookadmin.com/signup

FAQ

How do I stop Stripe from retrying a webhook?

Return a 2xx for it. Processing the event yourself, or a manual resend that returns 2xx, does not cancel Stripe's automatic retries, so when an already-processed event arrives, skip the work and return 2xx. If you disable or delete the endpoint while retries are pending, Stripe stops retrying that event.

What is Stripe's webhook retry interval?

Stripe documents exponential backoff for up to three days in live mode but does not list the individual intervals. The Event deliveries tab for your endpoint shows when the next retry is scheduled.

Do sandbox webhooks retry the same way as live mode?

No. Events created in a sandbox are retried three times over a few hours, so you cannot reproduce live mode's multi-day retries there. Test deduplication and ordering by replaying events locally.

Related posts