Verify Standard Webhooks Webhook Signatures
Standard Webhooks (used by Svix, OpenAI, Anthropic and many others) signs the string {webhook-id}.{webhook-timestamp}.{body} with HMAC-SHA256. The base64 result is sent (prefixed v1,) in webhook-signature. The signing secret is base64 after its whsec_ prefix and is decoded before use. Paste the id, timestamp, body, secret and signature.
Everything runs in your browser — the payload and secret never leave this page. Want to verify a different provider? See the webhook signature verifier hub or the generic HMAC generator.
How Standard Webhooks signs webhooks
- Read
webhook-id,webhook-timestampandwebhook-signaturefrom the headers. - Build the signed content
{id}.{timestamp}.{raw body}. - Base64-decode your secret (the part after
whsec_) and use those bytes as the HMAC-SHA256 key. - Base64-encode the digest, prefix
v1,and constant-time compare against any signature inwebhook-signature.
Reference: Standard Webhooks signature documentation.
Verify Standard Webhooks signatures in code
const { Webhook } = require('standardwebhooks');
const wh = new Webhook(process.env.WEBHOOK_SECRET); // whsec_...
const payload = wh.verify(rawBody, {
'webhook-id': req.headers['webhook-id'],
'webhook-timestamp': req.headers['webhook-timestamp'],
'webhook-signature': req.headers['webhook-signature'],
});from standardwebhooks import Webhook
wh = Webhook(webhook_secret) # whsec_...
payload = wh.verify(raw_body, {
"webhook-id": headers["webhook-id"],
"webhook-timestamp": headers["webhook-timestamp"],
"webhook-signature": headers["webhook-signature"],
})Frequently asked questions
What is Standard Webhooks?
An open specification (backed by Svix and a steering committee from Zapier, Twilio, ngrok, Supabase and others) for signing and sending webhooks consistently. Providers like OpenAI, Anthropic and Google Gemini use it.
How is the secret used?
The signing secret is base64-encoded with a whsec_ prefix. Strip the prefix, base64-decode the rest to raw bytes, and use those bytes as the HMAC-SHA256 key — not the literal string.
How is this different from Stripe?
Both use HMAC-SHA256 with a timestamp, but Standard Webhooks also signs a unique message id, outputs base64 (not hex), and decodes its secret from base64 first.
Verify other providers
Receiving Standard Webhooks webhooks on a server behind a firewall or on localhost? Webhook Relay can forward them to your internal service and even verify or transform them before delivery.
