Saltar para o conteúdo principal
A atividade de autenticação e a entrega de webhooks que depende da versão estão documentadas em Eventos de autenticação e webhooks. Não registe com a API de destinos atual tipos de evento de autenticação que não estejam listados.

Visão geral

Os 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 empresarial, um utilizador de fornecedor, uma empresa de fornecedor ou uma transação muda de estado. Ao subscrever um ou mais destinos aos eventos que lhe interessam, pode reagir no momento em que um resultado está pronto, normalmente em poucos segundos após o utilizador que está a ser verificado concluir o seu fluxo. Os webhooks são o padrão de integração recomendado. O polling de GET /v3/session/{id}/decision/ é suportado como alternativa, mas é mais lento, consome mais pedidos e não recebe eventos como data.updated, transaction.status.updated ou alterações ao nível das entidades, que só são emitidos através de webhooks. Trate a entrega de webhooks como fonte de verdade e recorra ao polling apenas no arranque a frio ou para reconciliação. Este capítulo da lição de integração da Didit Academy continua a partir da visão geral dos webhooks. A lição de integração da Academy aborda os webhooks a partir dos 3:12: como adicionar um destino, escolher eventos e o segredo de assinatura que vai verificar mais abaixo.
Utilizadores do Cloudflare / WAF. A Didit envia webhooks a partir do IP estático 18.203.201.92 com User-Agent: DiditWebhook/2.0 +https://didit.me. Se o seu perímetro bloquear clientes desconhecidos, permita este IP em Security > WAF > Tools > IP Access Rules e escolha Permitir para o nome de anfitrião que recebe os webhooks.

Tipos de eventos

Use o valor exato no array subscribed_events de um destino. Não existe carácter universal: indique cada família que pretende receber, e pode distribuir os eventos por vários destinos. Os valores desta tabela são o conjunto completo de eventos a que se pode subscrever. Não existe session.status.updated, kyc.completed nem nada de semelhante. A única outra entrega feita pela Didit é o callback kyb.registry_search.resolved sem assinatura, que é enviado para o webhook_url indicado em cada pedido ao endpoint POST /v3/kyb/search/, nunca para um destino.
O menu Business Console > API & Webhooks > Try Webhook envia payloads completos para cada um destes eventos (aprovados, recusados, em análise, nomes em Unicode, KYC/KYB, entidade, atividade e transação). Use-o para validar o endpoint antes de entrar em produção.

Estrutura do payload

Envelope

Todos os webhooks partilham o mesmo envelope. Os campos são sempre serializados com sort_keys=True e separadores compactos (, / :), para que o mesmo payload reproduza a mesma assinatura dos dois lados. Para eventos de sessão (status.updated, data.updated em sessões regulares e empresariais), o envelope inclui ainda:

Exemplo de envelope de sessão

O objeto decision tem o mesmo esquema devolvido por GET /v3/session/{id}/decision/. Para a referência canónica de campos por funcionalidade (cada propriedade de id_verifications[], aml_screenings[], etc.), consulte Modelos de dados. Não repetimos aqui as tabelas de campos por funcionalidade, para que o esquema exista num único lugar.

Arrays plurais V3 (importante)

Dentro de decision, cada resultado por funcionalidade é um array plural, para que um único fluxo possa incluir várias instâncias da mesma funcionalidade (por exemplo, várias verificações de identidade em vários documentos):
Cada item tem um node_id que corresponde ao grafo do fluxo, mais um status por funcionalidade. Não leia os campos singulares legados do V2 (id_verification, nfc, liveness, face_match, phone, email, poa, aml, ip_analysis, database_validation); só aparecem se um destino estiver explicitamente fixado em webhook_version: "v2". Os resultados de Assinatura eletrónica estão em signatures[], presentes apenas quando o fluxo tem um passo de assinatura eletrónica: um item por signatário, com o signatário, a confirmação do código, o certificado, o carimbo de data/hora, os hashes e os caminhos de transferência de cada documento e o PDF de prova. Não existe um evento de assinatura separado: o status.updated indica quando deve ler esses dados. Consulte o relatório de assinatura eletrónica. Os resultados de Verificação bancária estão em bank_verifications[], um item por passo de Verificação bancária. O method de cada item indica como a conta foi verificada: open_banking (início de sessão no banco), account_lookup (verificação da conta), ou uma alternativa statement ou microdeposits, e fica null até que uma conta seja avaliada. Quando a pessoa escolheu Continue sem o seu banco, 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 seu banco. Uma conta verificada por consulta de conta não lê dados financeiros, por isso financial_data.not_collected indica os saldos, transações ou rendimentos que o passo pedia. Consulte Métodos de verificação bancária.

