Skip to content

Recuperar eventos perdidos ​

Seu servidor ficou fora do ar, o endpoint foi desativado por falhas seguidas, ou um pico estourou o teto horário. O que fazer para não ficar com buracos.

Primeiro: descubra o que aconteceu ​

Em Integrações › Webhooks › Log, o status de cada entrega diz onde ela parou:

StatusO que aconteceuRecuperação
successVocê respondeu 2xxNada a fazer
pendingAguardando próxima tentativaAguarde — o retry ainda vai rodar
failedEsgotou as 5 tentativasReenvio manual
droppedBarrada pelo teto horário, ou o endpoint estava desativadoReenvio manual

dropped não é "nunca existiu"

Uma entrega barrada pelo teto aparece no log com o payload guardado, justamente para você distinguir "foi descartada" de "o evento nunca ocorreu". Se ela não estivesse lá, você não teria como saber o que perdeu.

Reenvio manual ​

Cada linha do log tem Reenviar. Isso reabre a mesma entrega — mesmo corpo, mesmo id de evento — com uma tentativa adicional.

Como o id não muda, seu consumidor deduplica normalmente. Reenviar algo que você já processou é seguro — desde que você tenha implementado a deduplicação ou uma gravação idempotente.

Use quando:

  • Você consertou o servidor e quer as entregas failed de volta
  • Um pico gerou dropped pelo teto
  • O endpoint ficou desativado por um período

Quando o volume é grande ​

Reenviar dezenas de entregas uma a uma no painel é inviável. Nesse caso, a varredura por período recupera tudo de uma vez, e costuma ser mais rápida:

js
// Recupera o intervalo do incidente. O UPSERT torna repetição inofensiva.
for await (const resposta of varrerRespostas(FORM_ID, {
  from: '2026-07-26',
  to: '2026-07-28',
})) {
  await salvarNoCrm(resposta);
}

Isso funciona para respostas. Para eventos de convite (invite.opened, invite.delivered…), o equivalente é listar os convites e ler o effectiveStatus e os timestamps de cada um:

js
for await (const convite of varrerConvites(FORM_ID)) {
  await sincronizarStatus(convite.externalId, {
    status: convite.effectiveStatus,
    enviadoEm: convite.sentAt,
    abertoEm: convite.openedAt,
    respondidoEm: convite.respondedAt,
    falhaEm: convite.failedAt,
    motivoFalha: convite.failReason,
  });
}

O estado atual está sempre disponível pelo REST — o webhook é o atalho, não a única fonte. Isso é o que torna a recuperação sempre possível, mesmo sem log.

O log tem prazo curto

Ele guarda o payload das entregas, e payload de resposta contém dados pessoais. Não conte com ele como arquivo permanente: passado o prazo de retenção, a recuperação é pela varredura, não pelo reenvio.

Evitando o próximo incidente ​

Responda 2xx antes de processar. A causa mais comum de failed é o timeout de 10s. Confirme o recebimento, enfileire, processe num worker.

js
app.post('/edusati', express.raw({ type: 'application/json' }), async (req, res) => {
  const corpoBruto = req.body.toString('utf8');
  if (!assinaturaValida(req.get('x-edusati-signature'), corpoBruto)) {
    return res.sendStatus(401);
  }
  await fila.enfileirar(corpoBruto);   // rápido: só encosta na fila
  res.sendStatus(200);
});

Monitore o endpoint. 20 falhas consecutivas o desativam, e a partir daí as entregas em fila são descartadas. Um alerta no seu lado quando o handler começa a errar chega bem antes disso.

Nunca responda 410 por engano. Ele desativa o endpoint na hora, sem retry. Se seu framework devolve 410 para rota desconhecida, confira que o caminho do webhook está mesmo registrado.

Antecipe picos. Vai fazer um envio de 50 mil convites? O teto padrão é de 600 entregas por hora. Fale com o administrador da conta antes — depois do descarte, só o reenvio manual recupera.

Reconcilie por rotina. Uma varredura diária dos últimos dias, com gravação idempotente, transforma qualquer perda em algo que se resolve sozinho até o dia seguinte. É a rede de segurança que dispensa reagir a incidente. Ver Sincronizar com um CRM › Reconcilie periodicamente.

Manutenção programada ​

Não existe "pausar" um endpoint. Desativar descarta a fila pendente — não a segura para depois.

Se você vai derrubar o servidor para manutenção, as opções são:

  1. Deixar ligado e falhar. As entregas entram em retry com backoff (até 1h de espera, 5 tentativas). Manutenção curta é absorvida sem perda nenhuma. Esta é a melhor opção na maioria dos casos.
  2. Deixar um receptor mínimo no ar que só valida a assinatura, grava o corpo cru num arquivo ou fila e responde 200. Processa depois.
  3. Desativar e reconciliar depois pela varredura por período.

O que não funciona é desativar esperando que a fila aguarde.

Documentação da API pública do Edusati