Pular para o conteúdo principal
A Didit executa a troca de dados entre remetente e beneficiário exigida pelo GAFI (FATF) e pelo Regulamento de Transferências de Fundos (TFR) da UE para transferências de ativos virtuais: ela procura um canal que alcance o VASP da contraparte, negocia por ele os dados exigidos, acompanha a troca por um ciclo de vida de 13 estados e avisa você quando a troca for concluída, para que você possa liberar os fundos on-chain.

Visão geral

A Travel Rule do GAFI (Recomendação 16), implementada na UE como o Regulamento de Transferências de Fundos (TFR), exige que o Provedor de Serviços de Ativos Virtuais remetente (o VASP remetente) colete e transmita as informações do remetente e do beneficiário ao VASP destinatário (o VASP beneficiário) antes que uma transferência de ativo virtual seja liquidada. Ao contrário da maioria das jurisdições, o TFR da UE se aplica sem valor mínimo: toda transferência de cripto está no escopo, não apenas as transferências acima de um limiar de reporte. O produto Travel Rule da Didit é uma troca gerenciada, não apenas um campo de dados:
  • Você envia uma transferência com transaction_category: "travelRule".
  • A Didit tenta os trilhos em ordem de prioridade para alcançar o VASP da contraparte, executa a troca pelo primeiro que o alcança e, quando o outro lado retorna um nome de beneficiário, compara esse nome com o que você enviou.
  • Somente depois que a troca chegar a COMPLETED você deve transmitir a transferência on-chain.
  • Em seguida, você informa à Didit o hash da transação on-chain para encerrar a troca como FINISHED.
Sete trilhos estão disponíveis nesta versão, tentados em ordem estrita de prioridade: o primeiro que consegue alcançar a contraparte é o utilizado. Os trilhos de rede (GTR, TRUST, VERIFYVASP, SYGNA) exigem uma associação à rede do lado remetente e, hoje, essa associação precisa ser sua. Conecte as credenciais da sua associação no Marketplace do console (categoria de redes de Travel Rule), e suas transferências trafegam sob a sua própria identidade na rede. Hoje a Didit não possui associação de plataforma em nenhuma das quatro redes e está em processo de onboarding como provedor nelas. Até que esse onboarding seja concluído, platform_available é false para as quatro, o modo didit das configurações (roteamento pela associação de plataforma da Didit) não está disponível para nenhuma rede, e disabled_networks não tem nada para desativar. Uma associação que você mesmo conecta sempre tem precedência sobre uma associação de plataforma. Nenhuma associação de rede está incluída por padrão, nem mesmo a GTR. Ativar a Travel Rule não ativa GTR, TRUST, VerifyVASP nem Sygna. Consulte Obter configurações da Travel Rule para ver os modos efetivos de networks da sua aplicação, e Redes de Travel Rule para saber o que cada rede alcança hoje. Se as quatro informarem unavailable, nenhuma consegue rotear uma troca: conecte sua própria associação no Marketplace ou use uma contraparte alcançável por INTERNAL, TRP ou EMAIL. Ao salvar uma associação, o código de participante precisa ser o seu: a operação retorna 400 quando o código é o próprio código da Didit naquela rede ou um código que a associação de outra aplicação já possui. Uma associação GTR precisa da sua chave privada ed25519 (base64), aquela cuja chave pública está registrada no portal da GTR: ela criptografa os dados pessoais que você envia e descriptografa os dados que você recebe. Uma associação VerifyVASP aponta para o seu próprio VerifyVASP Enclave: a URL é a do seu Enclave, e o token é o que o seu Enclave apresenta à Didit. Mesmo com sua própria associação, um trilho de rede só roteia uma transferência quando o beneficiary_data dela traz o id da contraparte naquela rede (counterparty_gtr_vasp_code, counterparty_trust_membership_id, counterparty_verifyvasp_id ou counterparty_sygna_vasp_code), ou quando a entrada da contraparte no diretório a lista naquela rede (veja Rotas). platform_available informa se a associação de plataforma está configurada, e não é uma verificação em tempo real do status da rede. Da mesma forma, connected significa que as credenciais da sua associação estão salvas e passaram na validação local; a primeira troca real as verifica junto à rede. Um modo didit ou own não garante que a contraparte seja alcançável nem que a entrega seja bem-sucedida. Com sua própria associação, a Didit lê a resposta da contraparte via GTR, VERIFYVASP e SYGNA a partir da resposta da rede ou consultando a rede a cada 5 minutos, o que conclui ou recusa a transferência. TRUST apenas envia: uma transferência enviada por ela permanece em AWAITING_COUNTERPARTY até que confirmation_timeout_hours se esgote, depois passa para EXPIRED e o seu timeout_outcome é aplicado. O recebimento de uma transferência que outro VASP envia a você por uma rede ainda não está ativado, e nenhuma troca por uma rede foi concluída em uma rede de produção até agora: consulte Redes de Travel Rule. Outras redes (CODE, a aliança coreana, TRISA, Notabene e Veriscope) aparecem no Marketplace do console como blocos para solicitar acesso. A Didit ainda não tem integração com elas, então nenhuma transferência pode ser roteada por elas hoje. Quando nenhum dos sete canais consegue identificar uma contraparte, a Didit executa mais uma etapa de identificação antes de desistir: a atribuição por análise de blockchain. A carteira de destino é consultada nos dados de análise de blockchain; quando a carteira pertence a uma exchange ou custodiante conhecida, a Didit registra o VASP atribuído na transferência, adiciona-o ao diretório e executa os canais mais uma vez com o novo nome. Consulte Atribuição por análise de blockchain para ver o comportamento completo e os preços. Uma transferência cujo destino foi declarado como carteira autocustodiada ignora os sete canais, já que não há VASP de contraparte com quem trocar dados, e segue diretamente para a comprovação de propriedade da carteira pelo usuário final.
A Didit também opera o lado da troca voltado para a contraparte: os endpoints públicos de identidade e de consulta TRP que outros VASPs chamam para alcançar você, os endpoints de callback e o fluxo de retirada por e-mail. Você nunca chama esses endpoints diretamente, pois são infraestrutura gerenciada, mas a página Interoperabilidade de Travel Rule documenta cada um deles para que VASPs de contraparte possam se conectar a você. Você interage com a Travel Rule apenas pelos endpoints /v3/ descritos nesta página.

O que é executado quando você envia uma transferência

As verificações são executadas na única chamada POST /v3/transactions/. Quando você recebe a resposta, a triagem já foi executada, a transferência já está armazenada e as regras já foram avaliadas. A troca em si começa depois da resposta: a Didit escolhe o trilho e contata a contraparte fora da sua requisição, então nenhuma rede ou contraparte pode atrasar ou fazer a criação falhar. Cada mudança de status a partir daí chega como um webhook travel_rule.status.updated que informa o trilho. O objeto de transferência retornado pelos endpoints de transferência da Travel Rule traz um campo delivery que mostra se a mensagem foi entregue. Não há pipeline para consultar periodicamente: as partes assíncronas são a troca, a resposta da contraparte e qualquer ação do usuário final. Etapa por etapa:
  1. Validação e vinculação do titular. O payload é validado. Um transaction_id já usado na sua aplicação é rejeitado com 400. Quando duas requisições com o mesmo id concorrem, uma delas recebe 409. O subject é vinculado ao perfil do seu usuário ou da sua empresa por vendor_data, para que a transferência apareça nesse perfil para monitoramento. Um vendor_data de titular ou de contraparte que esteja na lista de bloqueio é rejeitado com 400, e nenhuma transação é criada. Carteiras, contas bancárias, IPs e dispositivos na lista de bloqueio são verificados na etapa 6 e recusam a transação nesse ponto, depois que o roteamento foi executado.
  2. Enriquecimento de dispositivo e rede. Os IPs das partes são enriquecidos com dados geográficos, e qualquer contexto de dispositivo (automático no envio pelo SDK) é normalizado no grafo de dispositivos. É o mesmo grafo alimentado pelas sessões de KYC, então a relação “relacionado por dispositivo” funciona entre onboarding e transações.
  3. Triagem cripto. Em transferências cripto com monitoramento ativado, a carteira relevante (ou o hash on-chain) passa por triagem com análise de blockchain antes de qualquer troca: exposição a sanções, proximidade com mixers e fundos roubados. Consulte Triagem cripto e de carteiras.
  4. Transferência da Travel Rule. O mecanismo de troca verifica o limiar e respeita uma declaração de carteira autocustodiada. Em seguida, armazena a transferência com o trilho ainda vazio: NOT_APPLICABLE abaixo do seu limiar, UNCONFIRMED_OWNERSHIP para uma carteira autocustodiada declarada, COMPLETED quando a outra carteira é a sua própria carteira verificada e AWAITING_COUNTERPARTY nos demais casos. Cada mudança de status coloca um evento travel_rule.status.updated na fila, e a Didit o envia depois do transaction.created da transação (etapa 7).
  5. Criação da sessão de propriedade da carteira. Se a transferência exige que o usuário final comprove o controle da carteira e auto_wallet_verification está ativado, uma sessão do widget de propriedade da carteira é criada e retornada em action_required.
  6. Avaliação de regras. Todas as regras ativas são executadas. O pacote EU TFR reage ao status de transferência definido na etapa 4, e suas regras personalizadas veem o resultado da triagem da etapa 3. Uma regra pode reter a transação (IN_REVIEW), recusá-la ou exigir uma verificação adicional (AWAITING_USER).
  7. Faturamento e notificação. Uma transação de saída é faturada em uma única linha: a linha da Travel Rule quando a transação iniciou uma troca, e Triagem de transações nos demais casos. Uma transferência de entrada não gera nenhuma das duas tarifas, e uma aplicação de sandbox nunca é cobrada. A resposta é enviada, e transaction.created é disparado para os seus destinos de webhook, seguido dos eventos travel_rule.status.updated da etapa 4.
  8. Roteamento, depois da resposta. A Didit percorre os sete trilhos em ordem de prioridade. Se nenhum deles encontrar a contraparte, a atribuição por análise de blockchain identifica a contraparte e os trilhos são executados novamente uma vez. O primeiro trilho alcançável conduz a troca. Nesse trilho, a transferência permanece em AWAITING_COUNTERPARTY enquanto a contraparte responde. Ela é liquidada na hora quando uma contraparte INTERNAL é encontrada (COMPLETED ou COUNTERPARTY_MISMATCHED_DATA), e passa a COUNTERPARTY_VASP_NOT_FOUND quando nenhum trilho alcança a contraparte. Cada mudança dispara travel_rule.status.updated, e suas regras são executadas novamente sempre que o status ou o trilho mudam. Uma transferência que o roteamento deixa em COUNTERPARTY_VASP_NOT_FOUND recebe nesse momento a sua sessão do widget de propriedade da carteira (quando auto_wallet_verification está ativado). Leia essa sessão no action_required da transação com Obter transação.

Como cada etapa corresponde às suas obrigações

Observação sobre testes. Aplicações de sandbox ignoram a avaliação de regras e o faturamento, e não enviam os webhooks transaction.created nem transaction.status.updated. As transações de sandbox permanecem APPROVED, a menos que uma transferência da Travel Rule que expira aplique o seu timeout_outcome, e nada é cobrado. O próprio mecanismo de troca da Travel Rule é executado em aplicações de sandbox quando a Travel Rule está ativada, com uma única contraparte: toda troca de saída vai para o Didit Test VASP no trilho TEST_VASP. Ele responde dentro da Didit com o cenário que você escolher, então a transferência é concluída, é recusada, apresenta divergência, fica inalcançável, expira ou aguarda a comprovação de propriedade da carteira. Nenhuma mensagem de conformidade chega a uma VASP real da contraparte, e os webhooks travel_rule.status.updated são entregues com environment: sandbox. Entrada: o test VASP pode enviar uma transferência para você (Acionar transferência de entrada do Test VASP), e o registro (POST /v3/travel-rule/inbound/) é liquidado com base no seu catálogo de endereços de carteira, como em uma aplicação de produção: ON_HOLD, UNCONFIRMED_OWNERSHIP, COUNTERPARTY_MISMATCHED_DATA ou COMPLETED e depois FINISHED. Consulte Testar a Travel Rule no sandbox.

Ciclo de vida

Toda transferência tem um status que assume um de 13 valores. A troca começa em AWAITING_COUNTERPARTY no caso normal, em NOT_APPLICABLE quando o valor está abaixo do seu threshold_amount ou quando uma solicitação de pagamento Lightning não indica nenhum beneficiário (consulte Lightning), ou em UNCONFIRMED_OWNERSHIP quando o destino foi declarado como carteira autocustodiada. Ela termina em um dos estados finais: FINISHED, CANCELLED ou EXPIRED. A transferência segue sua própria máquina de estados, separada do status de revisão da transação subjacente. Um status da troca nunca altera sozinho o status da transação, com uma exceção: uma expiração aplica o timeout_outcome que você configurou (ou uma política de sunrise ou de contraparte não responsiva, quando aplicável). Em vez disso, suas regras são executadas novamente a cada transição. Assim, as regras da EU TFR ou qualquer regra baseada em travel_rule_status podem mover a transação, por exemplo para IN_REVIEW. Uma transferência que exige que o usuário final comprove o controle da carteira adiciona um bloco action_required à transação, mas o status da transação permanece como suas regras o deixaram. Leia o estado da troca em travel_rule.status e o veredito de permitir / reter / recusar no próprio status da transação. Cada transição (e cada status informado passivamente) também é replicada nos valores personalizados da transação, para que as regras possam se basear neles: custom_values.travel_rule_status (status canônico), custom_values.travel_rule_rail (o canal que transportou a troca, vazio até que um seja selecionado) e custom_values.travel_rule_regime (derivado da jurisdiction nas suas configurações: SG → singapore, GB → uk e qualquer código de país membro da UE ou do EEE, como DE ou FR → eu. Códigos sem mapeamento são gravados em minúsculas, por exemplo US → us. Um props.travel_rule_regime que você mesmo envia sempre prevalece sobre o valor derivado).
Nunca transmita antes de COMPLETED. Liberar fundos on-chain enquanto uma transferência está em AWAITING_COUNTERPARTY, UNCONFIRMED_OWNERSHIP ou em qualquer estado de divergência ou recusa anula o propósito da troca. Condicione sua etapa de transmissão a status == "COMPLETED" e, em seguida, chame PATCH .../travel-rule/ com o payment_txn_id resultante para passar a FINISHED.
As transições em resumo (CANCELLED também pode ser alcançado a partir de qualquer estado não terminal com action: "cancel"):

Entrega e novas tentativas

