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 budget | not published by the vendor |
|---|---|
| Retry | 8 attempts: immediately, 5s, 5 min, 30 min, 2h, 5h, 10h, 10h. Then a message.attempt.exhausted operational webhook |
| Gives up | Endpoint disabled after all attempts fail for 5 days |
| Source | https://docs.svix.com/retries |
Signature
Verified against a working verifier proven by a test suite, not read from documentation. Last verified 2026-08-20.
| Algorithm | HMAC-SHA256 |
|---|---|
| Signed payload | {id}.{timestamp}.{body} |
| Encoding | base64 |
| Header | svix-signature = v1,base64 |
| Tolerance | none 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.