WebhooksApril 18, 20266 min read

How to Replay a Webhook When Your Server Was Down

Your server went down for an hour. Stripe, GitHub, and Shopify kept sending webhooks. Here is how to replay the events you missed — with and without a webhook relay.

Your database fell over at 2 AM. By the time you woke up and fixed it, three hours of webhooks had already been sent and rejected. Now you're staring at Slack wondering how many Stripe payments didn't get fulfilled and how many GitHub pushes didn't trigger the right CI job.

This post is the actual playbook for recovering missed webhooks — provider by provider, and then the pattern that makes this a one-click problem instead of a Sunday afternoon.

TL;DR

  • Stripe: manually redeliver per-event from the dashboard, or script via the Events API. No bulk UI.
  • GitHub: per-delivery redeliver button. Also one-at-a-time unless you script the Redelivery API.
  • Shopify: retries 19 times over 48h, then events are gone — re-query the Orders API to reconcile.
  • One-click replay needs upstream logging before delivery — that's the whole design of a webhook relay.

Stripe

Stripe lets you resend webhook events manually from the dashboard:

  1. Go to Developers → Events in the Stripe Dashboard
  2. Click the event you want to redeliver
  3. Scroll to Webhook attempts and click Resend

This works one-by-one. If you missed 300 events, you are clicking 300 buttons. There is a Stripe CLI command (stripe events resend <event_id>) but it still requires you to know each event ID.

Batch replaying Stripe events

There's no first-party bulk-replay UI. The workarounds:

  • Write a script that uses the Stripe API to list events in the outage window, filter by status, and POST each one back to your endpoint yourself (you're re-constructing the webhook from the event object — it isn't quite the same shape)
  • Or, if you logged your webhooks upstream of the outage, replay from your own log

The upstream-log approach is the one production teams build eventually. It's also exactly what a webhook relay does for you.

GitHub

GitHub shows a per-delivery redeliver button in repo Settings → Webhooks → (pick webhook) → Recent Deliveries. Click Redeliver next to each one.

Same issue: one-by-one. GitHub keeps deliveries for ~30 days, so you have breathing room, but a mass-replay still means a script hitting the Redelivery API.

Shopify

Shopify retries for up to 48 hours (19 attempts) before giving up. After that, the only way to recover is to re-query the Shopify API for what you missed — the webhooks are gone.

This is especially painful because Shopify's retry window is the shortest of the big three. If your server is down Friday night and you don't catch it until Monday, you're doing a full reconciliation from the Orders API.

The general pattern

Regardless of provider, the recovery procedure without a relay looks like:

  1. Identify the outage window — when did your server stop 2xx-ing?
  2. Pull affected events — usually a paginated API call per provider
  3. Re-fire each event — POST it at your own endpoint, or re-query the source of truth and sync state manually
  4. Dedupe — your handler must be idempotent (events may have partially delivered)

This takes hours. And you only get one shot — if you miss events past the retry window, they're gone.

The one-click version

The reason AnyHook exists is to turn this into one click. When you point your webhooks at in.anyhook.net/you/app:

  • Every event is persisted before delivery, encrypted at rest
  • If your server returns 5xx, AnyHook retries on exponential backoff (Free=3, Pro=5, Scale=10 attempts)
  • If your server is down long enough to exhaust retries, the event is marked failed — but the payload is still in your log
  • Open the dashboard, filter to failed events in your outage window, click Replay. That's it.

Replays don't count against your quota. They publish fresh to your endpoint with a new signature but the original inbound body and headers preserved, so your handler sees the event exactly as the provider sent it.

The API equivalent is a single POST:

curl -X POST https://anyhook.net/api/v1/apps/stripe-prod/replay-failed \
  -H "Authorization: Bearer $ANYHOOK_KEY" \
  -H "Content-Type: application/json" \
  -d '{"since": "2026-04-18T02:00:00Z", "limit": 100}'

One call, up to 100 events replayed, no dashboard clicking.

Design implication

The broader lesson: the thing that makes replay cheap is persistence at the edge before delivery. If your webhook log starts at your origin, you can only replay what your origin received. If your log starts at the network edge — before your origin has a chance to fail — you can replay anything that ever showed up.

That's the whole design. Move logging upstream, make replay idempotent, and your worst webhook outage becomes a one-minute recovery instead of a weekend.

Try it: anyhook.net.

All postsApril 18, 2026 · 6 min

Stop losing webhooks.

Change one URL. Get retries, event log, and one-click replay.