Stripe: como funciona a entrega de webhooks

Sem timeout publicado; na prática, 20 s. Novas tentativas por 3 dias, depois a Stripe desativa o endpoint. Assinatura verificada e verificador Node.

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

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 tentativasBackoff exponencial por até 3 dias no modo de produção. Sandbox: 3 tentativas ao longo de algumas horas
DesisteEndpoint desativado após falhas contínuas, com aviso prévio por e-mail. Os eventos ficam na Events API por 30 dias
Fontehttps://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.

AlgoritmoHMAC-SHA256
Payload assinado{timestamp}.{body}
Codificaçãohex
Cabeçalhostripe-signature = t=X,v1=hex
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");

// 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.

Como funciona →