Svix (Clerk, Resend): como funciona a entrega de webhooks

8 tentativas em cerca de um dia, aviso de desistência, desativação após 5 dias de falhas. A Svix também assina para Clerk e Resend; formato e verificador.

Comportamento de entrega

Lido na documentação do próprio provedor, verificado pela última vez em 2026-08-06. Onde o provedor não informa um número, esta tabela também não traz nenhum.

Prazo de respostanão publicado pelo provedor
Novas tentativas8 tentativas: imediatamente, 5 s, 5 min, 30 min, 2 h, 5 h, 10 h, 10 h. Depois, um webhook operacional message.attempt.exhausted
DesisteEndpoint desativado quando todas as tentativas falham por 5 dias
Fontehttps://docs.svix.com/retries

Assinatura

Verificada com um verificador funcional, comprovado por uma suíte de testes, e não lida na documentação. Última verificação em 2026-08-20.

AlgoritmoHMAC-SHA256
Payload assinado{id}.{timestamp}.{body}
Codificaçãobase64
Cabeçalhosvix-signature = v1,base64
Tolerância5 min

Verifique a assinatura

O corpo bruto da requisição, byte a byte, antes de qualquer parsing de JSON. Todos os esquemas desta página quebram no momento em que um framework serializa o payload de novo.

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);

Ou o SDK oficial: new Webhook(secret).verify(rawBody, headers). Ele também aplica a tolerância de 5 minutos no timestamp por você. O prefixo whsec_ é removido e o resto, decodificado de base64 antes de servir de chave para o HMAC; pular essa etapa é o erro clássico.

Armadilhas

Os webhooks da Clerk e da Resend são Svix por baixo, então um verificador cobre os três: os cabeçalhos e o formato são idênticos, só muda o painel onde fica o segredo.

O cronograma de novas tentativas tem 8 tentativas (imediatamente, 5 s, 5 min, 30 min, 2 h, 5 h, 10 h, 10 h), depois um webhook operacional message.attempt.exhausted avisa que a Svix desistiu. Cinco dias com tudo falhando desativam o endpoint.

Leia também

O AnyHook fica entre Svix e seus endpoints: responde em cerca de um segundo, tenta de novo segundo um cronograma próprio quando seu servidor está fora do ar e guarda cada evento disponível para replay. Troque uma URL e mantenha seu código; para aceitar novas tentativas e replays, verifique o cabeçalho AnyHook-Signature, porque a assinatura original do remetente (Svix) expira após 5 min.

Como funciona →