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:
- Go to Developers → Events in the Stripe Dashboard
- Click the event you want to redeliver
- 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:
- Identify the outage window — when did your server stop 2xx-ing?
- Pull affected events — usually a paginated API call per provider
- Re-fire each event — POST it at your own endpoint, or re-query the source of truth and sync state manually
- 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.