Novas tentativas e entrega

Como a Certivant repete entregas de webhook que falharam — cronograma exato de espera, regra de timeout de 10 segundos, recuperação de eventos esgotados e um padrão de manipulador rápido para ficar dentro do orçamento.

A Certivant foi projetada para entregar cada evento pelo menos uma vez. Se o seu endpoint ficar indisponível por um breve período — um deploy, uma falha momentânea do banco de dados, uma interrupção de 30 segundos —, as novas tentativas garantem que o evento ainda seja entregue. Esta página explica o comportamento exato para que você possa se planejar de acordo.

A política de novas tentativas em resumo

Valor
Máximo de tentativas de entrega5 (incluindo a primeira)
Cronograma de novas tentativas5s, 30s, 5min, 1h, 24h, cada um com variação aleatória de ±10% (jitter)
Retry-AfterRespeitado em qualquer tentativa com falha (em segundos ou como data HTTP, limitado a 24 h): a próxima tentativa nunca ocorre antes do que você pediu
Timeout por tentativa10 segundos
Critério de sucessoStatus HTTP 200–299
Critérios de falhaStatus >= 300, timeout, erro de conexão, falha de DNS
Janela total de entrega~25 horas a partir da primeira tentativa

Após a quinta tentativa com falha, o evento é marcado como esgotado. Ele não será repetido automaticamente. Um e-mail é enviado ao proprietário da organização avisando que os webhooks estão falhando.

A linha do tempo

gantt
  title Webhook delivery attempts
  dateFormat X
  axisFormat %s
  section Attempts
  Attempt 1 (immediate) :a1, 0, 1s
  Attempt 2 (+5s)       :a2, 5, 1s
  Attempt 3 (+30s)      :a3, 35, 1s
  Attempt 4 (+5min)     :a4, 335, 1s
  Attempt 5 (+1h)       :a5, 3935, 1s
  Attempt 6 (+24h)      :a6, 90335, 1s

O relógio começa quando o evento é gerado. Se o seu endpoint estiver saudável na primeira tentativa, você nunca verá novas tentativas. Se ele ficar fora do ar durante as cerca de 25 horas completas, o evento se esgota.

Uma interrupção passageira e curta (um deploy, um failover do banco de dados, qualquer coisa de menos de um minuto) é totalmente absorvida pelo cronograma — o seu endpoint receberá a próxima tentativa cerca de 5 segundos depois e terá sucesso.

O que conta como sucesso

A Certivant considera o seu endpoint saudável quando:

  • O status HTTP é 2xx (200, 201, 204 etc.).
  • A resposta chega em até 10 segundos após o envio da requisição.

Qualquer outra coisa é uma falha de entrega:

  • Redirecionamentos 3xx — a Certivant não segue redirecionamentos. Aponte a URL do webhook para o destino final.
  • 4xx (incluindo 401 e 404) — a Certivant tenta novamente de qualquer forma, caso o problema seja passageiro (verificação de autenticação na inicialização a frio, rota ainda não publicada). A maioria das integrações deve investigar qualquer 4xx — em geral, isso indica uma configuração incorreta do seu lado.
  • 5xx — erro do servidor. Nova tentativa padrão.
  • Conexão recusada, falha de DNS, erro no handshake TLS — mesmo comportamento de novas tentativas.
  • Nenhuma resposta em 10 segundos — a Certivant cancela a requisição e a conta como falha. As novas tentativas continuam.

Como projetar um manipulador rápido

Você tem um orçamento de 10 segundos. Faça o mínimo necessário de forma síncrona:

app.post("/webhooks/certivant", async (c) => {
  const rawBody = await c.req.text();

  // 1. Verify signature
  if (!verifyCertivantSignature(rawBody, c.req.header("X-Certivant-Signature-V2"), SECRET)) {
    return c.json({ error: "Invalid signature" }, 401);
  }

  // 2. Persist to queue (single DB write, fast)
  const eventId = c.req.header("X-Certivant-Event-Id")!;
  await db.webhookEventQueue.create({
    data: { id: eventId, payload: rawBody },
  });

  // 3. Acknowledge immediately
  return c.json({ received: true }, 200);
});

