Provider reference / Svix

How Svix (Clerk, Resend) delivers webhooks

8 attempts over roughly a day, an exhausted-message notice, disable after 5 failing days. Svix signs for Clerk and Resend too; format and verifier.

Delivery behaviour

Read from the vendor's own documentation, last checked 2026-08-06. Where the vendor states no number, this table carries none.

Response budgetnot published by the vendor
Retry8 attempts: immediately, 5s, 5 min, 30 min, 2h, 5h, 10h, 10h. Then a message.attempt.exhausted operational webhook
Gives upEndpoint disabled after all attempts fail for 5 days
Sourcehttps://docs.svix.com/retries

Signature

Verified against a working verifier proven by a test suite, not read from documentation. Last verified 2026-08-20.

AlgorithmHMAC-SHA256
Signed payload{id}.{timestamp}.{body}
Encodingbase64
Headersvix-signature = v1,base64
Tolerancenone enforced

Verify it

The raw request body, byte for byte, before any JSON parsing. Every scheme on this page breaks the moment a framework re-serializes the payload.

const crypto = require("node:crypto");

// base64(HMAC-SHA256(base64-decoded secret, "{id}.{timestamp}.{body}"))
const id = req.headers["svix-id"];
const ts = req.headers["svix-timestamp"];
const key = Buffer.from(whsecSecret.replace("whsec_", ""), "base64");

const expected = crypto
  .createHmac("sha256", key)
  .update(`${id}.${ts}.${rawBody}`)
  .digest("base64");
// svix-signature holds space-separated candidates like "v1,<base64>"
const valid = req.headers["svix-signature"]
  .split(" ")
  .some((part) => part.split(",")[1] === expected);

Or the official SDK: new Webhook(secret).verify(rawBody, headers) — it also enforces the 5-minute timestamp tolerance for you. The whsec_ prefix is stripped and the rest base64-decoded before keying the HMAC; skipping that step is the classic mistake.

What bites

Clerk and Resend webhooks are Svix underneath, so one verifier covers all three — the headers and format are identical, only the dashboard where the secret lives differs.

The retry ladder is 8 attempts (immediately, 5s, 5min, 30min, 2h, 5h, 10h, 10h), then a message.attempt.exhausted operational webhook tells you it gave up. Five days of everything failing disables the endpoint.

Read more

AnyHook sits in front of endpoints that receive from Svix: it answers inside the budget above, retries on its own schedule when your server is down, and keeps every event replayable. Change one URL, keep your code.

How it works →