Webhook Tester
Receive and inspect webhook requests with a temporary endpoint. Use the webhook tester to debug headers, payloads, methods, retries, and provider behavior before wiring a webhook into your own backend.
Last updated: March 25, 2026
Find this tool useful? Support the project to keep it free!
Buy me a coffeeWhat is Webhook Tester?
A webhook is an HTTP callback: when an event occurs in a third-party service (a payment succeeds in Stripe, a PR is merged in GitHub, a form is submitted in Typeform), that service sends a POST request to a URL you specify — your webhook endpoint. Developing and debugging webhooks is traditionally difficult because the receiving endpoint needs to be a publicly accessible URL — your localhost:4000 isn't reachable from the internet.
The Webhook Tester solves this by providing a unique, publicly addressable temporary URL. Any HTTP request sent to your URL is captured and stored, and your browser polls for new requests every 3 seconds, displaying each one in the log panel with all its details: HTTP method, headers, query parameters, parsed JSON body, and raw body. This eliminates the need to run ngrok, deploy staging servers, or add debug logging just to see what a webhook payload looks like. Services this is commonly used for: Stripe (payment events), GitHub (repository webhooks), Shopify (order/product events), Twilio (SMS status callbacks), HubSpot (CRM webhooks), and Slack (interactive component payloads).
How to Use Webhook Tester
A unique webhook endpoint URL is automatically generated when the page loads — copy it with the "Copy URL" button
Paste this URL into the webhook configuration of the service you want to test (Stripe Dashboard → Developers → Webhooks, GitHub Repo Settings → Webhooks, etc.)
Trigger an event in the service (make a test payment, push a commit, submit a form)
Watch the incoming request appear in the log panel within a few seconds — showing method, headers, body, and timestamps
Click any logged request to expand it and inspect the full payload, then use "Copy as cURL" to reproduce the request locally
Common Use Cases
- Testing Stripe payment webhook payloads to understand the exact JSON structure of a "payment_intent.succeeded" event
- Debugging a GitHub Actions webhook integration — seeing exactly what headers and body shape GitHub sends on a push event
- Verifying that your own backend sends correctly-formatted webhooks to downstream services during development
- Inspecting Shopify webhook payloads (new_order, product_update) before writing the handler logic
- Testing Twilio SMS status callback payloads from twilio.com to understand delivery/failed status fields
- Sharing a webhook capture with a teammate by copying the URL — both can see incoming requests in real-time
- Using the "Respond with custom status" feature to test how the sending service handles 2xx vs 4xx vs 5xx responses
- Capturing a webhook payload to use as a test fixture in unit tests for your webhook handler function
Example Input and Output
Inspecting a Stripe "payment_intent.succeeded" webhook captured by the tester:
Webhook URL pasted in Stripe:
https://webtoolsplanet.com/api/webhook-endpoint/abc123xyz
Stripe event triggered:
Test → payment_intent.succeededIncoming request captured at 14:23:05 UTC
Method: POST
URL: /api/webhook-endpoint/abc123xyz
Headers:
Stripe-Signature: «redacted»
Content-Type: application/json
User-Agent: Stripe/1.0 (+https://stripe.com/docs/webhooks)
Body (parsed JSON):
{
"id": "evt_1234",
"type": "payment_intent.succeeded",
"data": {
"object": {
"id": "pi_1234",
"amount": 2000,
"currency": "usd",
"status": "succeeded"
}
}
}How This Tool Works
When the page loads, a unique endpoint ID is generated and a session row is created in our database with a 2-hour expiry. Incoming HTTP requests to the endpoint URL are received by the server, redacted for known-sensitive headers, and written to the database (bodies capped at 64KB). The browser polls the database every 3 seconds for new requests and renders them (method, URL, headers, body) in the log panel. The server keeps up to 50 requests per endpoint; the session and its requests are deleted when the 2-hour expiry passes, or sooner if you generate a new URL or clear the log.
Technical Stack
Privacy Warning
Webhook payloads are received and stored in our database for up to 2 hours (or until you generate a new URL or clear the log) so they can be displayed back to your browser — this is necessary for the tool to function, and it is real database storage, not just in-memory. Known-sensitive headers are redacted before storage, but do not use this tool with production webhooks containing personal data (names, emails, payment info); a payload you send is only as private as an unauthenticated URL and 2-hour retention window make it.
Saving Payloads as Test Fixtures
Use the "Copy JSON" button on each captured request to save the payload as a JSON test fixture file. Use this in your unit tests: const mockPayload = require("./fixtures/stripe-payment-succeeded.json"). This ensures your handler is tested against a real payload shape, not hand-crafted mock data that might miss edge cases in the actual API response structure.
Webhook Retry Behavior
Webhook retry policies vary by provider: Stripe retries failed webhooks (non-2xx) with exponential backoff for up to 3 days. GitHub retries once after 30 minutes. Shopify retries 19 times over 48 hours. Twilio retries up to 3 times. If your webhook endpoint returns 2xx immediately but processes asynchronously, always respond 200 first, then process in a background job — never respond after long processing since the provider may time out and retry unnecessarily.
Frequently Asked Questions
How is this different from ngrok?
ngrok is a tunneling tool: it creates an encrypted tunnel from a public URL to your local machine, so webhooks are forwarded to your localhost server. The Webhook Tester doesn't require tunneling or a running server — it's a hosted receiver that captures and displays requests in your browser. Use ngrok when you need your local application code to process the webhook in real time. Use the Webhook Tester when you just want to see what the payload looks like without writing any handler code first.
Are webhook payloads stored permanently?
No. Received requests are stored in our database (not just in memory) and automatically deleted after 2 hours, or sooner if you generate a new URL or clear the log yourself. Each endpoint keeps a maximum of the 50 most recent requests, sensitive-looking headers (Authorization, Cookie, API keys) are redacted before storage, and stored bodies are capped at 64KB. Never send production webhook payloads containing personal data (customer PII, payment card data) to this tool. For production webhook development, use ngrok or a staging environment with proper data handling.
How do I verify the webhook signature in my handler code?
Most webhook providers include a signature header for security — verifying it prevents attackers from sending fake webhooks to your endpoint. Stripe uses Stripe-Signature with HMAC-SHA256. GitHub uses X-Hub-Signature-256. Shopify uses X-Shopify-Hmac-Sha256. The Webhook Tester redacts any header ending in "-signature" before storing it, so you can confirm a provider is sending the header at all, but not read the actual value here. For verification code: use the provider's official SDK (stripe.webhooks.constructEvent() in Node.js) or implement HMAC verification with the raw request body in your own handler, where the real header is available.
Can I replay or re-send a captured webhook?
Yes. Click "Copy as cURL" on any captured request to get a cURL command that re-sends the exact same request — same body, same headers. Paste this command in your terminal to replay the webhook against your local handler: curl -X POST http://localhost:3000/webhook -H "Content-Type: application/json" -H "Stripe-Signature: ..." -d '{"type":"payment_intent.succeeded",...}'. This makes captured real payloads reusable as test fixtures during development.
Does this work with webhook services that require HTTPS?
Yes. All Webhook Tester endpoints are served over HTTPS with a valid TLS certificate. Services that require HTTPS (Stripe, PayPal, GitHub) will accept the generated URL. The URL format is: https://webtoolsplanet.com/api/webhook-endpoint/{unique-id}. TLS certificate validation is handled by our hosting infrastructure, so you don't need to configure any SSL settings.
Can I set a custom response status code for my webhook endpoint?
Yes. Use the "Response Configuration" panel to set a custom HTTP status code (200, 201, 204, 400, 500) and optional response body that your webhook endpoint returns. This lets you test how the sending service handles error responses — for example, Stripe will retry webhooks that receive 5xx responses up to 3 days. Setting a 500 status lets you see the retry behavior without writing any code.
Related Tools
HTTP Status Code Reference
Searchable reference for all HTTP status codes — with meaning, common causes, and fix recommendations.
JSON Formatter
Format, validate, and beautify JSON instantly — with clear error messages, Tree View, Diff mode, and Schema validation.
JWT Decoder
Decode and inspect JSON Web Tokens (JWT) without validation.
Base64 Encoder/Decoder
Encode text to Base64 or decode Base64 to plain text — with URL-safe mode, auto-detect, and size stats.
URL Encoder/Decoder
Encode and decode URL strings with special characters.
JSON Tree Viewer
Visualize JSON data in an interactive tree structure.