// Process the queue asynchronously
async function workerLoop() {
  while (true) {
    const event = await db.webhookEventQueue.findFirst({ where: { processedAt: null } });
    if (!event) { await sleep(1000); continue; }
    try {
      await handleEvent(JSON.parse(event.payload));
      await db.webhookEventQueue.update({ where: { id: event.id }, data: { processedAt: new Date() } });
    } catch (err) {
      // Bounded retry on your side; surface after N attempts
    }
  }
}

Esse padrão separa a confirmação de recebimento (que precisa ser rápida) da lógica de negócio (que pode ser lenta ou ser repetida de forma independente). Os seus serviços posteriores (enviar e-mails de boas-vindas, provisionar contas etc.) podem falhar sem fazer a Certivant repetir a entrega.

Quando o seu endpoint está realmente fora do ar

Se você ficar fora do ar por um período prolongado (manutenção, migração), as novas tentativas ainda cobrirão você por cerca de 25 horas. Depois disso:

  • Eventos esgotados continuam consultáveis por meio de GET /api/v1/kyc/requests/:id — o estado atual está sempre disponível na própria requisição. Percorra as requisições criadas durante a indisponibilidade e sincronize o estado manualmente.
  • O proprietário da organização recebe um e-mail quando um evento se esgota. O e-mail inclui o ID da requisição, para que seja fácil localizá-la.
  • O status de entrega do webhook (entregue / falhou / esgotado), a contagem de tentativas, o último código de resposta e a próxima nova tentativa agendada ficam visíveis no painel, em KYC → Configurações → Webhooks → Registro de entregas, onde cada evento com falha ou esgotado tem um botão Tentar agora (e uma repetição em lote).

Reenviar um evento esgotado

No registro de entregas, Tentar agora reenvia imediatamente um evento com falha ou esgotado, assinado com o segredo atual, e reinicia o seu contador de tentativas. Não existe um endpoint público (com chave de API) para disparar novamente um único evento. Outras opções:

  1. Busque o estado pela API. GET /api/v1/kyc/requests/:id sempre retorna o estado atual, incluindo a decisão final. Essa é a solução adequada para recuperar o atraso após uma indisponibilidade.
  2. Peça ao suporte para reenviar se estiver faltando um lote grande. Inclua os IDs das requisições ou a janela de tempo — o suporte pode reemitir os eventos para você.

Interação com o limite de requisições

A entrega de webhooks não conta no limite de requisições da sua chave de API — são sistemas separados. Você pode receber centenas de webhooks por minuto e, ao mesmo tempo, fazer centenas de chamadas de API por minuto com a mesma chave, e nenhum desses orçamentos afeta o outro.

Idempotência revisitada

Como existem novas tentativas, o mesmo evento lógico às vezes chegará duas vezes. Veja Eventos → Idempotência para o padrão recomendado de deduplicação usando X-KYC-Event-Id.

Sugestões de monitoramento

Uma integração de webhook saudável tem:

  • Tempo mediano de resposta no endpoint de webhook abaixo de 500 ms. Se ele subir, você corre o risco de atingir o timeout de 10 segundos sob carga.
  • Nenhum 4xx e nenhum 5xx vindo da URL do webhook em operação normal. Configure alertas para ambos.
  • Uma tabela de registro de idempotência que você possa consultar para confirmar que cada webhook foi processado pelo menos uma vez.

Se você estiver recebendo e-mails de eventos esgotados, as causas raiz mais comuns são: (a) a URL do webhook está errada (erro de digitação no painel), (b) o seu endpoint exige uma autenticação que a Certivant não fornece (a URL precisa aceitar POSTs sem autenticação — o cabeçalho de assinatura é a autenticação), (c) o seu endpoint é consistentemente mais lento que 10 segundos. Investigue cada uma delas.