A Didit envia cada mensagem que uma transferência deve enviar fora da requisição que a originou e tenta novamente até que o outro lado a receba. O objeto de transferência retornado por Finalizar, cancelar ou reenviar, Confirmar propriedade e registro sunrise traz a mensagem mais recente em delivery, assim como o objeto travel_rule incorporado à transação; ele é null quando a transferência nunca deveu nenhuma mensagem. Uma falha da qual a rede ainda pode se recuperar (sem resposta a tempo, falha de conexão, HTTP 408, 429 ou 5xx) é tentada novamente após 30 segundos, 2 minutos, 10 minutos, 30 minutos e 1 hora. Quando uma primeira mensagem falha definitivamente (a rede a recusou ou a sexta tentativa também falhou), a transferência passa para COUNTERPARTY_VASP_NOT_REACHABLE com last_error em sua timeline, e você pode tentar novamente com action: "resend". Qualquer outra mensagem que falhe definitivamente é registrada na timeline. delivery nunca substitui o status da transferência: acompanhe a troca pelo status e use delivery para ver por que uma transferência ainda está aguardando.

Valores de status legados

Se você já enviava travel_rule_details.status antes desta versão, esses valores continuam funcionando e são mapeados automaticamente. Grafias em camelCase de qualquer status (por exemplo counterpartyVaspNotFound) também são aceitas, tanto no envio quanto nos valores de condição de regras, e são normalizadas para a forma canônica:

Configuração

Configure o perfil do seu VASP e a política de negociação uma vez por aplicação com GET/PUT /v3/travel-rule/settings/.
PUT é uma atualização parcial: envie apenas os campos que você quer alterar.

Rigor da correspondência de nomes

Modos de validação de propriedade

ownership_validation_mode define quanta prova a propriedade de uma carteira exige antes que uma transferência se apoie nela: Uma carteira é memorizada por usuário final depois de verificada. Em FULL e SIMPLIFIED, uma transferência posterior só a reutiliza quando ela é respaldada por uma prova que o modo aceita para essa transferência. Quando inbound_auto_accept não tem uma carteira do catálogo de endereços para corresponder, uma carteira cripto que você registrou nas transações de exatamente um usuário final identifica o titular. A Didit adiciona essa carteira ao catálogo de endereços do usuário final como sua autodeclaração, verificada, a menos que o modo seja FULL. Ela nunca adiciona uma carteira que o catálogo de endereços já lista sob outro nome da mesma chain (eth e ethereum), incluindo uma registrada como de outro VASP. As verificações de endereço que outros VASPs fazem antes de enviar (via GTR, Sygna e VerifyVASP) também seguem o modo: em FULL, uma carteira que o usuário final apenas declarou não é informada como sua.

Compartilhamento de dados

data_sharing_fields escolhe quais campos a Didit envia à contraparte sobre os seus próprios usuários, separadamente para pessoas físicas e empresas:
  • Pessoas físicas podem compartilhar name, wallet_address, address, national_id, customer_identification, date_of_birth e place_of_birth. Empresas usam os cinco primeiros.
  • name e wallet_address são sempre enviados.
  • Um tipo de entidade para o qual você nunca fez uma escolha compartilha todos os campos. Uma lista vazia também é uma escolha: ela compartilha apenas o nome e a carteira.
  • Um PUT faz a mesclagem por tipo de entidade, então enviar individual mantém intacta a escolha de company armazenada.
  • Uma escolha que não consegue cumprir as obrigações do remetente do regime da sua jurisdiction (EU TFR ou Recomendação 16 do FATF), incluindo uma lista vazia, é recusada com 400. Os erros ficam em data_sharing_fields, indexados por tipo de entidade.

Correspondência por campo

matching_rules define o rigor com que cada campo dos dados da contraparte é comparado com o que você tem:
Cada valor é NONE, STRICT, CONTAINS, DEFAULT ou FUZZY. Padrões: name segue name_matching_strictness, date_of_birth e address são NONE, e account é STRICT. Um campo omitido mantém o seu padrão, e um campo que o tipo de entidade não compara (uma empresa não tem date_of_birth) é recusado com 400.

Limiares por jurisdição

threshold_amount existe porque o escopo do Travel Rule varia conforme o regulador. A Didit usa 0.00 como padrão (a posição da UE), então toda transferência é trocada, a menos que você aumente o valor deliberadamente: Defina threshold_amount com o valor do seu regulador; transferências abaixo dele resultam em NOT_APPLICABLE sem trocar nenhum dado de identidade. Os limiares mudam com o tempo: confirme o valor atual com a sua assessoria jurídica de conformidade em vez de tratar esta tabela como aconselhamento jurídico.

Modelo de dados IVMS 101

O padrão do setor para os dados trocados no âmbito da Travel Rule é o IVMS 101 (interVASP Messaging Standard). travel_rule_details.originator_data e travel_rule_details.beneficiary_data são payloads de pessoa no estilo IVMS 101. A Didit os encapsula no envelope nativo de cada trilho: o trilho TRP troca blocos IVMS101 (ivms101.2023, informado no campo ivms_version da transferência), o trilho Sygna usa sua variante IVMS criptografada com ECIES, e os trilhos GTR, TRUST e VERIFYVASP usam seus próprios envelopes criptografados. Assim, um único formato de payload chega a cada contraparte no formato que o protocolo dela espera. Ao montar a mensagem IVMS 101, a Didit lê estas chaves de cada payload de pessoa: first_name e last_name (ou um único name ou full_name), date_of_birth, place_of_birth, residence_country (ou country), vendor_data (ou customer_identification) e wallet_address. Duas regras práticas:
  • Alfabeto latino. O IVMS 101 exige valores em alfabeto latino, então translitere os nomes escritos originalmente em outro alfabeto. A correspondência de nomes da Didit compara conjuntos de tokens normalizados, então diferenças de ordem e de maiúsculas e minúsculas não fazem uma troca falhar. Alfabetos diferentes nos dois lados, sim.
  • Envie dados que você verificou. Quando o titular por trás de vendor_data é um usuário com uma verificação KYC da Didit aprovada, a Didit transmite a identidade verificada, não os valores que você digitou: consulte Dados verificados e procedência. Para qualquer outro titular, a Didit transmite exatamente os originator_data que você envia. Por isso, monte-os a partir da identidade que você verificou no onboarding, e não de um campo de formulário não verificado. É isso que exige a redação do FATF: “informações do remetente exigidas e precisas”. No trilho INTERNAL, a aplicação do beneficiário também recebe o subject que você enviou (nome, vendor_data, data de nascimento, país e endereço) como a parte contraparte da transação de entrada dela.

Dados verificados e procedência

Quando o titular de uma transferência é um dos seus usuários, uma pessoa física com uma verificação KYC aprovada, a Didit monta esse lado da troca a partir dos dados verificados:
  • o remetente de uma transferência de saída que você cria com POST /v3/transactions/;
  • o beneficiário de uma transferência de entrada que você informa com POST /v3/transactions/, ou com POST /v3/travel-rule/inbound/ quando o holder_vendor_data da carteira correspondente indica esse usuário.
Em POST /v3/transactions/, os dois casos se aplicam a uma transação cuja transaction_category é travel_rule enquanto a Travel Rule está ativada. Os nomes, a data e o local de nascimento, o número e o tipo do documento, o endereço e o país de residência (obtido desse endereço) verificados têm precedência sobre os valores que você enviou. Um campo que a verificação não contém mantém o seu valor. O mesmo vale para um endereço completo que você enviou quando o endereço verificado não está completo o suficiente para ser transmitido. Os metadata da transferência, no objeto travel_rule incorporado à transação, registram a origem de cada campo e onde os seus valores eram diferentes:
*_provenance associa cada campo a verified ou caller, e *_verified_differences lista todos os campos em que você enviou um valor diferente do verificado, sem considerar maiúsculas e minúsculas, espaços nem códigos de país de duas ou três letras. Enquanto os dados de uma transferência de entrada estão mascarados, as diferenças ficam de fora. A Didit calcula os dois, então cópias dessas chaves, ou de name_match, que você enviar em travel_rule_details.metadata são descartadas.

Envio direto de IVMS 101

Além dos objetos planos originator_data e beneficiary_data, travel_rule_details (em POST /v3/transactions/) e POST /v3/travel-rule/inbound/ aceitam IVMS 101 nativo:
  • um bloco originator e um bloco beneficiary, com originatorPersons ou beneficiaryPersons contendo uma naturalPerson ou uma legalPerson, e accountNumber;
  • os mesmos blocos dentro de um objeto ivms101 (ou IVMS101);
  • uma pessoa IVMS 101, ou um bloco inteiro, como originator_data ou beneficiary_data.
Cada lado aceita uma pessoa: uma naturalPerson ou uma legalPerson, o que torna a parte uma empresa. Um originator_data ou beneficiary_data plano não vazio prevalece sobre um bloco do mesmo lado.
Um bloco malformado retorna 400 com a chave do seu caminho, por exemplo {"travel_rule_details": {"originator.originatorPersons": ["must be a non-empty list of originator persons."]}}. Em POST /v3/travel-rule/inbound/, as mesmas chaves ficam no nível superior, sob ivms101. quando você usou o objeto envoltório.

Dados obrigatórios por regime

Enquanto a Travel Rule está ativada, uma transferência de saída igual ou acima do seu limiar deve conter o que o seu regime exige, ou retorna 400. Apenas os lados que você enviou são verificados, os dados verificados contam para o remetente, e os erros ficam sob travel_rule_details.originator_data ou travel_rule_details.beneficiary_data, por exemplo "EU TFR requires the originator name." ou "FATF Recommendation 16 requires the beneficiary wallet address.": Para o remetente, a verificação lê os campos que a sua aplicação compartilha em data_sharing_fields, porque são apenas esses que um trilho envia. O beneficiário é verificado tal como você o enviou. Quando a transferência só atende ao regime com um campo que você não compartilha, o 400 indica o requisito do regime e, em seguida, os campos que as suas configurações compartilham. O número do documento oficial é national_id (ou document_number), o número de identificação do cliente é customer_identification (ou vendor_data) e a data de nascimento é date_of_birth. Um beneficiary_data.wallet_address vazio é preenchido com counterparty.payment_method.account_id antes da verificação. Um saque UTXO cuja saída do beneficiário a Didit inferiu a partir de travel_rule_details.utxo conta como se contivesse esse dado. Uma transferência Lightning à qual a Travel Rule não se aplica não é verificada.

Endereços de viagem

Um endereço de viagem (travel address) é uma string compacta e codificada que aponta para o endpoint de consulta TRP de entrada de um VASP. Ele nunca expõe uma URL bruta nem qualquer endereço de carteira. Depois que a Travel Rule é ativada, a Didit gera o seu próprio travel_address (retornado como somente leitura nas configurações) para que você possa compartilhá-lo com outros VASPs que chegam até você pelo canal TRP. Cada carteira da sua própria agenda de endereços também recebe um receiving_travel_address próprio: uma consulta enviada a ele identifica essa carteira, então a Didit não precisa encontrá-la pelo número da conta ou pelo nome do titular. O host TRP público da Didit ainda não responde a outros VASPs, portanto o recebimento por TRP só estará disponível quando isso acontecer: consulte Redes da Travel Rule. Quando você souber o endereço de viagem de uma contraparte, armazene-o no registro da agenda de endereços de carteiras de destino para que a Didit encaminhe as transferências desse beneficiário diretamente por TRP, em vez de recorrer ao e-mail. A Didit valida os endereços de viagem que você armazena em um registro da agenda de endereços de carteiras ou envia em originating_vasp: cada um deve começar com ta e ser decodificado em uma URL de consulta que contenha t=i. Por isso, um valor provisório como ta... retorna 400. Um beneficiary_data.travel_address em uma transação não é validado: se ele não puder ser decodificado, o canal TRP é ignorado. A codificação é Base58Check com o prefixo ta: o host e o caminho do endpoint (que sempre contém o par de consulta t=i), mais um checksum double-SHA-256 de quatro bytes, codificados em base58. Um endereço real, portanto, tem esta aparência e chega a cerca de 100 caracteres:
Quando a Didit valida um endereço de viagem, um valor que não seja um endereço bem formado e com checksum válido retorna 400 com "Invalid travel address.". Use um endereço real obtido na resposta das suas próprias configurações ou fornecido pela própria contraparte.

Testes sem credenciais de rede

Você não precisa ser membro da GTR, TRUST, VerifyVASP ou Sygna para testar os caminhos que dispensam associação. Você ainda precisa de uma chave de API da Didit para a aplicação em teste.
  • Envio em sandbox: envie uma transação travelRule a partir de uma aplicação de sandbox. Após as verificações de limiar e de carteira autocustodiada, o Didit Test VASP responde a ela dentro da Didit com o cenário que você escolher pela carteira ou pelo nome do beneficiário: aceitar, recusar, divergência de nome, inacessível, tempo esgotado ou autocustodiada. Nenhuma rede, e-mail ou outro cliente da Didit recebe nada.
  • Recebimento em sandbox: faça o VASP de teste enviar uma transferência para você com Trigger Test VASP Inbound Transfer ou registre uma você mesmo com Register Inbound Travel Rule Transfer. Teste uma carteira desconhecida, uma carteira não verificada, uma divergência no nome do beneficiário e uma carteira verificada e correspondente. Esses testes acionam decisões reais de recebimento sem contatar nenhuma rede.
  • Duas aplicações de produção controladas: use o canal INTERNAL entre duas das suas próprias aplicações de produção (a que recebe pode ser descoberta e comprova o controle da carteira de destino com uma mensagem assinada ou um depósito de teste), ou uma contraparte TRP controlada, para testar uma troca entre duas partes sem credenciais comerciais de rede. Aplicações de produção podem gerar cobranças e notificações normais; use identidades de teste e contrapartes que você controla.
Consulte Testar a Travel Rule em sandbox para ver todos os cenários e o resultado exato de cada um. Testes bem-sucedidos em sandbox ou de protocolo local não validam as credenciais, a associação nem a interoperabilidade em produção de uma rede comercial. Isso exige um sandbox autorizado da rede ou uma troca controlada em produção com credenciais de associação válidas.

Envio de uma transferência

