# Webhook de atualização | Como testar o desfecho que muda depois

<https://unifokal.com/blog/webhook-de-atualizacao-sem-caso-real>

Guia · UNIFOKAL · 26 de setembro de 2026 · 6 min de leitura · Produto e integração

Uma verificação que termina em revisão e é decidida depois gera dois eventos. Como deduplicar pelo id, decidir pelo estado e provar a integração no sandbox sem esperar um caso real.

Quase toda integração com uma API de verificação nasce testada no caminho curto: o cadastro entra, a verificação termina, o webhook chega com aprovado ou reprovado, e a conta é liberada ou barrada. O caminho que quebra em produção é o outro. A verificação termina em revisão, a integração coloca o cadastro em espera, e horas depois a mesma verificação é decidida de novo. Chega um segundo evento sobre o mesmo caso, com um desfecho diferente, e o código que só conhecia o primeiro não sabe o que fazer com ele.

O problema não é raro por acaso. Revisão humana, resultado de consulta que chega depois e decisão de um analista que reabre um caso são parte normal de qualquer operação de verificação. O que é raro é conseguir provocar esse caminho em teste, e é por isso que ele costuma ser o último a ser exercitado.

## Dois eventos sobre o mesmo caso não são duplicata

A primeira decisão de desenho é separar duas coisas que parecem iguais: o mesmo evento entregue duas vezes e dois eventos diferentes sobre o mesmo objeto.

A especificação CloudEvents, mantida pela Cloud Native Computing Foundation, a CNCF, define essa separação no atributo `id`. O produtor deve garantir que a combinação de origem e `id` seja única para cada evento distinto; se um evento duplicado for reenviado, por exemplo por erro de rede, ele pode manter o mesmo `id`; e o consumidor pode presumir que eventos com a mesma origem e o mesmo `id` são duplicatas.

Aplicado ao caso da verificação, isso dá duas regras. Um reenvio do primeiro evento, com o mesmo `id`, é descartado sem efeito. O segundo evento, que traz o desfecho novo, tem `id` próprio e precisa ser processado, mesmo que a verificação a que ele se refere seja a mesma. Integração que deduplica pelo identificador da verificação, e não pelo identificador do evento, joga fora exatamente a atualização que importa.

## Deduplicar pelo id, decidir pelo estado

Separado o duplicado do novo, o processamento precisa ser idempotente. A RFC 9110, que define a semântica do HTTP, chama de idempotente o método em que o efeito pretendido no servidor de várias requisições idênticas é o mesmo de uma só. O mesmo critério vale para quem recebe webhook: aplicar o mesmo evento duas vezes não pode liberar a conta duas vezes, nem mandar dois e-mails, nem lançar dois créditos.

O jeito mais simples de chegar lá é guardar o estado, e não a sequência de eventos. Para cada verificação, a integração mantém o desfecho atual e o identificador do último evento aplicado. Cada evento que chega é conferido contra o que já foi visto; se for novo, o desfecho que ele traz substitui o anterior, e as consequências de negócio são recalculadas a partir do estado final, não somadas à anterior. O artigo sobre [reconciliação de webhook](https://unifokal.com/blog/reconciliacao-de-webhook) detalha o que fazer quando o evento não chega, e o sobre [webhooks seguros em KYC](https://unifokal.com/blog/webhooks-seguros-em-kyc) cobre a assinatura, que continua valendo para o segundo evento como valia para o primeiro.

## O que o segundo evento muda na sua operação

O desfecho tardio não é só um campo que muda de valor. Ele costuma disparar ação. Uma revisão que vira aprovação libera o cadastro que estava em espera e deveria avisar o usuário. Uma revisão que vira reprovação precisa desfazer o que foi concedido de forma provisória, se algo foi concedido, e registrar o motivo.

Três perguntas ajudam a desenhar esse trecho antes de ele virar incidente. O que o sistema concede enquanto a verificação está em revisão, se é que concede alguma coisa. Quem é avisado quando o desfecho final chega, e por qual canal. E o que acontece se a decisão humana, tomada no painel do fornecedor, chegar antes da decisão automática. Esta última é a que mais surpreende: numa operação saudável, a decisão de uma pessoa prevalece, e a integração tem de aceitar que o desfecho final pode vir de um analista.

## Por que testar sem esperar um caso real

Esperar um caso real de revisão para testar essa lógica tem dois problemas. O primeiro é tempo: em volume baixo, pode levar semanas até um caso cair em revisão e ser decidido. O segundo é que o teste vira uma observação única, impossível de repetir quando o código muda.

O que resolve é um ambiente de teste com desfecho determinístico, a propriedade descrita no artigo sobre [sandbox antes de produção](https://unifokal.com/blog/sandbox-antes-de-producao): o mesmo dado de entrada sempre produz o mesmo resultado, e existe um dado de entrada que produz a atualização tardia de propósito. Com ele, o caminho da revisão que vira aprovação e o da revisão que vira reprovação entram na suíte de testes da integração, rodam a cada mudança e param de depender da sorte.

Na UNIFOKAL, por exemplo, isso está no sandbox pelos sufixos de teste `-04` e `-05` do documento enviado pela API. A verificação termina em revisão e o primeiro `verification.completed` chega na hora; cerca de um minuto depois, ela é decidida de novo e chega um segundo `verification.completed`, com `id` de evento novo, aprovado no `-04` e reprovado no `-05`. Se alguém decidir a verificação pelo painel antes disso, vale a decisão da pessoa e o segundo evento não sai, que é justamente o terceiro cenário a testar. O passo a passo está na [documentação de ambientes](https://unifokal.com/docs/ambientes).

## Uma lista curta para a sua integração

Antes de ir para produção, vale conferir cinco pontos com testes automatizados, e não só com leitura de código:

- o reenvio do mesmo evento, com o mesmo `id`, não produz efeito nenhum;
- um evento novo sobre a mesma verificação substitui o desfecho anterior;
- a consequência de negócio é recalculada a partir do estado final;
- a decisão humana tomada no painel é aceita como desfecho final;
- a assinatura é verificada em todos os eventos, inclusive no segundo.

Nenhum desses pontos depende do fornecedor que você usa. Todos dependem de o caminho da atualização ter sido exercitado antes do primeiro caso real.

## Fontes citadas

- CloudEvents, especificação versão 1.0.2, Cloud Native Computing Foundation, atributo `id`: [github.com/cloudevents/spec](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md)
- RFC 9110, HTTP Semantics, IETF, seção 9.2.2, métodos idempotentes: [rfc-editor.org](https://www.rfc-editor.org/rfc/rfc9110)
- [Documentação de ambientes da UNIFOKAL](https://unifokal.com/docs/ambientes): os sufixos do sandbox e o desfecho tardio.