Bloco do Investigator

Uma decision V3 de uma sessão de utilizador ou de empresa inclui também investigator: a revisão Investigator mais recente da sessão, ou null se a sessão nunca teve uma. As funcionalidades de recolha de documentos, Documentos KYB e Document AI, não têm um array plural dedicado. Aparecem na lista features[] da decisão como { "feature": "DOCUMENT_AI", "node_id": "…" } (uma entrada por nó). Consulte Document AI. As decisões de Verificação de utilizadores incluem também um único objeto biometric_consent: indica se a sessão exigia consentimento biométrico explícito, o trigger, o status da resposta e as respetivas evidências. status: "pending" com reason: "BIOMETRIC_CONSENT_UNSUPPORTED_SDK" significa que um SDK nativo abaixo da versão 4.10.0 captou um rosto sem o passo de consentimento. Consulte Consentimento biométrico.

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

Cada item de id_verifications[] indica qual método de Verificação de identidade o produziu, para que um processador possa tratar as evidências que efetivamente recebeu: Os processadores existentes continuam a funcionar sem alterações: uma sessão de documento define verification_method como document e deixa o resto 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 estados das entidades são ACTIVE, FLAGGED ou BLOCKED. user.data.updated e business.data.updated mantêm o campo status e acrescentam um array changed_fields e um mapa changes de { 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 e o mesmo envelope, mas identificam a transação em vez de uma sessão:
action_required é null ou a ação do utilizador pendente (type wallet_ownership ou verification_session, com o respetivo url), descrita em Ações obrigatórias do utilizador. As novas transações ficam APPROVED por predefinição. Se uma regra, uma lista de bloqueio ou um fluxo alterar o estado durante a criação, o payload inicial de transaction.created reflete esse estado final. transaction.status.updated tem a mesma estrutura, com o status atualizado. Os estados de transação são APPROVED, IN_REVIEW, DECLINED ou AWAITING_USER; severity é UNKNOWN / LOW / MEDIUM / HIGH / CRITICAL e direction é INBOUND / OUTBOUND. Os eventos transaction.created e transaction.status.updated são entregues apenas para aplicações em produção. As trocas de Travel Rule em sandbox emitem travel_rule.status.updated com environment: sandbox.

Callback de pesquisa no registo KYB

O fluxo assíncrono POST /v3/kyb/search/ entrega um payload extra que não é um evento de destino: quando indica um webhook_url no pedido de pesquisa, a Didit envia um callback kyb.registry_search.resolved através de um pedido POST para esse URL, assim que o registo for resolvido. Difere dos webhooks de destino em três aspetos:
  • É sem assinatura: não tem cabeçalhos X-Signature*. Em vez disso, a Didit marca-o com X-Didit-Unsigned-Callback: true; valide-o comparando request_id com o ID devolvido pelo pedido de pesquisa.
  • O nome do evento está em event_type (não em webhook_type), e não existem application_id nem environment.
  • timestamp e created_at são inteiros de época (epoch), como outros webhooks, mas diferentes do created_at ISO do endpoint de pesquisa.
O callback segue a mesma política de novas tentativas dos webhooks de destino (as novas tentativas voltam a definir timestamp e continuam sem assinatura). Consulte a API do Registo KYB para o esquema completo da lista de candidatos.

Verificação da assinatura

Todos os webhooks são assinados com HMAC-SHA256, usando o secret_shared_key do destino. São enviados três cabeçalhos de assinatura, para que possa escolher o que funciona na sua stack: Cabeçalhos que a Didit envia sempre: Durante 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 (veja Rotação do segredo de assinatura).

Rotação do segredo de assinatura

Rode o segredo de assinatura de um destino na Business Console. Durante 24 horas após a rotação, cada entrega para esse destino inclui mais três cabeçalhos, calculados com o segredo que foi substituído: Um manipulador que aceite uma correspondência em qualquer cabeçalho de assinatura ou no respetivo cabeçalho -Previous continua a verificar durante a implementação do 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 isto. Implemente o novo segredo dentro das 24 horas, porque, depois disso, só o novo segredo permite verificar as assinaturas. O campo previous_secret_expires_at em GET /v3/webhook/destinations/{destination_uuid}/ indica quando terminam as 24 horas. As novas tentativas e os reenvios são assinados de novo com o segredo atual do destino, no momento do envio, e só incluem os cabeçalhos -Previous enquanto durarem as 24 horas. Se rodar novamente dentro das 24 horas, o segredo mais antigo é retirado de imediato: apenas o segredo que estava ativo até à nova rotação continua a ser verificado através dos cabeçalhos -Previous, durante 24 horas a contar da nova rotação. Os cabeçalhos -Previous existem apenas para destinos de webhook. O secret_shared_key de nível de aplicação, que assina o webhook_url legado, não tem um período de sobreposição: rodá-lo com rotate_secret_key em PATCH /v3/webhook/ invalida o segredo antigo de imediato.

X-Signature-Simple está obsoleto

X-Signature-Simple autentica o envelope, não o payload. A sua string canónica cobre apenas timestamp, session_id, status e webhook_type. Não cobre decision, nem resubmit_info, metadata, vendor_data ou event_id. Um pedido cujo decision tenha sido reescrito, deixando intactos esses quatro campos, continua a passar a verificação de X-Signature-Simple.É ainda mais fraco nos eventos que não têm qualquer session_id. Os eventos de transação (transaction_id, txn_id, amount, score) e de entidade (vendor_user_id, vendor_business_id) assinam "{timestamp}::{status}:{webhook_type}", o que não identifica qual a transação ou entidade a que o evento diz respeito: duas transações diferentes, reportadas com o mesmo estado no mesmo segundo, têm a mesma X-Signature-Simple. Os eventos travel_rule.status.updated, workflow.compliance_changed e transaction_rule_suggestions.created também não têm status, pelo que assinam "{timestamp}:::{webhook_type}", por exemplo "{timestamp}:::travel_rule.status.updated".Se X-Signature-Simple for o único cabeçalho que verifica, trate tudo o que esteja fora desses quatro campos como não fiável e volte a obter o registo a partir da API: GET /v3/session/{session_id}/decision/ para uma sessão, GET /v3/transactions/{transaction_id}/ para uma transação, que é o servidor de referência.
Trata-se de uma restrição de compatibilidade, e não de algo que possamos corrigir diretamente. A string canónica de quatro campos é um contrato de transmissão fixo: cada recetor que verifica X-Signature-Simple recalcula exatamente esses quatro campos, por isso alterar o que o cabeçalho assina partiria silenciosamente todos eles no caminho da verificação. Cobrir o corpo exige também uma forma canónica especificada do JSON, que ambos os lados reproduzam byte a byte, e a Didit já disponibiliza uma, em X-Signature-V2. Em vez de acrescentar uma segunda variante que cubra o corpo, com regras de canonização próprias, o cabeçalho mantém-se exatamente como está e fica obsoleto a favor das variantes existentes que cobrem o payload completo. O que isto significa para si:
  • Nada muda na transmissão. X-Signature-Simple continua a ser enviado em todas as entregas, calculado da mesma forma. Os verificadores existentes continuam a funcionar, e anunciaremos com grande antecedência qualquer remoção.
  • As novas integrações devem usar X-Signature-V2. É seguro para middleware e cobre todo o payload.
  • Se não puder deixar de usar X-Signature-Simple, verifique-o e depois obtenha o registo através da API, em vez de o ler a partir do corpo do webhook.

Porque existem três variantes?

Algumas frameworks web (parsers de corpo do Express, middleware do Django, gateways de API) voltam a codificar silenciosamente o JSON antes de o seu manipulador o ler. Se o corpo original continha "José" e o 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 todos os middlewares reproduzem de forma determinística. O obsoleto X-Signature-Simple recorre à assinatura de apenas uma string curta, independente do parser, quando até isso falha. Como assina apenas essa string curta e nunca o corpo, não pode garantir a integridade do corpo.

Ordem de verificação recomendada

  1. Tente primeiro X-Signature-V2. Recodifique JSON.parse(body) com as chaves ordenadas e o Unicode preservado, depois calcule HMAC-SHA256(secret, canonical) e compare com o cabeçalho usando timingSafeEqual.
  2. Se a V2 falhar e conseguir ler os bytes em bruto, tente X-Signature contra HMAC-SHA256(secret, rawBody).
  3. Só se ambas falharem, recorra à X-Signature-Simple, obsoleta, contra HMAC-SHA256(secret, "{timestamp}:{session_id}:{status}:{webhook_type}"). Esta opção autentica apenas o envelope: trate a decision no corpo como não fiável e volte a obtê-la a partir de GET /v3/session/{session_id}/decision/ antes de agir.
Em cada passo, quando estiver presente o cabeçalho -Previous correspondente, aceite uma correspondência em qualquer dos dois cabeçalhos (ver Rotação do segredo de assinatura). Em todos os casos, rejeite qualquer pedido 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 volta a tentar até 2 vezes, com um intervalo de espera 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 (inicial e novas tentativas) é registada como uma entrada separada na Business Console, no separador Entregas do destino, para que possa repetir ou inspecionar qualquer tentativa. Cada tentativa no registo de entregas de um destino tem um número attempt: 1 para a primeira entrega de um evento e, em cada nova tentativa ou reenvio, o número da tentativa repetida mais um. As novas tentativas automáticas são enviadas para o URL para o qual a primeira tentativa foi enviada, mesmo que tenha alterado entretanto o url do destino. Um reenvio manual é enviado para o URL atual do destino, pelo que corrigir um URL também corrige o reenvio. Outras regras de entrega a conhecer:
  • O pedido HTTP de saída expira após 5 segundos.
  • A Didit bloqueia entregas para URLs privados ou localhost, como proteção contra SSRF, e nunca segue redirecionamentos. Use um endpoint HTTPS público que responda diretamente.
  • Um url de destino que contenha uma barra invertida bruta, um carácter de controlo ou mais do que um @ na autoridade é rejeitado como malformado; esse URL não pode ser criado, e um URL existente não pode ser reenviado nem repetido. Use um URL simples https://host/path com, no máximo, uma secção de userinfo (para URLs de webhook com autenticação básica).
  • Um 2xx é considerado sucesso. Os tempos limite e as falhas de ligação contam como passíveis de nova tentativa (aparecem como 504/503 no registo de entregas). As respostas 3xx e 4xx, exceto 404, não são repetidas.
  • Em cada nova tentativa, a Didit recalcula as assinaturas com um X-Timestamp novo, pelo que o par timestamp/assinatura fica sempre alinhado.
  • As novas tentativas e os 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 pela qual os webhooks lhe chegam. Cada entrega é colocada na fila de forma independente, e uma nova tentativa chega minutos após a primeira tentativa, pelo que um status.updated para Approved pode chegar antes de um anterior para In Progress. Crie o seu recetor a pensar nisso:
  • Trate um webhook como um sinal de que algo mudou. Quando a ordem importa, chame GET /v3/session/{session_id}/decision/ e atue com base no status atual.
  • Nunca deixe um evento mais antigo substituir um estado mais recente: compare o created_at do evento com o último que guardou para esse registo e ignore o que for mais antigo.
  • Identifique repetições pelo event_id, que se mantém igual em todas as novas tentativas.
A Didit coloca na fila os eventos de uma transferência Travel Rule por uma ordem definida, descrita em Alteração do estado de troca Travel Rule, mas uma nova tentativa pode ainda alterar a ordem pela qual chegam.

Configurar um destino

Pode gerir os destinos a partir de Business Console > API & Webhooks ou através da API de Gestão.
1

Crie o destino

Chame POST /v3/webhook/destinations/ (ou clique em Adicionar destino na consola) com um label, um url público, webhook_version ("v3") e um array subscribed_events que contenha todas as famílias de eventos que este endpoint deve receber. É obrigatório pelo menos um evento, e não existe curinga.
2

Guarde o secret_shared_key

A resposta à criação devolve o secret_shared_key do destino. Guarde-o junto com os seus outros segredos de servidor: pertence apenas a este destino e é o dado de entrada das três variantes de assinatura HMAC-SHA256. GET /v3/webhook/destinations/{destination_uuid}/ devolve-o novamente aos utilizadores que fazem chamadas com uma chave de API e aos utilizadores da consola que podem ler os webhooks.
3

Implemente o endpoint

Exponha uma rota POST HTTPS pública, leia o corpo em bruto, verifique a assinatura (dando preferência a X-Signature-V2), valide a janela do timestamp e, em seguida, encaminhe com base em webhook_type. Devolva 2xx assim que tiver colocado o trabalho na fila; faça o processamento pesado de forma assíncrona.
4

Confirme as receções

Acompanhe o separador Entregas do destino. Os webhooks em bom estado devolvem 200 em um ou dois segundos. 5xx/404 aciona a política de novas tentativas da Didit; as falhas persistentes são descartadas após a segunda nova tentativa.
5

Teste com o Try Webhook

Use os cenários da consola de Try Webhook para testar o seu endpoint com payloads de verificação aprovada, recusada, em análise, KYB, entidade, atividade e transação, antes de ativar o tráfego de produção.
Funcionalidade de teste de webhooks da Didit na Business Console

Envie webhooks de teste diretamente a partir da Business Console para validar o seu endpoint antes de passar a produção.

Pode criar tantos destinos quantos precisar. Um padrão comum é um destino por consumidor: por exemplo, eventos KYC → o seu serviço de autenticação, eventos 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 subscrições, pelo que um segredo renovado ou uma implementação com falhas num consumidor não afeta os restantes.

Exemplos de código

Para garantir a segurança do seu endpoint de webhook, verifique a autenticidade dos pedidos recebidos com o secret_shared_key do destino.
Use X-Signature-V2. É a variante mais resistente à recodificação feita por middleware e autentica por completo o corpo (incluindo decision).

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

Se conseguir ler os bytes brutos antes de qualquer parser os processar, a variante original X-Signature funciona da mesma forma, mas assina o corpo bruto. Mantemo-la na secção legada abaixo, por uma questão de completude.

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

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

Os valores predefinidos do JSON em PHP não reproduzem a forma canónica. Quatro deles têm de ser substituídos, e se faltar um único que seja, os bytes assinados mudam e o digest nunca corresponde: A armadilha dos objetos vazios é a que causa mais problemas. Os payloads do Didit incluem habitualmente mapas vazios, como risk_view.countries.risk_scores, risk_view.crimes.risk_scores e risk_view.custom_list, pelo que uma ida e volta associativa quebra a assinatura em sessões aprovadas comuns, e não num caso raro e excecional.
Duas outras coisas que convém saber:
  • Os floats com valor inteiro não precisam de tratamento especial em PHP. O Didit serializa-os como inteiros (100.0 → 100), e o json_encode do PHP escreve um float inteiro da mesma forma, pelo que não é necessário nenhum passo shortenFloats, ao contrário do exemplo de Node.js acima.
  • Mantenha serialize_precision em -1 (o predefinido desde o PHP 7.1). Se o seu alojamento o substituir por 17, o json_encode escreve 87.42 como 87.420000000000002 e todas as verificações de X-Signature-V2 falham.
Se não conseguir que a forma canónica coincida, verifySignatureRaw acima é a alternativa mais simples: o $request->getContent() do Laravel devolve os bytes sem alterações, pelo que X-Signature funciona desde que nada antes do PHP recodifique o corpo. É exatamente o caso que o X-Signature-V2 foi concebido para suportar, e é por isso que o V2 é tentado em primeiro lugar.

Testes

Não precisa de executar uma verificação completa para testar o seu endpoint.
  • A partir de 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 o URL do destino.
  • Todos os cenários são assinados 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 possa confirmar que o X-Signature-V2 funciona através do seu middleware. As entregas de teste contêm dados de exemplo e são marcadas com um cabeçalho adicional X-Didit-Test-Webhook: true (e um sufixo (Test) no User-Agent), para que não afetem o estado de produção.
  • Volte a reproduzir qualquer entrega histórica a partir do separador Entregas de um destino, se precisar de depurar uma regressão.
Para testes smoke de ponta a ponta, execute uma verificação real através de um fluxo 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 que os cenários do 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)