Inclua a transferência em POST /v3/transactions/ definindo transaction_category como travelRule (ou travel_rule) e anexando um objeto travel_rule_details (alias: travelRule). O bloco travel_rule_details em si é opcional, mas, depois que você o anexa, travel_rule_details.status passa a ser obrigatório: um bloco sem ele retorna 400. Quando o Travel Rule está ativado para a sua aplicação, a Didit ignora o valor de status que você envia e conduz a troca por conta própria:
  1. Se o valor estiver abaixo do threshold_amount configurado, a transferência é resolvida imediatamente como NOT_APPLICABLE e nada é negociado.
  2. Se o método de pagamento da contraparte declarar o destino como uma carteira autocustodiada (payment_method.method_type: "unhosted_wallet"), nenhum trilho é tentado: a transferência vai direto para UNCONFIRMED_OWNERSHIP e o widget de propriedade da carteira é gerado automaticamente (veja Carteiras autocustodiadas declaradas).
  3. Caso contrário, os trilhos são executados em ordem de prioridade, e o primeiro que conseguir alcançar a contraparte conduz a troca:
    • INTERNAL - exatamente um outro cliente da Didit tem uma prova por mensagem assinada ou por depósito de teste para beneficiary_data.wallet_address, feita depois da última troca de titular da carteira. A sua própria aplicação nunca conta e, quando o seu usuário final escolheu um membro da rede Didit no widget de propriedade da carteira, só a prova desse membro conta. A aplicação desse cliente está em produção (não em sandbox), tem o Travel Rule ativado e is_discoverable definido, e é o VASP que você indicou quando envia counterparty_vasp_lei ou counterparty_vasp_name. Uma carteira apenas autodeclarada, comprovada por captura de tela, não verificada ou apenas listada em um catálogo de endereços nunca recebe nada pelo INTERNAL.
    • TRP - o ativo da transferência tem um mapeamento de Digital Token Identifier para a rede da transferência (veja Identificadores de ativos TRP), e o payload traz beneficiary_data.travel_address, a entrada do catálogo de endereços do próprio destino armazena um, ou a contraparte é resolvida no diretório (por counterparty_vasp_lei ou counterparty_vasp_name) com um endpoint TRP.
    • GTR, TRUST, VERIFYVASP, SYGNA - você conectou a sua própria associação a essa rede em Marketplace, e a contraparte é resolvida para um ID de rede (campo explícito ou entrada do diretório; veja Campos de resolução da contraparte). A Didit ainda não tem associação de plataforma nessas redes (está em processo de onboarding como provedor), então disabled_networks não altera esta etapa hoje.
    • EMAIL - beneficiary_data.counterparty_vasp_email foi informado, ou counterparty_vasp_name é resolvido para uma entrada do diretório com um e-mail de conformidade.
  4. Se nenhum trilho conseguir resolver uma contraparte, a Didit executa a cadeia de descoberta de contraparte. Com vasp_attribution_enabled ativado, isso inclui a atribuição por análise de blockchain: a carteira de destino é associada ao VASP que a detém, o nome atribuído é gravado em beneficiary_data.counterparty_vasp_name (quando vazio) e no diretório, e os trilhos são executados novamente uma vez. Assim, uma carteira atribuída a um VASP cuja entrada no diretório traz um endpoint TRP, um ID de rede ou um e-mail de conformidade é roteada nesta segunda passagem.
  5. Se a contraparte continuar sem resolução, a transferência passa para COUNTERPARTY_VASP_NOT_FOUND. Em transferências de saída, a Didit gera automaticamente o widget de propriedade da carteira (quando auto_wallet_verification está ativado) para que a transferência ainda possa ser concluída como transferência para carteira autocustodiada, e você pode executar o roteamento novamente mais tarde com action: "resend" quando tiver dados melhores da contraparte.
As etapas 1 e 2 acontecem dentro da requisição. As etapas 3 a 5 são executadas logo após a resposta: a transferência retorna AWAITING_COUNTERPARTY com protocol: null, e cada resultado chega como um webhook travel_rule.status.updated.

Identificadores de ativos TRP

O TRP identifica o ativo transferido pelo seu Digital Token Identifier (DTI) da ISO 24165. Um DTI identifica um token em uma blockchain, portanto um token multichain tem um DTI por rede. A Didit envia transferências pelo TRP para estes ativos: Os identificadores de USDC são os que o emissor do token publica no seu white paper MiCA. Para um token multichain, a transferência deve indicar a sua rede em transaction_details.crypto_params.crypto_chain (por exemplo, CELO, BASE, OP, ARB ou POL). Sem uma rede, ou em uma rede sem mapeamento, a transferência não é enviada pelo TRP e a Didit tenta os trilhos restantes: primeiro as redes de interoperabilidade, depois o e-mail. O USDT ainda não está mapeado. Um token sem mapeamento de DTI, como a stablecoin própria de uma empresa, exige que o seu emissor registre um DTI junto à autoridade de registro da ISO 24165, um por token por blockchain. Depois que os DTIs existirem, entre em contato com o suporte da Didit informando cada DTI, a sua blockchain e as casas decimais do token, e a Didit adiciona o mapeamento. Consultas TRP de entrada que trazem um DTI por cadeia mapeado são registradas com a moeda do token, o valor nas casas decimais do token e a rede.

Descoberta de contraparte

Uma transferência que traz apenas um endereço de carteira ainda chega à sua contraparte sempre que alguém consegue identificá-la. Antes de uma transferência de saída ser declarada impossível de rotear, a Didit consulta, nesta ordem, e para na primeira etapa que indicar um VASP com uma rota: O campo discovery da transferência lista cada etapa executada com seu outcome (match, miss ou skipped), um reason legível por máquina, o vasp e o rail encontrados e um registro de data e hora. Um VASP escolhido por você ou pelo usuário final tem prioridade sobre todas as etapas automáticas: a descoberta nunca o substitui por um palpite próprio. Quando nenhuma etapa identifica uma contraparte, a transferência passa para COUNTERPARTY_VASP_NOT_FOUND, ou para COUNTERPARTY_VASP_NOT_REACHABLE quando um VASP foi identificado, mas nenhuma de suas rotas está disponível para sua aplicação. A transferência passa então a ter um reason (awaiting_end_user, no_directory_match, directory_match_no_route ou picked_member_without_proven_wallet quando o membro escolhido pelo usuário final não comprovou a carteira) e uma lista de next_actions: O link do widget é o url nas ações que o usuário final executa. Quando uma ação de propriedade de carteira está pendente, o bloco action_required da transação (tipo wallet_ownership) traz o mesmo reason e as mesmas next_actions, de modo que um cliente que já acompanha action_required exibe o seletor sem trabalho adicional.

Campos de resolução da contraparte

Tudo o que a Didit sabe sobre a contraparte vem de travel_rule_details.beneficiary_data. Estes campos orientam a resolução do rail; todos são opcionais:

Formatos de blockchain

Em uma blockchain baseada em contas (blockchains EVM, Solana, Tron), uma transferência move fundos de um endereço para outro, e a Didit lê as duas carteiras diretamente da transação. Três outros formatos exigem mais, e o que a Didit resolveu para eles fica na transferência como chain_details (vazio, {}, em uma blockchain baseada em contas). chain_details.originator e chain_details.beneficiary trazem, cada um, o address, seu memo e a source de onde veio, e a correspondência e o roteamento leem as carteiras primeiro a partir daí.

Transferências UTXO

Uma transação de Bitcoin, Litecoin, Bitcoin Cash ou Dogecoin gasta entradas de qualquer número de endereços e paga qualquer número de saídas, algumas delas como troco de volta ao remetente. Envie as entradas e saídas como travel_rule_details.utxo (valores na unidade da própria moeda, como strings decimais), e a Didit infere o que você não declarar:
  • Remetente: originator_data.wallet_address quando você o envia; caso contrário, o endereço de entrada que mais contribuiu (source: largest_input).
  • Beneficiário: a carteira declarada; caso contrário, a única saída que não devolve troco a um endereço de entrada (only_non_change_output); caso contrário, a única saída que paga o valor da transferência (amount_match).
A transferência passa a conter:
chain_details.warnings sinaliza o que não confere: declared_originator_not_an_input, declared_beneficiary_not_an_output, beneficiary_output_ambiguous (nenhuma saída pôde ser distinguida das demais) e beneficiary_output_amount_differs. utxo em qualquer outra chain resulta em 400, e cada lista contém no máximo 1.000 entradas. Um depósito informado recebe o mesmo objeto utxo (consulte Registro sunrise após o depósito).

Redes com memo e tag

Em XRP, Stellar (XLM), EOS, Cosmos (ATOM) e Hedera (HBAR), uma exchange recebe todos os clientes em um único endereço compartilhado e os distingue pela destination tag ou pelo memo. Por isso, o memo faz parte da carteira: envie-o como payment_method.memo no participante, ou como memo em originator_data / beneficiary_data (alias destinationTag), e a Didit compara o endereço e o memo em conjunto.
  • Uma entrada do catálogo de endereços com memo corresponde apenas às transferências que indicam esse memo. Uma entrada sem memo corresponde ao endereço inteiro. Uma transferência que não indica memo nunca chega a uma entrada que tem memo: em um endereço compartilhado, um depósito sem a sua tag não pertence a ninguém.
  • Um X-address de XRP traz a tag embutida: a Didit o divide no endereço clássico e na tag (source: x_address), de modo que uma carteira registrada em qualquer um dos formatos corresponde a uma transferência no outro.
  • Cada memo em um endereço compartilhado é um método de pagamento próprio na transação.
  • O que cada rede aceita: uma destination tag de XRP é um número inteiro de 0 a 4294967295 (um número JSON é aceito); um memo da Stellar tem até 28 bytes de texto, um id de 64 bits ou um hash de 32 bytes em hexadecimal; EOS aceita até 256 bytes, Cosmos até 256 caracteres e Hedera até 100 bytes. Um memo em uma chain que não tem memo (Bitcoin, chains EVM, Solana, Tron, Litecoin, Bitcoin Cash, Dogecoin, Lightning) resulta em 400.

Lightning

Um pagamento Lightning não tem endereço on-chain do beneficiário: o pagador tem uma solicitação de pagamento. Em uma transferência de cripto em bitcoin ou Lightning, payment_method.account_id pode ser essa solicitação, e a Didit identifica o beneficiário a partir dela sem contatar nenhuma rede: O recebedor é armazenado como a conta e como chain_details.beneficiary (source: invoice_payee), na chain LIGHTNING, e o conteúdo da solicitação fica em chain_details.lightning. Quando a solicitação não indica nenhum recebedor, uma transferência de saída fica NOT_APPLICABLE, com o motivo em chain_details.not_applicable_reason e na sua timeline: LIGHTNING_NO_PAYEE_IDENTIFIER, LIGHTNING_BOLT12_BLINDED_PAYEE ou LIGHTNING_LNURL_NAMES_NO_PAYEE. Um valor é interpretado como Lightning apenas em bitcoin, em LIGHTNING ou quando nenhuma chain é indicada (uma Lightning Address apenas em bitcoin ou LIGHTNING): em qualquer outra chain, ele é um endereço da própria chain.
O rail INTERNAL chega a outro cliente da Didit somente por meio de uma carteira que esse cliente comprovou controlar com uma mensagem assinada ou um depósito de teste, e essas comprovações existem hoje para Bitcoin, chains EVM, Solana e Tron. Portanto, em redes com memo, Lightning, Litecoin, Bitcoin Cash e Dogecoin, uma transferência nunca chega a outro cliente da Didit pelo INTERNAL. A correspondência por memo, tag e Lightning continua valendo para o seu próprio catálogo de endereços: transferências de entrada, depósitos informados e consultas TRP às suas carteiras.

Atualização da carteira do remetente

Um saque costuma ser declarado a partir da carteira principal do seu cliente e transmitido a partir de quaisquer endereços que detinham as moedas. Registre a carteira da qual os fundos realmente saíram com PATCH /v3/transactions/{transaction_id}/travel-rule/:
  • Somente transferências de saída, e nunca uma CANCELLED ou EXPIRED (409).
  • Quando as entradas UTXO da transferência são conhecidas, a carteira deve ser uma delas (caso contrário, 400). Em uma rede com memo, envie também memo.
  • Isso altera apenas o registro: nada é reenviado à contraparte e o status se mantém. chain_details.originator passa a ser a nova carteira com source: updated, a timeline registra a carteira anterior e a nova, e a contraparte INTERNAL da transferência é atualizada da mesma forma.

Atribuição por análise de blockchain

Quando você informa apenas um endereço de carteira, a Didit ainda consegue descobrir quem está do outro lado. Se nenhum rail consegue rotear a transferência, a Didit resolve a carteira de destino com base em dados de atribuição de análise de blockchain - a mesma análise que alimenta a triagem de transações cripto sabe quais carteiras pertencem a quais exchanges e custodiantes. A atribuição é executada apenas em transferências de saída que contêm tanto uma carteira de destino quanto uma chain (consulte Campos de resolução da contraparte); sem uma chain, ela é ignorada. Quando a carteira é atribuída a uma entidade conhecida, a Didit:
  1. Registra a atribuição na transferência: beneficiary_data.counterparty_vasp_name é preenchido (quando você não informou um), e os metadados da transferência contêm um bloco vasp_attribution com o nome da entidade, o tipo da entidade, o país e source: "blockchain_analytics".
  2. Adiciona a entidade ao diretório de VASPs (ou a associa à entrada existente), para que a atribuição se mantenha estável entre transferências.
  3. Executa os rails novamente uma vez com o nome atribuído - uma entrada do diretório que já tem um endpoint TRP faz a transferência ser roteada imediatamente, em vez de cair em COUNTERPARTY_VASP_NOT_FOUND.
A chamada de atribuição também funciona como uma triagem cripto completa: a transação recebe o resultado completo da triagem - pontuação de risco, categoria de risco da carteira, snapshot da rede - exatamente como se o monitoramento cripto tivesse sido executado, e o custom_values.aml_screening_trigger da transação é definido como travel_rule_attribution, para que você veja que a triagem foi executada porque o roteamento da Travel Rule a exigiu. Quando o monitoramento cripto já fez a triagem da mesma carteira nesta transação, o resultado armazenado é reutilizado - sem uma segunda chamada de análise e sem uma segunda cobrança. A atribuição nunca bloqueia a criação da transação: se a consulta de análise falhar ou o seu saldo não for suficiente para cobri-la, a transferência simplesmente segue para COUNTERPARTY_VASP_NOT_FOUND e nada é cobrado pela tentativa. Em action: "resend", uma atribuição registrada anteriormente é reutilizada em vez de ser consultada novamente. Desative a etapa inteira com vasp_attribution_enabled: false nas configurações. Consulte Preços para saber como a chamada de atribuição é cobrada. Quando a Travel Rule está desativada, travel_rule_details (incluindo um status informado por quem faz a chamada, legado ou atual) continua sendo registrado na transação, mas de forma passiva: nenhum rail é acionado. Use isso para preencher retroativamente dados de conformidade que você já acompanhava com o seu próprio processo. Uma transferência de saída passiva não inicia nenhuma troca, por isso é cobrada como Transaction Screening, e não na linha da Travel Rule. Com a Travel Rule ativada, esta requisição é roteada pelo rail EMAIL, porque informa o e-mail de conformidade da contraparte e nenhum rail anterior consegue alcançar o beneficiário:
A resposta, reduzida aos campos que importam aqui:
  • originator_data é o que você enviou, porque o titular do exemplo não tem uma verificação KYC aprovada. Para um usuário verificado, a Didit o monta a partir dos dados verificados (consulte Dados verificados e procedência). O rail EMAIL mostra ao destinatário apenas os campos do remetente que você compartilha em data_sharing_fields.
  • beneficiary_data.chain é ETH porque a requisição não informou nenhuma chain, então a Didit a obteve a partir da moeda.
  • status é APPROVED porque nenhuma regra atuou sobre a transação. Suas próprias regras podem definir outro status.
  • O contato de conformidade recebe o link de retirada. A transferência é concluída, falha na correspondência de nome ou é recusada quando ele responde, ou expira se ele não responder (consulte Retirada por e-mail).
