Payload and signing settings
Client-side onlyUse the exact raw body received by your endpoint. Even whitespace changes can invalidate the signature.
Dev Tools
Generate signatures and verify incoming webhook headers for Stripe-style and generic HMAC workflows. Great for debugging payload mismatches, wrong secrets, or encoding issues.
Generated signature and verification update automatically as you edit.
Use the exact raw body received by your endpoint. Even whitespace changes can invalidate the signature.
// Signature will appear hereIn Stripe mode this should look like t=1715000000,v1=....
Enter a payload, secret, and signature to verify.
timestamp.payloadEverything runs in your browser. Payloads and secrets are never sent to a backend by this tool.
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.
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.whsec_… value). The secret never leaves your browser.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.
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.
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.
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.
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.
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.
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.
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….
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.
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.
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.
Yes. Select HMAC-SHA1 from the Algorithm dropdown. SHA1 is used by some older webhook implementations. For new integrations, prefer SHA256 or SHA512.
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.