Every webhook provider claims it retries failed deliveries. The details — how many times, with what backoff, what counts as "failed", whether it re-signs the payload, what happens after the last attempt — are usually half-documented and occasionally wrong. Before you build your handler's idempotency and error paths, observe the real behaviour.
$ curl https://catchhook.catchhook.workers.dev/new
Paste the /h/… URL into the provider's webhook config. Unlike your real
endpoint, this one lets you dial in any response — status, headers, body, and an
artificial delay — from the bin's settings page, and change it between deliveries.
Set the response status to 500, trigger one event, and watch the dashboard.
Each retry arrives as a separate capture with a timestamp, so the provider's real backoff
schedule is just… visible. Things worth checking:
4xx retry? Many providers retry 5xx but drop 4xx.
Flip the status to 410 and find out — some (GitHub, Shopify) may auto-disable
the hook entirely, which you want to know before production.X-Shopify-Retry-Count or changed delivery GUIDs.Set the response status back to 200 but add a response delay
of 10–30 seconds. Now you learn the sender's timeout policy: does it wait 5s or 30s? Does a
timeout count as a failure and trigger the retry schedule? (Almost always yes — which means
a slow-but-successful handler causes duplicate deliveries. This is the #1 argument
for the "ack fast, process async" pattern, and now you've seen it happen.)
Set the response to 200 with no delay. Watch the pending retries land and
stop. Replay any captured failure straight at your now-fixed real endpoint with one click.
Building the sending side? Point your service at a bin, make the bin return
503, and verify your code retries with the backoff you intended — the capture
timestamps are your test evidence. Then set a delay slightly above your client timeout and
verify your timeout handling too.
No signup needed. Or from your terminal: curl https://catchhook.catchhook.workers.dev/new