Skip to main content
CodeLint.Dev Dev Tools

Webhook Tester — Send Signed Test Requests

Fire a realistic webhook at your own endpoint — provider payload templates, custom headers, HMAC signing — and inspect the status, headers, body and latency that come back.

Template:

Request

Headers

Body

HMAC Signature — optional

Response

Send a request to see the response

Ctrl+Enter / ⌘+Enter

CORS note — Browsers block cross-origin requests unless the target server sends CORS headers. For echo testing, use webhook.site or requestbin.com as the destination — both return full request details with CORS enabled.

Your own API — Works directly if your server sets Access-Control-Allow-Origin: *.

Testing a receiver without waiting for a real event

Webhook handlers are awkward to develop against because you do not control when the provider sends anything. Triggering a real event means creating a real charge, opening a real pull request, or waiting for something to happen on a schedule you do not set.

This sends the request instead. Pick a template — a GitHub push, a Stripe event, a Slack payload — or compose your own method, headers and body, point it at your endpoint, and you get the full response back: status code, response headers, body and round-trip latency.

The part that saves the most time is signature testing. Enter your webhook secret and a header name, and the request is signed with HMAC-SHA256 over the exact body being sent. If your handler rejects it, the problem is in your verification code, and you have found that out in seconds rather than after a provider's retries have already exhausted.

The secret is used locally: the HMAC is computed in your browser with the Web Crypto API and only the resulting signature header is transmitted, to the endpoint you named. The secret itself never leaves the page and is gone on reload.

Signature verification failures

The most common webhook problem, and almost always one of these four. Testing here isolates which:

Signature never matches, verification code looks correct

Cause:You are hashing the parsed-and-re-serialised body rather than the raw bytes. Any middleware that JSON-parses the request first destroys the exact byte sequence that was signed — key order, whitespace and unicode escaping all shift.

Fix:Capture the raw body before any body-parsing middleware runs. In Express, use express.raw() on the webhook route specifically; in Next.js, disable the built-in body parser for that handler.

Comparison is correct but leaks the secret over time

Cause:Comparing signatures with == or === returns as soon as bytes differ, so response time reveals how many leading bytes matched. That is a practical timing attack.

Fix:Use a constant-time comparison: crypto.timingSafeEqual in Node, hmac.compare_digest in Python.

Works locally, fails in production

Cause:A proxy, load balancer or CDN in front of the application is modifying the body — recompressing it, or normalising line endings — after the signature was computed.

Fix:Send the identical body to both environments and compare what each handler received. If they differ, the proxy is the culprit.

Verification passes but is rejected intermittently

Cause:A timestamp tolerance check failing because of clock skew between your server and the provider.

Fix:Run NTP. Most providers allow a five-minute window; a server drifting further fails sporadically and looks random.

Building a webhook receiver that holds up

Things provider docs assume you know and rarely state outright — each is worth testing before you ship:

  • Respond fast, process laterMost providers time out in 5–30 seconds and treat a slow response as a failure. Validate the signature, enqueue the payload, return 200. Do the real work off the request path — the latency figure here tells you whether you are close to the limit.
  • Expect duplicatesAt-least-once delivery is the norm. A network blip after you responded means the provider retries and you get the same event twice. Store the event ID and make handling idempotent — send the same payload twice here and check nothing double-applies.
  • Expect out-of-order arrivalRetries mean an older event can land after a newer one. Use the event’s own timestamp or sequence number to decide whether to apply it, not arrival order.
  • Return the right status2xx means received. A 4xx usually tells the provider to stop retrying — right for an unparseable payload, badly wrong for a transient database error, where 5xx gets you a retry.
  • Never trust the payload contentsEven with a valid signature, treat the body as data. Use the IDs it contains to re-fetch authoritative state from the provider’s API rather than acting on amounts or statuses in the payload directly.
  • Log the raw body for a retention windowWhen a webhook goes wrong at 3am, the raw payload is the only artefact that lets you reconstruct what happened. Redact secrets and keep it a few days.