protocol ainda é null porque o rail é escolhido depois da resposta (por exemplo, EMAIL quando você informou counterparty_vasp_email). Obter transação o mostra depois de escolhido, e todo webhook travel_rule.status.updated posterior o traz em rail. Se a carteira do beneficiário pertencer a outro cliente da Didit que comprovou ter controle sobre ela, o rail INTERNAL conclui toda a troca logo após a resposta, e esse webhook já informa COMPLETED (ou COUNTERPARTY_MISMATCHED_DATA). Quando o nome não corresponde, sua transferência fica em COUNTERPARTY_MISMATCHED_DATA e o outro cliente não recebe nada. Sem counterparty_vasp_email, e quando nem os rails nem a atribuição conseguem alcançar o beneficiário, a transferência termina depois em COUNTERPARTY_VASP_NOT_FOUND, com uma ação wallet_ownership na transação.
O objeto travel_rule incorporado à transação traz os campos próprios da transferência (uuid, status, protocol, required, obligations_count, originator_data, beneficiary_data, metadata), o que a Didit resolveu e comparou (chain_details, name_match, data_match, mismatched_fields e os campos de mascaramento data_masked e data_unmasked) e os campos que indicam em que ponto ela está: direction, rail, counterparty_vasp, delivery, discovery, reason e next_actions (consulte Por que uma transferência fica travada). Cada linha de GET /v3/transactions/ traz o mesmo bloco, ou null para uma transação sem transferência. Os endpoints dedicados a transferências descritos abaixo também retornam esses campos, além de ivms_version, ownership_confirmed, deadline_at, timeline e created_at, mas não obligations_count nem metadata.
Para encerrar uma transferência de saída COMPLETED depois de transmiti-la on-chain:
Isso exige que a transferência seja uma transferência de saída no status COMPLETED; caso contrário, a API retorna 409. Em caso de sucesso, tanto a transferência de saída quanto a sua contraparte no rail INTERNAL passam para FINISHED, e o payment_txn_id da transação recebe o hash que você informou. No rail TRP, a Didit também envia o hash para o callback de confirmação da contraparte. Para cancelar uma transferência que ainda não chegou a um estado final, envie {"action": "cancel"} para o mesmo endpoint. A contraparte no rail INTERNAL também é cancelada e, no rail TRP, depois que a contraparte aprova a consulta, a Didit envia o cancelamento para o callback de confirmação dela. Uma transferência que já está em FINISHED, CANCELLED ou EXPIRED retorna 409. Uma requisição sem payment_txn_id e sem uma action compatível retorna 400. Em uma transferência que passou por GTR, VERIFYVASP ou SYGNA, a Didit informa o hash on-chain (ou o cancelamento) à rede depois da resposta, com as mesmas novas tentativas. O delivery da resposta mostra essa mensagem. Para tentar novamente uma transferência de saída que não conseguiu alcançar a contraparte, ou seja, uma que esteja atualmente em COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE ou NOT_ENOUGH_COUNTERPARTY_DATA, primeiro melhore os dados da contraparte. Por exemplo, adicione um travel_address à entrada da carteira de destino, adicione um contato à entrada da contraparte no diretório ou catalogue o VASP no diretório. Em seguida, envie {"action": "resend"} para o mesmo endpoint. A Didit reinicia o prazo de confirmação e coloca a sequência de roteamento novamente na fila desde o início, usando os dados armazenados na transferência: a resposta mostra a transferência de volta em AWAITING_COUNTERPARTY (com resend queued no seu timeline), e o resultado chega como um webhook travel_rule.status.updated. Um reenvio feito enquanto uma tentativa anterior ainda está em andamento é enviado assim que essa tentativa termina. Qualquer outro status, ou uma transferência de entrada, retorna 409.
Para indicar você mesmo a contraparte quando a descoberta não conseguiu, envie {"action": "beneficiary_vasp", "beneficiary_vasp": "<directory VASP id>"} (o id de GET /v3/travel-rule/vasps/). A transferência é roteada para esse VASP e enviada novamente. Somente uma transferência de saída em COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE ou NOT_ENOUGH_COUNTERPARTY_DATA aceita essa ação. Qualquer outro status retorna 409, e um id desconhecido retorna 404.

Por que uma transferência fica travada

Uma transferência em COUNTERPARTY_VASP_NOT_FOUND ou COUNTERPARTY_VASP_NOT_REACHABLE informa por que está travada e o que a faz avançar, em toda leitura da sua transação. O bloco travel_rule de GET /v3/transactions/{transaction_id}/, do 201 de POST /v3/transactions/ e de cada linha de GET /v3/transactions/ traz essa informação, assim como o objeto de transferência com que o endpoint de transferência responde:
  • reason é a causa legível por máquina, "" em qualquer outro status.
  • next_actions lista o que faz a transferência avançar, [] em qualquer outro status.
  • delivery é a mensagem mais recente que a transferência deve entregar à outra parte: kind, status (QUEUED, SENDING, RETRYING, DELIVERED ou FAILED), rail, attempts, last_error, next_attempt_at e delivered_at, ou null quando não houve nenhuma a entregar.
  • discovery mostra onde a Didit procurou a contraparte, com uma entrada por etapa executada: step, outcome (match, miss ou skipped), reason, vasp, rail e at.
email_undeliverable e delivery_failed resultam de uma entrega com falha e aparecem apenas em COUNTERPARTY_VASP_NOT_REACHABLE. Uma entrega com falha define o reason primeiro, de modo que uma contraparte que a Didit encontrou nunca é informada como uma que ela não conseguiu encontrar. Os outros quatro vêm do rastro de descoberta, em qualquer um dos dois status. Um reenvio faz a transferência avançar, então o reason dela é limpo. A entrada da linha do tempo de uma transição causada por uma entrega com falha traz o mesmo valor em reason. Se o provedor de e-mail recusar o e-mail de conformidade da transferência de exemplo acima, o bloco travel_rule da transação fica assim, de forma resumida:
Aqui delivery coincide com reason, porque o próprio envio foi recusado. Uma recusa em um lembrete, ou um bounce informado depois, mantém delivery.status em DELIVERED: o primeiro e-mail de fato foi enviado. Leia reason, não delivery, para saber por que uma transferência está travada. Para corrigir, informe novamente o e-mail de conformidade da contraparte e depois reenvie:
update_compliance_email mantém o endereço como beneficiary_data.counterparty_vasp_email desta transferência: ele pertence somente a esta transferência e não entra em nenhuma entrada do diretório nem em nenhuma lista de contatos. O status não muda, a linha do tempo ganha compliance email updated e a transferência mantém reason: email_undeliverable até que o reenvio envie a requisição para o novo endereço. Somente uma transferência de saída em COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE ou NOT_ENOUGH_COUNTERPARTY_DATA aceita essa ação; qualquer outra transferência responde 409, e um compliance_email ausente ou malformado responde 400.

Carteiras autocustodiadas declaradas

Quando seu cliente informar que o destino é a própria carteira autocustodiada (não hospedada), declare isso na transação em vez de deixar o roteamento descobrir que não há nenhum VASP por trás dela: defina o tipo de método de pagamento da contraparte como unhosted_wallet.
A declaração ignora o roteamento por completo:
  • Nenhum rail é tentado (não há VASP de contraparte com quem trocar dados) e a transferência é criada diretamente em UNCONFIRMED_OWNERSHIP.
  • Quando auto_wallet_verification está ativado (o padrão), a Didit gera automaticamente uma sessão do widget de propriedade da carteira vinculada à transação e a retorna no bloco action_required da transação; os SDKs a abrem automaticamente no envio pelo lado do cliente.
  • Assim que o cliente comprova o controle da carteira, a transferência executa a correspondência do nome do beneficiário e avança para COMPLETED (ou COUNTERPARTY_MISMATCHED_DATA se a correspondência falhar).
Esta é a obrigação do EU TFR para carteiras autocustodiadas em forma de API: verificar a propriedade da carteira não hospedada em vez de trocar dados com um VASP de contraparte. A declaração é lida do método de pagamento no lado de destino de uma transferência de saída e no lado de origem de uma transferência de entrada; em ambos os casos, o participante contraparte. Uma transferência declarada como não hospedada já está em seu caminho final sem rail, então UNCONFIRMED_OWNERSHIP não é um estado que permite reenvio: conclua a comprovação de propriedade (ou cancele) em vez de chamar action: "resend".

Recebimento

Confirmação de propriedade da carteira

Uma transferência fica em UNCONFIRMED_OWNERSHIP em dois casos:
  • Uma transferência de entrada corresponde a uma entrada do catálogo de endereços cuja propriedade ainda não foi verificada.
  • A carteira da contraparte foi declarada autocustodiada (counterparty.payment_method.method_type: "unhosted_wallet"), em um saque de saída ou em um depósito de entrada. Consulte Carteiras autocustodiadas declaradas.
Sua aplicação confirma ou recusa a transferência:
O corpo aceita confirmed (obrigatório, booleano) e um wallet_address opcional. O endpoint aceita uma transferência em qualquer um destes estados e retorna 409 com {"detail": "Transfer is not awaiting ownership confirmation."} para qualquer outro:
  • UNCONFIRMED_OWNERSHIP, em qualquer direção.
  • ON_HOLD em uma transferência de entrada.
  • UNCONFIRMED_OWNERSHIP, ON_HOLD ou COUNTERPARTY_MISMATCHED_DATA em uma transferência TRP de entrada, para que um responsável por conformidade possa resolver manualmente uma consulta da contraparte.
Em uma transferência que a própria Didit criou (trilho INTERNAL, registro sunrise ou carteira autocustodiada declarada):
  • confirmed: true marca a entrada correspondente do catálogo de endereços de carteiras como verificada quanto à propriedade e, em seguida, executa a correspondência de nome com o holder_name dessa entrada: COMPLETED se ela for aprovada, COUNTERPARTY_MISMATCHED_DATA se não for. A contraparte no trilho INTERNAL, quando existe, recebe o mesmo resultado. Para uma carteira autocustodiada declarada, confirmed: true registra que seu cliente verificou quem controla a carteira da contraparte e conclui a transferência (COMPLETED), seja de saída ou de entrada. Uma transferência de entrada cujo depósito já foi liquidado passa então diretamente para FINISHED.
  • confirmed: false move os dois lados da transferência para COUNTERPARTY_VASP_GENERAL_DECLINE.
  • A entrada correspondente é buscada no seu próprio catálogo de endereços apenas pelo endereço da carteira, sem considerar a blockchain. Resolver uma transferência de entrada em ON_HOLD sem entrada correspondente cria a entrada a partir do beneficiary_data.wallet_address da transferência e a marca como verificada. Uma carteira autocustodiada declarada é a exceção: a carteira é registrada no seu catálogo de endereços como verificada quanto à propriedade, conforme descrito abaixo. Em todos os outros casos, uma entrada inexistente retorna 409 com {"detail": "wallet address entry no longer available"}, que também é o que uma entrada excluída retorna.
Em uma transferência TRP de entrada, a mesma chamada responde à consulta da contraparte:
  • confirmed: true exige um endereço de pagamento a ser retornado, obtido do wallet_address da requisição, depois da entrada correspondente e depois de beneficiary_data.wallet_address. Sem nenhum dos três, a requisição retorna 400 com {"wallet_address": ["wallet_address is required to approve."]}. A Didit cria ou verifica a entrada, envia o callback de resolução da consulta à contraparte, define ownership_confirmed e move a transferência para COMPLETED.
  • confirmed: false envia uma resolução de recusa e move a transferência para COUNTERPARTY_VASP_GENERAL_DECLINE.
  • Se o endpoint de callback da contraparte não puder ser alcançado, a requisição retorna 502 e a transferência mantém seu status atual. Em uma aprovação, a entrada do catálogo de endereços de carteiras ainda é criada ou marcada como verificada.
Para uma carteira autocustodiada declarada, a carteira que você verifica é a da contraparte: o destino de um saque de saída ou a origem (a carteira do remetente) de um depósito de entrada. A Didit a adiciona ao catálogo de endereços de carteiras como verificada quanto à propriedade, sob o nome da contraparte, de modo que a carteira é comparada com o nome da contraparte (o remetente, no caso de um depósito). Se o catálogo de endereços já contiver essa carteira sob um nome de titular diferente, a transferência passa para COUNTERPARTY_MISMATCHED_DATA. Se a transferência não indicar nenhuma carteira da contraparte, informe wallet_address no corpo da requisição. Quando nem a transferência nem a requisição fornecem um endereço de carteira, a requisição é rejeitada com 400.
  • Uma transferência de rede já respondida pela própria rede (uma transferência VerifyVASP, ou uma transferência GTR ou Sygna Bridge já decidida) retorna 409 (consulte Transferências de uma rede).
A resposta é o objeto de transferência mais completo descrito acima. Uma nova transferência INTERNAL nunca fica aguardando aqui: ela só chega a um cliente que já comprovou a carteira. Uma transferência INTERNAL mais antiga, ainda aguardando desde antes dessa regra, mantém os dados do remetente ocultos até que você comprove o controle da carteira (uma mensagem assinada ou um depósito de teste), e confirmá-la retorna 409 até que você o faça. Recusá-la continua funcionando. Quando a contraparte responde que a carteira é autocustodiada (hoje, o Didit Test VASP dá essa resposta no sandbox), confirmar adiciona a carteira ao seu catálogo de endereços sob o nome do beneficiário e executa a correspondência de nome: uma correspondência conclui a transferência e marca a carteira como verificada.

Transferências de uma rede

A Didit também pode receber transferências Travel Rule que uma contraparte envia por GTR, VERIFYVASP ou SYGNA. O recebimento é ativado pela Didit para cada rede separadamente, e nenhuma está ativada hoje: ele também exige que cada rede registre os endpoints da Didit, e a Didit ainda não é membro dessas redes. Transferências TRUST não podem ser recebidas. Depois que uma rede é ativada, uma mensagem entregue por ela é tratada assim:
  • Roteamento. A mensagem chega à sua aplicação quando indica o código de participante da sua própria associação conectada a essa rede. Uma mensagem endereçada à associação da própria Didit só chega até você quando você é o único cliente da Didit em produção que comprovou o controle da carteira do beneficiário. Qualquer outra é recusada, para que nenhum cliente jamais receba a transferência de outro cliente.
  • Decisão. A Didit cria a transferência de entrada na sua aplicação e a decide como uma consulta TRP: correspondência de carteira, propriedade, correspondência de nome e inbound_auto_accept.
  • Uma única vez. As redes reenviam uma mensagem até que ela seja respondida. Uma repetição recebe a mesma resposta que a primeira cópia recebeu, e nada é criado ou decidido duas vezes.
  • Sua revisão, por GTR e SYGNA. Uma transferência que aguarda por você (UNCONFIRMED_OWNERSHIP, ON_HOLD ou COUNTERPARTY_MISMATCHED_DATA) é decidida com POST .../travel-rule/ownership/: confirmed: true a aprova (informe wallet_address quando a transferência não indicar nenhum) e confirmed: false a recusa. A Didit responde à rede depois da resposta, com as mesmas novas tentativas. Uma transferência que já foi respondida retorna 409.
  • Sem resposta posterior por VERIFYVASP. A VerifyVASP recebe a resposta no momento em que pergunta, então uma transferência que precisaria da sua revisão é recusada imediatamente e não pode ser decidida depois (409).

Dados mascarados da contraparte

