Pular para o conteúdo principal
A atividade de autenticação e a entrega de webhooks correspondente, que depende da versão, estão documentadas em Eventos de autenticação e webhooks. Não registre tipos de evento de autenticação não listados na API atual de destinos.

Visão geral

Webhooks são a forma como a Didit envia atualizações em tempo real para o seu backend sempre que uma sessão de verificação, uma sessão de empresa, um usuário (vendor user), uma empresa (vendor business) ou uma transação muda de estado. Ao inscrever um ou mais destinos nos eventos que interessam a você, é possível reagir no momento em que um resultado fica pronto, normalmente poucos segundos depois de o usuário em verificação concluir o fluxo. Webhooks são o padrão de integração recomendado. Consultar periodicamente GET /v3/session/{id}/decision/ é suportado como alternativa, mas é mais lento, consome mais requisições e deixa de fora eventos como data.updated, transaction.status.updated e alterações no nível de entidade, que são emitidos apenas por webhooks. Trate a entrega de webhooks como a fonte da verdade e faça consultas apenas na inicialização a frio ou para reconciliação. Este capítulo da aula de integração da Didit Academy retoma a partir da visão geral de webhooks. A aula de integração da Academy aborda webhooks a partir de 3:12: como adicionar um destino, escolher eventos e o segredo de assinatura que você vai verificar a seguir.
Usuários de Cloudflare / WAF. A Didit entrega webhooks a partir do IP estático 18.203.201.92 com User-Agent: DiditWebhook/2.0 +https://didit.me. Se a sua infraestrutura de borda bloquear clientes desconhecidos, libere esse IP em Security > WAF > Tools > IP Access Rules e escolha Allow para o hostname receptor.

Tipos de evento

Use o valor exato no array subscribed_events de um destino. Não há curinga: liste cada família que você quer receber. Você pode distribuir os eventos entre vários destinos. Os valores desta tabela são o conjunto completo de eventos que você pode assinar: não existe session.status.updated, kyc.completed nem nada parecido. A única outra entrega que a Didit faz é o callback kyb.registry_search.resolved, sem assinatura, que vai para a webhook_url informada em cada requisição em POST /v3/kyb/search/, nunca para um destino.
O menu Business Console > API & Webhooks > Try Webhook envia payloads completos para cada um desses eventos (aprovado, recusado, em revisão, nomes com caracteres Unicode, KYC/KYB, entidade, atividade e transação). Use-o para validar seu endpoint antes de entrar em produção.

Formato do payload

Envelope

Todo webhook compartilha o mesmo envelope. Os campos são sempre serializados com sort_keys=True e separadores compactos (, / :), para que o mesmo payload gere a mesma assinatura nos dois lados. Nos eventos de sessão (status.updated, data.updated em sessões comuns e de empresas), o envelope também traz:

Exemplo de envelope de sessão

O objeto decision tem o mesmo schema retornado por GET /v3/session/{id}/decision/. Para a referência canônica de campos por recurso (todas as propriedades de id_verifications[], aml_screenings[] etc.), consulte Modelos de dados. Não duplicamos de propósito as tabelas de campos por recurso aqui, para que o schema fique em um único lugar.

Arrays no plural da V3 (importante)

Dentro de decision, cada resultado por recurso é um array no plural, para que um único fluxo possa incluir várias instâncias do mesmo recurso (por exemplo, várias verificações de identidade em documentos diferentes):
Cada item traz um node_id correspondente ao grafo do fluxo, além de um status por recurso. Não leia os campos legados no singular da V2 (id_verification, nfc, liveness, face_match, phone, email, poa, aml, ip_analysis, database_validation). Eles só aparecem se um destino estiver fixado explicitamente em webhook_version: "v2". Os resultados de Assinatura eletrônica ficam em signatures[], presente somente quando o fluxo tem uma etapa de Assinatura eletrônica: um item por signatário, com o signatário, a confirmação por código, o certificado, o carimbo de data e hora, os hashes e caminhos de download de cada documento e o PDF de evidências. Não existe um evento de assinatura separado: o status.updated indica quando lê-los. Consulte o relatório de Assinatura eletrônica. Os resultados de Verificação bancária ficam em bank_verifications[], com um item por etapa de Verificação bancária. O method de cada item indica como a conta foi verificada: open_banking (login no banco), account_lookup (verificação da conta) ou uma alternativa statement ou microdeposits. O valor é null até que uma conta seja avaliada. Quando a pessoa escolheu Continue without your bank, continued_without_bank é true e continuation indica o motivo. Nesse caso, method é none, a menos que uma tentativa tenha sido avaliada antes: consulte Quando a pessoa não consegue verificar o banco. Uma conta verificada por verificação da conta não lê dados financeiros, então financial_data.not_collected lista os saldos, transações ou rendimentos que a etapa solicitou. Consulte Métodos de verificação bancária.