About

The Webhook Tester lets you craft and send HTTP requests — choosing from POST, GET, PUT, PATCH, or DELETE — with full control over headers and a JSON request body, then inspect the status code, response headers, and response body without leaving your browser. Three realistic payload templates are pre-loaded: a GitHub Push event, a Stripe payment_intent.succeeded event, and a Slack Events API callback. Load any template and customise it to match your exact use case in seconds. For webhook providers that require signed payloads, enter your secret and the tool computes an HMAC-SHA256 signature in your browser using the Web Crypto API, then attaches it as the appropriate header — compatible with GitHub (X-Hub-Signature-256), Shopify, and any service using the sha256=<hex> convention. Your secret and payload never pass through any CodeLint.Dev server.

How to use

  1. 1 Paste your webhook endpoint URL into the URL field at the top and select the HTTP method — POST is the default for most webhook providers.
  2. 2 Click the Templates dropdown and choose GitHub Push, Stripe payment_intent.succeeded, or Slack Events API to pre-load a realistic JSON payload, or start with a blank Custom body.
  3. 3 Edit the JSON body in the editor to match the exact payload your endpoint expects.
  4. 4 Add or remove request headers using the Headers panel — common headers like Content-Type and Authorization are pre-filled.
  5. 5 To sign the request, enter your webhook secret in the Signing Secret field and specify the header name (e.g. X-Hub-Signature-256) — the HMAC-SHA256 signature is computed in your browser and added automatically.
  6. 6 Click Send Request to fire the request, then inspect the response status code, response headers, and body in the Response panel on the right.
Why does my request fail with a CORS error?
Browsers enforce the Same-Origin Policy and block cross-origin requests unless the target server responds with the correct CORS headers (Access-Control-Allow-Origin). Most production webhook endpoints are designed for server-to-server communication and do not include CORS headers, so browser-originated requests are blocked. To work around this during testing, use an echo service as your target — webhook.site and requestbin.com both accept any origin and reflect the full request back to you with CORS enabled. For testing your own local server, add permissive CORS headers to your development configuration.
How does HMAC-SHA256 signing work?
Webhook providers like GitHub, Shopify, and Twilio require the sender to compute an HMAC-SHA256 hash of the raw request body using a shared secret, then include the hex-encoded result in a specific header (e.g. X-Hub-Signature-256: sha256=<hex>). The Webhook Tester performs this computation in your browser using the Web Crypto API — your secret is used locally and never transmitted to any server, including CodeLint.Dev.
Can I test my local development server?
Yes. Enter a localhost URL such as http://localhost:3000/webhooks and the request will go directly from your browser to your local server. You will need to have CORS headers enabled in your development server configuration — most frameworks (Express, FastAPI, Laravel, Rails) have a development-mode setting or middleware that allows all origins.
Why does the tool show a network error instead of a response?
A network error (as opposed to an HTTP error status like 400 or 500) usually means one of two things: the target server is unreachable (wrong URL, server not running, firewall), or a CORS preflight request was rejected before the actual request could be sent. Check that your URL is correct and that your server is running, then check the browser console for a more specific CORS error message.
What is the difference between a webhook and a regular API call?
A regular API call is initiated by your client polling a server for data. A webhook is event-driven — the provider server pushes a notification to your endpoint the moment something happens (a payment is made, a commit is pushed, a message is posted). Testing a webhook means simulating that incoming push, which is exactly what this tool does: it fires the HTTP request a provider would send, so you can verify your endpoint handles it correctly before going live.
Is my payload or webhook secret sent to CodeLint.Dev?
No. Requests are sent directly from your browser to the target URL you enter — they do not route through any CodeLint.Dev server or proxy. HMAC signatures are computed entirely in your browser. Your webhook secret, payload contents, and response data are never visible to us.