Webhook Payload Inspector — see what your endpoint receives

Paste the webhook payload your endpoint received and its signature header, and this inspector shows whether they match, field by field, with the parts of the signature broken out and the computed hash shown next to the one that arrived. Signature verification is the step most people get wrong on their first integration, and the reason is almost always the same: the hash covers the exact bytes that were sent, and a framework that parses the JSON before your handler sees it has already destroyed them. Re-serialising an object produces different bytes - a different key order, different spacing - and therefore a different hash, so the check fails even though the request was genuine. This tool also renders the event shape so you can see which fields your handler should read, and flags the timestamp when it falls outside the tolerance window, which is the other common failure and usually means a server clock has drifted. Everything happens in your browser; nothing is sent anywhere.

Copy it from a request log or your framework's raw-body buffer. A body that was parsed and re-encoded will fail the signature even when the delivery was genuine.

How it works

The first thing the inspector does with a pasted body is check it against the envelope every delivery is wrapped in. That envelope is fixed: an event id, the id of the channel the event belongs to, a millisecond timestamp, the API version, the event name and a data object whose shape depends on the event. The schema the page validates against is the one the API itself publishes, copied into the site at build time, so a body that passes here is a body the API would have produced, and a body that fails names the field that is wrong - a missing key, a timestamp written as a string, an event name that does not exist, or an extra top-level key that a hand-written test fixture picked up somewhere. Paste a delivery straight from your logs and the three fields your handler routes on are shown at the top.

The signature header carries two members: a timestamp in milliseconds and a hex digest. The digest is a keyed hash over the timestamp, a dot, and the raw request body, computed with the webhook's secret. To verify it, you recompute the same hash over the same bytes and compare, and this page does exactly that using the cryptography built into your browser, with the secret you paste never leaving the tab. When the two digests differ, the pasted body is not byte-for-byte the body that was signed: whitespace, key order, a trailing newline added by an editor, or a framework that decoded and re-encoded the JSON before you copied it. Copy the raw body from as close to the wire as you can - a request log, a proxy capture, the raw-body buffer your framework exposes on the webhook route - and try again.

The timestamp is inside the signed string for a reason: it stops a captured request from being replayed later with the same valid signature. Receivers should reject a delivery whose timestamp is more than a few minutes from their own clock, and the inspector shows the age of the timestamp you pasted so you can see whether a genuine delivery would have been refused for staleness. When real deliveries start failing that check in production, the sender's clock is not the problem; your server's is. Once the body validates and the signature matches, the test endpoint linked below will fire a real delivery at your URL so you can repeat the exercise against your own handler rather than against a paste.

Do it with the API

This tool is the browser-side version of one API call.

Frequently asked questions

Why does my signature never match?

Because the body was parsed before it was hashed, in almost every case. Configure your framework to hand you the raw bytes on the webhook route specifically - raw body middleware in Express, the request body in FastAPI, php://input in PHP - and hash those. Parse the JSON afterwards, from the same bytes.

What is the timestamp part for?

It stops somebody replaying a request they captured earlier. The signature covers the timestamp as well as the body, and a delivery whose timestamp is far from your server's clock should be rejected. If genuine deliveries start failing that check, your server clock has drifted rather than anything being wrong with the sender.

Is my payload sent anywhere?

No. The comparison runs entirely in your browser, which is why you can paste a real delivery and a real secret without worrying. That also means the tool cannot tell you whether the delivery genuinely came from us - only whether the bytes and the header you pasted are consistent with the secret you pasted.

Related

Try it on your own number

Create a channel, link a WhatsApp number by QR or pairing code, and call the API in a couple of minutes. The Sandbox plan is free and needs no card.