9314JIUsi
Developer utilities · Free · No signup

Webhook Debugger: See Exactly What Your Provider Sends

Wiring up GitHub or Stripe webhooks is guesswork until you can see the real payload. Click once for a temporary callback URL, point your provider at it, and every incoming request shows up below — method, source IP, headers, body — ready to replay as a cURL command.

Temporary callback URL~2-second polling refreshJSON auto-formattingCopy as cURLAuto-wipes in 10 minNo signup
hook.php — temporary callback console Idle

This is a callback receiver for developers: you generate a temporary URL that only you know, and anything sent to it — a GitHub push event, a Stripe payment event, or your own curl — gets recorded exactly as it arrived.

Generate a callback URLA temporary URL that stays valid for 600 seconds. Extend or replace it any time.
Paste it into your provider's webhook settingsGitHub, Stripe, or any system that lets you configure a callback endpoint.
Come back and read the requestsThe page polls roughly every 2 seconds. New requests land on top with method, headers, and body.

Your callback URL and local settings stay in this browser — nothing on this device is uploaded, and there's no account. Captured requests are held on the server for up to 10 minutes and then wiped automatically, so don't send real API keys or sensitive data while testing. To wipe what's stored on this device, use "Clear my data" in the footer.

This callback URL has expired

After 600 seconds, the server wipes the URL along with every captured request. Your local record has been cleared too — generate a fresh one and keep debugging.

Requests

· Polling about every 2 seconds

Once you generate a URL, requests sent to it appear here in reverse chronological order (up to 50 kept).

No requests yet. Put the URL above into your provider's webhook settings, then send a test event — or try it yourself:
curl -X POST 'the URL above' -H 'Content-Type: application/json' -d '{"hello":"world"}'

Last month a Stripe endpoint refused to fire in our test environment. I had no public IP, so I faked payloads with curl — and wasted most of an afternoon, because my homemade request was missing the Stripe-Signature header entirely. The fix took 10 minutes once I caught one real callback on a temporary URL and diffed it against what I'd been sending.

TL;DR

  • Generate a temporary callback URL (valid 600 seconds), paste it into GitHub or Stripe webhook settings, and let the real payloads come to you.
  • The page polls roughly every 2 seconds: method, source IP, headers, and body all show up, with JSON formatted automatically.
  • Any request can be copied as a cURL command and replayed locally — stop guessing what the provider sent.
  • The server only holds captured requests temporarily and wipes them after 10 minutes; your device stores just the token.

1. Catch it first, diff it second

The biggest gap in webhook work is that you can't see what the other side actually sent. The docs say one thing; production traffic says another. Header names drift, event bodies gain a nesting level, retries arrive four minutes apart — documentation lags all of it.

Simulating the payload yourself means debugging with guessed data. I've burned hours on a signature check that failed purely because the provider sent x-signature while the docs insisted on X-Signature. Catch one real callback and every one of those questions answers itself.

2. From generate to replay, three steps

Click "Generate callback URL" and you get a URL with its own token. Drop it into a GitHub repository's Webhooks page, a Stripe Endpoint, or any system that accepts a custom callback, then trigger an event.

The page polls roughly every 2 seconds; new requests appear at the top and flash once. Open the headers section to inspect the allowlisted fields plus every X-* header; JSON bodies are pretty-printed for you.

When something looks wrong, hit "Copy as cURL" and paste the command into your terminal. The exact request replays instantly — tweak a field and resend, no waiting for the provider's next event.

3. Know the limits before they bite

Each URL lives 600 seconds; the server wipes it and its captured requests on expiry, and "Extend" adds another 600. Each URL keeps at most 50 requests, dropping the oldest; each body is capped at 256KB and flagged when truncated.

Headers are limited to common fields plus all X-* headers, with values capped at 4KB. I'd argue these limits are features, not defects — debugging needs "clearly visible", not "stored forever", and 50 requests cover a full integration session.

One habit worth keeping: don't wire production secrets into a webhook while you're still debugging. When signatures won't match, compare against the raw request here first, then switch to real keys once the logic is proven.

FAQ

How long does a callback URL live?

Each URL works for 600 seconds (10 minutes) after you generate it; when it expires, the server wipes the URL together with every captured request. Hit "Extend" mid-debug to add another 600 seconds. Reloading the page does not extend it — the countdown is always visible at the top of the console.

Is what I send safe?

Captured requests are held on the server for up to 10 minutes and then wiped automatically, so don't send real API keys or other sensitive data while testing. This device only stores your token and unread count in localStorage. To wipe that, use "Clear my data" in the footer — it asks for confirmation first.

What details do I get for each request?

HTTP method, time, source IP, the raw query string, headers (common fields plus every X-* header, each value capped at 4KB), and the request body (up to 256KB; longer bodies are truncated and flagged). Any request can be copied as a cURL command with one click and replayed locally.

How fast do new requests show up?

About 2 seconds. The page polls the server roughly every 2 seconds — there is no long-lived connection, and the server side is nothing more than lightweight temporary storage. Polling pauses while the tab is in the background and fires immediately when you come back.