Webhooks em KYC, integração segura para decisões que valem dinheiro
A decisão de uma verificação chega por webhook, e webhook mal integrado vira fraude ou perda de evento. Assinatura HMAC (RFC 2104), idempotência, retentativas e os erros clássicos.
Numa integração de verificação de identidade, o webhook é o momento em que o dinheiro muda de mãos: é por ele que a plataforma avisa que a verificação foi aprovada ou recusada, e é em cima dele que o seu sistema libera a conta, concede o limite ou credita o saldo. Isso faz do webhook a superfície mais sensível da integração inteira. Um endpoint que aceita qualquer POST bem formatado aceita, por definição, um POST forjado por um fraudador que leu a sua documentação.
Este artigo percorre o desenho de uma integração de webhook que aguenta produção: autenticidade, idempotência, retentativas e os erros que aparecem repetidamente em integrações reais.
Autenticidade: assinatura, não origem
A primeira pergunta do seu endpoint diante de uma notificação: quem mandou isso? A resposta errada é confiar na origem da rede, porque IPs de plataformas mudam e cabeçalhos são forjáveis. A resposta consolidada na indústria é a assinatura criptográfica do corpo da mensagem com um segredo compartilhado, usando HMAC, o código de autenticação de mensagem baseado em hash definido na RFC 2104 do IETF, tipicamente com SHA-256.
O contrato funciona assim: a plataforma calcula a assinatura do corpo exato da requisição com o segredo do seu endpoint e a envia num cabeçalho; o seu servidor recalcula com o mesmo segredo e compara. Três detalhes de implementação separam a proteção real da decorativa:
- O timestamp entra na assinatura. Assinar apenas o corpo permite o replay: reenviar amanhã uma notificação legítima de hoje. Com o horário assinado e uma janela de tolerância curta, a mensagem velha é rejeitada mesmo com assinatura válida. É o desenho documentado publicamente por provedores de pagamento como a Stripe, cuja documentação de webhooks descreve exatamente essa composição de corpo, timestamp e tolerância.
- A comparação é de tempo constante, para não vazar por temporização quantos bytes da assinatura estavam certos. Bibliotecas padrão têm função própria para isso.
- O corpo verificado é o corpo cru recebido, byte a byte. Verificar sobre o JSON já interpretado e reserializado quebra a assinatura de formas intermitentes e cria o pior tipo de bug.
O segredo de assinatura é credencial: um por endpoint e por ambiente, guardado como os demais segredos, com rotação possível sem janela de invalidez, o que pede aceitar duas versões do segredo durante a troca.
Idempotência: toda entrega pode acontecer duas vezes
Sistemas de entrega de webhook prometem, com razão, entrega ao menos uma vez. A rede falha, o seu servidor responde lento, o timeout dispara depois de o seu banco já ter gravado, e a plataforma reenvia. Consequência inevitável: o mesmo evento vai chegar mais de uma vez, e o seu processamento precisa ser idempotente, produzir o mesmo estado final na primeira e na quinta entrega.
O mecanismo é registrar o identificador único do evento no mesmo ato transacional que aplica o efeito, e ignorar silenciosamente o identificador repetido. O detalhe que derruba implementações ingênuas é o mesmo ato transacional: checar se o evento existe e depois aplicar o efeito em outra transação abre a janela clássica de corrida em que duas entregas simultâneas passam juntas pela checagem. Em consequência prática para KYC: creditar de novo, liberar de novo, ou notificar o cliente duas vezes.
Idempotência importa dobrado quando o evento dispara movimentação financeira. O princípio de arquitetura que adotamos na UNIFOKAL, e que vale para qualquer integração, é que só o webhook confirmado credita, num único ponto do código: resposta síncrona de API não movimenta dinheiro, e a reconciliação periódica confere se todo evento aplicado corresponde ao estado da plataforma.
Retentativas, ordem e o estado consultável
A política de retentativa da plataforma define o comportamento sob falha: intervalos crescentes, por horas ou dias, até desistir. Do seu lado, três consequências de desenho:
- Responda rápido e processe depois. O endpoint valida assinatura, enfileira e responde com sucesso em milissegundos. Processar tudo em linha na requisição transforma qualquer lentidão sua em tempestade de retentativas.
- Não assuma ordem. Entre retentativas e eventos concorrentes, o evento mais novo pode chegar antes do mais velho. Decida pelo estado, não pela sequência de chegada: um evento que descreve estado anterior ao que você já tem é ignorável.
- Tenha o caminho de reconciliação. Se o seu endpoint ficou fora por mais tempo que a janela de retentativa, eventos se perderam. A integração completa consulta o estado atual pela API da plataforma, na volta de incidentes e periodicamente, e corrige divergências. Webhook é notificação; a fonte da verdade é consultável.
Erros que aparecem em toda auditoria de integração
- Endpoint sem TLS válido ou com certificado vencido, fazendo a entrega falhar em silêncio.
- Segredo de assinatura commitado no repositório ou compartilhado entre ambientes de teste e produção.
- Verificação de assinatura desligada em desenvolvimento e esquecida desligada em produção.
- Resposta de sucesso antes de persistir, perdendo o evento quando o processo morre no meio.
- Fila de processamento sem tratamento de veneno: um evento malformado que sempre lança erro trava as retentativas atrás dele.
- Logs do corpo do webhook com dados pessoais completos, criando um segundo banco de dados sensível não governado, problema que a Lei 13.709/2018 alcança do mesmo jeito que o banco principal.
Nada nesta lista é exótico; tudo já foi visto em integrações reais de produção. A boa notícia é que o custo de fazer certo é baixo e pontual, uma vez na integração, enquanto o custo de fazer errado é recorrente e cresce com o volume. Teste a assinatura com casos inválidos, force entregas duplicadas no sandbox, derrube o seu endpoint de propósito e veja a recuperação acontecer, antes de o primeiro cliente real depender disso.
Fontes citadas
- RFC 2104, do IETF, HMAC: Keyed-Hashing for Message Authentication
- Documentação pública de webhooks da Stripe, exemplo de referência da indústria para assinatura com timestamp e janela de tolerância
- Lei 13.709/2018, LGPD, sobre o alcance do tratamento de dados pessoais em logs e sistemas auxiliares, disponível no portal do Planalto: planalto.gov.br