Bloco do Investigator

Uma decision V3 de uma sessão de usuário ou de empresa também traz investigator: a revisão mais recente da sessão feita pelo Investigator, ou null quando a sessão nunca teve uma. Os recursos de coleta de documentos, Documentos KYB e Document AI, não têm um array dedicado no plural: eles aparecem na lista features[] da decisão como { "feature": "DOCUMENT_AI", "node_id": "…" } (uma entrada por nó). Veja Document AI. As decisões de Verificação de usuários também trazem um único objeto biometric_consent: se a sessão exigiu consentimento biométrico explícito, o trigger, o status da resposta e a evidência correspondente. status: "pending" com reason: "BIOMETRIC_CONSENT_UNSUPPORTED_SDK" significa que um SDK nativo anterior à versão 4.10.0 capturou um rosto sem a etapa de consentimento. Veja Consentimento biométrico.

Chaves do método de Verificação de identidade

Cada item de id_verifications[] informa qual método de Verificação de identidade o gerou, para que um handler possa ramificar conforme a evidência que de fato recebeu: Os handlers existentes continuam funcionando sem alterações: uma sessão de documento define verification_method como document e deixa os demais como null. Os tipos campo a campo estão em Modelos de dados.

Sessão de carteira aprovada (status.updated)

Payloads de eventos de entidade

Os status de entidade são ACTIVE, FLAGGED ou BLOCKED. user.data.updated e business.data.updated mantêm o campo status e adicionam um array changed_fields e um mapa changes no formato { field: { previous, current } }. Os eventos business.* usam vendor_business_id em vez de vendor_user_id.

Payloads de eventos de transação

Os webhooks de transação usam a mesma infraestrutura de distribuição (fan-out) e o mesmo envelope, mas identificam a transação em vez de uma sessão:
action_required é null ou a ação pendente do usuário (type wallet_ownership ou verification_session, com a respectiva url) descrita em Ações exigidas do usuário. Novas transações têm APPROVED como padrão. Se uma regra, lista de bloqueio ou fluxo alterar o status durante a criação, o payload inicial de transaction.created reflete esse status final. transaction.status.updated traz o mesmo formato com o status atualizado. Os status de transação são APPROVED, IN_REVIEW, DECLINED ou AWAITING_USER; severity é UNKNOWN / LOW / MEDIUM / HIGH / CRITICAL e direction é INBOUND / OUTBOUND. transaction.created e transaction.status.updated são entregues apenas para aplicações em produção. As trocas de Travel Rule em sandbox emitem, sim, travel_rule.status.updated com environment: sandbox.

Callback de busca no registro KYB

O fluxo assíncrono de POST /v3/kyb/search/ entrega um payload extra que não é um evento de destino: quando você passa uma webhook_url na requisição de busca, a Didit envia um POST com o callback kyb.registry_search.resolved para essa URL assim que a consulta ao registro é concluída. Ele difere dos webhooks de destino em três aspectos:
  • Ele é sem assinatura: não tem cabeçalhos X-Signature*. Em vez disso, a Didit o marca com X-Didit-Unsigned-Callback: true; valide-o comparando o request_id com o ID retornado pela requisição de busca.
  • O nome do evento fica em event_type (e não em webhook_type), e não há application_id nem environment.
  • timestamp e created_at são inteiros epoch, como nos outros webhooks, mas diferentes do created_at em ISO do endpoint de busca.
