Webhook tester: see every request, then misbehave on purpose

Most webhook testers answer one question: what did my service send? This one also answers the expensive question: what does my service do when the receiver is slow, flaky or down? You get a URL that logs every request and answers with exactly the status, delay, error rate or scripted failure you choose.

How it works

Step 1

Create an endpoint

You get a URL like https://your-slug.supercrontab.com/ that accepts any method on any path, including trailing slashes and sub-paths.

Step 2

Point your service at it

Paste the URL where your app, Stripe, GitHub or Zapier expects a webhook target, then send a test event.

Step 3

Read the log

Every request is stored with method, path, query, headers, up to 16 KB of body, the caller IP and the status you answered with.

Step 4

Shape the response

Return any status, body and headers, add a delay, fail a percentage of calls, or script a fault sequence per Idempotency-Key.

What a logged request looks like

Send anything to your URL and it shows up in the endpoint's log on refresh. Credential headers are redacted before storage; everything else is kept as sent.

curl -i -X POST https://your-slug.supercrontab.com/orders/42 \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 7f3c9a10' \
  -d '{"type":"invoice.paid"}'
2026-09-20 09:14:02 UTC  POST /orders/42  202  203.0.113.24
  content-type: application/json
  idempotency-key: 7f3c9a10
  user-agent: Stripe/1.0 (+https://stripe.com/docs/webhooks)
  stripe-signature: t=1789895642,v1=5257a869e7ecebeda32a...
  authorization: [redacted]

  {"id":"evt_1Q2w","type":"invoice.paid","data":{"object":{"id":"in_1Q2v","amount_paid":600}}}

The same log is available as JSON from GET /v1/endpoints/{id}/requests, so a CI job can assert on what your service sent.

Webhook cheat sheet: signatures, deadlines and retries

What the big senders put in the request, how long they wait, and what they do when you fail. The deadline column is the number to beat with the delay setting when you test timeouts. Providers change these; check their docs before you rely on a number.

SenderSignature headerHow it is signedAnswer withinOn failure
StripeStripe-SignatureHMAC-SHA256 over "timestamp.body", sent as t=...,v1=...answer 2xx promptly, before doing slow workretries with backoff for up to 3 days in live mode
GitHubX-Hub-Signature-256HMAC-SHA256 of the raw body, hex, prefixed sha256=10 secondsno automatic retry; failed deliveries are redelivered by hand or API
Slack Events APIX-Slack-SignatureHMAC-SHA256 over "v0:timestamp:body", prefixed v0=3 secondsup to 3 retries, marked with X-Slack-Retry-Num
ShopifyX-Shopify-Hmac-Sha256HMAC-SHA256 of the raw body, base645 secondsretries over several hours, then removes the subscription after repeated failures
TwilioX-Twilio-SignatureHMAC-SHA1 over the full URL plus sorted POST params, base6415 secondsno retry by default; configurable per webhook

Five tests worth running

Each one is a setting on the endpoint form, not code. The second uses fault sequences, which make a specific failure reproducible in CI.

Does my sender time out correctly?

Set the delay just above the provider deadline (11,000 ms for GitHub, 3,500 ms for Slack) and answer 200. A correct sender gives up and treats it as failed even though the status was fine.

Does a retry create a duplicate?

Use a fault sequence: step one drop, step two respond 200. The first delivery is logged and cut, the retry with the same Idempotency-Key succeeds. You should see two requests in the log and one side effect in your system.

What happens when the receiver is flaky?

Status 202, delay 3,000 ms, error rate 10%. One call in ten returns your error status. Leave it running for a day and count what your sender lost.

Do I sign requests correctly?

Turn on inbound auth: Basic, Bearer, an API key header, or HMAC-SHA256 of the raw body in hex with an optional prefix (the GitHub scheme). A wrong signature gets 401, and a failed auth never consumes a sequence step.

Does my alerting fire?

Answer 500 for every call and wait. If nothing pages you within the window you expect, you found the gap before production did.

When another tool is the better pick

If you need a throwaway URL in five seconds and never want to see it again, an anonymous request bin is faster: there is no signup. If you need to forward webhooks to localhost, a tunnel such as ngrok or Cloudflare Tunnel does that and this does not.

Use this one when the URL should still exist tomorrow, when the log must be private to you, when you want the receiver to fail in a controlled way, or when you want a scheduled job calling the same endpoint so the whole loop is tested end to end.

Questions

Is the webhook tester free?

Yes. The free plan has 3 endpoints, 30 requests a minute and 500 a day, keeps the newest 25 requests per endpoint, and does not expire. Paid plans raise those limits.

Why do I need an account to receive webhooks?

Anonymous receivers get used as drop boxes for data nobody should be storing. Tying each receiver to an account keeps logs private to you and lets you delete them. If you only need to see a canned response, the 112 demo endpoints need no account.

Are secrets in the request stored?

Authorization, Cookie, Proxy-Authorization, X-Api-Key and X-Signature headers are redacted before the request is written to the log. Bodies are stored as sent, up to 16 KB, so do not send production secrets in the body.

Can it verify Stripe or Slack signatures?

Not directly. Those schemes sign a timestamp together with the body, while the built-in HMAC check covers a plain HMAC-SHA256 of the raw body (the GitHub scheme). For Stripe and Slack, read the signature header from the log and verify it in your own code.

Can I replay a logged request to my local machine?

Not yet. Today you copy the logged body and headers into curl. Replaying to another URL and exporting a log as HAR are the two features planned next.

How is a dropped connection simulated?

The endpoint runs on Cloudflare Workers, which can cut a response in the middle of the body but not before the status line. A drop step therefore looks like a truncated response: curl exits with code 18, and most HTTP clients raise a read error, which is the same retry path as a reset.