Estado da troca Travel Rule alterado (travel_rule.status.updated)

travel_rule_status assume um dos 13 estados de troca documentados em Travel Rule. rail é INTERNAL, TRP, GTR, TRUST, VERIFYVASP, SYGNA ou EMAIL (valor vazio até ser selecionado um canal, se não for possível determinar nenhum, e sempre nos registos sunrise), ou TEST_VASP para uma transferência de sandbox à qual o Didit Test VASP respondeu, e direction é INBOUND ou OUTBOUND. Um evento de sandbox inclui "environment": "sandbox", e um evento TEST_VASP inclui também 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 registo sunrise após depósito, uma consulta TRP de entrada ou a etapa de entrada no canal INTERNAL), envia primeiro o evento transaction.created dessa transação e, depois, os eventos travel_rule.status.updated da transferência. Uma regra que altere o estado da transação durante essa etapa também pode enviar transaction.status.updated antes de transaction.created, e um registo sunrise que se associe a uma transação de depósito já criada não envia transaction.created. Cada webhook é entregue e repetido de forma independente, pelo que um evento que tenha sido tentado novamente pode chegar depois de um evento posterior: use transaction_id como chave no seu manipulador e volte a ler a transação quando precisar do estado atual. Uma transferência enviada por TRUST nunca recebe um evento COMPLETED, porque a TRUST não devolve nada que a Didit consiga ler: fica em AWAITING_COUNTERPARTY até ao prazo de confirmação e termina depois em EXPIRED. Através de GTR, VerifyVASP e Sygna Bridge, a Didit lê a resposta da contraparte na rede e o evento segue-a (ver redes Travel Rule).