O callback segue a mesma política de novas tentativas dos webhooks de destino (as novas tentativas atualizam o timestamp e continuam sem assinatura). Veja a API de registro KYB para o schema completo da lista de candidatos.

Verificação de assinatura

Todo webhook é assinado com HMAC-SHA256 usando a secret_shared_key do destino. São enviados três cabeçalhos de assinatura para que você escolha aquele que funcione com sua stack: Cabeçalhos que a Didit sempre envia: Por 24 horas após a rotação do segredo de assinatura de um destino, as entregas também incluem X-Signature-Previous, X-Signature-V2-Previous e X-Signature-Simple-Previous (consulte Rotação do segredo de assinatura).

Rotação do segredo de assinatura

Você faz a rotação do segredo de assinatura de um destino no Business Console. Por 24 horas após uma rotação, toda entrega para esse destino inclui mais três cabeçalhos, gerados com o segredo que foi substituído: Um handler que aceita a correspondência tanto em um cabeçalho de assinatura quanto no seu cabeçalho -Previous continua verificando enquanto você implanta o novo segredo: o segredo antigo corresponde ao cabeçalho -Previous, e o novo corresponde ao cabeçalho normal. Os exemplos de código abaixo fazem isso. Implante o novo segredo dentro das 24 horas, porque, depois disso, somente o novo segredo valida as assinaturas. O campo previous_secret_expires_at em GET /v3/webhook/destinations/{destination_uuid}/ informa quando as 24 horas terminam. Novas tentativas e reenvios são assinados novamente com o segredo atual do destino no momento do envio, e incluem os cabeçalhos -Previous somente enquanto durarem as 24 horas. Fazer uma nova rotação dentro das 24 horas desativa imediatamente o segredo mais antigo: somente o segredo que era o atual até a nova rotação continua validando as assinaturas dos cabeçalhos -Previous, por 24 horas a partir da nova rotação. Os cabeçalhos -Previous existem somente para destinos de webhook. A secret_shared_key no nível da aplicação, que assina o webhook_url legado, não tem período de sobreposição: fazer a rotação dela com rotate_secret_key em PATCH /v3/webhook/ invalida o segredo antigo imediatamente.

X-Signature-Simple está obsoleto

X-Signature-Simple autentica o envelope, não o payload. Sua string canônica cobre somente timestamp, session_id, status e webhook_type. Ela não cobre decision, nem resubmit_info, metadata, vendor_data ou event_id. Uma requisição cujo decision foi reescrito, mantendo intactos esses quatro campos, ainda passa na verificação de X-Signature-Simple.Ela é ainda mais fraca nos eventos que não incluem nenhum session_id. Eventos de transação (transaction_id, txn_id, amount, score) e eventos de entidade (vendor_user_id, vendor_business_id) assinam "{timestamp}::{status}:{webhook_type}", que não identifica qual transação ou entidade é o objeto do evento: duas transações diferentes informadas com o mesmo status no mesmo segundo têm o mesmo X-Signature-Simple. Os eventos travel_rule.status.updated, workflow.compliance_changed e transaction_rule_suggestions.created também não incluem status, então assinam "{timestamp}:::{webhook_type}", por exemplo "{timestamp}:::travel_rule.status.updated".Se X-Signature-Simple for o único cabeçalho que você verifica, trate tudo fora desses quatro campos como não confiável e busque novamente o registro na API, que é a fonte oficial dos dados: GET /v3/session/{session_id}/decision/ para uma sessão, GET /v3/transactions/{transaction_id}/ para uma transação.
Esta é uma restrição de compatibilidade, não algo que possamos corrigir sem quebrar a compatibilidade. A string canônica de quatro campos é um contrato de comunicação: todo receptor que verifica X-Signature-Simple recalcula exatamente esses quatro campos, então mudar o que o cabeçalho assina quebraria silenciosamente todos eles na verificação de assinatura. Cobrir o corpo também exige uma forma canônica especificada do JSON que os dois lados reproduzam byte a byte, e a Didit já oferece uma como X-Signature-V2. Em vez de adicionar uma segunda variante que cubra o corpo, com suas próprias regras de canonicalização, o cabeçalho permanece exatamente como está e fica obsoleto em favor das variantes existentes que cobrem o payload completo. O que isso significa para você:
  • Nada muda na comunicação. X-Signature-Simple continua sendo enviado em toda entrega, calculado da mesma forma. Os verificadores existentes continuam funcionando, e anunciaremos qualquer remoção com bastante antecedência.
  • Novas integrações devem usar X-Signature-V2. Ele é seguro com middleware e cobre o payload inteiro.
  • Se você não puder deixar de usar X-Signature-Simple, verifique-o e depois busque o registro na API, em vez de lê-lo do corpo do webhook.

