Debugging a webhook from your laptop usually means running a tunnel: the URL changes on every restart, the provider has to be reconfigured, and half of the event types only fire in production. A catch-all webhook URL in the cloud solves this differently: your provider always talks to the same address, and you read the captured request whenever you want.

Why a catch-all URL beats a local tunnel

  • Stable address — configure the provider once, including its retries and test events.
  • No ports on your machine — nothing to expose, nothing to keep running while you sleep.
  • Full history — you can compare the last ten attempts of the same event, not just the one you caught live.
  • Shareable — a read-only link lets a teammate look at the payload without access to your account.

Step 1. Create a webhook URL

Create a webhook and copy the URL it generates. Any HTTP method and any content type is accepted: the request is stored with the method, full URL, query string, all headers, the raw body, the client IP, the user agent and the time.

Step 2. Point the provider at it

Add the URL as an endpoint in the provider's dashboard, then trigger an event:

  • Stripe — Developers → Webhooks → Add endpoint; use Send test webhook or Resend on a real event.
  • GitHub — Repository → Settings → Webhooks; the Redeliver button replays any previous delivery.
  • Telegram / Slack / your own service — call it yourself:
curl -X POST https://your-sandbox-host/w/YOUR_TOKEN \
  -H "Content-Type: application/json" \
  -H "X-Custom-Signature: test" \
  -d '{"event":"payment.succeeded","id":42}'

Step 3. Inspect what actually arrived

Open the request detail: query string as a table, headers, and the body pretty-printed when it is JSON. This is where most integration bugs become obvious:

  • the provider sent application/x-www-form-urlencoded, and your parser expects JSON;
  • the signature header is missing because the endpoint is in test mode;
  • the payload nests the object one level deeper than the docs suggested;
  • the event is a retry of an event you already processed twice.

Note that signatures are computed over the raw body, with the exact bytes and header value. Store and compare the raw body, never the re-serialised JSON.

Step 4. Replay it into your local code

Copy the body and header set from the capture and send the same request to your development server. Because you can see the original request in full, a failing local handler is easy to reproduce — no guessing, no waiting for the provider to fire again.

Tips

  • If a provider retries, group requests by their event id (Stripe sends one in the header) to spot duplicates.
  • Give the URL to a colleague read-only: create a share link and revoke it when the debugging session ends.
  • For automation, the share link also answers as JSON — see Review rendered emails with an AI assistant.

Next steps