Pular para o conteúdo

Boas práticas

Um recebimento de webhook bem montado aguenta três coisas que vão acontecer: a mesma entrega chegar duas vezes, os eventos chegarem fora de ordem e o seu servidor ficar fora do ar por um tempo.

A tentativa tem 15 segundos. Passou disso, ela conta como falha e o evento volta depois, mesmo que o seu sistema tenha terminado o trabalho.

Então, no recebimento, faça só o mínimo:

  1. confira a assinatura;
  2. guarde o evento (numa fila, numa tabela);
  3. responda 200.

O trabalho de verdade (atualizar o ERP, mandar e-mail, chamar outro sistema) roda depois, fora da requisição.

A mesma entrega pode chegar mais de uma vez: a sua resposta se perdeu na rede, passou dos 15 segundos, ou alguém fez o reenvio manual. Em todos esses casos o webhook-id (e o id do corpo) é o mesmo.

Guarde o webhook-id de cada evento que você processou e, antes de processar, confira se ele já está lá. Se estiver, responda 200 e não faça nada. Uma restrição de unicidade no banco resolve isso sem corrida entre dois recebimentos simultâneos.

Os eventos não chegam necessariamente na ordem em que aconteceram. Uma entrega que falhou volta minutos ou horas depois, quando outras do mesmo registro já chegaram; até 5 entregas do mesmo endpoint podem estar em andamento ao mesmo tempo; e dois eventos da mesma gravação não têm ordem entre si.

Para decidir qual informação é a mais nova:

  • compare o timestamp do corpo, que é o horário em que o evento aconteceu (não o webhook-timestamp do cabeçalho, que é o horário do envio);
  • ou compare o updated_at do objeto com o que você já tem guardado.

Se o evento que chegou é mais velho do que o que você já tem, ignore os dados dele. Um client.updated que chega depois de um client.deleted do mesmo cliente, por exemplo, é de antes da exclusão.

Com data.object_truncated: true, o objeto veio só com object e id: ou porque passava de 256 KB, ou porque a gravação veio de um caminho que manda o evento resumido (WhatsApp, automações, Open Finance, rotinas automáticas). Busque o objeto pela API, com o GET do recurso. Ele chega como está agora.

Buscar pela API também é o jeito certo quando o objeto é grande ou muda muito: trate o evento como um aviso de “esse registro mudou” e leia o estado atual.

Algumas mudanças não geram evento (veja O que não gera evento), um endpoint desligado não guarda o que perdeu, e o seu servidor pode ficar fora do ar por mais que os 3 dias de novas tentativas. Para o dado que precisa estar exato:

  • rode de tempos em tempos uma sincronização com updated_after, que traz o que mudou desde a última vez, na ordem em que mudou. Veja Paginação;
  • depois de uma queda do seu lado, use GET /public/v1/events para ver o que aconteceu nos últimos 30 dias, e o reenvio manual para as entregas que falharam.
  • Confira a assinatura em toda entrega, e recuse carimbo de tempo com mais de 5 minutos de diferença.
  • Guarde o segredo como guarda uma senha: fora do código, fora do repositório, fora do log.
  • Não devolva dado sensível no corpo da resposta: até 2 KB dele ficam no log de entregas, que dono e administradores leem.
  • Rotacione o segredo quando alguém que o conhecia sai, ou quando ele passou por um lugar que você não controla. Veja Rotacionar o segredo.