Documentation Menu

Svix Webhook Signature Verification Failed? Fix Guide

Why Is Svix Webhook Signature Verification Failing?

Svix-managed webhooks throw signature mismatch errors on receipt.

Root Causes of Svix Signature Verification Errors

  • Incorrectly formatted verification string — missing the webhook-id.timestamp. prefix
  • Missing message ID (`webhook-id`) or timestamp header
  • Clock skew bypassing 5-minute tolerance limit
  • Using the raw whsec_ string as a key without Base64-decoding it

How to Fix Svix Signature Verification — Correct whsec_ Decoding & String Format

  1. 1Capture raw body as a Buffer using express.raw() — JSON middleware will corrupt it.
  2. 2Extract three headers: webhook-id, webhook-timestamp, webhook-signature.
  3. 3Build the signed content string exactly: `${webhookId}.${webhookTimestamp}.${rawBody}`
  4. 4Strip the "whsec_" prefix from your secret, then Base64-decode the remainder to get raw bytes.
  5. 5HMAC-SHA256 the signed content string using those decoded secret bytes.
  6. 6Base64-encode the result and compare against each signature in webhook-signature (space-separated).

Working Svix Webhook Verification Code — Node.js & Python

Copy-paste verified examples. Use the tab that matches your stack.

javascript
const crypto = require('crypto');

app.post('/webhooks/svix', express.raw({ type: 'application/json' }), (req, res) => {
  const webhookId        = req.headers['webhook-id'];
  const webhookTimestamp = req.headers['webhook-timestamp'];
  const webhookSignature = req.headers['webhook-signature'];

  if (!webhookId || !webhookTimestamp || !webhookSignature) {
    return res.status(400).send('Missing Svix headers');
  }

  // Build the exact signed content Svix expects
  const signedContent = `${webhookId}.${webhookTimestamp}.${req.body.toString()}`;

  // Strip "whsec_" prefix, then Base64-decode to get raw key bytes
  const secretBytes = Buffer.from(
    process.env.SVIX_WEBHOOK_SECRET.replace(/^whsec_/, ''),
    'base64'
  );

  const computed = crypto
    .createHmac('sha256', secretBytes)
    .update(signedContent)
    .digest('base64');

  // Header may contain multiple signatures: "v1,<base64> v1a,<base64>"
  const isValid = webhookSignature
    .split(' ')
    .map(s => s.split(',')[1])
    .some(sig => sig === computed);

  if (!isValid) return res.status(401).send('Invalid signature');

  const event = JSON.parse(req.body);
  console.log('Svix event:', event.type);
  res.status(200).send('OK');
});

Most Common Svix Signature Mistakes

  • Hashing the body directly instead of building the structured Svix string.
  • Failing to decode the secret from Base64 before hashing.
  • Using the full whsec_xxx string as the HMAC key.

Svix Webhook Debugging Workflow

Extract headers → decode secret → construct signature string → hash → compare.

How to Prevent Svix Signature Failures

  • Replay test callbacks safely to catch timestamp skew tolerance limits using Hookmetry.

Works with webhooks and other async event systems (including AI callbacks). Instead of guessing, inspecting the exact payload and headers can help debug faster.

Try the free webhook tester

Was this page helpful?

Your feedback helps us improve the docs.