Pular para o conteúdo

Boas práticas de webhooks

Verifique a assinatura, enfileire o evento (linha no banco de dados, fila, job em segundo plano) e retorne 2xx imediatamente. O SpacePost espera no máximo 15 segundos, e um handler lento vira novas tentativas e duplicatas.

A entrega é feita pelo menos uma vez. Guarde o webhook-id de cada entrega processada (uma constraint de unicidade basta) e ignore as repetidas.

const inserted = await db.insert(processedWebhooks).values({ id: webhookId }).onConflictDoNothing().returning();
if (inserted.length === 0) return new Response("duplicate", { status: 200 });

Use o corpo bruto, rejeite horários com mais de 5 minutos de diferença, compare as assinaturas em tempo constante (o SDK e as bibliotecas já fazem isso). Veja Verificar assinaturas.

Os eventos podem chegar fora de ordem, principalmente depois de novas tentativas. Compare o created_at do payload com o que você tem armazenado e aplique apenas as mudanças que fazem o estado avançar. O próprio last_event do SpacePost segue a mesma regra.

Evento Ação típica
email.bounced Marque o endereço como inválido no seu banco de dados; pare de enviar para ele.
email.complained Cancele imediatamente a inscrição do usuário em e-mails não essenciais.
email.delivery_delayed Em geral, nada; alerte se for um e-mail crítico em termos de tempo (redefinição de senha).
email.failed Registre data.failed.reason em log, alerte e, se possível, tente de novo com uma correção.
email.suppressed Um destinatário estava na sua lista de supressão; mostre isso na sua interface de administração.

Assine apenas os eventos que você trata. Menos eventos significam menos tráfego e menos falhas.

  • Sirva por HTTPS com um certificado válido.
  • Não registre segredos nem payloads completos com dados pessoais em logs.
  • Use um caminho dedicado, sem outro comportamento, e retorne um corpo genérico.
  • Guarde o signing_secret em um gerenciador de segredos, não no controle de versão.

Acompanhe o log de entregas no painel ou crie alertas para falhas repetidas: se o seu endpoint ficar fora do ar por mais de cerca de 27 horas, todas as novas tentativas se esgotam, e depois disso você precisa fazer o reenvio manualmente.