Até que a propriedade da carteira seja confirmada, os dados pessoais da contraparte em uma transferência recebida vêm mascarados, em vez de omitidos. A primeira letra de cada palavra é mantida, e a carteira, a chain e o roteamento do VASP continuam legíveis. data_masked é true, e a parte contraparte no detalhe da transação, na lista e na exportação CSV é mascarada da mesma forma. Assim que a propriedade é confirmada, os valores reais aparecem e data_unmasked registra a entrada de auditoria:
reason é ownership_confirmed, wallet_proof, address_book_match, own_verified_wallet, inquiry_approved (você aprovou uma consulta TRP ou uma mensagem GTR ou Sygna), known_payment_method (a carteira do usuário final nos seus próprios registros respondeu) ou travel_address (o travel address por carteira identificou a carteira). Uma transferência recebida INTERNAL traz data_unmasked com reason: wallet_proof desde o momento em que é criada, porque só um destinatário que comprovou a carteira recebe uma. actor é o e-mail do usuário do console ou o rótulo da chave de API, e fica em branco para uma decisão automática. O relatório Registro de transferências da Travel Rule (CSV e PDF) mascara os nomes de uma transferência recebida da mesma forma até que a propriedade seja confirmada. Os relatórios que você envia a um regulador, como o XML do goAML e o PDF do relatório regulatório, trazem os dados reais da contraparte.

Retorno sobre divergências

Uma transferência COUNTERPARTY_MISMATCHED_DATA agora indica os campos que divergem. data_match contém a comparação e mismatched_fields lista os campos. Ambos trazem apenas nomes de campos e resultados, nunca valores, por isso continuam legíveis enquanto os dados estão mascarados:
A entrada da linha do tempo indica os campos, por exemplo “beneficiary date of birth does not match wallet holder”. Uma rejeição TRP após uma divergência informa ao VASP remetente quais campos divergem, por exemplo “Beneficiary data does not match the wallet holder: name”. O que o outro VASP fica sabendo é limitado de propósito: enquanto o nome estiver errado, o nome é o único campo informado (mismatched_fields: ["name"], todos os outros campos not_compared), e, assim que o nome corresponde, todo campo que diverge é indicado. Isso se aplica ao lado do remetente de uma troca INTERNAL e a uma rejeição TRP. Um nome ausente nos dois lados aparece como not_compared e não é uma divergência, e um país corresponde pelo que ele designa, então ES e ESP coincidem.

Pontuação de correspondência de nomes

Toda transferência cujo nome foi comparado traz name_match, e a entrada da linha do tempo que decidiu isso traz o mesmo objeto ao lado do seu detail:
  • score é a similaridade entre os dois nomes completos, de 0 a 100, e 0 quando algum deles está em branco. matched é o resultado no nível de strictness, então os dois podem discordar: FUZZY decide pela própria razão de similaridade de 0.85.
  • matched_names são as palavras do nome da transferência encontradas no outro nome; mismatched_names são as palavras que um dos lados tem e o outro não.
  • method é none, exact_token, token_subset, token_containment ou sequence_ratio, para NONE, STRICT, DEFAULT, CONTAINS e FUZZY.
  • compared_with é wallet_holder (o titular registrado para a carteira) ou counterparty_vasp (o nome que a contraparte respondeu na página de resposta por e-mail, ou a resposta do Didit Test VASP).
  • O resultado da transferência segue data_match, que compara todos os campos, então uma transferência pode ser COUNTERPARTY_MISMATCHED_DATA enquanto name_match.matched é true.
  • name_match está no objeto de transferência que os endpoints da Travel Rule retornam e no travel_rule incorporado da transação, e é null até que um nome seja comparado. A lista de transferências e os webhooks não o incluem.
  • Os nomes ficam ocultos enquanto as partes estão mascaradas e na cópia do outro cliente de uma troca INTERNAL.

Mensagens e solicitações de documentos

Dois VASPs podem resolver uma transferência contestada dentro da Didit, em vez de por e-mail. GET e POST /v3/transactions/{transaction_id}/travel-rule/messages/ listam e enviam mensagens em uma transferência:
  • kind é MESSAGE (padrão) ou DOCUMENT_REQUEST. Uma solicitação de documento precisa de pelo menos uma entrada em requested_documents (até 10); uma mensagem precisa de um body (até 5000 caracteres) ou de um arquivo.
  • reply_to indica uma mensagem anterior da mesma transferência. Uma resposta do outro lado que traz um documento atende à solicitação de documento que ela responde, e fulfilled_at é preenchido nela. Sua própria resposta nunca atende à sua própria solicitação.
  • Envie multipart com files para anexar até 5 arquivos de 10 MB cada, em PDF, PNG, JPEG ou WebP. A Didit verifica o conteúdo de cada arquivo, não apenas o tipo declarado, e qualquer outro arquivo retorna 400 em files (“Attach PDF, PNG, JPEG or WebP files only.”).
  • Uma transferência comporta até 100 mensagens, das quais até 20 podem ter anexos (cada uma com até 5 arquivos), contando os dois lados; além de qualquer um desses limites, a requisição retorna 400. Os anexos de mensagens não contam para os documentos da própria transação.
  • As mensagens funcionam nos rails INTERNAL e EMAIL. No INTERNAL, o outro cliente da Didit vê a mensagem no seu lado do par. No EMAIL, a contraparte recebe um e-mail e responde no portal de retirada. Se esse e-mail de notificação não puder ser enviado, a mensagem é salva mesmo assim e a requisição retorna 201.
  • A requisição retorna 409 com um motivo em detail para uma transferência por TRP, GTR, TRUST, VerifyVASP ou Sygna (esses protocolos não transportam mensagens), uma transferência ainda sem contraparte, uma transferência INTERNAL cujos dados não corresponderam ao titular da carteira (nada chegou ao destinatário), uma transferência INTERNAL cujo destinatário ainda não comprovou o controle da carteira (nos dois lados, até que comprove), uma transferência EMAIL cuja contraparte não tem mais um endereço de e-mail de conformidade e uma transferência EMAIL cujo link de retirada expirou ou cuja transferência está encerrada.
  • Nenhum webhook é disparado quando a contraparte responde. Consulte o endpoint de mensagens.
  • O e-mail que avisa a contraparte sobre uma nova mensagem é enviado em inglês.

Catálogo de endereços de carteiras

Registre as carteiras que você controla para que as transferências recebidas (rail INTERNAL, consultas TRP recebidas e registros após o depósito) possam ser resolvidas com base nelas, usando POST/GET /v3/travel-rule/wallet-addresses/ e PATCH/DELETE /v3/travel-rule/wallet-addresses/{entry_uuid}/.
PATCH aceita holder_name, holder_vendor_data, entity_type e travel_address, e retorna apenas esses quatro campos. DELETE exclui a entrada (204): o endereço fica liberado para novo registro e ela deixa imediatamente de corresponder a novas transferências.
A correspondência não diferencia maiúsculas de minúsculas no endereço, inclui o memo em uma rede com memo e é delimitada por chain. Quando uma transferência informa uma blockchain, uma entrada só corresponde se o chain dela tiver o mesmo valor (sem diferenciar maiúsculas de minúsculas) ou estiver vazio. Os nomes de blockchain são comparados como texto, sem conversão, portanto uma entrada armazenada como ethereum não corresponde a uma transferência cuja blockchain é ETH. As transferências enviadas obtêm a blockchain de beneficiary_data.chain, depois de transaction_details.crypto_params.crypto_chain, depois de custom_properties.crypto_chain e depois da moeda (por exemplo, ETH, ou, para USDT e USDC, a blockchain inferida a partir de payment_reference_id), definida apenas quando é uma blockchain que a Didit reconhece; os registros após depósito a obtêm do campo chain, em minúsculas. As consultas TRP recebidas ignoram a blockchain: elas correspondem pelo endereço ou, quando a consulta não nomeia nenhuma carteira, pelo nome do beneficiário em relação às suas entradas verificadas. POST .../travel-rule/ownership/ também corresponde apenas pelo endereço. Quando várias entradas correspondem, o trilho INTERNAL e os registros após depósito preferem uma entrada com propriedade verificada e, em seguida, a mais antiga; a busca TRP de saída usa a entrada mais antiga que armazena um travel address. As consultas TRP recebidas e o endpoint de propriedade usam qualquer uma das entradas correspondentes, portanto mantenha uma entrada por endereço sempre que possível. O trilho INTERNAL não corresponde a nenhuma entrada quando existem entradas verificadas para o endereço em mais de uma outra aplicação.

Importação de carteiras em massa

Importe até 10.000 carteiras em uma única chamada com POST /v3/travel-rule/wallet-addresses/import/, em JSON ({"entries": [...]} ou um array simples) ou como um arquivo CSV UTF-8 de no máximo 5 MB com uma linha de cabeçalho. Uma linha identifica uma carteira pelo address, pelo address_hash (o SHA-256 do endereço em minúsculas, com 64 caracteres hexadecimais ou 44 em base64) ou por ambos, além de qualquer um dos campos de entrada acima. Envie apenas o hash para registrar uma carteira sem revelar o endereço: ela corresponde a transferências para esse endereço como qualquer outra entrada e pode ser comprovada com o widget de propriedade de carteira.
A importação é idempotente e informa cada linha na ordem de envio: created, existing (a mesma carteira, blockchain e memo já está no cadastro e não foi alterada), duplicate (repete uma linha anterior, indicada em duplicate_of_row) ou failed com seus errors. Uma linha com erro nunca faz as outras falharem: a resposta é 200 quando nenhuma linha falhou e 207 quando alguma falhou, com as contagens em total, created, existing, duplicate e failed. Uma célula vazia no CSV conta como não enviada, e as colunas que a importação não lê são ignoradas, então uma exportação de outra ferramenta é importada como está. Em GET /v3/travel-rule/transfers/, cada linha traz originator_memo e beneficiary_memo ao lado das duas carteiras.

Coleta por e-mail para contrapartes inacessíveis

Quando nenhum trilho de protocolo consegue alcançar a contraparte, a Didit recorre ao EMAIL: ela envia um link de coleta de uso único para beneficiary_data.counterparty_vasp_email (ou para um e-mail obtido a partir de beneficiary_data.counterparty_vasp_name no registro do diretório de VASPs). O destinatário não precisa de uma conta Didit nem de uma chave de API: o token do link é a autenticação. Como a requisição é enviada:
  • Para os endereços certos. Um counterparty_vasp_email que você informa é o único destinatário. Caso contrário, a Didit escreve para até três endereços: os contatos da contraparte que não tiveram devolução (os seus primeiro, depois os contatos da plataforma, com os que já responderam antes em primeiro lugar) e, em seguida, o e-mail de conformidade da entrada do diretório, quando sobra uma vaga. Cada endereço recebe o próprio e-mail.
  • Em seu nome. O e-mail sai do endereço da Didit como “sua razão social via Didit”, no idioma da jurisdição da contraparte (inglês quando nenhuma é conhecida), e o link abre a página de resposta nesse idioma. Você não recebe cópia: acompanhe a linha do tempo da transferência.
  • Com lembretes. Até a contraparte responder, a Didit envia lembretes 72, 24 e 6 horas antes do prazo, com no mínimo 12 horas após a requisição ou o último lembrete, e nunca depois do prazo.
  • Com tratamento de devoluções. Uma devolução ou uma denúncia de spam marca o contato atingido como inválido, com o motivo, e a linha do tempo da transferência registra isso. Um contato da plataforma passa então a ser inválido para todos os clientes da Didit; o contato próprio da sua aplicação, apenas para a sua aplicação. Quando a entrega de e-mails da Didit para totalmente de enviar para um endereço (após uma devolução permanente, uma denúncia de spam ou um cancelamento de inscrição), todos os contatos nesse endereço são marcados como inválidos (suppressed) e voltam a ser válidos assim que o envio para o endereço é retomado. Quando não resta nenhum endereço para escrever, a transferência passa a COUNTERPARTY_VASP_NOT_REACHABLE, com o motivo do servidor de e-mail de destino na linha do tempo. Uma devolução permanente ou uma denúncia de spam no counterparty_vasp_email que você informou faz isso imediatamente, porque ele é o único destinatário; uma devolução temporária (soft_bounce) nele, ou no próprio e-mail de conformidade da entrada do diretório, mantém a requisição aberta para os lembretes.
O link abre uma página hospedada que mostra a troca pendente e chama estes dois endpoints públicos para o destinatário. Para a transferência de exemplo acima, os dados de coleta são:
reference é o uuid da transferência. originator_data e o ivms_request IVMS 101 gerado a partir dele contêm apenas os campos do remetente que você compartilha em data_sharing_fields; o nome e a carteira são sempre incluídos. fiat_amount e fiat_currency ficam vazios quando você não enviou nenhum valor convertido, contact repete o valor ?contact= do link e decline_reasons lista os valores aceitos por decline_reason. join_invitation.eligible é true enquanto a contraparte tiver um convite ativo para entrar na Didit; o link do convite em si só é enviado no e-mail. Este endpoint retorna o valor armazenado sem alterações, por isso traz as 18 casas decimais completas, e não a forma reduzida usada pelo objeto de detalhes da transação.
decision é accept ou decline. Em accept, o beneficiary_name informado é comparado com o beneficiary_data.name da transferência segundo a sua regra de nomes: COMPLETED quando há correspondência, COUNTERPARTY_MISMATCHED_DATA caso contrário. Em vez disso, a contraparte pode enviar uma resposta IVMS 101 completa como ivms_response; nesse caso, o nome do beneficiário dessa resposta prevalece sobre beneficiary_name. Em decline, a transferência passa para COUNTERPARTY_VASP_GENERAL_DECLINE. A contraparte pode informar um decline_reason de decline_reasons, com um decline_detail (até 512 caracteres, obrigatório para other), e a linha do tempo da sua transferência registra isso, por exemplo counterparty declined: The beneficiary is not our customer. A resposta é o {"status": "..."} resultante, mais decline_reason após uma recusa. Depois que a contraparte responde, os dois endpoints retornam 410. Os dois endpoints retornam 404 para um token desconhecido e 410 quando a janela se encerra: ou a transferência saiu de AWAITING_COUNTERPARTY, ou o prazo de confirmação dela (confirmation_timeout_hours após a criação ou o último reenvio) já passou. A contraparte lê e responde pelo link de coleta com GET e POST /v3/travel-rule/pickup/{token}/messages/. Ela não precisa de chave de API, aceita apenas anexos em PDF, PNG, JPEG ou WebP e responde 410 quando o link expira ou a transferência é encerrada. Uma mensagem que você enviou mostra o nome do seu VASP como author e como uploaded_by do anexo, nunca a pessoa ou a chave de API por trás dela.

Depósitos sem correspondência

