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.

Paste the webhook-signature value above to compare

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

  1. Read webhook-id, webhook-timestamp and webhook-signature from the headers.
  2. Build the signed content {id}.{timestamp}.{raw body}.
  3. Base64-decode your secret (the part after whsec_) and use those bytes as the HMAC-SHA256 key.
  4. Base64-encode the digest, prefix v1, and constant-time compare against any signature in webhook-signature.

Reference: Standard Webhooks signature documentation.

Verify Standard Webhooks signatures in code

Node.js
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'],
});
Python
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.