Conformidade do fluxo alterada (workflow.compliance_changed)

transition.from e transition.to assumem um dos seguintes valores: compliant, gaps_detected, pending_change, unknown_coverage ou not_evaluated. severity é actionable quando foram detetadas lacunas, indicative para uma alteração pendente e informative quando as lacunas foram resolvidas. A Didit envia um evento por cada fluxo que tenha sido alterado.

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

kind é ADD para uma nova regra, TWEAK para uma alteração a uma regra existente e DISABLE para desativar uma regra. rule_id é null em ADD. open_count é o número de sugestões ainda abertas após a execução, incluindo as novas. As definições das sugestões de regras ativam ou desativam este webhook; ver 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 que todos os outros eventos. Contêm apenas identificadores e valores numéricos: nunca um nome, um motivo escrito por um revisor, uma narrativa ou qualquer conteúdo escrito pelo utilizador final. Não têm session_id; o item a que dizem respeito está indicado em item.
provenance indica a versão do Investigator que escreveu o relatório:
  • engine é a versão do motor do Investigator: um identificador opaco de oito caracteres. Muda sempre que o motor muda, pelo que 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 política que o relatório seguiu.
  • model_id é um alias obsoleto que tem o mesmo valor que engine. Utilize engine em vez disso.
  • prompt_hash já não é 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 respetivo identificador. Os carimbos de data/hora cujo nome termina em _at são cadeias ISO 8601. Subscreva estes eventos indicando as cadeias exatas em subscribed_events, como em qualquer outro evento.