Um depósito de entrada pode chegar antes dos dados de Travel Rule do VASP de origem. Esse depósito permanece em AWAITING_COUNTERPARTY ou NOT_ENOUGH_COUNTERPARTY_DATA até os dados chegarem. Liste os depósitos que ainda estão aguardando com uma chave de API que tenha o privilégio de transações:
A resposta usa as mesmas linhas de GET /v3/travel-rule/transfers/, limitadas aos depósitos de entrada que aguardam os dados do VASP de origem. Quando os dados tiverem chegado como uma mensagem recebida separada, faça você mesmo o pareamento entre os dois:
{transaction_uuid} é o depósito. transaction_id é a transação da mensagem de Travel Rule recebida. A chamada retorna { "deposit": ..., "message": ... }. Ela responde 404 quando alguma das transações não existe mais e 409 com travel_rule_match_conflict (“This deposit can no longer be matched.”) quando algum dos lados já avançou.

Registro sunrise após o depósito

Quando um depósito de cripto é liquidado on-chain antes de qualquer troca de Travel Rule ter ocorrido (o VASP remetente estava inacessível, ou você está preenchendo retroativamente depósitos históricos), registre-o posteriormente com POST /v3/travel-rule/inbound/.
originating_vasp.travel_address deve ser um travel address real e com checksum válido: um valor fictício retorna 400 com "Invalid travel address.". originating_vasp.lei deve estar vazio ou ter 20 caracteres no formato LEI (18 letras ou dígitos, seguidos de 2 dígitos); qualquer outro valor retorna 400 com "Invalid LEI: expected 20 alphanumeric characters (ISO 17442).". A Didit verifica apenas esse formato, não os dígitos de verificação da ISO 17442. Didit cria uma transação travelRule de entrada (ou reutiliza um depósito de entrada que você já enviou com o mesmo hash e a mesma carteira, se ele ainda não tiver uma transferência Travel Rule) e confere a transferência com o seu catálogo de endereços de carteiras, pelo endereço e pelo seu memo:
  • Nenhuma entrada correspondente -> ON_HOLD. Resolva com POST .../travel-rule/ownership/: confirmed: true adiciona a carteira ao seu catálogo de endereços como verificada e executa a correspondência de nomes; se houver correspondência, a transferência passa para COMPLETED e depois para FINISHED.
  • A entrada existe, mas a propriedade não foi comprovada -> UNCONFIRMED_OWNERSHIP.
  • O nome do beneficiário não corresponde ao holder_name da entrada -> COUNTERPARTY_MISMATCHED_DATA.
  • Entrada verificada e o nome corresponde -> COMPLETED e, logo em seguida, FINISHED (o depósito já foi liquidado).
Com a entrada verificada do catálogo de endereços registrada no exemplo acima, a resposta é:
O txn_id da nova transação é tr-in-, seguido dos primeiros 80 caracteres do txid e de um hash de 12 caracteres do txid e da carteira. created é true (HTTP 201) quando esta chamada registrou o depósito, e false (HTTP 200) quando o mesmo txid e o mesmo wallet_address já estavam registrados; nesse caso, a transferência existente é retornada sem alterações. No caminho da entrada verificada, as duas transições acontecem antes de o endpoint responder, então a resposta síncrona já mostra o status final FINISHED. A etapa intermediária COMPLETED continua registrada no timeline da transferência. Cada transição dispara um webhook travel_rule.status.updated (COMPLETED e FINISHED disparam um cada). Quando Didit cria uma nova transação, envia primeiro transaction.created e, depois dele, esses eventos. O registro não gera tarifa de Travel Rule nem de monitoramento. Quando o monitoramento de cripto está ativado e a chain é uma que Didit consegue analisar, um depósito recém-criado também passa por triagem e é cobrado uma única vez pela tarifa de Wallet Verification & Screening.

Widget de propriedade da carteira

Para tirar uma transferência de UNCONFIRMED_OWNERSHIP, ou para pré-verificar uma carteira antes da chegada de qualquer transferência, gere um widget hospedado de propriedade da carteira com POST /v3/travel-rule/widget-session/ e envie o seu cliente para a url retornada. O widget comprova o controle da carteira por assinatura de mensagem (incluindo contas de smart contract EVM, por meio de ERC-1271 e ERC-6492), teste de Satoshi, captura de tela ou autodeclaração e, em seguida, marca como verificada a entrada correspondente do catálogo de endereços para que a troca possa continuar. A captura de tela é a exceção: ela nunca verifica a carteira sozinha. Por isso, a sua equipe de conformidade a analisa e confirma uma transferência em UNCONFIRMED_OWNERSHIP com POST .../travel-rule/ownership/. Consulte Widget de propriedade da carteira para ver o fluxo completo, os métodos de comprovação e o aviso importante de que o widget deve ser aberto em um navegador real, nunca dentro de uma webview de SDK móvel.

Diretório

GET /v3/travel-rule/vasps/ pesquisa o diretório de VASPs: as entradas do diretório compartilhado e os membros da rede Didit. Cada linha informa como sua aplicação pode alcançar esse VASP hoje.
search corresponde a um trecho de nome ou alias, a um LEI exato ou a um domínio (counterparty.example ou uma URL nele). Restrinja os resultados com: Os membros da rede Didit não recebem pontuação, portanto risk e responsiveness retornam apenas entradas do diretório. Os resultados são ordenados por nome e paginados com limit (padrão 50) e offset. Uma rede, um código de país, uma faixa de risco ou um status de responsividade desconhecido retorna 400 indicando o campo. GET /v3/travel-rule/vasps/{vasp_id}/ retorna uma linha pelo seu id. Seu próprio perfil de VASP nunca aparece nos seus próprios resultados. dd_status, dd_score, dd_score_breakdown, dd_assessed_at, dd_score_semantic, risk_level, responsiveness e essential_checks trazem a avaliação de due diligence compartilhada de uma entrada do diretório. decision, entity_screening e questionnaires são os registros próprios da sua aplicação sobre o VASP, e nenhum outro cliente os vê. Consulte Due diligence de contrapartes para saber o que cada um significa, e condicione o fluxo a eles com os campos de regra de contraparte em vez de criar ramificações no código com base neles. Os membros da rede Didit não recebem pontuação: dd_status é COMPLETED, dd_score é null, risk_level fica vazio e o detalhamento fica vazio.

Rotas

routes lista as formas de entrega ao VASP disponíveis para sua aplicação, na ordem em que a sequência de roteamento as tenta, e reachable é true quando pelo menos uma está available:
  • TRP quando a entrada traz um endpoint TRP verificado pelo diretório.
  • GTR, TRUST, VERIFYVASP, SYGNA quando uma rede lista o VASP sob um código. A rota fica available somente quando sua aplicação pode enviar por essa rede hoje (via: own_membership para a sua própria associação conectada, via: didit_membership para a da Didit). Caso contrário, fica unavailable com reason: no_membership ou reason: network_switched_off, e nunca é exibida como uma forma de alcançar o VASP. As associações da própria Didit às redes ainda não estão ativas, portanto hoje uma rota de rede só fica disponível por meio de uma associação que você conectou no Marketplace.
  • EMAIL quando existe um contato de conformidade para a entrada.
  • INTERNAL para um membro da rede Didit.
Uma listagem TRISA aparece em networks e informa a identidade do VASP na TRISA, mas a Didit não tem um canal TRISA, portanto ela nunca é uma rota. Uma aplicação de sandbox envia apenas para o Didit Test VASP, portanto nenhuma rota do diretório fica disponível para ela: todas as rotas ficam unavailable com reason: sandbox_application, todas as linhas têm reachable: false e reachable=true não retorna nenhuma linha.

Marcas e suas entidades

Uma marca que opera por meio de várias entidades reguladas é uma única linha cujas entities são as entidades jurídicas que recebem suas transferências; uma linha de entidade aponta de volta para sua marca em umbrella. Uma transferência que indica a marca vai para uma de suas entidades, escolhida entre todas elas: a que está na jurisdição informada em beneficiary_data.counterparty_vasp_jurisdiction; senão, a entidade que a atribuição por análise de blockchain vinculou à carteira de destino; senão, a única entidade da marca quando nenhuma jurisdição é informada. Só então essa entidade precisa estar acessível; se não estiver, a transferência nunca é enviada a outra entidade nem à marca em seu lugar. Quando nenhuma entidade se encaixa (duas se encaixam igualmente, ou foi informada uma jurisdição em que nenhuma delas está), é usada a rota da própria marca e, sem ela, a transferência fica COUNTERPARTY_VASP_NOT_FOUND. Qual entidade jurídica recebe os dados do remetente nunca é um palpite, e nunca é decidida pela entidade que por acaso tenha um contato. Várias entradas com o mesmo nome, como empresas de um grupo que compartilham um nome comercial, são diferenciadas pela mesma regra: a que está na jurisdição informada; senão, a que a atribuição por análise de blockchain vinculou. Quando nenhum dos dois critérios escolhe uma, nenhuma é usada, e os dados são tratados como se não indicassem nenhuma entrada do diretório.

Contatos

contacts são os endereços de e-mail para os quais o canal EMAIL envia mensagens. Os contatos scope: platform atendem a todos os clientes da Didit: a Didit os seleciona (source: staff), ou um endereço em um dos domínios do próprio VASP respondeu a uma requisição pelo seu link de resposta (source: learned). Os contatos scope: application são privados da sua aplicação: os que você adiciona (source: application) e um endereço fora dos domínios do próprio VASP que respondeu a uma de suas requisições (source: learned). Uma transferência envia e-mail primeiro ao contato da sua própria aplicação, depois a um contato da plataforma que já respondeu antes (verified_at preenchido) e, em seguida, aos demais. Gerencie os contatos da sua própria aplicação com a API de contatos de contrapartes:
  • GET /v3/travel-rule/counterparty-contacts/ lista todos os contatos para os quais sua aplicação pode enviar, incluindo contatos da plataforma e os que retornaram com falha de entrega, do mais recente para o mais antigo, paginados com limit e offset. Filtre com ?counterparty= e o id de uma entrada do diretório; um valor que não seja um UUID retorna 400.
  • POST adiciona um contato privado (counterparty, email, name opcional) e retorna 201. Adicionar um endereço que a entrada já tem entre os seus próprios contatos retorna esse contato. Uma entrada desconhecida retorna 400 ("No directory entry with this id.").
  • DELETE /v3/travel-rule/counterparty-contacts/{contact_uuid}/ exclui um dos seus próprios contatos (204). Os contatos da plataforma não podem ser excluídos e retornam 404.
Um contato cujo e-mail retornou com falha de entrega ou que gerou reclamação tem is_invalid: true, com invalid_reason (hard_bounce, soft_bounce, spam_complaint ou suppressed), invalid_detail e invalid_at, e o canal EMAIL o ignora. created_by fica vazio nos contatos da plataforma e nos contatos adicionados por uma chave de API.

Como as entradas chegam ao diretório

  • O registro provisório MiCA da ESMA de prestadores de serviços de criptoativos, lido toda semana: o nome, o LEI e o estado-membro de origem de cada prestador.
  • O diretório público da TRISA, lido toda semana: quem é cada membro, seu país e sua listagem na TRISA. Uma listagem que o diretório deixa de exibir por três semanas é removida.
  • O registro global de LEI informa o LEI, outros nomes jurídicos e o país de uma entrada, e encontra o LEI de uma entrada pelo seu nome jurídico exato no seu país.
  • A atribuição por análise de blockchain adiciona ou associa o VASP dono de uma carteira de destino e mantém o nome atribuído como alias.
  • A equipe da Didit faz a curadoria das entradas: identificadores de roteamento e listagens de rede que verificou, contatos de conformidade, aliases, marcas e suas entidades, duplicatas mescladas e entradas ocultas.
Os dados que um cliente informa sobre uma contraparte, como um originating_vasp de entrada ou um Travel Address, ficam na transferência desse cliente e nunca alteram uma entrada compartilhada. As entradas são associadas primeiro pelo LEI, depois pelo nome exato ou alias, e são enriquecidas em vez de duplicadas.

A rede Didit

Seu perfil de VASP é membro da rede Didit, de modo que outros clientes da Didit o encontram no diretório e no seletor de VASP do usuário final, somente enquanto todas estas condições forem atendidas:
  • sua aplicação está em produção (não em sandbox) e a Travel Rule está ativada;
  • is_discoverable é true e legal_name está definido;
  • compliance_email está definido e confirmado: envie a solicitação de confirmação com POST /v3/travel-rule/settings/compliance-email/confirmation/ e abra o link recebido por e-mail. Alterar o endereço exige uma nova confirmação;
  • a Didit não marcou a aplicação como de teste, demonstração ou interna.
O próprio canal INTERNAL faz a entrega para uma carteira cuja titularidade você comprovou, conforme descrito em Envio de uma transferência: ele exige sua aplicação em produção, a Travel Rule ativada e is_discoverable, e não o restante da lista. GET /v3/travel-rule/settings/ retorna didit_network: listed, compliance_email_confirmed e, em missing, cada condição ainda não atendida (travel_rule_off, sandbox_application, not_discoverable, legal_name_missing, compliance_email_missing, compliance_email_unconfirmed, excluded_by_staff, internal_organization).

Identificadores de roteamento

O roteamento de saída consulta uma entrada do diretório sempre que sua transferência identifica a contraparte por counterparty_vasp_lei ou counterparty_vasp_name (um alias também funciona). Uma entrada contém um identificador para cada rede pela qual pode ser alcançada, um endpoint TRP verificado e seus contatos de conformidade, e routes mostra quais deles sua aplicação pode usar. Você sempre pode ignorar o diretório em uma única transferência informando os campos explícitos em Campos de resolução da contraparte.

Due diligence de contrapartes

Antes que os fundos dos seus clientes cheguem a outro VASP, você precisa saber quem é esse VASP e se você o aceita. A due diligence de uma contraparte tem duas camadas:
  • A avaliação compartilhada. Cada entrada do diretório traz uma pontuação de due diligence, seu nível de risco, um status de capacidade de resposta e um relatório de verificações essenciais. A Didit os calcula a partir dos próprios dados da plataforma, então todos os clientes veem os mesmos valores.
  • Seus próprios registros. Sua decisão sobre o VASP, sua triagem de sanções e mídia adversa dele e os questionários de due diligence que você trocou com ele pertencem apenas à sua aplicação. Nenhum outro cliente os vê, e eles nunca alteram a entrada compartilhada.
Seus próprios registros funcionam tanto para uma entrada do diretório quanto para um membro da rede Didit: referencie-os pelo id que o diretório mostra.

Pontuação e nível de risco

dd_score vai de 0 a 100 e quanto maior, mais seguro. Todo resultado indica isso em dd_score_semantic, que é sempre higher_is_safer. risk_level é a faixa em que a pontuação se encaixa: A pontuação é a soma de sete componentes. dd_score_breakdown mostra cada um como {points, max, reason, detail}: max é o peso do componente, reason é um código legível por máquina que você pode traduzir, e detail é uma explicação de uma linha em inglês. Os pontos são arredondados para uma casa decimal e o total para um número inteiro. history lê as mesmas requisições que a capacidade de resposta, sem janela de tempo: uma troca COMPLETED ou FINISHED é um sucesso, e uma troca EXPIRED, COUNTERPARTY_MISMATCHED_DATA ou COUNTERPARTY_VASP_GENERAL_DECLINE é uma falha. Um cancelamento é um ato do próprio remetente e nunca conta. A Didit recalcula a avaliação quando uma troca com a entrada é concluída, finalizada, expira, apresenta divergência ou é recusada, quando ela atualiza ou faz a curadoria da entrada, e para todas as entradas na atualização semanal do diretório. dd_assessed_at indica quando ela foi executada pela última vez; uma entrada ainda não avaliada não tem dd_assessed_at, tem dd_score igual a 0 e risk_level vazio, então leia risk_level em vez da pontuação bruta. Os membros da rede Didit não são pontuados: o dd_score deles é null, o risk_level é vazio e o dd_score_breakdown é vazio.