Por que três variantes?

Alguns frameworks web (parsers de corpo do Express, middleware do Django, API gateways) recodificam o JSON silenciosamente antes que seu handler o leia. Se o corpo original continha "José" e seu middleware o reescreve como "José", os bytes mudam, embora os dados sejam idênticos. Nesse caso, X-Signature falha. X-Signature-V2 é calculado a partir de uma forma canônica do JSON (chaves ordenadas, separadores compactos, Unicode sem escape) que quase todo middleware reproduz de forma determinística, e o obsoleto X-Signature-Simple recorre a assinar somente uma string curta, independente do parser, quando até isso falha. Como ele assina somente essa string curta e nunca o corpo, não pode garantir a integridade do corpo.

Ordem de verificação recomendada

  1. Tente primeiro o X-Signature-V2. Recodifique JSON.parse(body) com as chaves ordenadas e os caracteres Unicode preservados, calcule HMAC-SHA256(secret, canonical) e compare o resultado com o cabeçalho usando timingSafeEqual.
  2. Se a V2 falhar e você conseguir ler os bytes brutos, tente o X-Signature com HMAC-SHA256(secret, rawBody).
  3. Somente se ambas falharem, recorra ao X-Signature-Simple, que está obsoleto, com HMAC-SHA256(secret, "{timestamp}:{session_id}:{status}:{webhook_type}"). Ele autentica apenas o envelope: trate a decision do corpo como não confiável e busque-a novamente em GET /v3/session/{session_id}/decision/ antes de agir com base nela.
Em cada etapa, quando o cabeçalho -Previous correspondente estiver presente, aceite uma correspondência em qualquer um dos dois cabeçalhos (consulte Rotação do segredo de assinatura). Em todos os casos, rejeite qualquer requisição com mais de 5 minutos (abs(now - X-Timestamp) > 300) para se proteger contra ataques de repetição.

Política de novas tentativas

Se o seu endpoint responder com 5xx ou 404, a Didit tenta novamente até 2 vezes, com backoff exponencial:
  • 1ª nova tentativa: cerca de 1 minuto após a falha inicial.
  • 2ª nova tentativa: cerca de 4 minutos após a 1ª nova tentativa.
Após a segunda nova tentativa, a entrega é descartada. Cada tentativa de entrega (a inicial e as novas tentativas) é registrada como uma entrada separada no Business Console, na aba Deliveries do destino, para que você possa reenviar ou inspecionar qualquer tentativa. Cada tentativa no registro de entregas de um destino tem um número attempt: 1 para a primeira entrega de um evento e, para cada nova tentativa ou reenvio, um a mais que o número da tentativa que ele repete. As novas tentativas automáticas vão para a URL para a qual a primeira tentativa foi enviada, mesmo que você tenha alterado a url do destino depois disso. Um reenvio manual vai para a URL atual do destino, então corrigir uma URL também corrige o reenvio. Outras regras de entrega que você deve conhecer:
  • A requisição HTTP de saída atinge o tempo limite após 5 segundos.
  • A Didit bloqueia entregas para URLs privadas ou de localhost como proteção contra SSRF e nunca segue redirecionamentos. Use um endpoint HTTPS público que responda diretamente.
  • Uma url de destino que contenha uma barra invertida literal, um caractere de controle ou mais de um @ na autoridade é rejeitada como malformada: uma URL assim não pode ser criada, e uma já existente não pode ter entregas reenviadas nem repetidas. Use uma URL simples https://host/path com no máximo uma seção de userinfo (para URLs de webhook no estilo basic auth).
  • 2xx é tratado como sucesso. Timeouts e falhas de conexão contam como passíveis de nova tentativa (aparecem como 504/503 no registro de entregas); respostas 3xx e 4xx diferentes de 404 não geram novas tentativas.
  • Em cada nova tentativa, a Didit recalcula as assinaturas com um X-Timestamp novo, de modo que o par timestamp/assinatura sempre corresponde.
  • Novas tentativas e reenvios são assinados com o segredo de assinatura atual do destino no momento em que são enviados.