Estado da entidade de utilizador alterado (user.status.updated)

Sessão reenviada

Legado: X-Signature com corpo bruto

O X-Signature continua a ser enviado em cada entrega. É um HMAC-SHA256 calculado sobre os bytes exatos que a Didit transmite (json.dumps(..., sort_keys=True, separators=(",", ":"))). Use-o apenas quando puder ler o corpo bruto antes de qualquer middleware o modificar.

Legado: formato de webhook V2

Os campos abaixo só se aplicam quando um destino está fixado em webhook_version: "v2". Existe ainda uma fixação "v1", ainda mais antiga (uma terceira estrutura de decisão, no singular), para destinos criados antes da V2; contacte o suporte antes de depender dela. As novas integrações devem usar a V3 (a predefinida), documentada acima, que utiliza arrays no plural.
Os próprios objetos por funcionalidade são iguais nas duas versões: um destino V2 recebe exatamente o match_score, risk_score, score_breakdown, risk_view e review_status por cada correspondência, bem como o score agregado, tal como o V3 (ver Relatório AML). Fixar a V2 altera apenas a posição do relatório AML em decision, e não o seu conteúdo. Se um consumidor a jusante ainda precisar das estruturas V2, crie um destino separado fixado em webhook_version: "v2" e mantenha os novos consumidores na V3.

Relacionado

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