Verificações essenciais

essential_checks é um relatório curto sobre quatro verificações que a Didit executa em todas as entradas do diretório, apenas a partir das fontes verificadas da plataforma, nunca a partir de dados informados por um cliente: Cada verificação em checks informa seu status (pass, fail ou unknown quando nenhuma fonte registrada consegue decidi-la), um reason legível por máquina e um detail de uma linha em inglês. passed, failed, unknown e total fazem a contagem delas, level é essential, e checked_at indica quando o relatório foi gerado. O componente essentials pontua a proporção das verificações decididas que passam, então uma verificação unknown não conta nem a favor nem contra a entrada. O relatório fica vazio até que a atualização semanal do diretório verifique uma entrada pela primeira vez, e é sempre vazio para um membro da rede Didit.

Capacidade de resposta

responsiveness indica se o VASP responde às requisições de Travel Rule:
total conta as requisições que os clientes da Didit iniciaram em direção ao VASP nos últimos 90 dias cujo resultado está decidido, e answered conta as que ele respondeu:
  • Contadas: requisições enviadas por um canal de rede ou de protocolo, e requisições enviadas por e-mail para um endereço compartilhado, que é o endereço de conformidade da entrada ou um contato da plataforma.
  • Nunca contadas: uma requisição enviada por e-mail para um endereço digitado por um cliente ou para um contato privado de um cliente. Essa troca permanece no histórico de transferências do próprio cliente e nunca rotula o VASP para os demais.
  • Respondidas: COMPLETED, FINISHED, COUNTERPARTY_VASP_GENERAL_DECLINE ou COUNTERPARTY_MISMATCHED_DATA. Uma recusa ou uma divergência é uma resposta: o VASP interagiu.
  • Não respondidas: EXPIRED.
  • Nenhuma das duas: todos os outros status. Uma requisição CANCELLED é um ato do próprio remetente, COUNTERPARTY_VASP_NOT_REACHABLE pode ser uma falha do lado do remetente, e uma requisição ainda em andamento ainda não está decidida.
Os membros da rede Didit respondem dentro da Didit e sempre mostram UNKNOWN com contagens zeradas. Aja sobre uma contraparte que não responde com a política de não resposta ou com o preset travel-rule-counterparty-unresponsive.

Sua decisão sobre uma contraparte

Registre o parecer da sua equipe de conformidade sobre uma contraparte com PUT /v3/travel-rule/vasps/{vasp_id}/decision/:
  • A decisão é privada da sua aplicação: nenhum outro cliente a vê, e ela nunca altera a entrada compartilhada.
  • Uma decisão não altera nada por si só e nunca muda a forma como uma transferência é roteada. Ela chega às suas transações por meio do campo de regra counterparty_dd_status: instale os presets ou escreva sua própria regra sobre ele.
  • Uma decisão sobre uma marca abrange cada uma das suas entidades que não tenha decisão própria, e a entidade mostra a marca em inherited_from. Uma decisão sobre a entidade substitui a da marca para essa entidade.
  • GET retorna a decisão que se aplica, ou {"decision": null}. DELETE remove a sua própria decisão e retorna o que passa a se aplicar: a decisão da marca, no caso de uma entidade, ou então null. Ele responde 404 quando sua aplicação não tem decisão própria sobre a contraparte.
  • reason é opcional, tem até 255 caracteres, e cada PUT o substitui. decided_by é o usuário do console que tomou ou alterou por último a decisão, e fica vazio quando foi uma chave de API.

Triagem da contraparte

A triagem da contraparte verifica o próprio VASP da contraparte, como empresa, contra sanções e mídia adversa. Ela é opcional e cobrada: ative-a com counterparty_screening_enabled nas suas configurações. Enquanto estiver desativada, nada é verificado nem cobrado.
  • Faturamento. Cada nova triagem custa o preço de Análise AML de empresas da sua organização. GET /v3/travel-rule/vasps/{vasp_id}/screening/ retorna esse price, fresh_days e se a triagem está enabled, sem custo. Uma triagem com menos de 30 dias é recente: POST a retorna novamente com 200 e outcome: reused e não cobra nada, a menos que você envie refresh: true. Uma nova triagem responde 201 com outcome: screened. Aplicações de sandbox nunca são verificadas nem cobradas.
  • Triagem automática. Com a triagem ativada, a Didit também verifica a contraparte alcançada por uma troca de saída quando a troca começa, antes de suas regras avaliarem a transação, com a mesma reutilização e o mesmo faturamento. Uma recusa ou falha nesse ponto nunca faz a transferência falhar.
  • Resultado. status é Approved quando nenhuma possível correspondência exige atenção, e In Review ou Declined para uma possível correspondência em sanções ou mídia adversa. flagged é true enquanto uma triagem recente estiver In Review ou Declined.
  • Efeito. Enquanto sua triagem mais recente de uma contraparte estiver sinalizada e a triagem permanecer ativada, counterparty_risk_level é HIGH nas suas regras, de modo que o preset travel-rule-counterparty-high-risk, uma vez instalado, retém as transferências dela. O risk_level compartilhado no diretório não muda.
  • Privacidade. A triagem é privada da sua aplicação: nenhum outro cliente a vê, e ela nunca altera a entrada compartilhada. O diretório mostra a mais recente como entity_screening.
  • Recusas. 409 quando a triagem está desativada, para uma aplicação de sandbox ou enquanto uma triagem da mesma contraparte já estiver em andamento. 403 com code: insufficient_credits quando seu saldo não cobre o preço. 502 quando a triagem não pôde ser concluída. Nenhuma delas gera cobrança.

Questionário de due diligence

Solicite a uma contraparte suas respostas de due diligence com o questionário padrão da Didit. POST /v3/travel-rule/vasps/{vasp_id}/questionnaires/ o envia por e-mail para um endereço de conformidade registrado da contraparte, com um link de uso único para uma página de respostas:
  • Para onde vai. sent_to deve ser um endereço de conformidade registrado: para uma entrada do diretório, seu endereço de conformidade ou um contato que sua aplicação vê em contacts; para um membro da rede Didit, seu e-mail de conformidade confirmado. Omita-o para usar o endereço para o qual vai um e-mail de Travel Rule à contraparte: primeiro o seu próprio contato, depois um contato da plataforma e, por fim, o endereço de conformidade da entrada. A Didit nunca envia o questionário para nenhum outro lugar e responde 400 quando a contraparte não tem endereço de conformidade registrado.
  • Respostas. O link abre /v3/travel-rule/questionnaires/{token}/, uma página para uma pessoa da contraparte que não exige conta nem chave de API. Ela responde a todas as perguntas, com até 2.000 caracteres cada (N/A quando uma não se aplica), e envia uma única vez. Uma contraparte também pode enviar {"answers": {"<question id>": "<answer>"}} para o mesmo link. Um link que já foi usado, foi substituído ou passou do prazo mostra uma página de expiração. O e-mail e a página são traduzidos; as perguntas em si estão sempre em inglês, para que seu significado nunca mude entre idiomas.
  • Prazos. A contraparte tem 30 dias para responder (expires_at). As respostas permanecem válidas por 365 dias (valid_until), e current é true até lá. Um questionário sem resposta após o prazo, e respostas após sua validade, passam a EXPIRED.
  • Um questionário aberto por contraparte. Um novo envio substitui seu questionário anterior sem resposta para a mesma contraparte: ele passa a EXPIRED e seu link deixa de funcionar. Um e-mail por minuto pode ser enviado a um endereço; um envio mais rápido responde 429.
  • Leitura das respostas. GET /v3/travel-rule/vasps/{vasp_id}/questionnaires/ lista seus questionários com a contraparte, do mais recente para o mais antigo, com answers indexado pelo id da pergunta depois de respondido. O diretório os mostra como questionnaires. Eles são privados da sua aplicação.
A versão 1 do formulário faz estas doze perguntas:

Transferências com uma contraparte

GET /v3/travel-rule/transfers/?counterparty={vasp_id} lista as transferências da Travel Rule da sua aplicação com uma contraparte, das mais recentes para as mais antigas, pelo id exibido no diretório: as suas transferências cuja contraparte é essa entrada do diretório ou as suas trocas INTERNAL com esse membro da rede Didit. Um valor que não seja um ID válido retorna 400. Cada linha traz reason logo depois de status: o próprio reason da transferência, para que a lista diferencie um e-mail de conformidade devolvido de uma contraparte sem rota sem que seja preciso abrir cada transferência.

Políticas de sunrise e de não resposta

Quando uma transferência expira (confirmation_timeout_hours se esgotou enquanto ela estava em AWAITING_COUNTERPARTY), timeout_outcome decide o que acontece com a transação correspondente. Duas configurações permitem tratar de forma diferente dois motivos comuns de expiração: Ambas aceitam HOLD, REJECT ou PROCEED, com o mesmo significado que têm em timeout_outcome, ou uma string vazia para seguir timeout_outcome. Ambas ficam vazias por padrão, então nada muda até que você defina uma delas:
A primeira das opções a seguir que se aplicar decide o resultado:
  1. sunrise_policy, quando está definida e a jurisdição da contraparte está em sunrise_jurisdictions.
  2. non_responsive_policy, quando está definida e a contraparte está UNRESPONSIVE.
  3. timeout_outcome em todos os outros casos, inclusive em uma transferência para um membro da rede Didit ou para uma contraparte sem entrada no diretório.
sunrise_jurisdictions é somente leitura e atualmente vale ["CO", "KH", "VN"]. Apenas esses países são considerados em período de sunrise: qualquer outra jurisdição, assim como uma vazia ou desconhecida, segue timeout_outcome, de modo que uma contraparte nunca recebe a sua política de sunrise por acidente. A linha do tempo da transferência expirada informa o resultado aplicado, por exemplo sunrise_policy=PROCEED (counterparty jurisdiction CO does not enforce the Travel Rule yet). Suas regras continuam sendo executadas após a expiração, portanto uma regra como a tr_eu_expired_review do EU TFR ainda pode mover a transação para revisão com PROCEED.

Campos e presets de regras

Quatro campos de regra contêm o que a sua aplicação sabe sobre a contraparte alcançada pela troca da Travel Rule de uma transação: a entrada dela no diretório ou, em uma troca INTERNAL, o cliente Didit que a recebeu. Cada campo fica vazio quando a troca não alcançou nenhuma contraparte conhecida. Cinco presets do pacote travel_rule atuam sobre esses campos. Instale-os em Transactions → Rules → Library no Business Console ou com a API da biblioteca de regras: Os cinco se aplicam somente a transações da Travel Rule.

Webhooks

Inscreva um destino no evento travel_rule.status.updated para ser notificado a cada transição de status de cada transferência da sua aplicação, de saída e de entrada, incluindo os trechos pela rede INTERNAL. O roteamento é executado após a resposta à criação da transação, então resultados como COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE ou uma troca INTERNAL que é liquidada imediatamente chegam até você por esse evento, e não na resposta de criação.
rail fica vazio até que um trilho seja selecionado. Para uma mesma transação, a Didit envia travel_rule.status.updated depois de transaction.created: quando a Didit cria a transação (seu POST /v3/transactions/, um registro de sunrise, uma consulta TRP de entrada ou a perna de entrada do trilho INTERNAL), ela envia transaction.created primeiro. Cada evento é entregue e reenviado de forma independente, então um transaction.created que precisou ser reenviado ainda pode chegar depois de um evento de status: indexe seu handler por transaction_id e consulte a transação quando um evento de status mencionar uma que você ainda não viu. Uma transferência enviada por TRUST não recebe evento COMPLETED: o TRUST não devolve nada que a Didit consiga ler, então, a menos que o envio falhe ou você o cancele, seu último evento é EXPIRED. Em GTR, VERIFYVASP e SYGNA, o evento segue a resposta que a Didit lê da rede. Aplicações de sandbox também enviam esse evento, com "environment": "sandbox"; uma transferência respondida pelo Didit Test VASP inclui rail: "TEST_VASP", test_vasp: true e test_vasp_scenario. Consulte o guia de webhooks para ver o catálogo completo de eventos, a verificação de assinatura e a política de novas tentativas.

Preços

A tarifa da Travel Rule é de $0.02 por troca de saída iniciada, cobrada uma única vez quando a transação é criada, independentemente de quantas transições de status a troca tenha depois. Um resend nunca gera nova cobrança.
  • Ela se aplica a uma transação travelRule de saída em uma aplicação com a Travel Rule ativada, cujo valor seja igual ou superior ao seu threshold_amount, de modo que a Didit inicia uma troca gerenciada para ela. Uma transferência para uma carteira autocustodiada, ou para a própria carteira verificada do seu usuário, também conta: a prova de propriedade é a sua troca.
  • Toda outra transação de saída que carrega dados da Travel Rule é faturada como Triagem de transações padrão, que o seu plano inclui até a sua franquia mensal de transações e cobra a $0.001 além dela: uma transferência abaixo do seu limiar, um pagamento Lightning ao qual a Travel Rule não se aplica e uma transferência registrada passivamente enquanto a Travel Rule está desativada. Uma transação é faturada em uma das duas linhas, nunca nas duas.
  • Transações travelRule de entrada não têm tarifa de Travel Rule nem de monitoramento: a transação de entrada que a Didit cria na aplicação do beneficiário pelo trilho INTERNAL, as consultas TRP de entrada e os registros após o depósito.
  • Uma aplicação que aderiu à Travel Rule gratuitamente não paga nenhuma das duas tarifas em transações travelRule de saída até ativar o faturamento de saída com POST /v3/travel-rule/workspace/billing/; o recebimento continua gratuito.
  • Aplicações de sandbox nunca são cobradas.
  • A tarifa da Travel Rule é de $0.02 e a Triagem de transações custa $0.001 além da sua franquia. Cada transação é cobrada pelo preço da linha em que é faturada.
  • Se a triagem de AML cripto e de carteiras também for executada na mesma transação (por exemplo, um depósito de entrada com currency_kind: "crypto" e monitoramento ativado), ela é faturada separadamente pela tarifa padrão de Verificação e triagem de carteiras; não está incluída na tarifa da Travel Rule.
  • A triagem de contrapartes é opcional e faturada separadamente, pelo preço da Análise AML de empresas por triagem; uma triagem com menos de 30 dias é reutilizada sem custo. Decisões, questionários e a avaliação de due diligence do diretório não custam nada.

Preços da atribuição