Ordem de entrega

A Didit não garante a ordem em que os webhooks chegam até você. Cada entrega entra na fila de forma independente e uma nova tentativa chega minutos após a primeira tentativa, então um status.updated para Approved pode chegar antes de um anterior para In Progress. Construa o seu receptor levando isso em conta:
  • Trate um webhook como um sinal de que algo mudou. Quando a ordem importar, chame GET /v3/session/{session_id}/decision/ e aja com base no status atual.
  • Nunca permita que um evento mais antigo sobrescreva um estado mais recente: compare o created_at do evento com o do último que você armazenou para aquele registro e ignore o mais antigo.
  • Identifique repetições pelo event_id, que permanece o mesmo em todas as novas tentativas.
A Didit coloca na fila os eventos de uma transferência de Travel Rule em uma ordem definida, descrita em Status da troca de Travel Rule alterado, mas uma nova tentativa ainda pode alterar a ordem em que eles chegam.

Configurar um destino

Você pode gerenciar destinos em Business Console > API & Webhooks ou pela Management API.
1

Crie o destino

Chame POST /v3/webhook/destinations/ (ou clique em Add destination no console) com um label, uma url pública, webhook_version ("v3") e um array subscribed_events contendo todas as famílias de eventos que esse endpoint deve receber. É necessário pelo menos um evento, e não existe curinga.
2

Armazene o secret_shared_key

A resposta da criação retorna o secret_shared_key do destino. Armazene-o junto com os outros segredos do seu servidor: ele pertence apenas a esse destino e é a entrada das três variantes de assinatura HMAC-SHA256. GET /v3/webhook/destinations/{destination_uuid}/ o retorna novamente para quem chama a API com uma chave de API e para usuários do console que podem ler webhooks.
3

Implemente o endpoint

Exponha uma rota POST HTTPS pública, leia o corpo bruto, verifique a assinatura (dando preferência ao X-Signature-V2), verifique se o timestamp está dentro da janela permitida e, em seguida, faça o despacho com base no webhook_type. Retorne 2xx assim que tiver colocado o trabalho na fila; faça o processamento pesado de forma assíncrona.
4

Confirme os recebimentos

Acompanhe a aba Deliveries do destino. Webhooks em bom funcionamento retornam 200 em um ou dois segundos. 5xx/404 aciona a política de novas tentativas da Didit; falhas persistentes são descartadas após a segunda tentativa.
5

Itere com o Try Webhook

Use os cenários do Try Webhook no console para fazer o seu endpoint processar payloads de aprovado, recusado, em revisão, KYB, entidade, atividade e transação antes de ativar o tráfego de produção.
Recurso de teste de webhooks da Didit no Business Console

Envie webhooks de teste diretamente do Business Console para validar o seu endpoint antes de entrar em produção.

Você pode criar quantos destinos precisar. Um padrão comum é um destino por consumidor: por exemplo, eventos de KYC → o seu serviço de autenticação, eventos de KYB → o seu serviço de operações de conformidade, transações → a sua fila de fraude. Cada destino tem o seu próprio segredo, versão e lista de eventos aos quais está inscrito, então um segredo rotacionado ou um deploy com problema em um consumidor não afeta os demais.

Exemplos de código

Para garantir a segurança do seu endpoint de webhook, verifique a autenticidade das requisições recebidas usando a secret_shared_key do destino.
Use X-Signature-V2. É a variante mais resistente à recodificação por middleware e autentica o corpo por completo (incluindo decision).

Node.js / Express (recomendado: X-Signature-V2)

Se você consegue ler os bytes brutos antes que qualquer parser os processe, a variante original X-Signature funciona da mesma forma, mas assina o corpo bruto. Ela é mantida na seção legada abaixo para fins de completude.

