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 resposta | não publicado pelo provedor A Stripe não publica um número. A documentação dela diz apenas para responder 2xx antes de qualquer lógica lenta. A comunidade trabalha com 20 s |
|---|---|
| Novas tentativas | Backoff exponencial por até 3 dias no modo de produção. Sandbox: 3 tentativas ao longo de algumas horas |
| Desiste | Endpoint desativado após falhas contínuas, com aviso prévio por e-mail. Os eventos ficam na Events API por 30 dias |
| Fonte | https://docs.stripe.com/webhooks |
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.
| Algoritmo | HMAC-SHA256 |
|---|---|
| Payload assinado | {timestamp}.{body} |
| Codificação | hex |
| Cabeçalho | stripe-signature = t=X,v1=hex |
| Tolerância | 5 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");
// stripe-signature: "t=1700000000,v1=abc..." — HMAC-SHA256 over "{t}.{body}"
const pairs = Object.fromEntries(
req.headers["stripe-signature"].split(",").map((p) => p.split("=")),
);
const expected = crypto
.createHmac("sha256", endpointSecret) // whsec_... from the endpoint's page
.update(`${pairs.t}.${rawBody}`)
.digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(pairs.t)) < 300;
const received = Buffer.from(pairs.v1 ?? "");
const wanted = Buffer.from(expected);
// timingSafeEqual throws on a length mismatch, so check that first.
const valid =
fresh && received.length === wanted.length && crypto.timingSafeEqual(received, wanted);Ou deixe o SDK fazer isso: stripe.webhooks.constructEvent(rawBody, sig, secret). Ele precisa do corpo bruto, então aplique express.raw() na rota do webhook antes de qualquer parser de JSON.
Armadilhas
A Stripe nunca publica um prazo de resposta. A documentação diz apenas para responder 2xx antes de qualquer lógica lenta; 20 segundos é o número com que a comunidade trabalha, e handlers que gravam de forma síncrona num banco de dados lento chegam perto dele a cada evento.
Depois de 3 dias de falhas, o evento sai da fila de novas tentativas silenciosamente. Falhas contínuas fazem a Stripe desativar o endpoint, com aviso prévio por e-mail, e os eventos continuam disponíveis para busca na Events API por 30 dias.
Leia também
O AnyHook fica entre Stripe 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 (Stripe) expira após 5 min.