A atribuição por análise de blockchain exige uma consulta de carteira junto ao provedor de análise, e você sempre recebe o valor completo dessa consulta:
  • O monitoramento cripto já fez a triagem da carteira nesta transação: o resultado armazenado é reutilizado. Uma chamada de análise, uma cobrança de Verificação e triagem de carteiras (a já efetuada pelo monitoramento cripto). A atribuição não acrescenta nada.
  • O monitoramento cripto não foi executado: a Didit faz a chamada de análise necessária uma única vez e repassa todo o seu valor: a transação é cobrada pela tarifa padrão de Verificação e triagem de carteiras ($0.15 com análise gerenciada pela Didit) e recebe em troca o resultado completo da triagem cripto (pontuação de risco, categoria de risco da carteira, snapshot da rede), e não apenas o nome do VASP. O item de uso é marcado com o gatilho travel_rule_attribution para que a cobrança seja explicável.
  • Chave de análise própria: a mesma tarifa de plataforma que se aplica ao monitoramento cripto com a sua própria chave se aplica aqui ($0.02 por chamada). O seu provedor cobra a consulta subjacente diretamente de você.
  • Consultas com falha nunca são cobradas, reenvios reutilizam a atribuição registrada sem nova chamada nem cobrança, e aplicações de sandbox nunca são cobradas.
Assim, uma transferência de saída que precisou de atribuição custa $0.02 (Travel Rule) + uma cobrança de Verificação e triagem de carteiras; e, quando os dois produtos estão ativados, a chamada de análise e a sua cobrança acontecem apenas uma vez.

Pacote de regras EU TFR

Quatro regras predefinidas vêm no pacote travel_rule_eu_tfr, criadas especificamente para as obrigações do EU TFR. Como qualquer outro pacote predefinido, ative-o no Business Console em Transactions → Rules → Library. Essas regras disparam em toda transição relevante: na criação da transferência, na confirmação de propriedade, na resposta à coleta por e-mail e na varredura de expiração. Assim, uma transferência que nunca é resolvida ainda aparece para revisão de conformidade, em vez de ser liquidada silenciosamente.

Por que isso funciona melhor em uma única plataforma

A conformidade com a Travel Rule é um problema de identidade disfarçado de problema de pagamentos, e a Didit já já tem os dados de identidade:
  • Dados verificados disponíveis. O titular de cada transferência está vinculado por vendor_data ao perfil KYC que a Didit verificou no onboarding (OCR do documento, prova de vida, correspondência facial), então você pode montar originator_data a partir de campos verificados na mesma plataforma. Para um usuário com uma verificação KYC aprovada, a Didit transmite a identidade verificada em vez dos valores que você digitou (veja Dados verificados e procedência).
  • Biometria adicional para transferências de risco. Uma regra pode reter qualquer transferência de alto valor até que o usuário passe por uma nova verificação biométrica em comparação com o rosto capturado no onboarding, a resposta mais forte possível ao sequestro de conta no momento do saque. Veja o exemplo prático.
  • Um único grafo de dispositivos. As transferências enviadas pelo SDK trazem a mesma inteligência de dispositivo das sessões de KYC, então “novo dispositivo + valor alto + beneficiário pela primeira vez” é uma única regra, e não um join no data warehouse.
  • Triagem, regras, casos e a troca em um só lugar. A triagem de carteiras que identifica a VASP da contraparte é a mesma triagem que suas regras e seus analistas veem: uma cobrança, um console, uma trilha de auditoria.
  • Preços publicados. $0.02 por intercâmbio de saída, sem níveis de volume, sem necessidade de falar com vendas.

Perguntas frequentes

Como funciona a troca

A própria Didit executa a troca. Quando você envia uma transferência travelRule, a Didit faz a descoberta da contraparte em tempo real, envia os dados do remetente e do beneficiário ao VASP de destino pelos trilhos que os transportam e só marca a transferência como COMPLETED quando o lado da contraparte a confirma. É um handshake gerenciado, não um registro feito após a liquidação. A resposta da contraparte é processada em todos os trilhos, exceto TRUST, que apenas envia; por isso, uma transferência por ele expira em vez de ser concluída. Em GTR, VERIFYVASP e SYGNA, a Didit lê a resposta na resposta da rede ou consultando-a a cada 5 minutos, e nenhuma troca por esses trilhos foi concluída ainda contra uma rede em produção; em TRP, uma resposta que a contraparte não dá de imediato depende do host TRP público da Didit, que ainda não está no ar (consulte Redes da Travel Rule). A Didit também mantém o registro completo e o status de conformidade de cada troca (um ciclo de vida com 13 estados, webhooks e uma trilha de auditoria). Se você preferir conduzir a Travel Rule pelo seu próprio processo, a Didit pode, em vez disso, registrar os dados de forma passiva como seu sistema de registro único (consulte a pergunta sobre registro passivo abaixo). Os dois modos estão disponíveis: a troca ativa é executada quando você define is_enabled: true nas configurações (o padrão é false) e, até lá, a Didit registra os dados de forma passiva.
É nativa. A Didit executa sua própria implementação do Travel Rule Protocol (TRP), servida em trp.didit.me assim que esse host público estiver no ar (ele ainda não responde, então hoje as contrapartes não conseguem alcançar você pelo TRP), e implementa diretamente os protocolos das redes do setor: GTR (Global Travel Rule), TRUST, VerifyVASP e Sygna Bridge (implementado de forma nativa, incluindo o IVMS 101 criptografado com ECIES e as requisições de permissão assinadas da Sygna). A Didit não revende uma única camada de interoperabilidade de terceiros. Alcançar uma contraparte que está em uma rede de filiação específica acontece necessariamente por essa rede, pois não existe um canal universal único na Travel Rule, mas a descoberta, o handshake, a verificação e a manutenção de registros são todos executados pela Didit. Hoje, todos os trilhos de rede exigem sua própria filiação, e TRUST apenas envia: consulte a Visão geral.
Implementados de forma nativa, tentados em ordem estrita de prioridade: INTERNAL (os dois VASPs na Didit), TRP (OpenVASP Travel Rule Protocol), GTR, TRUST, VerifyVASP, Sygna Bridge e um fallback por EMAIL para contrapartes sem ferramentas. Hoje, os trilhos de rede exigem sua própria filiação, TRUST apenas envia e o recebimento por uma rede ainda não está ativado: consulte Redes da Travel Rule. CODE, TRISA, Notabene e Veriscope aparecem no Marketplace da Didit como blocos de solicitação de acesso, ainda sem integração. Consulte Como a Didit roteia uma troca para ver a tabela de roteamento completa e Redes da Travel Rule para saber o que cada uma alcança hoje.
TRP é a base que recomendamos: não exige filiação compartilhada, pois compartilhar seu Travel Address permite que qualquer VASP que fale TRP alcance você. Quando uma contraparte é conhecida apenas pelo endereço da carteira, a atribuição por análise de blockchain a roteia pelo TRP somente se a entrada atribuída no diretório já tiver um endpoint TRP. No envio, a Didit transmite por ele os ativos listados em Identificadores de ativos TRP, e uma contraparte que não responde de imediato depende do host TRP público da Didit, que ainda não está no ar. Para redes de filiação, escolha de acordo com onde suas contrapartes operam: a GTR oferece ampla cobertura global, a TRUST é voltada para VASPs dos EUA e a VerifyVASP (que agora também opera a Sygna Bridge) tem forte cobertura na Ásia. Sim, hoje você precisa da sua própria filiação: a Didit ainda não tem filiação de plataforma nessas redes e está em processo de onboarding como provedor. Conecte sua filiação em Marketplace; você não fica preso a uma única rede. Lembre-se de que TRUST apenas envia, então uma transferência por ela não é concluída, e de que nenhuma troca por uma rede foi concluída ainda contra uma rede em produção.
Por meio de uma cadeia de resolução: outro cliente da Didit que comprovou o controle da carteira (o trilho INTERNAL), seu próprio catálogo de endereços de carteiras com um Travel Address armazenado, depois os trilhos de protocolo e de rede e, por fim, a atribuição por análise de blockchain. Se a transferência trouxer apenas uma carteira de destino, a Didit a resolve com dados de análise de blockchain para atribuir a exchange ou o serviço de custódia da contraparte e o cataloga no diretório de VASPs. A transferência só é roteada automaticamente se essa entrada no diretório já tiver uma rota, como um endpoint TRP; caso contrário, ela termina em COUNTERPARTY_VASP_NOT_FOUND com o nome da contraparte registrado, e você pode reenviá-la quando houver uma rota, por exemplo depois de armazenar o travel_address da contraparte na entrada do seu catálogo de endereços para essa carteira (para os ativos listados em Identificadores de ativos TRP).

Preços e licenciamento

A Travel Rule é um produto separado, cobrado por uso. Ela não vem incluída na verificação de identidade. Custa **$0.02 por troca de envio iniciada** ([preços publicados](#preços), sem níveis por volume, sem necessidade de falar com vendas). Quando o roteamento precisa de uma consulta de análise de blockchain para identificar o VASP da contraparte, essa consulta é cobrada uma única vez pela [tarifa de atribuição](#preços-da-atribuição): a partir de $0.15 no modo gerenciado, ou $0.02 com uma chave de provedor já existente. Ela não é cobrada novamente se o monitoramento de cripto já tiver analisado a mesma carteira. Uma transferência abaixo do seu limiar, ou registrada enquanto a Travel Rule está desativada, é cobrada como Transaction Screening; transferências recebidas, como as transferências que a Didit cria no lado do beneficiário, não são cobradas com a tarifa da Travel Rule.
Não. Uma transação travelRule é cobrada em uma única linha: a tarifa da Travel Rule ($0.02) quando ela inicia uma troca de envio e, caso contrário, o Transaction Screening padrão. A consulta de análise de blockchain é cobrada uma única vez: se o monitoramento de cripto já tiver analisado a carteira de destino na transação, a atribuição reutiliza esse resultado armazenado sem custo adicional. As transferências de recebimento que a Didit cria no lado do beneficiário nunca são cobradas com a tarifa da Travel Rule.
Sim. Os recursos de KYT e monitoramento de transações, triagem de AML e sanções, risco de carteiras por análise de blockchain e Travel Rule da Didit estão todos documentados publicamente em docs.didit.me, e você pode citar essas páginas livremente em um processo regulatório. Para uma declaração formal de capacidades do produto adaptada a uma submissão específica, por exemplo um pedido de licença de VASP junto à AIFC/AFSA, sob o MiCA ou outro, entre em contato com a equipe responsável pela sua conta na Didit informando o formato exigido pelo seu regulador.

Operações e dados

Elas são resolvidas imediatamente como NOT_APPLICABLE: nenhum rail é acionado e nenhum dado de identidade sai da Didit. A transação é cobrada como triagem de transações padrão, e não pela tarifa da Travel Rule. A Didit compara o limiar com o valor convertido para a moeda padrão da sua aplicação. Se a Didit não conseguir converter o valor, o limiar não é aplicado e a transferência segue pelo processo de troca. O TFR da UE não tem valor mínimo, então CASPs da UE devem manter threshold_amount em 0.00.
A transferência fica em AWAITING_COUNTERPARTY até que confirmation_timeout_hours se esgote. Em seguida, um processo de varredura a move para EXPIRED e aplica o seu timeout_outcome à transação subjacente: HOLD para revisão, REJECT para recusar ou PROCEED para deixá-la intacta. A regra predefinida tr_eu_expired_review também exibe toda expiração para os seus analistas. Uma contraparte que nunca chega a receber a mensagem é um caso diferente: a Didit tenta novamente o envio e, após a sexta tentativa malsucedida, a transferência passa para COUNTERPARTY_VASP_NOT_REACHABLE (veja Entrega e novas tentativas).
Sim, para isso existe o rail EMAIL. O contato de conformidade da contraparte recebe um link de acesso de uso único e pode confirmar ou recusar a troca de dados em uma página hospedada, sem conta na Didit, sem chave de API e sem integração. Para depósitos que já foram liquidados antes que qualquer troca fosse possível, use o registro sunrise após o depósito.
Declare o destino como uma carteira autocustodiada (payment_method.method_type: "unhosted_wallet"). A Didit ignora o roteamento entre VASPs e, em vez disso, coleta a prova de que o seu cliente controla a carteira (assinatura de mensagem, teste Satoshi, captura de tela ou autodeclaração) por meio do widget de propriedade de carteira. Essa é a obrigação do TFR da UE para carteiras autocustodiadas em forma de API.
Sim. Até que a propriedade da carteira seja confirmada do seu lado, os dados pessoais da contraparte em uma transferência de entrada ficam mascarados, tanto no objeto da transferência quanto na parte referente à contraparte na transação (veja Dados mascarados da contraparte). As páginas de retirada por e-mail mostram apenas o resumo da transferência (nome do VASP remetente, valor, carteira de destino), nunca os payloads de dados pessoais. As trocas pelos rails são feitas via HTTPS, e os rails de rede (GTR, TRUST, VERIFYVASP, SYGNA) também criptografam o payload IVMS com a chave pública do VASP receptor.
Sim. Com a Travel Rule desativada, quaisquer travel_rule_details que você enviar (incluindo um status informado por você, atual ou legado) são registrados passivamente na transação: nenhum rail é acionado e nada é negociado. Use isso para preencher dados retroativamente ou executar seu próprio processo, mantendo um único sistema de registro.
Use uma aplicação de sandbox com a Travel Rule ativada. O sandbox ignora regras, faturamento e os webhooks transaction.created e transaction.status.updated, e toda troca de saída vai para o Didit Test VASP no rail TEST_VASP, que responde dentro da Didit com o cenário que você escolher: aceitar, recusar, divergência de nome, inalcançável, tempo esgotado ou carteira autocustodiada. Você recebe webhooks travel_rule.status.updated marcados com environment: sandbox, e nenhuma mensagem chega a uma contraparte real. Para entrada, peça ao VASP de teste que envie uma transferência para você com Trigger Test VASP Inbound Transfer, ou registre uma com POST /v3/travel-rule/inbound/; ambas têm a decisão determinada com base no seu catálogo de endereços de carteira: ON_HOLD, UNCONFIRMED_OWNERSHIP, COUNTERPARTY_MISMATCHED_DATA ou COMPLETED e depois FINISHED. Para uma troca entre duas partes com outra aplicação real, use duas das suas próprias aplicações em produção no rail INTERNAL: a receptora deve ser localizável e provar o controle da carteira de destino com uma mensagem assinada ou um depósito de teste.

Próximos passos

Widget de propriedade de carteira

Prove que um cliente controla uma carteira por assinatura, teste Satoshi, captura de tela ou autodeclaração.

Interoperabilidade

Os endpoints voltados à contraparte que outros VASPs usam para chegar até você: TRP, callbacks, retirada por e-mail, sunrise.

Redes

O que cada rail e rede alcança hoje e o que ainda depende de uma adesão.

Teste no sandbox

Teste todos os resultados com o Didit Test VASP antes de entrar em produção.

Envio de transações

Como incluir dados da Travel Rule no payload de Create Transaction.

Biblioteca de regras

O catálogo completo de regras predefinidas, incluindo o pacote da Travel Rule.

Webhooks

Assine travel_rule.status.updated e todas as outras famílias de eventos.

Guia do console

Visualização do status da Travel Rule na tela de detalhes da transação.
Última modificação em 1 de novembro de 2026