Python / FastAPI (recomendado: X-Signature-V2)

PHP / Laravel (recomendado: X-Signature-V2)

Os padrões de JSON do PHP não reproduzem a forma canônica. Quatro deles precisam ser substituídos, e esquecer qualquer um deles altera os bytes assinados, de modo que o digest nunca coincide: A armadilha do objeto vazio é a que mais causa problemas. Os payloads da Didit trazem com frequência mapas vazios como risk_view.countries.risk_scores, risk_view.crimes.risk_scores e risk_view.custom_list, então uma conversão de ida e volta associativa quebra a assinatura em sessões aprovadas comuns, e não em algum caso extremo raro.
Mais duas coisas que vale a pena saber:
  • Floats com valor inteiro não precisam de tratamento especial no PHP. A Didit os serializa como inteiros (100.0 → 100), e o json_encode do PHP escreve um float inteiro da mesma forma, então nenhuma etapa shortenFloats é necessária, ao contrário do exemplo de Node.js acima.
  • Mantenha serialize_precision em -1 (o padrão desde o PHP 7.1). Se o seu servidor o substituir para 17, o json_encode escreve 87.42 como 87.420000000000002 e toda verificação de X-Signature-V2 falha.
Se você não conseguir fazer a forma canônica corresponder, verifySignatureRaw acima é a alternativa mais simples: o $request->getContent() do Laravel retorna os bytes intactos, então X-Signature funciona desde que nada à frente do PHP recodifique o corpo. Esse é exatamente o cenário ao qual X-Signature-V2 foi projetado para resistir, e é por isso que a V2 é testada primeiro.

Testes

Você não precisa executar uma verificação completa para testar o seu endpoint.
  • Em Business Console > API & Webhooks > Try Webhook, escolha um cenário (por exemplo, approved_full_features, declined_face_mismatch, in_review_aml_hit, business_session_approved, transaction_created, activity_created, user_status_updated) e envie um webhook completo para a URL do seu destino.
  • Todo cenário é assinado com os mesmos três cabeçalhos de assinatura e a mesma codificação canônica do tráfego de produção, incluindo dados de teste em unicode (approved_kyc_with_unicode), para que você possa confirmar que X-Signature-V2 funciona através do seu middleware. As entregas de teste trazem dados de exemplo e são marcadas com um cabeçalho extra X-Didit-Test-Webhook: true (e um sufixo (Test) no User-Agent), para que você possa impedir que elas afetem o estado de produção.
  • Reenvie qualquer entrega anterior pela aba Deliveries de um destino se precisar depurar uma regressão.
Para testes de fumaça de ponta a ponta, execute uma verificação real por meio de um workflow de teste na sua própria aplicação. Os webhooks resultantes usam o mesmo envelope, os mesmos cabeçalhos e a mesma política de novas tentativas dos cenários de Try Webhook.

Exemplos

Sessão KYC aprovada (status.updated)

Sessão recusada com avisos (status.updated)

Sessão de empresa aprovada (status.updated, KYB)

Transação criada (transaction.created)

Status do intercâmbio da Travel Rule alterado (travel_rule.status.updated)

travel_rule_status traz um dos 13 status de intercâmbio documentados em Travel Rule. rail é INTERNAL, TRP, GTR, TRUST, VERIFYVASP, SYGNA ou EMAIL (string vazia até que um canal seja selecionado, quando nenhum pôde ser determinado e sempre em registros sunrise), ou TEST_VASP para uma transferência de sandbox respondida pelo Didit Test VASP, e direction é INBOUND ou OUTBOUND. Um evento de sandbox traz "environment": "sandbox", e um evento TEST_VASP também traz test_vasp: true e test_vasp_scenario (o cenário que respondeu). Quando a Didit cria uma transação para uma transferência Travel Rule (uma chamada a POST /v3/transactions/, um registro sunrise após o depósito, uma consulta TRP de entrada ou a perna de entrada do canal INTERNAL), ela envia primeiro o evento transaction.created dessa transação e, depois dele, os eventos travel_rule.status.updated da transferência. Uma regra que altera o status da transação durante essa etapa também pode enviar transaction.status.updated antes de transaction.created, e um registro sunrise vinculado a uma transação de depósito que você já criou não envia transaction.created. Cada webhook é entregue e reenviado de forma independente, então um evento reenviado ainda pode chegar depois de um evento posterior: use transaction_id como chave no seu handler e consulte a transação novamente quando precisar do estado atual dela. Uma transferência enviada pelo TRUST nunca recebe um evento COMPLETED, porque o TRUST não devolve nada que a Didit consiga ler: ela permanece em AWAITING_COUNTERPARTY até o prazo de confirmação e então termina como EXPIRED. No GTR, no VerifyVASP e no Sygna Bridge, a Didit lê a resposta da contraparte na rede e o evento a acompanha (consulte Redes Travel Rule).

