How to test a webhook online
- 1
Copy your webhook URL. The Inbox gives you a unique URL the moment the page loads.
- 2
Point the sender at it. Paste it as the endpoint in Stripe, GitHub, Slack, Shopify, Zapier, n8n or your own code, then trigger an event.
- 3
Inspect the request. It lands in the inbox within a couple of seconds: method, every header, and the body exactly as sent, formatted when it's JSON.
- 4
Verify or replay it. One click opens it in the signature verifier; Copy as curl replays it anywhere.
Send a test webhook from Stripe, GitHub or Slack
Waiting for a real payment or push to debug a handler is slow. Send a test builds the request the provider would send (same headers, same body shape, same signature scheme) and delivers it to your endpoint, then shows the status, headers and body your server answers with.
- Stripe test webhooks:
payment_intent.succeeded,checkout.session.completed,customer.subscription.created,invoice.payment_failed, signed withStripe-Signature. - GitHub test webhooks:
ping,push,pull_request,issues, withX-GitHub-EventandX-Hub-Signature-256. - Slack test webhooks:
app_mention,url_verificationand channel messages, signed withX-Slack-Signature. - Anything else: describe the scheme under Custom (header, signed string, SHA-1/256/512, hex or base64) and it signs the same way.
Test webhooks locally
Providers can't reach localhost, and neither can a website. Two ways around it: expose your machine with a tunnel such as ngrok http 3000 and use that URL as the endpoint, or use Copy as curl and run the signed request yourself. For Stripe specifically, stripe listen --forward-to localhost:3000/webhooks forwards real test-mode events, but note it signs them with its own whsec_ secret, not your dashboard's.
Why webhook signature verification fails
Paste the request and your secret into the verifier and it recomputes the signature step by step. When it doesn't match, it retries the common mistakes and tells you which one reproduces the provider's signature:
- The body was re-serialized.
JSON.stringify(req.body)changes spacing and key order. Hash the raw bytes. - The wrong secret. Test vs live mode, a different endpoint's secret, or a trailing newline from an
.envfile. - Encoding and prefixes. Hex vs base64, or a missing
sha256=/v0=prefix. - Stale timestamps. Stripe and Slack reject requests older than five minutes.
Stripe: “No signatures found matching the expected signature for payload”
That's the Stripe SDK saying the HMAC didn't match, almost always because a body parser ran before stripe.webhooks.constructEvent(). Give that route express.raw({ type: "application/json" }) (or await request.text() in a Next.js route handler) and use the signing secret of the endpoint that received the event.
Every provider signs webhooks differently
They agree on HMAC and almost nothing else: what gets signed, how the result is encoded, and whether replays are prevented all vary.
| Slack | Stripe | GitHub | |
|---|---|---|---|
| Headers | X-Slack-Signature, X-Slack-Request-Timestamp | Stripe-Signature: t={ts},v1={sig}[,v1=…] | X-Hub-Signature-256 |
| Signed string | v0:{timestamp}:{raw body} | {timestamp}.{raw body} | {raw body} only |
| Algorithm | HMAC-SHA256 | HMAC-SHA256 | HMAC-SHA256 |
| Encoding | hex, prefixed with v0= | hex | hex, prefixed with sha256= |
| Replay window | 5 minutes (you enforce it) | 5 minutes (SDK default) | None: no timestamp is signed |
Webhooks for MCP servers and AI agents
MCP (Model Context Protocol) servers give AI agents tools to call, and more and more agent workflows start with a webhook: a Stripe payment, a GitHub pull request or a Slack message arrives, your backend checks it, and an agent acts on it through an MCP tool. Three places this tester helps:
- Design the MCP tool input from the real payload. Point the provider at your inbox URL, trigger an event, and build the tool's input schema from the exact JSON instead of guessing field names.
- Verify before the model sees anything. Anyone can POST to a public endpoint, so an unverified webhook body is untrusted text, and putting it in an agent's context invites prompt injection. Check the signature first; only then hand the payload to the MCP server.
- Rehearse the trigger. Send a signed test event to the endpoint that feeds your MCP server or agent and watch how it responds, without waiting for a real event.
A webhook.site alternative with signature checks
webhook.site made the capture-URL workflow popular. This tester covers the same basics (a unique URL, any HTTP method, full headers and exact bodies) and adds the parts webhook work usually gets stuck on: signed test events for Stripe, GitHub and Slack, and a verifier that explains why a signature check fails. It's free, with no account.
Questions
Is this webhook tester free?
Yes. There's no account and no sign-up: open the page and you get a unique webhook URL straight away. Sending test webhooks and verifying signatures are free too.
How do I test a webhook URL?
Copy your unique URL from the Inbox tab and paste it wherever the provider asks for a webhook endpoint (Stripe, GitHub, Slack, Shopify, Zapier, n8n, or your own code). Trigger an event and the request appears in the inbox within a couple of seconds, with its method, headers and exact body.
How do I send a test webhook to my own endpoint?
Switch to “Send a test”, pick a provider and an event such as payment_intent.succeeded or push, paste your endpoint URL and press send. You'll see the exact request your server receives and its response. Add your signing secret to have the request signed the way the provider signs it.
Can I test a webhook running on localhost?
Our server can't reach your machine, so expose your local server with a tunnel such as ngrok and use that URL, or use Copy as curl and run the command yourself. For Stripe, the CLI command stripe listen --forward-to localhost:3000/webhooks forwards real test events to your local route.
Why does my webhook signature never match?
Nine times out of ten, the body you hashed isn't the raw bytes the provider signed. A JSON body parser runs first, and JSON.stringify(req.body) produces different spacing or key order, so the HMAC can't match. Capture the raw body before parsing: express.raw(), request.text(), or your framework's rawBody option.
Can I test webhooks that trigger an MCP server or AI agent?
Yes. Capture the real payload in the inbox to design your MCP tool's input, send signed test events to the endpoint that feeds your agent, and verify signatures before any payload reaches the model. See the MCP section above.
Is it safe to paste my signing secret here?
Yes. Signature checks run entirely in your browser with the Web Crypto API, and test events are signed in the browser too; the secret is never sent, logged or stored. Captured inbox requests are stored on our server so the inbox can show them.
How long are captured requests kept?
Each inbox keeps its last 50 requests for 7 days. Anyone who has the URL can see them, so don't share it, and use New URL to start a fresh inbox at any time.