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.
Responda 2xx rápido e processe depois
Seção intitulada “Responda 2xx rápido e processe depois”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:
- confira a assinatura;
- guarde o evento (numa fila, numa tabela);
- responda
200.
O trabalho de verdade (atualizar o ERP, mandar e-mail, chamar outro sistema) roda depois, fora da requisição.
Ignore duplicata pelo webhook-id
Seção intitulada “Ignore duplicata pelo webhook-id”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.
A ordem não é garantida
Seção intitulada “A ordem não é garantida”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
timestampdo corpo, que é o horário em que o evento aconteceu (não owebhook-timestampdo cabeçalho, que é o horário do envio); - ou compare o
updated_atdo 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.
Quando vier object_truncated, busque o objeto
Seção intitulada “Quando vier object_truncated, busque o objeto”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.
Webhook não substitui a sincronização
Seção intitulada “Webhook não substitui a sincronização”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/eventspara ver o que aconteceu nos últimos 30 dias, e o reenvio manual para as entregas que falharam.
Proteja o endpoint
Seção intitulada “Proteja o endpoint”- 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.