Conformidade do fluxo alterada (workflow.compliance_changed)

transition.from e transition.to são um dos valores compliant, gaps_detected, pending_change, unknown_coverage ou not_evaluated. severity é actionable quando foram detectadas lacunas, indicative para uma mudança pendente e informative quando as lacunas foram resolvidas. A Didit envia um evento por fluxo alterado.

Sugestões de regras de transação criadas (transaction_rule_suggestions.created)

kind é ADD para uma nova regra, TWEAK para uma alteração em uma regra existente e DISABLE para desativar uma regra. rule_id é null para ADD. open_count é o número de sugestões ainda abertas após a execução, incluindo as novas. As configurações de sugestão de regras ativam ou desativam este webhook; consulte Webhooks de transação.

Eventos do Investigator (investigator.*)

Os doze eventos investigator.* usam o mesmo envelope (event_id, webhook_type, timestamp, created_at, application_id, environment) e os mesmos cabeçalhos de assinatura usados por todos os outros eventos. Eles trazem apenas ids e números: nunca um nome, um motivo digitado por um revisor, uma narrativa ou qualquer coisa que o usuário final tenha escrito. Eles não têm session_id; o item a que se referem é identificado em item.
provenance indica qual versão do Investigator escreveu o relatório:
  • engine é a versão do motor do Investigator: um id opaco de oito caracteres. Ele muda sempre que o motor muda, então dois relatórios com o mesmo engine foram escritos pelo mesmo motor.
  • agent_version é a versão do agente.
  • policy_version é a versão da sua própria política que o relatório seguiu.
  • model_id é um alias obsoleto que traz o mesmo valor de engine. Use engine em vez dele.
  • prompt_hash não é mais enviado.
item.kind indica o tipo de item (uma sessão, uma sessão de empresa, uma transação ou um caso) e item.id, o id dele. Os timestamps terminados em _at são strings ISO 8601. Assine esses eventos listando as strings exatas em subscribed_events, como qualquer outro evento.

Status da entidade de usuário alterado (user.status.updated)

Sessão reenviada

Legado: X-Signature com corpo bruto

O X-Signature continua sendo enviado em todas as entregas; ele é um HMAC-SHA256 calculado sobre os bytes exatos que a Didit transmite (json.dumps(..., sort_keys=True, separators=(",", ":"))). Use-o somente quando você conseguir ler o corpo bruto antes que qualquer middleware o modifique.

Legado: formato de webhook V2

Os campos abaixo só se aplicam quando um destino está fixado em webhook_version: "v2". Também existe uma configuração ainda mais antiga, "v1" (um terceiro formato de decisão, com objetos no singular), para destinos criados antes da V2; entre em contato com o suporte antes de depender dela. Novas integrações devem usar a V3 (o padrão), documentada acima, que usa arrays no plural.
Os objetos de cada recurso são os mesmos nas duas versões: um destino V2 recebe exatamente os mesmos match_score, risk_score, score_breakdown, risk_view e review_status por ocorrência e o mesmo score agregado que a V3 (consulte o relatório AML). Configurar para V2 muda onde o relatório AML fica dentro de decision, não o que ele contém. Se um consumidor downstream ainda precisar dos formatos V2, crie um destino separado fixado em webhook_version: "v2" e mantenha seus novos consumidores na V3.

Relacionados

Última modificação em 1 de novembro de 2026