Dev Tools

Webhook Signature Tester

Generate signatures and verify incoming webhook headers for Stripe-style and generic HMAC workflows. Great for debugging payload mismatches, wrong secrets, or encoding issues.

Live output

Generated signature and verification update automatically as you edit.

Payload and signing settings

Client-side only

Use the exact raw body received by your endpoint. Even whitespace changes can invalidate the signature.

Generated signature

// Signature will appear here

Signature to verify

In Stripe mode this should look like t=1715000000,v1=....

Verification result

Enter a payload, secret, and signature to verify.

What this helps with

  • • Stripe webhook debugging
  • • GitHub, Clerk, Svix, and custom HMAC signatures
  • • Detecting mismatched secrets or altered raw payloads
  • • Comparing hex vs base64 vs base64url output

Common mistakes

  • • Re-stringifying parsed JSON instead of using the original raw body
  • • Using the wrong secret or environment secret
  • • Forgetting Stripe signs timestamp.payload
  • • Confusing hex signatures with base64 signatures

Privacy

Everything runs in your browser. Payloads and secrets are never sent to a backend by this tool.

What Is a Webhook Signature Tester?

A webhook signature tester lets you generate and verify the HMAC-based signatures that services like Stripe, GitHub, Clerk, and Svix attach to outgoing webhook requests. When a provider sends an event to your endpoint, it signs the request body with a shared secret using an algorithm such as HMAC-SHA256 and includes the signature in an HTTP header. Your server must recompute the same signature and compare it to confirm the request is authentic and unmodified.

This tool lets you perform that entire sign-then-verify cycle in the browser — useful when debugging integration failures, understanding the signing format of a new provider, or reproducing a mismatched-signature error without spinning up a local server.

How to Test Webhook Signatures Online

  1. 1 Choose a preset or start from scratch — click the Stripe, GitHub, or Generic example buttons to load realistic sample values. Each preset configures the correct mode, algorithm, and encoding for that provider.
  2. 2 Select the verification mode — choose Stripe-style header to use the t=timestamp,v1=sig format, or Standard signature value for a plain HMAC hex or base64 string as used by GitHub, Slack, and most custom implementations.
  3. 3 Enter your webhook secret — paste the secret from your provider's dashboard (e.g. Stripe's whsec_… value). The secret never leaves your browser.
  4. 4 Paste the raw request body — use the exact bytes received at your endpoint. Do not re-stringify parsed JSON; even a single whitespace difference produces a completely different signature.
  5. 5 Read the live output — the generated signature and verification result update instantly. Paste the header value from the provider's request into Signature to verify to confirm whether it matches.

Common Use Cases

Debugging Stripe webhook failures

Paste a Stripe event body, your endpoint secret, and the Stripe-Signature header value to instantly see whether the signature matches and why it might not.

Verifying GitHub webhook signatures

GitHub sends a X-Hub-Signature-256 header using HMAC-SHA256 hex. Select Standard mode with SHA256 and hex encoding to reproduce and verify the value.

Building a custom webhook server

When designing a webhook sender, use this tool to generate reference signatures for each encoding and algorithm combination, then validate your server-side implementation produces identical output.

Comparing encoding formats

Switch between hex, base64, and base64url to see how the same HMAC key produces different string representations. Useful when a vendor's docs are ambiguous about which encoding they expect.

Reproducing production errors locally

Copy a real webhook payload from your server logs, paste it here with your signing secret, and confirm whether the raw body your framework exposes matches what was actually signed.

Testing Clerk, Svix, or Zapier webhooks

Many SaaS platforms use HMAC-SHA256 with base64 or hex encoding. Use the Generic preset as a starting point and adjust the algorithm and encoding to match each provider's documentation.

Frequently Asked Questions

Why does my Stripe signature not match?

The most common cause is that your framework automatically parses and re-serializes the request body. Stripe signs the original raw bytes, so you must read the raw body (e.g. using express.raw() or request.text()) before verifying the signature.

What is the Stripe-style signing format?

Stripe concatenates the Unix timestamp and raw body as timestamp.payload, then HMAC-SHA256 signs that string with your endpoint secret. The resulting Stripe-Signature header looks like t=1715000000,v1=abc123….

Which algorithm does GitHub use for webhooks?

GitHub uses HMAC-SHA256 and sends the signature as a hex string prefixed with sha256= in the X-Hub-Signature-256 header. Select Standard mode, SHA256, and Hex encoding, then compare the output to the header value after stripping the prefix.

Is my webhook secret safe to enter here?

Yes. All computation happens entirely in your browser using the Web Crypto API. No payloads, secrets, or results are transmitted to any server. You can verify this by running the tool with your network tab open — no outbound requests are made.

What is the difference between hex and base64 encoding?

Both are ways to represent the raw HMAC bytes as text. Hex uses lowercase a–f characters and is twice as long. Base64 is more compact and uses A–Z, a–z, 0–9, and +/=. Base64url replaces + with - and / with _ to make the value URL-safe.

Can I test HMAC-SHA1 signatures?

Yes. Select HMAC-SHA1 from the Algorithm dropdown. SHA1 is used by some older webhook implementations. For new integrations, prefer SHA256 or SHA512.

Why does whitespace in the payload matter?

HMAC signs every byte of the input. A trailing newline, an extra space, or pretty-printed JSON vs minified JSON all produce completely different signatures. Always use the exact raw bytes from the HTTP request body, not a parsed and re-serialized version.