Overview
Il Travel Rule del GAFI (Raccomandazione 16), recepito nell’UE come Regolamento sul trasferimento dei fondi (Transfer of Funds Regulation, TFR), impone al prestatore di servizi per le attività virtuali mittente (il VASP ordinante) di raccogliere e trasmettere i dati dell’ordinante e del beneficiario al prestatore di servizi per le attività virtuali ricevente (il VASP beneficiario) prima che il trasferimento di attività virtuali venga regolato. A differenza della maggior parte delle giurisdizioni, il TFR dell’UE si applica senza alcun importo minimo: ogni trasferimento di cripto-attività rientra nell’ambito, non solo quelli sopra una soglia di segnalazione. Il prodotto Travel Rule di Didit è uno scambio gestito, non solo un campo dati:- Invii un trasferimento con
transaction_category: "travelRule". - Didit prova i canali in ordine di priorità per raggiungere il VASP controparte, esegue lo scambio sul primo che lo raggiunge e, quando l’altra parte restituisce un nome del beneficiario, lo confronta con quello che hai inviato.
- Solo quando lo scambio raggiunge
COMPLETEDdovresti trasmettere il trasferimento on-chain. - Comunichi quindi a Didit l’hash della transazione on-chain per chiudere lo scambio con stato
FINISHED.
GTR, TRUST, VERIFYVASP, SYGNA) richiedono un’adesione alla rete dal lato mittente, e oggi tale adesione deve essere la tua.
Collega le credenziali di adesione nel Marketplace della console (categoria Reti Travel Rule), e i tuoi trasferimenti vengono effettuati con la tua identità di rete.
Didit non ha alcuna adesione alla piattaforma per nessuna delle quattro reti oggi, e sta effettuando l’onboarding come fornitore per queste reti.
Fino al completamento di tale onboarding, platform_available è false per tutte e quattro, la modalità didit nelle impostazioni (instradamento tramite l’adesione alla piattaforma di Didit) non è disponibile per nessuna rete, e disabled_networks non ha nulla da disattivare.
Un’adesione che colleghi tu stesso ha sempre la precedenza su un’adesione della piattaforma.
Nessuna adesione a una rete è inclusa di default, GTR compreso.
Abilitare Travel Rule non attiva GTR, TRUST, VerifyVASP o Sygna.
Consulta Ottieni le impostazioni Travel Rule per le modalità networks effettive della tua applicazione, e reti Travel Rule per ciò che ciascuna rete raggiunge oggi.
Se tutte e quattro risultano unavailable, nessuna può instradare uno scambio: collega una tua adesione in Marketplace, oppure usa una controparte raggiungibile tramite INTERNAL, TRP o EMAIL.
Quando salvi un’adesione, il suo codice partecipante deve essere tuo: il salvataggio restituisce 400 se il codice è quello di Didit su quella rete, oppure un codice già detenuto dall’adesione di un’altra applicazione.
Un’adesione GTR richiede la propria chiave privata ed25519 (base64), quella la cui chiave pubblica è registrata nel portale GTR: cifra i dati personali che invii e decifra quelli che ricevi.
Un’adesione VerifyVASP punta al tuo Enclave VerifyVASP: il suo URL è quello del tuo Enclave e il suo token è quello che il tuo Enclave presenta a Didit.
Anche con una tua adesione, un canale di rete instrada un trasferimento solo se il suo beneficiary_data contiene l’id della controparte su quella rete (counterparty_gtr_vasp_code, counterparty_trust_membership_id, counterparty_verifyvasp_id o counterparty_sygna_vasp_code), oppure se la voce della directory della controparte lo elenca per quella rete (vedi Instradamenti).
platform_available indica se l’adesione alla piattaforma è configurata, non un controllo dello stato della rete in tempo reale. Analogamente, connected significa che le tue credenziali di adesione sono salvate e hanno superato la validazione locale; il primo scambio reale le verifica con la rete. Una modalità didit o own non garantisce che la controparte sia raggiungibile né che la consegna vada a buon fine.
Con la tua iscrizione, Didit legge la risposta della controparte su GTR, VERIFYVASP e SYGNA dalla risposta della rete oppure interrogando la rete ogni 5 minuti, e completa o rifiuta il trasferimento.
TRUST prevede solo l’invio: un trasferimento inviato tramite questo canale resta in AWAITING_COUNTERPARTY finché non sono trascorse le ore indicate da confirmation_timeout_hours, poi passa a EXPIRED e si applica il tuo timeout_outcome.
La ricezione di un trasferimento che un altro VASP ti invia tramite una rete non è ancora attiva, e nessuno scambio su una rete è stato ancora completato con una rete in produzione: vedi Reti Travel Rule.
Altre reti (CODE, l’alleanza coreana, TRISA, Notabene e Veriscope) sono elencate nel Marketplace della console come riquadri di richiesta di accesso.
Didit non ha ancora alcuna integrazione con queste reti, quindi oggi nessun trasferimento può essere instradato su di esse.
Quando nessuno dei sette canali riesce a identificare una controparte, Didit esegue un ulteriore passaggio di risoluzione prima di rinunciare: l’attribuzione tramite analisi blockchain.
Il wallet di destinazione viene cercato nei dati di analisi blockchain; quando il wallet appartiene a un exchange o a un custode noto, Didit registra il VASP attribuito sul trasferimento, lo aggiunge alla directory ed esegue di nuovo i canali una sola volta con il nuovo nome.
Vedi Attribuzione tramite analisi blockchain per il comportamento completo e i prezzi.
Un trasferimento la cui destinazione è dichiarata come wallet in autocustodia salta tutti e sette i canali, poiché non esiste un VASP controparte con cui scambiare dati, e passa direttamente alla prova di proprietà del wallet da parte dell’utente finale.
/v3/ descritti in questa pagina.Cosa viene eseguito quando invii un trasferimento
I controlli vengono eseguiti all’interno dell’unica chiamataPOST /v3/transactions/ - quando ricevi la risposta, lo screening è stato completato, il trasferimento è stato salvato e le regole sono state valutate.
Lo scambio vero e proprio inizia dopo la risposta: Didit sceglie il rail e contatta la controparte al di fuori della tua richiesta, quindi nessuna rete o controparte può rallentare o far fallire la creazione.
Ogni cambio di stato successivo arriva come webhook travel_rule.status.updated che indica il rail, e l’oggetto del trasferimento restituito dagli endpoint dei trasferimenti Travel Rule contiene un campo delivery che mostra se il messaggio è stato recapitato.
Non esiste alcuna pipeline da interrogare; le parti asincrone sono lo scambio, la risposta della controparte e qualsiasi azione dell’utente finale.
Passo dopo passo:
- Validazione e associazione del soggetto. Il payload viene validato.
Un
transaction_idgià usato nella tua applicazione viene rifiutato con400, e quando due richieste con lo stesso id arrivano in concorrenza, una delle due riceve409. Ilsubjectviene collegato al tuo profilo utente o aziendale tramitevendor_data, così il trasferimento compare su quel profilo per il monitoraggio. Unvendor_datadel soggetto o della controparte presente in blocklist viene rifiutato con400, e nessuna transazione viene creata. I wallet, i conti bancari, gli IP e i dispositivi in blocklist vengono controllati al passo 6 e fanno sì che la transazione venga rifiutata al passo 6, dopo che il routing è stato eseguito. - Arricchimento di dispositivo e rete. Gli IP delle parti vengono arricchiti con le informazioni geografiche, e qualsiasi contesto del dispositivo (automatico in caso di invio tramite SDK) viene normalizzato nel grafo dei dispositivi - lo stesso grafo alimentato dalle sessioni KYC, così la relazione “collegati per dispositivo” funziona tra onboarding e transazioni.
- Screening crypto. Per i trasferimenti crypto con il monitoraggio attivo, il wallet pertinente (o l’hash on-chain) viene sottoposto allo screening rispetto alle analisi blockchain prima che si avvii qualsiasi scambio - esposizione a sanzioni, vicinanza a mixer, fondi rubati. Vedi Screening crypto e dei wallet.
- Trasferimento Travel Rule. Il motore di scambio verifica la soglia e tiene conto di una dichiarazione di wallet in autocustodia, poi salva il trasferimento:
NOT_APPLICABLEsotto la tua soglia,UNCONFIRMED_OWNERSHIPper un wallet in autocustodia dichiarato,COMPLETEDquando l’altro wallet è un tuo wallet verificato, eAWAITING_COUNTERPARTYnegli altri casi, con il rail ancora vuoto. Ogni cambio di stato accoda un eventotravel_rule.status.updated, e Didit lo invia dopotransaction.createddella transazione (passo 7). - Generazione della verifica della proprietà del wallet. Se il trasferimento richiede la prova di controllo da parte dell’utente finale e
auto_wallet_verificationè attivo, viene generata una sessione del widget di verifica della proprietà del wallet e restituita inaction_required. - Valutazione delle regole. Ogni regola attiva viene eseguita - il bundle EU TFR reagisce allo stato del trasferimento impostato al passo 4, le tue regole personalizzate vedono l’output dello screening del passo 3, e una regola può trattenere la transazione (
IN_REVIEW), rifiutarla o richiedere una verifica rafforzata (AWAITING_USER). - Fatturazione e notifica. Una transazione in uscita viene fatturata su un’unica voce: la voce Travel Rule quando ha avviato uno scambio, e Transaction Screening negli altri casi. Un trasferimento in entrata non comporta alcuna commissione, e un’applicazione sandbox non viene mai addebitata.
La risposta viene restituita,
transaction.createdviene inviato alle tue destinazioni webhook, seguito dagli eventitravel_rule.status.updateddel passo 4. - Routing, dopo la risposta. Didit percorre i sette rail in ordine di priorità; se nessuno dà esito, l’attribuzione tramite analisi blockchain identifica la controparte e i rail vengono rieseguiti una sola volta. Il primo rail raggiungibile gestisce lo scambio: il trasferimento resta
AWAITING_COUNTERPARTYsu quel rail mentre la controparte risponde, viene regolato subito quando viene trovata una controparteINTERNAL(COMPLETEDoppureCOUNTERPARTY_MISMATCHED_DATA), oppure diventaCOUNTERPARTY_VASP_NOT_FOUNDquando nessun rail raggiunge la controparte. Ogni cambiamento inviatravel_rule.status.updated, e le tue regole vengono rieseguite ogni volta che cambiano lo stato o il rail. Un trasferimento che il routing lascia inCOUNTERPARTY_VASP_NOT_FOUNDriceve in quel momento la sessione del widget di verifica della proprietà del wallet (quandoauto_wallet_verificationè attivo); la leggi daaction_requireddella transazione con Get transaction.
Come ogni passo corrisponde ai tuoi obblighi
transaction.created o transaction.status.updated. Le transazioni sandbox restano APPROVED a meno che un trasferimento Travel Rule con scadenza applichi il tuo timeout_outcome, e non viene addebitato nulla.
Il motore di scambio Travel Rule vero e proprio viene eseguito sulle applicazioni sandbox quando Travel Rule è abilitato, con una sola controparte: ogni scambio in uscita va alla Didit Test VASP sul rail TEST_VASP, che risponde all’interno di Didit con lo scenario che scegli, così il trasferimento viene completato, rifiutato, risulta in mancata corrispondenza, diventa irraggiungibile, scade o attende la verifica della proprietà del wallet.
Nessun messaggio di compliance raggiunge mai una VASP controparte reale, e i webhook travel_rule.status.updated vengono consegnati con environment: sandbox.
In entrata, il VASP di test può inviarti un trasferimento (Trigger Test VASP Inbound Transfer), e la registrazione (POST /v3/travel-rule/inbound/) si regola sulla tua rubrica dei wallet come su un’applicazione di produzione - ON_HOLD, UNCONFIRMED_OWNERSHIP, COUNTERPARTY_MISMATCHED_DATA, oppure COMPLETED seguito da FINISHED.
Vedi Testare Travel Rule in sandbox.Ciclo di vita
Ogni trasferimento ha unostatus scelto tra 13 valori.
Lo scambio inizia con AWAITING_COUNTERPARTY nel caso normale, con NOT_APPLICABLE quando l’importo è inferiore al tuo threshold_amount oppure una richiesta di pagamento Lightning non indica un beneficiario (vedi Lightning), oppure con UNCONFIRMED_OWNERSHIP quando la destinazione è stata dichiarata un wallet in autocustodia. Termina in uno degli stati finali: FINISHED, CANCELLED o EXPIRED.
Il trasferimento segue una propria macchina a stati, separata dallo stato di revisione della transazione sottostante.
Lo stato dello scambio non modifica mai da solo lo stato della transazione, con un’unica eccezione: alla scadenza si applica il tuo timeout_outcome configurato (oppure una politica sunrise o per mancata risposta, quando ne è applicabile una).
Le tue regole vengono rieseguite a ogni transizione, quindi le regole EU TFR o qualsiasi regola basata su travel_rule_status possono spostare la transazione, ad esempio in IN_REVIEW.
Un trasferimento che richiede la prova del controllo del wallet da parte dell’utente finale aggiunge un blocco action_required alla transazione, ma il suo status resta quello definito dalle tue regole.
Leggi lo stato dello scambio da travel_rule.status; leggi il verdetto di autorizzazione / sospensione / rifiuto dallo status della transazione stessa.
Ogni transizione (e ogni stato riportato passivamente) viene anche replicato nei valori personalizzati della transazione, così le regole possono basarsi su di essi: custom_values.travel_rule_status (stato canonico), custom_values.travel_rule_rail (il canale che ha trasportato lo scambio, vuoto finché non ne viene selezionato uno) e custom_values.travel_rule_regime (derivato dal jurisdiction nelle tue impostazioni: SG → singapore, GB → uk e qualsiasi codice di membro UE o SEE, come DE o FR, → eu; i codici non mappati vengono scritti in minuscolo, ad esempio US → us. Un props.travel_rule_regime che invii tu ha sempre la precedenza sul valore derivato).
CANCELLED è inoltre raggiungibile da ogni stato non finale con action: "cancel"):
Consegna e nuovi tentativi
Didit invia ogni messaggio dovuto da un trasferimento al di fuori della richiesta che lo ha generato, e lo ritenta finché l’altra parte non lo accetta. L’oggetto trasferimento restituito da Completamento, annullamento o reinvio, Conferma dell’assetto proprietario e registrazione sunrise contiene l’ultimo messaggio indelivery, e lo stesso vale per l’oggetto travel_rule incorporato nella transazione; è null quando il trasferimento non ne ha mai dovuto inviare uno.
408, 429 o 5xx) viene effettuato un nuovo tentativo dopo 30 secondi, 2 minuti, 10 minuti, 30 minuti e 1 ora.
Quando un primo messaggio fallisce in modo definitivo (la rete lo ha rifiutato, oppure è fallito anche il sesto tentativo), il trasferimento passa a COUNTERPARTY_VASP_NOT_REACHABLE con last_error nella sua timeline, e puoi riprovare con action: "resend".
Qualsiasi altro messaggio che fallisce in modo definitivo viene annotato nella timeline.
delivery non sostituisce mai lo status del trasferimento: leggi lo scambio dallo status e usa delivery per capire perché un trasferimento è ancora in attesa.
Valori di stato legacy
Se inviavi giàtravel_rule_details.status prima di questa versione, quei valori continuano a funzionare e vengono mappati automaticamente.
I nomi in camelCase di qualsiasi stato (per esempio counterpartyVaspNotFound) sono accettati anche in fase di invio e nei valori delle condizioni delle regole, e vengono normalizzati nella forma canonica:
Configurazione
Configura il profilo VASP e la policy di negoziazione una sola volta per applicazione conGET/PUT /v3/travel-rule/settings/.
PUT è un aggiornamento parziale: invia solo i campi che vuoi modificare.
Rigore della corrispondenza dei nomi
Modalità di validazione dell’assetto proprietario
ownership_validation_mode decide quanta prova serve per l’assetto proprietario di un wallet prima che un trasferimento possa basarsi su di esso:
FULL e SIMPLIFIED, un trasferimento successivo lo riutilizza solo se una prova accettata dalla modalità per quel trasferimento lo supporta.
Quando inbound_auto_accept non trova alcun wallet corrispondente nella rubrica, un wallet di criptovalute che hai registrato nelle transazioni di un solo utente finale identifica il titolare.
Didit aggiunge quel wallet alla rubrica dell’utente finale come tua autodichiarazione, verificato a meno che la modalità non sia FULL. Non aggiunge mai un wallet che la rubrica elenca già con un altro nome della stessa catena (eth ed ethereum), incluso quello registrato come appartenente a un altro VASP.
I controlli sugli indirizzi che gli altri VASP effettuano prima di inviare (tramite GTR, Sygna e VerifyVASP) seguono anch’essi la modalità: con FULL, un wallet che l’utente finale ha solo dichiarato non viene riportato come tuo.
Condivisione dei dati
data_sharing_fields stabilisce quali campi Didit invia alla controparte sui tuoi utenti, separatamente per persone fisiche e aziende:
- Le persone fisiche possono condividere
name,wallet_address,address,national_id,customer_identification,date_of_birtheplace_of_birth. Le aziende usano i primi cinque. nameewallet_addressvengono sempre inviati.- Un tipo di entità che non hai mai scelto condivide tutti i campi. Un elenco vuoto è comunque una scelta: condivide solo il nome e il wallet.
- Un
PUTunisce per tipo di entità, quindi inviareindividuallascia invariata la sceltacompanysalvata. - Una scelta che non può soddisfare gli obblighi dell’ordinante previsti dal regime della tua
jurisdiction(EU TFR o FATF Recommendation 16), compreso un elenco vuoto, viene rifiutata con400. Gli errori si trovano sottodata_sharing_fields, indicizzati per tipo di entità.
Corrispondenza per campo
matching_rules stabilisce quanto rigorosamente ogni campo dei dati della controparte viene confrontato con quanto detieni:
NONE, STRICT, CONTAINS, DEFAULT oppure FUZZY.
Valori predefiniti: name segue name_matching_strictness, date_of_birth e address sono NONE, e account è STRICT.
Un campo omesso mantiene il suo valore predefinito, e un campo che il tipo di entità non confronta (un’azienda non ha date_of_birth) viene rifiutato con 400.
Soglie per giurisdizione
threshold_amount esiste perché l’ambito della Travel Rule varia a seconda dell’autorità di vigilanza.
Didit usa come predefinito 0.00, la posizione UE, quindi ogni trasferimento viene scambiato a meno che tu non alzi la soglia deliberatamente:
threshold_amount sulla cifra fissata dalla tua autorità di vigilanza; i trasferimenti sotto di essa si risolvono in NOT_APPLICABLE senza scambiare alcun dato identificativo.
Le soglie cambiano: verifica la cifra attuale con il tuo consulente legale in ambito compliance, senza considerare questa tabella come consulenza legale.
Modello dati IVMS 101
Lo standard del settore per i dati scambiati nell’ambito della Travel Rule è IVMS 101 (interVASP Messaging Standard).travel_rule_details.originator_data e travel_rule_details.beneficiary_data sono payload di persone in stile IVMS 101: Didit li inserisce nella busta nativa di ciascun canale. Il canale TRP scambia blocchi IVMS101 (ivms101.2023, riportato nel campo ivms_version del trasferimento), il canale Sygna usa la sua variante IVMS cifrata con ECIES, e i canali GTR, TRUST e VERIFYVASP usano le proprie buste cifrate. Così una sola struttura del payload raggiunge ogni controparte nel formato previsto dal suo protocollo.
Quando costruisce il messaggio IVMS 101, Didit legge queste chiavi da ciascun payload di persona: first_name e last_name (oppure un singolo name o full_name), date_of_birth, place_of_birth, residence_country (oppure country), vendor_data (oppure customer_identification) e wallet_address.
Due regole pratiche:
- Sistema di scrittura latino. IVMS 101 richiede valori in sistema di scrittura latino, quindi traslittera i nomi scritti originariamente in un altro sistema di scrittura. Il confronto dei nomi di Didit confronta insiemi di token normalizzati, perciò differenze di ordine e di maiuscole/minuscole non fanno fallire uno scambio, mentre sistemi di scrittura diversi sui due lati sì.
- Invia dati che hai verificato. Quando il soggetto indicato in
vendor_dataè un utente con una verifica KYC Didit approvata, Didit trasmette l’identità verificata, non i valori che hai digitato: vedi Dati verificati e provenienza. Per qualsiasi altro soggetto, Didit trasmette esattamente iloriginator_datache invii, quindi costruiscilo a partire dall’identità verificata in fase di onboarding e non da un campo di modulo non verificato. È ciò che richiede la formulazione della FATF “richieste e accurate informazioni sull’ordinante”. Sul canaleINTERNAL, anche l’applicazione del beneficiario riceve ilsubjectche hai inviato (nome,vendor_data, data di nascita, paese e indirizzo) come controparte della sua transazione in entrata.
Dati verificati e provenienza
Quando il soggetto di un trasferimento è uno dei tuoi utenti, cioè una persona fisica con una verifica KYC approvata, Didit costruisce quel lato dello scambio a partire dai dati verificati:- l’ordinante di un trasferimento in uscita che crei con
POST /v3/transactions/; - il beneficiario di un trasferimento in entrata che segnali con
POST /v3/transactions/, oppure conPOST /v3/travel-rule/inbound/quandoholder_vendor_datadel wallet abbinato indica quell’utente.
POST /v3/transactions/, entrambi i casi si applicano a una transazione il cui transaction_category è travel_rule mentre la Travel Rule è attiva.
Nome e cognome verificati, data e luogo di nascita, numero e tipo del documento, indirizzo e paese di residenza (ricavato da quell’indirizzo) hanno la precedenza sui valori che hai inviato. Un campo che la verifica non contiene mantiene il tuo valore, e così accade anche per un indirizzo completo che hai inviato quando quello verificato non è abbastanza completo da essere trasmesso.
Il metadata del trasferimento, nell’oggetto travel_rule incorporato nella transazione, registra la provenienza di ogni campo e i punti in cui i tuoi valori differivano:
*_provenance associa ogni campo a verified o caller, mentre *_verified_differences elenca ogni campo in cui hai inviato un valore diverso da quello verificato, ignorando maiuscole/minuscole, spaziature e codici paese di due o tre lettere. Mentre i dati di un trasferimento in entrata sono mascherati, le differenze non vengono incluse. Didit calcola entrambe queste chiavi, quindi le copie di queste chiavi, o di name_match, che invii in travel_rule_details.metadata vengono eliminate.
Invio diretto di IVMS 101
Oltre agli oggetti piattioriginator_data e beneficiary_data, travel_rule_details (su POST /v3/transactions/) e POST /v3/travel-rule/inbound/ accettano IVMS 101 nel formato standard:
- un blocco
originatore un bloccobeneficiary, conoriginatorPersonsobeneficiaryPersonsche contengono unnaturalPersonoppure unlegalPerson, eaccountNumber; - gli stessi blocchi all’interno di un oggetto
ivms101(oIVMS101); - una singola persona IVMS 101, oppure un intero blocco, come
originator_dataobeneficiary_data.
naturalPerson oppure un legalPerson, che rende la parte un’azienda. Un originator_data o beneficiary_data piatto e non vuoto prevale su un blocco per lo stesso lato.
400 con il percorso come chiave, per esempio {"travel_rule_details": {"originator.originatorPersons": ["must be a non-empty list of originator persons."]}}. Su POST /v3/travel-rule/inbound/ le stesse chiavi si trovano al livello superiore, sotto ivms101. quando usi il wrapper.
Dati richiesti per regime
Con la Travel Rule attiva, un trasferimento in uscita pari o superiore alla tua soglia deve contenere quanto richiesto dal suo regime, altrimenti restituisce400. Vengono controllati solo i lati che hai inviato, i dati verificati valgono per l’ordinante, e gli errori compaiono in travel_rule_details.originator_data o travel_rule_details.beneficiary_data, per esempio "EU TFR requires the originator name." o "FATF Recommendation 16 requires the beneficiary wallet address.":
data_sharing_fields, perché sono tutti quelli che un canale trasmette; il beneficiario viene controllato così come lo hai inviato. Quando il trasferimento soddisfa il regime solo grazie a un campo che non condividi, il 400 indica il requisito del regime e poi i campi che le tue impostazioni condividono.
Il numero del documento ufficiale è national_id (oppure document_number), il numero di identificazione del cliente è customer_identification (oppure vendor_data), e la data di nascita è date_of_birth. Un beneficiary_data.wallet_address vuoto viene riempito con counterparty.payment_method.account_id prima del controllo, e un prelievo UTXO il cui output del beneficiario è stato dedotto da Didit a partire da travel_rule_details.utxo viene considerato come contenente tale indirizzo. Un trasferimento Lightning a cui la Travel Rule non si applica non viene controllato.
Travel Address
Un Travel Address è una stringa compatta e codificata che punta all’endpoint di richiesta in entrataTRP di una VASP. Non espone mai un URL grezzo né alcun indirizzo wallet.
Dopo aver attivato la Travel Rule, Didit genera il tuo travel_address (restituito in sola lettura nelle impostazioni), così puoi condividerlo con le altre VASP che ti raggiungono tramite il canale TRP.
Ciascun wallet della tua rubrica degli indirizzi dei wallet riceve anche un receiving_travel_address specifico: una richiesta inviata a quell’indirizzo indica il wallet, quindi Didit non deve individuarlo tramite numero di conto o nome del titolare.
L’host TRP pubblico di Didit non risponde ancora alle altre VASP, quindi la ricezione tramite TRP non è disponibile finché non lo farà: vedi reti Travel Rule.
Quando conosci il Travel Address di una controparte, salvalo nella voce della rubrica degli indirizzi dei wallet di destinazione, così Didit instrada i trasferimenti di quel beneficiario direttamente tramite TRP invece di ricorrere all’email.
Didit valida i Travel Address che salvi in una voce della rubrica degli indirizzi wallet o invii in originating_vasp: ognuno deve iniziare con ta ed essere decodificabile in un URL di richiesta che contiene t=i, quindi un segnaposto come ta... restituisce 400.
Un beneficiary_data.travel_address su una transazione non viene validato: se non si decodifica, il canale TRP viene saltato.
La codifica è Base58Check con prefisso ta: host e percorso dell’endpoint (che include sempre la coppia di query t=i), più un checksum double-SHA-256 di quattro byte, codificato in base58. Un Travel Address reale ha quindi questo aspetto e arriva a circa 100 caratteri:
400 con "Invalid travel address.".
Usa un indirizzo reale dalla risposta relativa alle tue impostazioni o dalla controparte stessa.
Test senza credenziali di rete
Non ti serve l’adesione a GTR, TRUST, VerifyVASP o Sygna per testare i percorsi che non richiedono adesione. Ti serve comunque una chiave API Didit per l’applicazione in test.- Sandbox in uscita: invia una transazione
travelRuleda un’applicazione sandbox. Dopo i controlli sulla soglia e sui wallet in autocustodia, il Test VASP di Didit risponde all’interno di Didit con lo scenario che scegli in base al wallet o al nome del beneficiario: accettazione, rifiuto, mancata corrispondenza del nome, non raggiungibile, timeout o wallet in autocustodia. Nessuna rete, nessuna email e nessun altro cliente Didit riceve nulla. - Sandbox in entrata: fai inviare al Test VASP un trasferimento verso di te con Attiva trasferimento in entrata del Test VASP, oppure registrane uno tu stesso con Registra trasferimento Travel Rule in entrata. Prova un wallet sconosciuto, un wallet non verificato, una mancata corrispondenza del nome del beneficiario e un wallet verificato e corrispondente. Questi scenari riproducono decisioni reali in entrata senza contattare alcuna rete.
- Due applicazioni controllate in produzione: usa il canale
INTERNALtra due tue applicazioni in ambiente di produzione (quella ricevente è rilevabile e dimostra il controllo del wallet di destinazione con un messaggio firmato o un deposito di prova), oppure una controparte TRP che controlli tu, per testare uno scambio a due parti senza credenziali commerciali di rete. Le applicazioni in produzione possono generare i normali addebiti e le normali notifiche; usa identità e controparti di test che controlli tu.
Invio di un trasferimento
Includi il trasferimento suPOST /v3/transactions/ impostando transaction_category su travelRule (oppure travel_rule) e allegando un oggetto travel_rule_details (alias: travelRule).
Il blocco travel_rule_details è facoltativo, ma una volta allegato, travel_rule_details.status è obbligatorio: un blocco senza questo campo restituisce 400.
Quando Travel Rule è abilitata per la tua applicazione, Didit ignora il valore status che invii e gestisce lo scambio da sola:
- Se l’importo è inferiore alla tua
threshold_amountconfigurata, il trasferimento si risolve immediatamente inNOT_APPLICABLEe non viene negoziato nulla. - Se il metodo di pagamento della controparte dichiara la destinazione come wallet in autocustodia (
payment_method.method_type: "unhosted_wallet"), non viene tentato alcun canale: il trasferimento passa direttamente aUNCONFIRMED_OWNERSHIPe il widget di verifica della proprietà del wallet viene generato automaticamente (vedi Wallet in autocustodia dichiarati). - Altrimenti i canali vengono eseguiti in ordine di priorità, e il primo in grado di raggiungere la controparte porta lo scambio:
INTERNAL- esattamente un altro cliente Didit possiede una prova con messaggio firmato o con deposito di test perbeneficiary_data.wallet_address, creata dopo l’ultimo cambio di titolare del wallet. La tua applicazione non viene mai considerata, e quando il tuo utente finale ha scelto un membro della rete Didit nel widget di verifica della proprietà del wallet, conta solo la prova di quel membro. L’applicazione di quel cliente è attiva (non sandbox), ha Travel Rule abilitata eis_discoverableimpostato, ed è il VASP che indichi quando inviicounterparty_vasp_leiocounterparty_vasp_name. Un wallet solo dichiarato dall’utente, provato con uno screenshot, non verificato o presente soltanto nella rubrica degli indirizzi non riceve mai nulla tramiteINTERNAL.TRP- l’asset del trasferimento ha una mappatura del Digital Token Identifier per la rete del trasferimento (vedi Identificatori di asset TRP), e il payload contienebeneficiary_data.travel_address, oppure la voce della rubrica degli indirizzi della destinazione ne memorizza uno, oppure la controparte si risolve nella directory (tramitecounterparty_vasp_leiocounterparty_vasp_name) con un endpoint TRP.GTR,TRUST,VERIFYVASP,SYGNA- hai collegato la tua adesione a quella rete in Marketplace, e la controparte si risolve in un ID di rete (campo esplicito o voce della directory - vedi Campi di risoluzione della controparte). Didit non dispone ancora di alcuna adesione alla piattaforma su queste reti (è in fase di onboarding come provider), quindidisabled_networksoggi non modifica questo passaggio.EMAIL- è stato fornitobeneficiary_data.counterparty_vasp_email, oppurecounterparty_vasp_namesi risolve in una voce della directory con un’email di compliance.
- Se nessun canale riesce a risolvere la controparte, Didit esegue la catena di scoperta della controparte. Con
vasp_attribution_enabledattivo, questa include attribuzione tramite blockchain analytics: il wallet di destinazione viene ricondotto al VASP proprietario, il nome attribuito viene scritto inbeneficiary_data.counterparty_vasp_name(se vuoto) e nella directory, e i canali vengono rieseguiti una volta - quindi un wallet attribuito a un VASP la cui voce nella directory contiene un endpoint TRP, un ID di rete o un’email di compliance viene instradato in questo secondo passaggio. - Se la controparte resta non risolta, il trasferimento passa a
COUNTERPARTY_VASP_NOT_FOUND. Sui trasferimenti in uscita Didit genera automaticamente il widget di verifica della proprietà del wallet (quandoauto_wallet_verificationè attivo), così il trasferimento può comunque completarsi come trasferimento verso un wallet in autocustodia, e puoi rieseguire l’instradamento più tardi conaction: "resend"quando avrai dati più accurati sulla controparte.
AWAITING_COUNTERPARTY e protocol: null, e ogni esito arriva come webhook travel_rule.status.updated.
Identificatori di asset TRP
TRP identifica l’asset trasferito tramite il suo Digital Token Identifier (DTI) ISO 24165.
Un DTI identifica un token su una singola blockchain, quindi un token multi-chain ha un DTI per ogni rete.
Didit invia trasferimenti tramite TRP per questi asset:
USDC sono quelli che l’emittente del token pubblica nel suo white paper MiCA.
Per un token multi-chain, il trasferimento deve indicare la rete in transaction_details.crypto_params.crypto_chain (ad esempio CELO, BASE, OP, ARB o POL).
Senza una rete, o su una rete senza mappatura, il trasferimento non viene inviato tramite TRP e Didit prova i canali rimanenti: prima le reti di interoperabilità, poi l’email.
USDT non è ancora mappato.
Un token senza mappatura DTI, come lo stablecoin proprietario di un’azienda, richiede che il suo emittente registri un DTI presso l’autorità di registrazione ISO 24165, uno per token per blockchain.
Una volta che i DTI esistono, contatta il supporto Didit indicando ogni DTI, la sua blockchain e i decimali del token, e Didit aggiunge la mappatura.
Le richieste TRP in entrata che contengono un DTI associato alla singola rete vengono registrate con la valuta del token, l’importo nei decimali del token e la rete.
Scoperta della controparte
Un trasferimento che contiene solo un indirizzo raggiunge comunque la sua controparte ogni volta che qualcuno riesce a identificarla. Prima che un trasferimento in uscita venga dichiarato non instradabile, Didit verifica, in quest’ordine, e si ferma al primo passaggio che indica un VASP con un instradamento disponibile:discovery del trasferimento elenca ogni passaggio eseguito con il suo outcome (match, miss o skipped), un reason leggibile dalle macchine, il vasp e il rail trovati, e un timestamp.
Una VASP scelta da te o dall’utente finale prevale su ogni passaggio automatico: la discovery non la sostituisce mai con una propria ipotesi.
Quando nessun passaggio indica una controparte, il trasferimento passa a COUNTERPARTY_VASP_NOT_FOUND, oppure a COUNTERPARTY_VASP_NOT_REACHABLE quando è stata indicata una VASP ma nessuno dei suoi percorsi è disponibile per la tua applicazione.
Il trasferimento riporta quindi un reason (awaiting_end_user, no_directory_match, directory_match_no_route, oppure picked_member_without_proven_wallet quando il membro scelto dall’utente finale non ha dimostrato il possesso del wallet) e un elenco di next_actions:
url nelle azioni che l’utente finale esegue.
Quando un’azione di verifica della proprietà del wallet è in sospeso, il blocco action_required della transazione (tipo wallet_ownership) riporta lo stesso reason e gli stessi next_actions, così un client che già segue action_required mostra il selettore senza ulteriore lavoro.
Campi di risoluzione della controparte
Tutto ciò che Didit sa sulla controparte proviene datravel_rule_details.beneficiary_data.
Questi campi determinano la risoluzione del canale; sono tutti facoltativi:
Forme delle catene
Su una catena basata su account (catene EVM, Solana, Tron) un trasferimento sposta fondi da un indirizzo a un altro, e Didit legge entrambi i wallet direttamente dalla transazione. Per altre tre forme servono informazioni aggiuntive, e i dati che Didit ha risolto per queste forme sono riportati nel trasferimento comechain_details (vuoto, {}, su una catena basata su account).
chain_details.originator e chain_details.beneficiary riportano ciascuno l’address, il suo memo e la source da cui proviene, e la corrispondenza e l’instradamento leggono prima da lì i wallet.
Trasferimenti UTXO
Una transazione Bitcoin, Litecoin, Bitcoin Cash o Dogecoin spende input provenienti da un numero qualsiasi di indirizzi e paga un numero qualsiasi di output, alcuni dei quali restituiscono il resto al mittente. Invia input e output cometravel_rule_details.utxo (importi nell’unità propria della moneta, come stringhe decimali), e Didit deduce ciò che non dichiari:
- Ordinante:
originator_data.wallet_addressquando lo invii, altrimenti l’indirizzo di input che ha contribuito di più (source: largest_input). - Beneficiario: il wallet dichiarato, altrimenti l’unico output che non restituisce un resto a un indirizzo di input (
only_non_change_output), altrimenti l’unico output che paga l’importo del trasferimento (amount_match).
chain_details.warnings segnala le incongruenze: declared_originator_not_an_input, declared_beneficiary_not_an_output, beneficiary_output_ambiguous (nessun singolo output poteva essere distinto dagli altri) e beneficiary_output_amount_differs.
utxo su qualsiasi altra catena restituisce 400, e ciascuna lista contiene al massimo 1.000 voci.
Un deposito segnalato usa lo stesso oggetto utxo (vedi Registrazione sunrise dopo il deposito).
Reti con memo e tag
Su XRP, Stellar (XLM), EOS, Cosmos (ATOM) e Hedera (HBAR) un exchange riceve tutti i propri clienti su un unico indirizzo condiviso e li distingue tramite il destination tag o il memo. Il memo fa quindi parte del wallet: invialo comepayment_method.memo sul partecipante, oppure come memo in originator_data / beneficiary_data (alias destinationTag), e Didit confronta insieme indirizzo e memo.
- Una voce della rubrica degli indirizzi con un memo corrisponde solo ai trasferimenti che indicano quel memo. Una voce senza memo corrisponde a tutto l’indirizzo. Un trasferimento che non indica alcun memo non raggiunge mai una voce che ne ha uno: su un indirizzo condiviso, un deposito senza il suo tag non appartiene a nessuno.
- Un X-address di XRP contiene al proprio interno il tag: Didit lo separa nell’indirizzo classico e nel tag (
source: x_address), quindi un wallet registrato in una delle due forme corrisponde a un trasferimento nell’altra. - Ogni memo su un indirizzo condiviso è un metodo di pagamento a sé stante nella transazione.
- Cosa accetta ciascuna rete: un destination tag XRP è un numero intero da 0 a 4294967295 (è accettato un numero JSON); un memo Stellar è un testo fino a 28 byte, un ID a 64 bit o un hash a 32 byte in esadecimale; EOS accetta fino a 256 byte, Cosmos fino a 256 caratteri, Hedera fino a 100 byte. Un memo su una catena che non lo prevede (Bitcoin, catene EVM, Solana, Tron, Litecoin, Bitcoin Cash, Dogecoin, Lightning) restituisce
400.
Lightning
Un pagamento Lightning non ha un indirizzo beneficiario on-chain: il pagatore detiene una richiesta di pagamento. Su un trasferimento crypto su Bitcoin o Lightning,payment_method.account_id può contenere quella richiesta, e Didit identifica il beneficiario a partire da essa senza contattare alcuna rete:
chain_details.beneficiary (source: invoice_payee), sulla catena LIGHTNING, mentre ciò che dichiara la richiesta è in chain_details.lightning.
Quando la richiesta non indica alcun beneficiario, un trasferimento in uscita assume lo stato NOT_APPLICABLE, con il motivo in chain_details.not_applicable_reason e nel suo timeline: LIGHTNING_NO_PAYEE_IDENTIFIER, LIGHTNING_BOLT12_BLINDED_PAYEE oppure LIGHTNING_LNURL_NAMES_NO_PAYEE.
Un valore viene interpretato come Lightning solo su bitcoin, su LIGHTNING, oppure quando non è indicata alcuna catena (un Lightning Address solo su bitcoin o LIGHTNING): su qualsiasi altra catena è l’indirizzo proprio di quella catena.
INTERNAL raggiunge un altro cliente Didit solo tramite un wallet che tale cliente ha dimostrato di controllare con un messaggio firmato o un deposito di prova, e tali prove oggi esistono per Bitcoin, catene EVM, Solana e Tron.
Sulle reti con memo, su Lightning, Litecoin, Bitcoin Cash e Dogecoin, un trasferimento quindi non raggiunge mai un altro cliente Didit tramite INTERNAL.
Il confronto di memo, tag e Lightning continua però a valere per la tua rubrica degli indirizzi: trasferimenti in entrata, depositi segnalati e richieste TRP verso i tuoi wallet.Aggiornare il wallet dell’ordinante
Un prelievo viene spesso dichiarato dal wallet principale del cliente e trasmesso dagli indirizzi che detenevano effettivamente le monete. Registra il wallet da cui i fondi sono effettivamente usciti conPATCH /v3/transactions/{transaction_id}/travel-rule/:
- Solo per i trasferimenti in uscita, e mai per uno in stato
CANCELLEDoEXPIRED(409). - Quando gli input UTXO del trasferimento sono noti, il wallet deve essere uno di essi (altrimenti
400). Invia anchememosu una rete con memo. - Modifica solo il record: nulla viene inviato di nuovo alla controparte e lo stato resta invariato.
chain_details.originatordiventa il nuovo wallet consource: updated, iltimelineregistra il wallet precedente e quello nuovo, e la controparteINTERNALdel trasferimento viene aggiornata allo stesso modo.
Attribuzione tramite analisi blockchain
Quando passi solo l’indirizzo di un wallet, Didit può comunque stabilire chi si trova dall’altra parte. Se nessun rail può instradare il trasferimento, Didit risolve il wallet di destinazione tramite i dati di attribuzione dell’analisi blockchain: la stessa analisi che alimenta lo screening delle transazioni crypto sa quali wallet appartengono a quali exchange e custodi. L’attribuzione viene eseguita solo sui trasferimenti in uscita che riportano sia un wallet di destinazione sia unachain (vedi Campi di risoluzione della controparte); senza una catena viene saltata.
Quando il wallet è attribuito a un’entità nota, Didit:
- Registra l’attribuzione sul trasferimento:
beneficiary_data.counterparty_vasp_nameviene compilato (se non l’hai fornito tu), e i metadati del trasferimento contengono un bloccovasp_attributioncon nome dell’entità, tipo di entità, paese esource: "blockchain_analytics". - Aggiunge l’entità alla directory dei VASP (oppure ne abbina una voce esistente), così l’attribuzione resta stabile tra un trasferimento e l’altro.
- Riesegue una sola volta i rail con il nome attribuito: una voce della directory che già possiede un endpoint TRP fa sì che il trasferimento venga instradato subito, invece di finire in
COUNTERPARTY_VASP_NOT_FOUND.
custom_values.aml_screening_trigger della transazione viene impostato a travel_rule_attribution, così puoi vedere che lo screening è stato eseguito perché richiesto dall’instradamento Travel Rule.
Quando il monitoraggio crypto ha già sottoposto a screening lo stesso wallet per questa transazione, viene riutilizzato il risultato memorizzato: nessuna seconda chiamata all’analisi, nessun secondo addebito.
L’attribuzione non blocca mai la creazione della transazione: se la ricerca tramite l’analisi fallisce o il tuo saldo non è sufficiente a coprirla, il trasferimento prosegue semplicemente verso COUNTERPARTY_VASP_NOT_FOUND e il tentativo non viene addebitato.
Con action: "resend", un’attribuzione già registrata viene riutilizzata invece di essere richiesta di nuovo.
Disattiva l’intero passaggio con vasp_attribution_enabled: false nelle impostazioni.
Consulta Prezzi per sapere come viene fatturata la chiamata di attribuzione.
Quando Travel Rule è disattivato, travel_rule_details (incluso uno status fornito dal chiamante, legacy o attuale) viene comunque registrato sulla transazione, ma in modo passivo - non viene attivato nessun rail.
Usalo per integrare retroattivamente i dati di compliance che hai già tracciato con il tuo processo.
Un trasferimento passivo in uscita non avvia alcuno scambio, quindi viene fatturato come Screening delle transazioni, non sulla voce Travel Rule.
Con Travel Rule attivo, questa richiesta passa tramite il rail EMAIL, perché indica l’email di compliance della controparte e nessun rail precedente può raggiungere il beneficiario:
originator_dataè quello che hai inviato, perché il soggetto dell’esempio non ha una verifica KYC approvata; per un utente verificato Didit lo costruisce a partire dai dati verificati (vedi Dati verificati e provenienza). Il railEMAILmostra al destinatario solo i campi dell’ordinante che condividi indata_sharing_fields.beneficiary_data.chainèETHperché la richiesta non indicava alcuna chain, quindi Didit l’ha ricavata dalla valuta.statusèAPPROVEDperché nessuna regola ha agito sulla transazione; le tue regole possono impostare un altro stato.- Il contatto di compliance riceve il link di ritiro e il trasferimento si completa, non supera il controllo del nome o viene rifiutato quando risponde, oppure scade se non risponde (vedi Ritiro via email).
protocol resta null perché il rail viene scelto dopo la risposta (ad esempio EMAIL quando fornisci counterparty_vasp_email): Ottieni una transazione lo mostra una volta scelto, e ogni successivo webhook travel_rule.status.updated lo riporta in rail.
Se il wallet del beneficiario appartiene a un altro cliente Didit che ne ha dimostrato il controllo, il rail INTERNAL regola l’intero scambio subito dopo la risposta, e quel webhook riporta già COMPLETED (oppure COUNTERPARTY_MISMATCHED_DATA). Quando il nome non corrisponde, il tuo trasferimento è COUNTERPARTY_MISMATCHED_DATA e l’altro cliente non riceve nulla.
Senza counterparty_vasp_email, e quando né i rail né l’attribuzione possono raggiungere il beneficiario, il trasferimento termina più tardi in COUNTERPARTY_VASP_NOT_FOUND con un’azione wallet_ownership sulla transazione.
travel_rule incorporato nella transazione contiene i campi propri del trasferimento (uuid, status, protocol, required, obligations_count, originator_data, beneficiary_data, metadata), ciò che Didit ha risolto e confrontato (chain_details, name_match, data_match, mismatched_fields, e i campi di mascheramento data_masked e data_unmasked), e i campi che indicano a che punto si trova: direction, rail, counterparty_vasp, delivery, discovery, reason e next_actions (vedi Perché un trasferimento è bloccato).
Ogni riga di GET /v3/transactions/ contiene lo stesso blocco, oppure null per una transazione senza trasferimento.
Gli endpoint dedicati ai trasferimenti riportati sotto restituiscono anche questi campi, più ivms_version, ownership_confirmed, deadline_at, timeline e created_at, ma non obligations_count né metadata.COMPLETED dopo averlo trasmesso on-chain:
COMPLETED; altrimenti l’API restituisce 409.
In caso di successo, sia il trasferimento in uscita sia la sua controparte sul rail INTERNAL passano a FINISHED, e il payment_txn_id della transazione viene impostato sull’hash che hai fornito.
Sul rail TRP, Didit invia inoltre l’hash al callback di conferma della controparte.
Per annullare un trasferimento che non ha ancora raggiunto uno stato finale, invia {"action": "cancel"} allo stesso endpoint.
Anche la copia sul rail INTERNAL viene annullata e, sul rail TRP, una volta che la controparte ha approvato la richiesta, Didit invia l’annullamento al suo callback di conferma.
Un trasferimento già in FINISHED, CANCELLED o EXPIRED restituisce 409.
Una richiesta senza né payment_txn_id né un action supportato restituisce 400.
Su un trasferimento inviato tramite GTR, VERIFYVASP o SYGNA, Didit comunica l’hash on-chain (o l’annullamento) alla rete dopo la risposta, con gli stessi nuovi tentativi; il campo delivery della risposta mostra quel messaggio.
Per ritentare un trasferimento in uscita che non ha potuto raggiungere la sua controparte, cioè uno che si trova in COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE o NOT_ENOUGH_COUNTERPARTY_DATA, migliora prima i dati della controparte, ad esempio aggiungendo un travel_address alla voce del wallet di destinazione, un contatto per la voce della controparte nella directory, oppure catalogando il VASP nella directory.
Poi invia {"action": "resend"} allo stesso endpoint.
Didit riavvia il termine per la conferma e rimette in coda la sequenza di instradamento dall’inizio, usando i dati memorizzati sul trasferimento: la risposta mostra nuovamente il trasferimento in AWAITING_COUNTERPARTY (con resend queued nella sua timeline) e l’esito arriva come webhook travel_rule.status.updated.
Un nuovo invio effettuato mentre un tentativo precedente è ancora in corso viene eseguito quando quel tentativo si conclude.
Qualsiasi altro stato, o un trasferimento in entrata, restituisce 409.
{"action": "beneficiary_vasp", "beneficiary_vasp": "<directory VASP id>"} (il id di GET /v3/travel-rule/vasps/).
Il trasferimento viene instradato verso quel VASP e inviato di nuovo.
Solo un trasferimento in uscita in COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE o NOT_ENOUGH_COUNTERPARTY_DATA accetta questa azione; qualsiasi altro stato restituisce 409, e un id sconosciuto restituisce 404.
Perché un trasferimento è bloccato
Un trasferimento inCOUNTERPARTY_VASP_NOT_FOUND o COUNTERPARTY_VASP_NOT_REACHABLE indica il motivo per cui è bloccato e cosa lo fa avanzare, in ogni lettura della sua transazione.
L’oggetto travel_rule di GET /v3/transactions/{transaction_id}/, del 201 di POST /v3/transactions/ e di ogni riga di GET /v3/transactions/ lo contiene, e lo contiene anche l’oggetto del trasferimento restituito dall’endpoint del trasferimento:
reasonè la causa leggibile dalla macchina,""per qualsiasi altro stato.next_actionselenca ciò che fa avanzare il trasferimento,[]per qualsiasi altro stato.deliveryè il messaggio più recente che il trasferimento deve inviare alla controparte:kind,status(QUEUED,SENDING,RETRYING,DELIVEREDoFAILED),rail,attempts,last_error,next_attempt_atedelivered_at, oppurenullquando non ne deve alcuno.discoveryindica dove Didit ha cercato la controparte, con una voce per ogni passaggio eseguito:step,outcome(match,missoskipped),reason,vasp,raileat.
email_undeliverable e delivery_failed provengono da una consegna fallita e compaiono solo su COUNTERPARTY_VASP_NOT_REACHABLE.
Una consegna fallita determina prima reason, quindi una controparte che Didit ha trovato non viene mai segnalata come non trovata.
Gli altri quattro provengono dalla traccia di ricerca, in entrambi gli stati.
reason viene azzerato.
La voce della cronologia di una transizione causata da una consegna fallita riporta lo stesso valore in reason.
Se il provider di posta rifiuta l’email di compliance del trasferimento di esempio sopra, il blocco travel_rule della sua transazione, in forma abbreviata, riporta:
delivery concorda con reason, perché l’invio stesso è stato rifiutato.
Un rifiuto su un sollecito, o un bounce segnalato più tardi, lascia delivery.status su DELIVERED: la prima email è stata effettivamente inviata.
Per sapere perché un trasferimento è bloccato, leggi reason, non delivery.
Per risolvere, fornisci di nuovo l’email di compliance della controparte, poi rilancia:
update_compliance_email salva l’indirizzo come beneficiary_data.counterparty_vasp_email di questo trasferimento: appartiene solo a questo trasferimento e non entra in nessuna voce della directory né in nessun elenco di contatti.
Lo stato non cambia, la cronologia si arricchisce di compliance email updated e il trasferimento mantiene reason: email_undeliverable finché il nuovo invio non spedisce la richiesta al nuovo indirizzo.
Lo accetta solo un trasferimento in uscita in COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE o NOT_ENOUGH_COUNTERPARTY_DATA; ogni altro trasferimento riceve 409, e viene restituito 400 se compliance_email manca o è malformato.
Wallet in autocustodia dichiarati
Quando il tuo cliente ti comunica che la destinazione è un proprio wallet in autocustodia (non custodito), dichiaralo sulla transazione invece di lasciare che l’instradamento scopra che non c’è alcun VASP dietro: imposta il tipo di metodo di pagamento della controparte suunhosted_wallet.
- Non viene tentato nessun rail: non c’è un VASP della controparte con cui scambiare dati. Il trasferimento viene creato direttamente in
UNCONFIRMED_OWNERSHIP. - Quando
auto_wallet_verificationè attivo (impostazione predefinita), Didit genera automaticamente una sessione del widget di verifica della proprietà del wallet collegata alla transazione e la restituisce nel bloccoaction_requireddella transazione; gli SDK la avviano automaticamente all’invio lato client. - Quando il cliente dimostra il controllo del wallet, il trasferimento esegue il confronto del nome del beneficiario e passa a
COMPLETED(oppure aCOUNTERPARTY_MISMATCHED_DATAse il confronto fallisce).
UNCONFIRMED_OWNERSHIP non è uno stato da reinviare: completa la prova di proprietà (oppure annulla) invece di chiamare action: "resend".
Ricezione
Conferma dell’assetto proprietario del wallet
Un trasferimento resta inUNCONFIRMED_OWNERSHIP in due casi:
- Un trasferimento in entrata viene associato a una voce della rubrica degli indirizzi il cui assetto proprietario non è ancora verificato.
- Il wallet della controparte è stato dichiarato in autocustodia (
counterparty.payment_method.method_type: "unhosted_wallet"), in un prelievo in uscita o in un deposito in entrata. Vedi Wallet in autocustodia dichiarati.
confirmed (obbligatorio, booleano) e un wallet_address facoltativo.
L’endpoint accetta un trasferimento in uno qualsiasi di questi stati e restituisce 409 con {"detail": "Transfer is not awaiting ownership confirmation."} per qualsiasi altro stato:
UNCONFIRMED_OWNERSHIP, in entrambe le direzioni.ON_HOLDsu un trasferimento in entrata.UNCONFIRMED_OWNERSHIP,ON_HOLDoCOUNTERPARTY_MISMATCHED_DATAsu un trasferimentoTRPin entrata, così un responsabile della compliance può risolvere manualmente una richiesta della controparte.
INTERNAL, registrazione sunrise o wallet in autocustodia dichiarato):
confirmed: truecontrassegna la voce della rubrica dei wallet corrispondente come con assetto proprietario verificato, poi esegue il confronto dei nomi con ilholder_namedi quella voce:COMPLETEDse il confronto va a buon fine,COUNTERPARTY_MISMATCHED_DATAse non va a buon fine. La controparte sulla railINTERNAL, quando esiste, riceve lo stesso esito. Per un wallet in autocustodia dichiarato,confirmed: trueregistra che il tuo cliente ha verificato chi controlla il wallet della controparte e completa il trasferimento (COMPLETED), in uscita o in entrata. Un trasferimento in entrata il cui deposito è già regolato passa direttamente aFINISHED.confirmed: falseporta entrambi i lati del trasferimento aCOUNTERPARTY_VASP_GENERAL_DECLINE.- La voce corrispondente viene cercata nella tua rubrica degli indirizzi solo in base all’indirizzo, senza considerare la catena.
Risolvere un
ON_HOLDin entrata senza una voce corrispondente crea la voce a partire dabeneficiary_data.wallet_addressdel trasferimento e la contrassegna come verificata. Un wallet in autocustodia dichiarato fa eccezione: il wallet viene registrato nella tua rubrica degli indirizzi come con assetto proprietario verificato, come descritto più sotto. In tutti gli altri casi, una voce mancante restituisce409con{"detail": "wallet address entry no longer available"}, che è anche la risposta a una voce eliminata.
TRP in entrata, la stessa chiamata risponde alla richiesta della controparte:
confirmed: truerichiede un indirizzo di pagamento da restituire, preso dalwallet_addressdella richiesta, poi dalla voce abbinata, poi dabeneficiary_data.wallet_address. Se non ce n’è nessuno dei tre, la richiesta restituisce400con{"wallet_address": ["wallet_address is required to approve."]}. Didit crea o verifica la voce, invia alla controparte il callback di risoluzione della richiesta, impostaownership_confirmede porta il trasferimento aCOMPLETED.confirmed: falseinvia una risoluzione di rifiuto e porta il trasferimento aCOUNTERPARTY_VASP_GENERAL_DECLINE.- Se l’endpoint di callback della controparte non è raggiungibile, la richiesta restituisce
502e il trasferimento mantiene lo stato attuale. In caso di approvazione, la voce del wallet viene comunque creata o contrassegnata come verificata.
COUNTERPARTY_MISMATCHED_DATA.
Se il trasferimento non indica affatto un wallet della controparte, passa wallet_address nel corpo della richiesta.
Quando né il trasferimento né la richiesta forniscono un indirizzo, la richiesta viene rifiutata con 400.
- Un trasferimento su rete a cui è già stata fornita una risposta sulla rete (un trasferimento VerifyVASP, oppure un trasferimento GTR o Sygna Bridge già deciso) restituisce
409(vedi Trasferimenti da una rete).
INTERNAL non resta mai in attesa qui: raggiunge solo un cliente che ha già dimostrato il controllo del wallet. Un trasferimento INTERNAL più vecchio ancora in attesa da prima di questa regola mantiene nascosti i dati del mittente finché non dimostri il controllo del wallet (un messaggio firmato o un deposito di prova), e confermarlo restituisce 409 fino a quel momento. Rifiutarlo funziona ancora.
Quando la controparte ha risposto che il wallet è in autocustodia (oggi il Didit Test VASP fornisce questa risposta in sandbox), la conferma aggiunge il wallet alla tua rubrica degli indirizzi a nome del beneficiario ed esegue il confronto dei nomi: se il confronto va a buon fine, il trasferimento si completa e il wallet viene contrassegnato come verificato.
Trasferimenti da una rete
Didit può ricevere anche trasferimenti Travel Rule che una controparte invia tramiteGTR, VERIFYVASP o SYGNA.
La ricezione viene attivata da Didit separatamente per ogni rete, e oggi nessuna è attiva: richiede anche la registrazione degli endpoint di Didit presso ciascuna rete, e Didit non è ancora membro di queste reti.
I trasferimenti TRUST non possono essere ricevuti.
Quando una rete è attiva, un messaggio da essa consegnato viene gestito così:
- Instradamento. Il messaggio arriva alla tua applicazione quando indica il codice partecipante della tua appartenenza connessa su quella rete. Un messaggio indirizzato all’appartenenza di Didit arriva a te solo se sei l’unico cliente Didit attivo che ha dimostrato il controllo del wallet del beneficiario. Qualsiasi altro messaggio viene rifiutato, così nessun cliente riceve mai il trasferimento di un altro cliente.
- Decisione. Didit crea il trasferimento in entrata nella tua applicazione e lo decide come una richiesta TRP: confronto del wallet, assetto proprietario, confronto dei nomi e
inbound_auto_accept. - Una sola volta. Le reti reinviano un messaggio finché non riceve risposta. Un duplicato riceve la stessa risposta della prima copia, e nulla viene creato o deciso due volte.
- La tua revisione, su
GTReSYGNA. Un trasferimento che attende te (UNCONFIRMED_OWNERSHIP,ON_HOLDoCOUNTERPARTY_MISMATCHED_DATA) si decide conPOST .../travel-rule/ownership/:confirmed: truelo approva (passawallet_addressquando il trasferimento non ne indica uno) econfirmed: falselo rifiuta. Didit risponde alla rete dopo la risposta, con gli stessi nuovi tentativi. Un trasferimento già risposto restituisce409. - Nessuna risposta successiva su
VERIFYVASP. VerifyVASP riceve la risposta nel momento in cui la chiede, quindi un trasferimento che richiederebbe la tua revisione viene rifiutato subito e non può essere deciso in seguito (409).
Dati della controparte mascherati
Finché la titolarità del wallet non è confermata, i dati personali della controparte su un trasferimento in entrata vengono restituiti mascherati anziché omessi. Viene mantenuta la prima lettera di ogni parola, mentre wallet, blockchain e instradamento VASP restano leggibili.data_masked è true, e la controparte nel dettaglio della transazione, nell’elenco e nell’esportazione CSV viene mascherata allo stesso modo.
Una volta confermata la titolarità compaiono i valori reali e data_unmasked registra la voce di audit:
reason è ownership_confirmed, wallet_proof, address_book_match, own_verified_wallet, inquiry_approved (hai approvato una richiesta TRP o un messaggio GTR o Sygna), known_payment_method (il wallet dell’utente finale presente nei tuoi registri ha dato risposta) oppure travel_address (il Travel Address per wallet ha indicato il wallet).
Un trasferimento INTERNAL in entrata riporta data_unmasked con reason: wallet_proof fin dalla creazione, perché solo un destinatario che ha dimostrato il possesso del wallet ne riceve uno.
actor è l’email dell’utente della console o l’etichetta della chiave API, e resta vuoto per una decisione automatica.
Il report Registro dei trasferimenti Travel Rule (CSV e PDF) maschera i nomi di un trasferimento in entrata allo stesso modo finché la titolarità non è confermata. I report che invii a un’autorità di vigilanza, come il file XML goAML e il report normativo in PDF, riportano i dati reali della controparte.
Riscontro sulle mancate corrispondenze
Un trasferimentoCOUNTERPARTY_MISMATCHED_DATA ora indica i campi che non corrispondono.
data_match contiene il confronto e mismatched_fields elenca i campi.
Entrambi riportano solo nomi di campi e risultati, mai valori, così restano leggibili mentre i dati sono mascherati:
TRP dopo una mancata corrispondenza indica al VASP di origine quali campi differiscono, ad esempio “I dati del beneficiario non corrispondono al titolare del wallet: nome”.
Ciò che apprende l’altro VASP è limitato di proposito: finché il nome è errato, il nome è l’unico campo segnalato (mismatched_fields: ["name"], con ogni altro campo not_compared), e quando il nome corrisponde, viene indicato ogni campo che differisce. Questo vale per il lato mittente di uno scambio INTERNAL e per un rifiuto TRP.
Un nome mancante da entrambi i lati risulta not_compared e non è una mancata corrispondenza, e un paese corrisponde in base a ciò che indica, quindi ES e ESP coincidono.
Punteggio di corrispondenza del nome
Ogni trasferimento il cui nome è stato confrontato riportaname_match, e la voce della cronologia che lo ha deciso riporta lo stesso oggetto accanto al proprio detail:
scoreè la somiglianza dei due nomi completi, da 0 a 100, e0se uno dei due è vuoto.matchedè il risultato secondostrictness, quindi i due valori possono non coincidere:FUZZYdecide in base al proprio rapporto di somiglianza di0.85.matched_namessono le parole del nome del trasferimento trovate nell’altro nome;mismatched_namessono le parole che un lato ha e l’altro no.methodènone,exact_token,token_subset,token_containmentosequence_ratio, perNONE,STRICT,DEFAULT,CONTAINSeFUZZY.compared_withèwallet_holder(il titolare registrato per il wallet) oppurecounterparty_vasp(il nome fornito dalla controparte nella pagina di risposta via email, o la risposta del Didit Test VASP).- L’esito del trasferimento segue
data_match, che confronta ogni campo, quindi un trasferimento può risultareCOUNTERPARTY_MISMATCHED_DATAmentrename_match.matchedètrue. name_matchè presente nell’oggetto trasferimento restituito dagli endpoint Travel Rule e nel campotravel_ruleincorporato nella transazione, ed ènullfinché non è stato confrontato un nome. L’elenco dei trasferimenti e i webhook non lo riportano.- I nomi restano nascosti finché le parti sono mascherate, e sulla copia dell’altro cliente di uno scambio
INTERNAL.
Messaggi e richieste di documenti
Due VASP possono risolvere un trasferimento contestato all’interno di Didit anziché via email.GET e POST /v3/transactions/{transaction_id}/travel-rule/messages/ elencano e inviano messaggi su un trasferimento:
kindèMESSAGE(predefinito) oDOCUMENT_REQUEST. Una richiesta di documenti richiede almeno una voce inrequested_documents(fino a 10); un messaggio richiede unbody(fino a 5000 caratteri) o un file.reply_toindica un messaggio precedente dello stesso trasferimento. Una risposta dall’altro lato che contiene un documento soddisfa la richiesta di documenti a cui risponde, e su di essa viene impostatofulfilled_at. Una tua risposta non soddisfa mai una tua richiesta.- Invia una richiesta multipart con
filesper allegare fino a 5 file da 10 MB ciascuno, in formato PDF, PNG, JPEG o WebP. Didit verifica il contenuto di ogni file, non solo il tipo dichiarato, e qualsiasi altro file restituisce400sufiles(“Attach PDF, PNG, JPEG or WebP files only.”). - Un trasferimento contiene fino a 100 messaggi, di cui fino a 20 possono avere allegati (ciascuno con fino a 5 file), contando entrambi i lati; oltre uno dei due limiti la richiesta riceve la risposta
400. Gli allegati dei messaggi non contano tra i documenti propri della transazione. - I messaggi funzionano sui canali
INTERNALedEMAIL. SuINTERNAL, l’altro cliente Didit vede il messaggio dal proprio lato della coppia. SuEMAIL, alla controparte viene inviata un’email e risponde nel portale di ritiro. Se non è possibile inviare questa email di notifica, il messaggio viene comunque salvato e la richiesta riceve la risposta201. - La richiesta riceve la risposta
409con il motivo indetailper un trasferimento suTRP,GTR,TRUST,VerifyVASPoSygna(questi protocolli non prevedono messaggi), un trasferimento senza ancora una controparte, un trasferimentoINTERNALi cui dati non corrispondevano al titolare del wallet (nulla è arrivato al destinatario), un trasferimentoINTERNALil cui destinatario non ha ancora dimostrato il controllo del wallet (da entrambi i lati, finché non lo fa), un trasferimentoEMAILla cui controparte non ha più un indirizzo email di compliance, e un trasferimentoEMAILil cui link di ritiro è scaduto o il cui trasferimento è chiuso. - Nessun webhook viene inviato quando la controparte risponde. Leggi l’endpoint dei messaggi.
- L’email che informa la controparte di un nuovo messaggio viene inviata in inglese.
Rubrica degli indirizzi wallet
Registra i wallet che controlli affinché i trasferimenti in entrata (canaleINTERNAL, richieste TRP in entrata e registrazioni successive al deposito) possano essere confrontati con essi, tramite POST/GET /v3/travel-rule/wallet-addresses/ e PATCH/DELETE /v3/travel-rule/wallet-addresses/{entry_uuid}/.
PATCH accetta holder_name, holder_vendor_data, entity_type e travel_address, e restituisce solo questi quattro campi.
DELETE elimina la voce (204): il suo indirizzo torna disponibile per una nuova registrazione e smette immediatamente di abbinarsi ai nuovi trasferimenti.
memo su una rete con memo e si applica per chain.
Quando un trasferimento riporta una chain, una voce viene abbinata solo se il suo chain è lo stesso valore (senza distinguere maiuscole e minuscole) oppure è vuoto.
I nomi delle chain vengono confrontati come testo, non tradotti: quindi una voce salvata come ethereum non viene abbinata a un trasferimento la cui chain è ETH.
I trasferimenti in uscita prendono la chain da beneficiary_data.chain, poi da transaction_details.crypto_params.crypto_chain, poi da custom_properties.crypto_chain, poi dalla valuta (ad esempio ETH, oppure per USDT e USDC la chain dedotta da payment_reference_id), impostata solo quando è una chain riconosciuta da Didit, e le registrazioni post-deposito dal loro campo chain, in minuscolo.
Le richieste TRP in entrata ignorano la chain: si abbinano per indirizzo oppure, quando la richiesta non indica alcun wallet, per nome del beneficiario tra le tue voci verificate.
POST .../travel-rule/ownership/ abbina anche solo per indirizzo.
Quando più voci corrispondono, il canale INTERNAL e le registrazioni post-deposito preferiscono una voce con assetto proprietario verificato, poi la più vecchia, mentre la ricerca TRP in uscita prende la voce più vecchia che memorizza un Travel Address.
Le richieste TRP in entrata e l’endpoint dell’assetto proprietario accettano una qualsiasi delle voci corrispondenti, quindi mantieni una sola voce per indirizzo dove possibile.
Il canale INTERNAL non abbina alcuna voce quando esistono voci verificate per l’indirizzo in più di un’altra applicazione.Importazione di wallet in blocco
Importa fino a 10,000 wallet in una sola chiamata conPOST /v3/travel-rule/wallet-addresses/import/, in formato JSON ({"entries": [...]} oppure un semplice array) o come file CSV in UTF-8 di al massimo 5 MB con una riga di intestazione.
Una riga indica un wallet tramite il suo address, tramite address_hash (lo SHA-256 dell’indirizzo convertito in minuscolo, 64 caratteri esadecimali o 44 caratteri base64), o entrambi, più uno qualsiasi dei campi della voce descritti sopra.
Invia solo l’hash per registrare un wallet senza rivelarne l’indirizzo: abbina i trasferimenti verso quell’indirizzo come qualsiasi altra voce e può essere dimostrato con il widget di verifica dell’assetto proprietario del wallet.
created, existing (lo stesso wallet, chain e memo sono già presenti nel registro e non sono stati modificati), duplicate (ripete una riga precedente, indicata in duplicate_of_row) oppure failed con i relativi errors.
Una riga errata non fa fallire le altre: la risposta è 200 quando nessuna riga è fallita e 207 quando ne è fallita una, con i conteggi in total, created, existing, duplicate e failed.
Una cella CSV vuota viene considerata come non inviata, e le colonne che l’importazione non legge vengono ignorate, quindi un’esportazione da un altro strumento può essere importata così com’è.
Su GET /v3/travel-rule/transfers/, ogni riga riporta originator_memo e beneficiary_memo accanto ai due wallet.
Invio via email alle controparti non raggiungibili
Quando nessun canale di protocollo può raggiungere la controparte, Didit ricorre aEMAIL: invia un link monouso per il ritiro a beneficiary_data.counterparty_vasp_email (oppure a un’email ricavata da beneficiary_data.counterparty_vasp_name tramite il registro della directory VASP).
Il destinatario non ha bisogno di un account Didit né di una chiave API: il token del link è l’autenticazione.
Ecco come viene inviata la richiesta:
- Ai destinatari giusti. Un
counterparty_vasp_emailche passi è l’unico destinatario. Altrimenti Didit scrive a un massimo di tre indirizzi: i contatti della controparte che non hanno subito rimbalzi (prima i tuoi, poi i contatti della piattaforma, quelli che hanno risposto prima), poi l’email di conformità della voce della directory quando resta uno slot libero. Ogni indirizzo riceve una propria email. - A tuo nome. L’email proviene dall’indirizzo di Didit come “la tua ragione sociale via Didit”, nella lingua della giurisdizione della controparte (inglese quando non è nota), e il link apre la pagina di risposta in quella lingua. Non ricevi una copia: segui la cronologia del trasferimento.
- Con i solleciti. Finché la controparte non risponde, Didit la sollecita 72, 24 e 6 ore prima della scadenza, almeno 12 ore dopo la richiesta o l’ultimo sollecito, e mai dopo la scadenza.
- Con la gestione dei rimbalzi. Un rimbalzo o una segnalazione di spam contrassegna come non valido il contatto raggiunto, indicandone il motivo, e la cronologia del trasferimento lo registra. Un contatto della piattaforma diventa quindi non valido per ogni cliente Didit; il contatto della tua applicazione solo per la tua applicazione. Quando il servizio di invio email di Didit smette di inviare del tutto a un indirizzo (dopo un rimbalzo permanente, una segnalazione di spam o una cancellazione dell’iscrizione), ogni contatto a quell’indirizzo viene contrassegnato come non valido (
suppressed), e tali contatti tornano validi quando l’invio a quell’indirizzo riprende. Quando non resta alcun indirizzo a cui scrivere, il trasferimento diventaCOUNTERPARTY_VASP_NOT_REACHABLEcon il motivo del server di posta ricevente nella sua cronologia. Un rimbalzo permanente o una segnalazione di spam sulcounterparty_vasp_emailche hai passato produce questo esito subito, perché è l’unico destinatario; un rimbalzo temporaneo (soft_bounce) su di esso, o sull’email di conformità della voce della directory, lascia la richiesta aperta per i solleciti.
reference è lo uuid del trasferimento. originator_data e l’ivms_request IVMS 101 costruito a partire da esso contengono solo i campi dell’ordinante che condividi in data_sharing_fields; il nome e il wallet sono sempre inclusi. fiat_amount e fiat_currency sono vuoti se non hai inviato un valore convertito, contact riporta il valore ?contact= del link, e decline_reasons elenca i valori accettati da decline_reason. join_invitation.eligible è true finché la controparte ha un invito attivo a unirsi a Didit; il link di invito viaggia solo nell’email.
Questo endpoint restituisce l’importo memorizzato così com’è, quindi include tutte e 18 le cifre decimali invece della forma troncata usata nell’oggetto di dettaglio della transazione.
decision è accept oppure decline.
In caso di accept, il beneficiary_name fornito viene confrontato con beneficiary_data.name del trasferimento secondo la tua regola sul nome: COMPLETED in caso di corrispondenza, COUNTERPARTY_MISMATCHED_DATA altrimenti. La controparte può invece inviare una risposta IVMS 101 completa come ivms_response; in quel caso il nome del beneficiario da essa indicato prevale su beneficiary_name.
In caso di decline, il trasferimento passa a COUNTERPARTY_VASP_GENERAL_DECLINE. La controparte può indicare un decline_reason tra quelli in decline_reasons, con un decline_detail (fino a 512 caratteri, obbligatorio per other), e la cronologia del trasferimento lo registra, per esempio counterparty declined: The beneficiary is not our customer.
La risposta è il {"status": "..."} risultante, più decline_reason dopo un rifiuto. Una volta che la controparte ha risposto, entrambi gli endpoint restituiscono 410.
Entrambi gli endpoint restituiscono 404 per un token sconosciuto e 410 quando la finestra si chiude, cioè quando il trasferimento è uscito da AWAITING_COUNTERPARTY oppure quando è trascorso il termine di conferma (confirmation_timeout_hours dopo la creazione o l’ultimo reinvio).
La controparte legge e risponde tramite il link di ritiro con GET e POST /v3/travel-rule/pickup/{token}/messages/.
Non richiede una chiave API, accetta solo allegati PDF, PNG, JPEG o WebP, e restituisce 410 quando il link scade o il trasferimento si chiude.
Un messaggio inviato da te mostra il nome del tuo VASP come author e come uploaded_by dell’allegato, mai la persona o la chiave API che lo ha inviato.
Depositi non abbinati
Un deposito in entrata può arrivare prima che i dati Travel Rule del VASP di origine siano disponibili. Tale deposito resta inAWAITING_COUNTERPARTY o NOT_ENOUGH_COUNTERPARTY_DATA finché i dati non arrivano.
Elenca i depositi che sono ancora in attesa con una chiave API che ha il privilegio transactions:
GET /v3/travel-rule/transfers/, limitate ai depositi in entrata che attendono i dati del VASP di origine.
Quando i dati sono arrivati come messaggio ricevuto separato, abbinali tu stesso:
{transaction_uuid} è il deposito.
transaction_id è la transazione del messaggio Travel Rule ricevuto.
La chiamata restituisce { "deposit": ..., "message": ... }.
Risponde 404 quando una delle due transazioni non esiste più, e 409 con travel_rule_match_conflict (“Questo deposito non può più essere abbinato.”) quando una delle due parti è già passata oltre.
Registrazione postuma del deposito (sunrise)
Quando un deposito in criptovalute viene regolato on-chain prima che avvenga qualsiasi scambio Travel Rule, perché il VASP mittente non era raggiungibile oppure stai recuperando depositi storici, registralo a posteriori conPOST /v3/travel-rule/inbound/.
originating_vasp.travel_address deve essere un Travel Address reale e con checksum valido: un valore segnaposto restituisce 400 con "Invalid travel address.".
originating_vasp.lei deve essere vuoto oppure composto da 20 caratteri nel formato LEI (18 lettere o cifre, seguite da 2 cifre); qualsiasi altro valore restituisce 400 con "Invalid LEI: expected 20 alphanumeric characters (ISO 17442).".
Didit verifica solo questo formato, non le cifre di controllo ISO 17442.
travelRule in entrata (oppure riutilizza un deposito in entrata già inviato con lo stesso hash e wallet, se non ha ancora alcun trasferimento Travel Rule) e risolve il trasferimento confrontando indirizzo e memo con la tua rubrica degli indirizzi dei wallet:
- Nessuna voce corrispondente ->
ON_HOLD. Risolvilo conPOST .../travel-rule/ownership/:confirmed: trueaggiunge il wallet alla tua rubrica come verificato ed esegue il confronto del nome; in caso di corrispondenza il trasferimento passa aCOMPLETED, poi aFINISHED. - La voce esiste ma la proprietà non è dimostrata ->
UNCONFIRMED_OWNERSHIP. - Il nome del beneficiario non corrisponde al
holder_namedella voce ->COUNTERPARTY_MISMATCHED_DATA. - Voce verificata e nome corrispondente ->
COMPLETED, poi immediatamenteFINISHED(il deposito è già stato regolato).
txn_id della nuova transazione è tr-in-, seguito dai primi 80 caratteri del txid e da un hash di 12 caratteri calcolato su txid e wallet.
created è true (HTTP 201) quando questa chiamata ha registrato il deposito, e false (HTTP 200) quando lo stesso txid e lo stesso wallet_address erano già registrati; in quel caso il trasferimento esistente viene restituito invariato.
Nel percorso con voce verificata, entrambe le transizioni avvengono prima che l’endpoint risponda, quindi la risposta sincrona mostra già lo stato finale FINISHED; il passaggio intermedio COMPLETED resta comunque registrato nella timeline del trasferimento.
Ogni transizione genera un webhook travel_rule.status.updated (sia COMPLETED sia FINISHED ne generano uno).
Quando Didit ha creato una nuova transazione, invia prima transaction.created e poi questi eventi.
La registrazione non comporta alcun costo per Travel Rule o monitoraggio.
Quando il monitoraggio crypto è attivo e il chain è uno di quelli che Didit può analizzare, anche un deposito appena creato viene sottoposto a screening e fatturato una sola volta alla tariffa Wallet Verification & Screening.
Widget di verifica della proprietà del wallet
Per far uscire un trasferimento daUNCONFIRMED_OWNERSHIP, oppure per verificare in anticipo un wallet prima dell’arrivo di qualsiasi trasferimento, genera un widget ospitato per la verifica della proprietà del wallet con POST /v3/travel-rule/widget-session/ e invia al tuo cliente l’url restituito. Il widget dimostra il controllo del wallet tramite firma di messaggi (inclusi gli account smart contract EVM, tramite ERC-1271 e ERC-6492), un test Satoshi, uno screenshot oppure un’autodichiarazione, quindi contrassegna come verificata la voce corrispondente nella rubrica, così lo scambio può proseguire.
Lo screenshot fa eccezione: da solo non verifica mai il wallet, quindi il tuo team di compliance lo esamina e conferma un trasferimento in UNCONFIRMED_OWNERSHIP con POST .../travel-rule/ownership/.
Per il flusso completo, i metodi di prova e l’avvertenza importante che il widget deve essere aperto in un browser reale, mai all’interno di una webview di un SDK mobile, consulta Widget di verifica della proprietà del wallet.
Directory
GET /v3/travel-rule/vasps/ cerca nella directory dei VASP: le voci della directory condivisa più i membri della rete Didit. Ogni riga indica come la tua applicazione può raggiungere quel VASP oggi.
search corrisponde a un frammento del nome o di un alias, a un LEI esatto oppure a un dominio (counterparty.example o un URL su quel dominio). Restringi i risultati con:
risk e responsiveness restituiscono solo voci della directory. I risultati sono ordinati per nome e paginati con limit (predefinito 50) e offset. Una rete, un codice paese, una fascia di rischio o uno stato di reattività sconosciuti restituiscono 400 con il nome del campo. GET /v3/travel-rule/vasps/{vasp_id}/ restituisce una sola riga tramite il suo id. Il tuo profilo VASP non compare mai nei tuoi risultati.
dd_status, dd_score, dd_score_breakdown, dd_assessed_at, dd_score_semantic, risk_level, responsiveness e essential_checks contengono la valutazione di due diligence condivisa di una voce della directory. decision, entity_screening e questionnaires sono i registri che la tua applicazione tiene sul VASP, e nessun altro cliente li vede. Vedi Due diligence sulle controparti per il significato di ciascuno, e basati su di essi tramite i campi delle regole sulle controparti invece di creare rami condizionali in linea. I membri della rete Didit non ricevono un punteggio: dd_status è COMPLETED, dd_score è null, risk_level è vuoto e il dettaglio è vuoto.
Route
routes elenca i modi in cui la tua applicazione può consegnare al VASP, nell’ordine in cui la scala di instradamento li prova, e reachable è true quando almeno una route è available:
TRPquando la voce contiene un endpoint TRP verificato dalla directory.GTR,TRUST,VERIFYVASP,SYGNAquando una rete elenca il VASP con un codice. La route èavailablesolo quando la tua applicazione può inviare tramite quella rete oggi (via: own_membershipper la tua appartenenza collegata,via: didit_membershipper quella di Didit). Altrimenti èunavailableconreason: no_membershiporeason: network_switched_off, e non viene mai mostrata come un modo per raggiungere il VASP. Le adesioni di Didit alle reti non sono ancora attive, quindi oggi una route di rete è disponibile solo tramite un’adesione che hai collegato nel Marketplace.EMAILquando la voce ha un contatto di compliance.INTERNALper un membro della rete Didit.
TRISA compare in networks e ti indica chi è il VASP su TRISA, ma Didit non ha un canale TRISA, quindi non è mai una route.
Un’applicazione in sandbox invia solo al Didit Test VASP, quindi nessuna route della directory è disponibile per essa: ogni route è unavailable con reason: sandbox_application, ogni riga ha reachable: false, e reachable=true non restituisce righe.
Brand e relative entità
Un brand che opera tramite più entità regolamentate è una sola riga i cuientities sono le entità giuridiche che ricevono i suoi trasferimenti; una riga di entità punta al proprio brand tramite umbrella. Un trasferimento che indica il brand va a una delle sue entità, scelta tra tutte: quella nella giurisdizione indicata in beneficiary_data.counterparty_vasp_jurisdiction, altrimenti l’entità collegata all’indirizzo del wallet di destinazione dall’attribuzione dell’analisi blockchain, altrimenti l’unica entità del brand quando non viene indicata alcuna giurisdizione. Solo a quel punto l’entità deve essere raggiungibile; se non lo è, il trasferimento non va mai a un’altra entità né al brand. Quando nessuna entità corrisponde (due corrispondono ugualmente, oppure la giurisdizione indicata non è quella di nessuna di esse), si usa la route propria del brand e, in sua assenza, il trasferimento è COUNTERPARTY_VASP_NOT_FOUND. La scelta di quale entità giuridica riceve i dati dell’originatore non è mai una supposizione e non viene mai decisa in base a quale entità ha un contatto.
Più voci con lo stesso nome, come società del gruppo che condividono una denominazione commerciale, si distinguono con la stessa regola: quella nella giurisdizione indicata, altrimenti quella collegata dall’attribuzione dell’analisi blockchain. Quando nessuna delle due ne sceglie una, non ne viene usata nessuna, e i dettagli contano come se non indicassero alcuna voce della directory.
Contatti
contacts sono gli indirizzi a cui scrive la route EMAIL. I contatti con scope: platform servono ogni cliente Didit: Didit li cura (source: staff), oppure un indirizzo su un dominio proprio del VASP ha risposto a una richiesta tramite il suo link di risposta (source: learned). I contatti con scope: application sono riservati alla tua applicazione: quelli che aggiungi tu (source: application) e un indirizzo esterno ai domini propri del VASP che ha risposto a una tua richiesta (source: learned). Un trasferimento invia un’email prima al contatto della tua applicazione, poi a un contatto della piattaforma che ha già risposto in passato (con verified_at valorizzato), poi agli altri.
Gestisci i contatti della tua applicazione con l’API dei contatti delle controparti:
GET /v3/travel-rule/counterparty-contacts/elenca ogni contatto a cui la tua applicazione può inviare, inclusi i contatti della piattaforma e quelli con consegna non riuscita, in ordine dal più recente, con paginazione tramitelimiteoffset. Filtra con?counterparty=e uniddi voce della directory; un valore che non è un UUID restituisce400.POSTaggiunge un contatto privato (counterparty,email,namefacoltativo) e restituisce201. Aggiungere un indirizzo che la voce ha già tra i tuoi contatti restituisce quel contatto. Una voce sconosciuta restituisce400("No directory entry with this id.").DELETE /v3/travel-rule/counterparty-contacts/{contact_uuid}/elimina uno dei tuoi contatti (204). I contatti della piattaforma non possono essere eliminati e restituiscono404.
is_invalid: true, con invalid_reason (hard_bounce, soft_bounce, spam_complaint o suppressed), invalid_detail e invalid_at, e il canale EMAIL lo salta. created_by è vuoto nei contatti della piattaforma e in quelli aggiunti tramite una chiave API.
Come le voci entrano nella directory
- Il registro interinale ESMA dei prestatori di servizi per le cripto-attività MiCA, letto ogni settimana: nome di ciascun prestatore, LEI e Stato membro di origine.
- La directory pubblica TRISA, letta ogni settimana: l’identità di ciascun membro, il suo paese e la sua voce TRISA. Una voce che la directory smette di mostrare per tre settimane viene rimossa.
- Il registro LEI globale completa il LEI, gli altri nomi legali e il paese di una voce, e trova il LEI di una voce tramite il suo nome legale esatto nel suo paese.
- Attribuzione tramite analisi blockchain aggiunge o associa il VASP che possiede un wallet di destinazione, e mantiene il nome attribuito come alias.
- Lo staff di Didit cura le voci: identificativi di instradamento e voci di rete che ha verificato, contatti per la compliance, alias, marchi e relative entità, duplicati uniti e voci nascoste.
originating_vasp in entrata o un Travel Address, restano sul trasferimento di quel cliente e non modificano mai una voce condivisa. Le voci vengono associate prima per LEI, poi per nome esatto o alias, e vengono arricchite anziché duplicate.
La rete Didit
Il tuo profilo VASP è un membro della rete Didit, quindi altri clienti Didit lo trovano nella directory e nel selettore VASP dell’utente finale, solo quando tutte queste condizioni sono soddisfatte:- la tua applicazione è in produzione (non sandbox) e Travel Rule è attiva;
is_discoverableètrueelegal_nameè impostato;compliance_emailè impostato e confermato: invia la conferma conPOST /v3/travel-rule/settings/compliance-email/confirmation/e apri il link ricevuto via email. Cambiare l’indirizzo richiede una nuova conferma;- Didit non ha contrassegnato l’applicazione come di test, demo o interna.
INTERNAL invia a un wallet che hai dimostrato di possedere, come descritto in Invio di un trasferimento: richiede che la tua applicazione sia in produzione, Travel Rule attiva e is_discoverable, non il resto dell’elenco.
GET /v3/travel-rule/settings/ restituisce didit_network: listed, compliance_email_confirmed, e in missing ciascuna condizione ancora non soddisfatta (travel_rule_off, sandbox_application, not_discoverable, legal_name_missing, compliance_email_missing, compliance_email_unconfirmed, excluded_by_staff, internal_organization).
Identificativi di instradamento
L’instradamento in uscita consulta una voce della directory ogni volta che il tuo trasferimento indica la controparte tramitecounterparty_vasp_lei o counterparty_vasp_name (funziona anche un alias). Una voce contiene un identificativo per ciascuna rete su cui può essere raggiunta, un endpoint TRP verificato e i suoi contatti per la compliance, e routes mostra quali di essi la tua applicazione può usare. Puoi sempre aggirare la directory su un singolo trasferimento passando i campi espliciti descritti in Campi di risoluzione della controparte.
Due diligence sulla controparte
Prima che i fondi dei tuoi clienti raggiungano un altro VASP, devi sapere chi è quel VASP e se lo accetti. La due diligence su una controparte ha due livelli:- La valutazione condivisa. Ogni voce della directory riporta un punteggio di due diligence, il suo livello di rischio, uno stato di reattività e un report sui controlli essenziali. Didit li calcola dai dati della piattaforma, quindi ogni cliente vede gli stessi valori.
- I tuoi registri. La tua decisione sul VASP, il tuo screening di sanzioni e notizie negative su di esso e i questionari di due diligence scambiati con esso appartengono solo alla tua applicazione. Nessun altro cliente li vede e non modificano mai la voce condivisa.
id mostrato dalla directory.
Punteggio e livello di rischio
dd_score va da 0 a 100 e un valore più alto significa più sicurezza. Ogni risultato lo dichiara in dd_score_semantic, che vale sempre higher_is_safer. risk_level è la fascia in cui ricade il punteggio:
dd_score_breakdown mostra ciascuna come {points, max, reason, detail}: max è il peso della componente, reason un codice leggibile dalla macchina che puoi tradurre, e detail una spiegazione in inglese su una riga.
history considera le stesse richieste della reattività, senza finestra temporale: uno scambio COMPLETED o FINISHED è un successo, mentre EXPIRED, COUNTERPARTY_MISMATCHED_DATA o COUNTERPARTY_VASP_GENERAL_DECLINE sono un insuccesso. Un annullamento è un atto del mittente e non conta mai.
Didit ricalcola la valutazione quando uno scambio con la voce viene completato, terminato, scaduto, reso non corrispondente o rifiutato, quando la voce viene aggiornata o curata, e per ogni voce durante l’aggiornamento settimanale della directory. dd_assessed_at indica quando è stata eseguita l’ultima volta; una voce non ancora valutata non ha dd_assessed_at, ha dd_score pari a 0 e risk_level vuoto, quindi leggi risk_level invece del punteggio grezzo. I membri della rete Didit non vengono valutati: il loro dd_score è null, il loro risk_level è vuoto e il loro dd_score_breakdown è vuoto.
Controlli essenziali
essential_checks è un breve report su quattro controlli che Didit esegue su ogni voce della directory, usando solo le fonti verificate della piattaforma, mai dati segnalati da un cliente:
checks riporta il proprio status (pass, fail, oppure unknown quando nessuna fonte disponibile consente di determinarlo), un reason leggibile dalla macchina e un detail in inglese su una riga. passed, failed, unknown e total li contano, level vale essential e checked_at indica quando è stato generato il report. La componente essentials assegna il punteggio in base alla quota dei controlli definiti che risultano superati, quindi un controllo unknown non conta né a favore né contro la voce. Il report è vuoto finché il primo aggiornamento settimanale della directory non controlla una voce, ed è sempre vuoto per un membro della rete Didit.
Reattività
responsiveness indica se il VASP risponde alle richieste della Travel Rule:
total conta le richieste che i clienti Didit hanno avviato verso il VASP negli ultimi 90 giorni e il cui esito è definito, mentre answered conta quelle a cui ha risposto:
- Conteggiate: le richieste inviate tramite un canale di rete o di protocollo, e le richieste inviate via email a un indirizzo condiviso, cioè l’indirizzo di compliance della voce o un contatto della piattaforma.
- Mai conteggiate: una richiesta inviata via email a un indirizzo digitato da un cliente, o a un contatto privato di un cliente. Quello scambio resta nello storico trasferimenti del cliente e non etichetta mai il VASP per tutti gli altri.
- Con risposta:
COMPLETED,FINISHED,COUNTERPARTY_VASP_GENERAL_DECLINEoppureCOUNTERPARTY_MISMATCHED_DATA. Un rifiuto o una mancata corrispondenza è una risposta: il VASP ha interagito. - Senza risposta:
EXPIRED. - Non conteggiate in nessuno dei due casi: ogni altro stato. Una richiesta
CANCELLEDè un atto del mittente,COUNTERPARTY_VASP_NOT_REACHABLEpuò essere un problema dal lato del mittente, e una richiesta ancora in corso non ha un esito definito.
UNKNOWN con conteggi pari a zero. Agisci su una controparte non reattiva con la politica di non risposta oppure con il preset travel-rule-counterparty-unresponsive.
La tua decisione su una controparte
Registra il verdetto del tuo team di compliance su una controparte conPUT /v3/travel-rule/vasps/{vasp_id}/decision/:
- La decisione è privata per la tua applicazione: un altro cliente non la vede mai, e non modifica mai la voce condivisa.
- Una decisione da sola non cambia nulla e non cambia mai l’instradamento di un trasferimento. Raggiunge le tue transazioni tramite il campo di regola
counterparty_dd_status: installa i preset oppure scrivi una tua regola su di esso. - Una decisione su un marchio copre ciascuna delle sue entità che non ha una decisione propria, e l’entità mostra il marchio in
inherited_from. Una decisione sull’entità sostituisce quella del marchio per quell’entità. GETrestituisce la decisione applicabile, oppure{"decision": null}.DELETEcancella la tua decisione e restituisce quella che si applica dopo: la decisione del marchio per un’entità, altrimentinull. Risponde404quando la tua applicazione non ha una decisione propria sulla controparte.reasonè facoltativo, fino a 255 caratteri, e ogniPUTlo sostituisce.decided_byè l’utente della console che ha preso o modificato per ultimo la decisione, ed è vuoto quando l’ha fatto una chiave API.
Screening della controparte
Lo screening della controparte verifica il VASP della controparte in quanto azienda, rispetto a sanzioni e notizie negative. Richiede l’attivazione e comporta un costo: attivalo concounterparty_screening_enabled nelle tue impostazioni. Finché è disattivato, non viene eseguito alcuno screening né addebitato alcun costo.
- Fatturazione. Ogni nuovo screening costa il prezzo Screening AML aziendale della tua organizzazione.
GET /v3/travel-rule/vasps/{vasp_id}/screening/restituisce questoprice,fresh_dayse se lo screening èenabled, senza alcun costo. Uno screening di meno di 30 giorni è recente:POSTlo restituisce di nuovo con200eoutcome: reusedsenza addebitare nulla, a meno che tu non inviirefresh: true. Un nuovo screening restituisce201conoutcome: screened. Le applicazioni sandbox non vengono mai sottoposte a screening né addebitate. - Screening automatico. Con lo screening attivo, Didit sottopone a screening anche la controparte raggiunta da uno scambio in uscita quando lo scambio inizia, prima che le tue regole valutino la transazione, con lo stesso riutilizzo e la stessa fatturazione. Un rifiuto o un errore in questa fase non fa mai fallire il trasferimento.
- Esito.
statusèApprovedquando non c’è alcuna possibile corrispondenza che richieda attenzione, eIn ReviewoDeclinedper una possibile corrispondenza con sanzioni o notizie negative.flaggedètruementre uno screening recente èIn ReviewoDeclined. - Effetto. Finché il tuo ultimo screening di una controparte è segnalato e lo screening resta attivo,
counterparty_risk_levelvaleHIGHnelle tue regole, quindi il presettravel-rule-counterparty-high-risk, una volta installato, trattiene i suoi trasferimenti. Ilrisk_levelcondiviso nella directory non cambia. - Privacy. Lo screening è privato per la tua applicazione: un altro cliente non lo vede mai, e non modifica mai la voce condivisa. La directory mostra il tuo ultimo screening come
entity_screening. - Rifiuti.
409quando lo screening è disattivato, per un’applicazione sandbox, o mentre è già in corso uno screening della stessa controparte.403concode: insufficient_creditsquando il tuo saldo non copre il prezzo.502quando lo screening non può essere completato. In nessuno di questi casi viene addebitato alcunché.
Questionario di due diligence
Chiedi alla controparte le risposte di due diligence con il questionario standard di Didit.POST /v3/travel-rule/vasps/{vasp_id}/questionnaires/ lo invia via email a un indirizzo di compliance registrato per la controparte, con un link monouso a una pagina di risposta:
- Dove viene inviato.
sent_todeve essere un indirizzo di compliance registrato: per una voce della directory, il suo indirizzo di compliance o un contatto che la tua applicazione vede incontacts; per un membro della rete Didit, la sua email di compliance confermata. Omettilo per usare l’indirizzo a cui va un’email Travel Rule alla controparte: prima il tuo contatto, poi un contatto della piattaforma, poi l’indirizzo di compliance della voce. Didit non invia mai il questionario a nessun altro destinatario, e restituisce400quando la controparte non ha un indirizzo di compliance registrato. - Risposta. Il link apre
/v3/travel-rule/questionnaires/{token}/, una pagina per una persona della controparte che non richiede account né chiave API. Risponde a ogni domanda, fino a 2.000 caratteri ciascuna (N/Adove una domanda non si applica), e invia una sola volta. Una controparte può anche inviare{"answers": {"<question id>": "<answer>"}}allo stesso link. Un link già usato, sostituito o oltre la scadenza mostra invece una pagina di scadenza. L’email e la pagina sono tradotte; le domande stesse restano sempre in inglese, così il loro significato non cambia tra le lingue. - Scadenze. La controparte ha 30 giorni per rispondere (
expires_at). Le risposte restano valide per 365 giorni (valid_until), ecurrentètruefino ad allora. Un questionario senza risposta oltre la scadenza, e le risposte oltre la loro validità, diventanoEXPIRED. - Un questionario aperto per controparte. Un nuovo invio sostituisce il tuo precedente questionario senza risposta verso la stessa controparte: diventa
EXPIREDe il suo link smette di funzionare. A un indirizzo può essere inviata una sola email al minuto; un invio più rapido restituisce429. - Lettura delle risposte.
GET /v3/travel-rule/vasps/{vasp_id}/questionnaires/elenca i tuoi questionari con la controparte, dal più recente, conanswersindicizzate per l’ID della domanda una volta ricevute le risposte. La directory li mostra comequestionnaires. Sono privati per la tua applicazione.
1 del modulo pone queste dodici domande:
Trasferimenti con una controparte
GET /v3/travel-rule/transfers/?counterparty={vasp_id} elenca i trasferimenti Travel Rule della tua applicazione con una controparte, dal più recente al più vecchio, in base all’id mostrato dalla directory: i tuoi trasferimenti la cui controparte è quella voce della directory, oppure i tuoi scambi INTERNAL con quel membro della rete Didit. Un valore che non è un id valido restituisce 400.
Ogni riga riporta reason subito dopo status: la reason del trasferimento stesso, così l’elenco ti permette di distinguere il mancato recapito dell’email di compliance dall’assenza di un percorso per la controparte, senza aprire ogni trasferimento.
Politiche sunrise e per le controparti non responsive
Quando un trasferimento scade (è trascorsoconfirmation_timeout_hours mentre era AWAITING_COUNTERPARTY), timeout_outcome decide cosa accade alla sua transazione. Due impostazioni ti permettono di trattare in modo diverso due motivi comuni di timeout:
HOLD, REJECT o PROCEED, con lo stesso significato di timeout_outcome, oppure una stringa vuota per seguire timeout_outcome. Entrambe sono vuote per impostazione predefinita, quindi nulla cambia finché non ne imposti una:
sunrise_policy, quando è impostata e la giurisdizione della controparte è insunrise_jurisdictions.non_responsive_policy, quando è impostata e la controparte èUNRESPONSIVE.timeout_outcomein ogni altro caso, incluso un trasferimento verso un membro della rete Didit o verso una controparte senza voce nella directory.
sunrise_jurisdictions è di sola lettura e attualmente è ["CO", "KH", "VN"]. Solo questi paesi vengono considerati in un periodo sunrise: qualsiasi altra giurisdizione, e una giurisdizione vuota o sconosciuta, segue timeout_outcome, così una controparte non riceve mai la tua politica sunrise per errore. La cronologia del trasferimento scaduto indica l’esito applicato, per esempio sunrise_policy=PROCEED (counterparty jurisdiction CO does not enforce the Travel Rule yet). Le tue regole continuano a essere eseguite dopo la scadenza, quindi una regola come tr_eu_expired_review del TFR UE può ancora spostare la transazione in revisione con PROCEED.
Campi delle regole e preset
Quattro campi della regola contengono ciò che la tua applicazione sa sulla controparte raggiunta dallo scambio Travel Rule di una transazione: la sua voce nella directory o, per uno scambioINTERNAL, il cliente Didit che lo ha ricevuto. Ogni campo è vuoto quando lo scambio non ha raggiunto alcuna controparte nota.
travel_rule agiscono su questi campi. Installali da Transactions → Rules → Library nella Business Console oppure con la API della libreria di regole:
Webhook
Iscrivi una destinazione atravel_rule.status.updated per ricevere una notifica a ogni transizione di stato di ogni trasferimento nella tua applicazione, in uscita e in entrata, incluse le tratte sul rail INTERNAL.
Il routing viene eseguito dopo che la creazione della transazione restituisce una risposta, quindi esiti come COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE o uno scambio INTERNAL che si chiude subito ti arrivano tramite questo evento e non nella risposta della creazione.
rail resta vuoto finché non viene selezionato un rail.
Per una stessa transazione, Didit invia travel_rule.status.updated dopo transaction.created: quando Didit crea la transazione (con la tua POST /v3/transactions/, una registrazione sunrise, un’interrogazione TRP in entrata o la tratta in entrata sul rail INTERNAL), invia prima transaction.created.
Ogni evento viene consegnato e ritentato in modo indipendente, quindi un transaction.created che ha richiesto un nuovo tentativo può arrivare dopo un evento di stato. Usa transaction_id come chiave del tuo handler e leggi la transazione quando un evento di stato ne indica una che non hai ancora visto.
Un trasferimento inviato tramite TRUST non riceve l’evento COMPLETED: TRUST non restituisce nulla che Didit possa leggere, quindi, a meno che l’invio non fallisca o tu non lo annulli, il suo ultimo evento è EXPIRED. Tramite GTR, VERIFYVASP e SYGNA, l’evento segue la risposta che Didit legge dalla rete.
Anche le applicazioni sandbox inviano questo evento, con "environment": "sandbox". Un trasferimento a cui ha risposto il Didit Test VASP riporta rail: "TEST_VASP", test_vasp: true e test_vasp_scenario.
Consulta la guida ai webhook per il catalogo completo degli eventi, la verifica della firma e la politica di nuovo tentativo.
Prezzi
La commissione Travel Rule è di $0.02 per ogni scambio in uscita avviato, addebitata una sola volta alla creazione della transazione, indipendentemente da quante transizioni di stato lo scambio attraversi in seguito. Unresend non la addebita mai di nuovo.
- Si applica a una transazione
travelRulein uscita su un’applicazione con Travel Rule attiva, il cui importo è pari o superiore alla tuathreshold_amount, quindi Didit avvia per essa uno scambio gestito. Vi rientra anche un trasferimento verso un wallet in autocustodia o verso il wallet verificato del tuo utente: in quel caso la prova di proprietà è il suo scambio. - Ogni altra transazione in uscita che contiene dati Travel Rule viene fatturata come Transaction Screening standard, che il tuo piano include fino alla propria quota mensile di transazioni e che viene prezzato $0.001 oltre tale soglia: un trasferimento sotto la tua soglia, un pagamento Lightning a cui la Travel Rule non si applica e un trasferimento registrato in modo passivo mentre Travel Rule è disattivata. Una transazione viene fatturata su una sola delle due voci, mai su entrambe.
- Le transazioni
travelRulein entrata non comportano commissioni Travel Rule o di monitoraggio: la tratta in entrata che Didit crea sull’applicazione del beneficiario tramite il railINTERNAL, le interrogazioniTRPin entrata e le registrazioni successive al deposito. - Un’applicazione che ha aderito a Travel Rule gratuitamente non paga nessuna delle due commissioni sulle transazioni
travelRulein uscita finché non attiva la fatturazione in uscita conPOST /v3/travel-rule/workspace/billing/; la ricezione resta gratuita. - Le applicazioni sandbox non vengono mai addebitate.
- La commissione Travel Rule è di $0.02 e Transaction Screening costa $0.001 oltre la tua quota. Ogni transazione viene addebitata al prezzo della voce applicabile.
- Se sulla stessa transazione viene eseguito anche lo screening AML crittografico o dei wallet (per esempio un deposito in entrata con
currency_kind: "crypto"e monitoraggio attivo), questo viene fatturato a parte alla tariffa standard di Wallet Verification & Screening e non è incluso nella commissione Travel Rule. - Lo screening della controparte è facoltativo e viene fatturato a parte, al prezzo dello Screening AML per aziende per ogni screening; uno screening di età inferiore a 30 giorni viene riutilizzato senza costi. Decisioni, questionari e la valutazione di due diligence della directory non hanno alcun costo.
Prezzi dell’attribuzione
L’attribuzione tramite analisi blockchain richiede una ricerca del wallet presso il fornitore di analisi, e ottieni sempre il valore completo di quella ricerca:- Il monitoraggio crypto ha già sottoposto a screening il wallet su questa transazione: il risultato memorizzato viene riutilizzato. Una chiamata all’analisi, un addebito di Wallet Verification & Screening (quello già effettuato dal monitoraggio crypto). L’attribuzione non aggiunge nulla.
- Il monitoraggio crypto non è stato eseguito: Didit effettua una sola volta la chiamata necessaria all’analisi e ne trasferisce l’intero valore: la transazione viene addebitata alla tariffa standard di Wallet Verification & Screening ($0.15 con analisi gestita da Didit) e riceve in cambio l’output completo dello screening crypto, cioè punteggio di rischio, categoria di rischio del wallet e snapshot della rete, non solo il nome del VASP. La voce di utilizzo è contrassegnata con il trigger
travel_rule_attribution, così l’addebito è spiegabile. - Chiave di analisi propria: si applica la stessa commissione di piattaforma prevista per il monitoraggio crypto con la tua chiave ($0.02 per chiamata). Il tuo fornitore ti fattura direttamente la ricerca sottostante.
- Le ricerche non riuscite non vengono mai addebitate; i reinvii riutilizzano l’attribuzione registrata senza una nuova chiamata né un nuovo addebito, e le applicazioni sandbox non vengono mai addebitate.
Bundle di regole TFR UE
Quattro regole predefinite sono incluse nel bundletravel_rule_eu_tfr, pensato specificamente per gli obblighi del regolamento UE TFR.
Come ogni altro bundle di regole predefinite, attivalo dalla Business Console in Transactions → Rules → Library.
Perché funziona meglio su un’unica piattaforma
La conformità alla Travel Rule è un problema di identità travestito da problema di pagamenti, e Didit possiede già l’identità:- Dati verificati a portata di mano. Il soggetto di ogni trasferimento è collegato tramite
vendor_dataal profilo KYC che Didit ha verificato in fase di onboarding (OCR del documento, liveness, confronto facciale), quindi puoi costruireoriginator_dataa partire da campi verificati sulla stessa piattaforma. Per un utente con una verifica KYC approvata, Didit trasmette l’identità verificata e non i valori che hai digitato (vedi Dati verificati e provenienza). - Biometria di step-up per i trasferimenti rischiosi. Una regola può trattenere qualsiasi trasferimento di alto valore finché l’utente non supera un nuovo controllo biometrico a fronte del volto acquisito in fase di onboarding: la risposta più forte possibile alla compromissione dell’account nel momento del prelievo. Vedi l’esempio completo.
- Un unico grafo dei dispositivi. I trasferimenti inviati tramite SDK portano le stesse informazioni sul dispositivo delle sessioni KYC, quindi “nuovo dispositivo + importo elevato + primo beneficiario” è una sola regola, non un join in un data warehouse.
- Screening, regole, casi e scambio in un unico posto. Lo screening dei wallet che attribuisce il VASP controparte è lo stesso che vedono le tue regole e i tuoi analisti: un solo addebito, una sola console, un unico registro di audit.
- Prezzi pubblicati. $0.02 per scambio in uscita, nessuno scaglione di volume, nessuna chiamata commerciale.
FAQ
Come funziona lo scambio
Didit esegue lo scambio tra VASP da sé, oppure registra soltanto i dati della Travel Rule dopo che un'altra rete ha completato l'handshake?
Didit esegue lo scambio tra VASP da sé, oppure registra soltanto i dati della Travel Rule dopo che un'altra rete ha completato l'handshake?
travelRule, Didit esegue la ricerca attiva della controparte, invia i dati dell’ordinante e del beneficiario al VASP ricevente sulle reti che li trasportano, e segna il trasferimento come COMPLETED solo quando la controparte lo conferma - si tratta di un handshake gestito, non di un registro successivo al regolamento.
Una risposta della controparte viene elaborata su tutte le reti tranne TRUST, che si limita a inviare, quindi un trasferimento su questa rete scade invece di completarsi. Su GTR, VERIFYVASP e SYGNA, Didit legge la risposta dalla rete o interrogandola ogni 5 minuti, e nessuno scambio su queste reti è ancora stato completato con una rete attiva; su TRP, una risposta che la controparte non fornisce subito richiede l’host TRP pubblico di Didit, che non è ancora attivo (vedi Reti della Travel Rule).
Didit mantiene inoltre il registro completo e lo stato di conformità di ogni scambio (un ciclo di vita a 13 stati, webhook e un registro di audit).
Se preferisci gestire la Travel Rule con il tuo processo, Didit può invece registrare i dati in modo passivo come tuo unico sistema di riferimento (vedi la domanda sulla registrazione passiva qui sotto).
Entrambe le modalità sono disponibili: lo scambio attivo viene eseguito una volta impostato is_enabled: true nelle impostazioni (per impostazione predefinita è false), e fino ad allora Didit registra i dati in modo passivo.È una funzionalità nativa di Didit, o dipende da un provider di interoperabilità esterno (Notabene, Sygna, VerifyVASP, TRP)?
È una funzionalità nativa di Didit, o dipende da un provider di interoperabilità esterno (Notabene, Sygna, VerifyVASP, TRP)?
trp.didit.me una volta attivo l’host pubblico (al momento non risponde, quindi le controparti non possono raggiungerti tramite TRP oggi), e implementa direttamente i protocolli di rete del settore - GTR (Global Travel Rule), TRUST, VerifyVASP e Sygna Bridge (supportati nativamente, inclusi IVMS 101 cifrato con ECIES di Sygna e richieste di permesso firmate). Didit non è un rivenditore di un unico livello di interoperabilità di terze parti. Raggiungere una controparte che opera su una specifica rete di adesione avviene necessariamente tramite quella rete - non esiste un unico canale universale nella Travel Rule - ma la scoperta, l’handshake, la verifica e la tenuta delle registrazioni sono tutti eseguiti da Didit.
Oggi ogni rete richiede una tua adesione, e TRUST si limita a inviare: vedi Panoramica.Quali reti e protocolli della Travel Rule supporta Didit?
Quali reti e protocolli della Travel Rule supporta Didit?
INTERNAL (entrambi i VASP su Didit), TRP (OpenVASP Travel Rule Protocol), GTR, TRUST, VerifyVASP, Sygna Bridge, e un fallback EMAIL per le controparti senza strumenti.
Le reti richiedono oggi una tua adesione, TRUST si limita a inviare, e la ricezione su una rete non è ancora attiva: vedi Reti della Travel Rule.
CODE, TRISA, Notabene e Veriscope compaiono nel Marketplace di Didit come riquadri di richiesta di accesso, senza ancora un’integrazione.
Vedi Come Didit instrada uno scambio per la tabella di instradamento completa, e Reti della Travel Rule per ciò che ciascuna raggiunge oggi.Quale rete dovrei usare e mi servono adesioni proprie?
Quale rete dovrei usare e mi servono adesioni proprie?
TRP è la base che raccomandiamo: non richiede alcuna adesione condivisa - condividere il tuo Travel Address permette a qualsiasi VASP che parla TRP di raggiungerti - e quando una controparte è nota solo tramite indirizzo, l’attribuzione tramite analisi blockchain la instrada su TRP solo se la voce attribuita nella directory ha già un endpoint TRP.
In uscita, Didit invia su di essa gli asset elencati in identificatori di asset TRP, e una controparte che non risponde subito richiede l’host TRP pubblico di Didit, che non è ancora attivo.
Per le reti di adesione, scegli in base a dove operano le tue controparti: GTR offre un’ampia copertura globale, TRUST è orientata ai VASP statunitensi, e VerifyVASP (che ora gestisce anche Sygna Bridge) ha una forte copertura in Asia.
Sì, oggi ti servono adesioni proprie: Didit non detiene ancora un’adesione di piattaforma su queste reti ed è in fase di onboarding come provider.
Collega la tua adesione in Marketplace; non sei vincolato a una sola rete.
Ricorda che TRUST si limita a inviare, quindi un trasferimento su di essa non si completa, e che nessuno scambio su una rete è ancora stato completato con una rete attiva.Come trova Didit il VASP della controparte quando ho solo un indirizzo?
Come trova Didit il VASP della controparte quando ho solo un indirizzo?
INTERNAL), la tua rubrica degli indirizzi dei wallet per un Travel Address memorizzato, poi i protocolli e le reti di adesione, e infine l’attribuzione tramite analisi blockchain.
Se il trasferimento riporta solo un wallet di destinazione, Didit lo risolve con i dati di analisi blockchain per attribuire l’exchange di criptovalute o il servizio di custodia della controparte e lo cataloga nella directory dei VASP.
Il trasferimento viene poi instradato automaticamente solo se quella voce della directory ha già un percorso, come un endpoint TRP; altrimenti termina con COUNTERPARTY_VASP_NOT_FOUND con il nome della controparte registrato, e puoi reinviarlo quando esiste un percorso, ad esempio dopo aver memorizzato il travel_address della controparte nella voce della tua rubrica per quel wallet (per gli asset elencati in identificatori di asset TRP).Prezzi e licenze
Quanto costa la Travel Rule e rientra nel mio piano KYC o di verifica?
Quanto costa la Travel Rule e rientra nel mio piano KYC o di verifica?
Verrò addebitato due volte quando Travel Rule e il monitoraggio crypto girano insieme?
Verrò addebitato due volte quando Travel Rule e il monitoraggio crypto girano insieme?
travelRule viene fatturata su una sola riga: la tariffa Travel Rule ($0.02) quando avvia uno scambio in uscita, altrimenti il normale Transaction Screening. La ricerca di analisi blockchain viene addebitata una volta: se il monitoraggio delle crypto ha già analizzato il wallet di destinazione della transazione, l’attribuzione riutilizza quel risultato memorizzato senza costi aggiuntivi.
I trasferimenti in entrata che Didit genera sul lato del beneficiario non vengono mai fatturati con la tariffa Travel Rule.Didit può fornire documentazione o una dichiarazione di capacità per la licenza VASP o il fascicolo del regolatore?
Didit può fornire documentazione o una dichiarazione di capacità per la licenza VASP o il fascicolo del regolatore?
Operazioni e dati
Cosa succede ai trasferimenti sotto la mia soglia?
Cosa succede ai trasferimenti sotto la mia soglia?
NOT_APPLICABLE: non viene tentato alcun canale e nessun dato identificativo lascia Didit.
La transazione viene fatturata come normale Transaction Screening, non con la tariffa Travel Rule.
Didit confronta la soglia con l’importo convertito nella valuta predefinita della tua applicazione.
Se Didit non riesce a convertire l’importo, la soglia non viene applicata e il trasferimento viene eseguito.
Il regolamento TFR dell’UE non prevede un minimo, quindi i CASP UE dovrebbero mantenere threshold_amount a 0.00.Cosa succede se la controparte non risponde mai?
Cosa succede se la controparte non risponde mai?
AWAITING_COUNTERPARTY fino allo scadere di confirmation_timeout_hours; poi un processo di controllo lo sposta in EXPIRED e applica il tuo timeout_outcome alla transazione sottostante: HOLD per la revisione, REJECT per rifiutarla oppure PROCEED per lasciarla invariata. La regola predefinita tr_eu_expired_review segnala inoltre ai tuoi analisti ogni scadenza. Una controparte che non riceve affatto il messaggio è un caso diverso: Didit ritenta l’invio e, dopo il sesto tentativo fallito, il trasferimento passa a COUNTERPARTY_VASP_NOT_REACHABLE (vedi Consegna e nuovi tentativi).La mia controparte non ha alcuno strumento Travel Rule. Posso comunque essere conforme?
La mia controparte non ha alcuno strumento Travel Rule. Posso comunque essere conforme?
EMAIL. Il referente di compliance della controparte riceve un link monouso per il recupero e può confermare o rifiutare lo scambio da una pagina ospitata, senza account Didit, senza chiave API e senza alcuna integrazione. Per i depositi già regolati prima che fosse possibile qualsiasi scambio, usa la registrazione sunrise dopo il deposito.Come funzionano i prelievi verso il wallet dell'utente?
Come funzionano i prelievi verso il wallet dell'utente?
payment_method.method_type: "unhosted_wallet"). Didit salta l’instradamento verso i VASP e raccoglie invece la prova che il tuo cliente controlla il wallet, tramite firma di un messaggio, test Satoshi, screenshot o autodichiarazione, attraverso il widget di verifica della proprietà del wallet. Questo è l’obbligo del regolamento TFR dell’UE sui wallet in autocustodia, in forma di API.I dati personali della controparte sono protetti durante lo scambio?
I dati personali della controparte sono protetti durante lo scambio?
GTR, TRUST, VERIFYVASP, SYGNA) cifrano inoltre il payload IVMS con la chiave pubblica del VASP ricevente.Gestisco già la conformità Travel Rule con un mio processo. Posso limitarmi a registrarla?
Gestisco già la conformità Travel Rule con un mio processo. Posso limitarmi a registrarla?
travel_rule_details che invii (incluso uno status fornito dal chiamante, nel formato attuale o legacy) viene registrato in modo passivo sulla transazione: non viene avviato alcun canale e non si negozia nulla. Puoi usarlo per recuperare dati storici o per gestire un tuo processo mantenendo un unico sistema di registrazione.Come posso testare tutto prima di andare in produzione?
Come posso testare tutto prima di andare in produzione?
transaction.created e transaction.status.updated, e ogni scambio in uscita va al Didit Test VASP sul canale TEST_VASP, che risponde all’interno di Didit con lo scenario che scegli: accettazione, rifiuto, mancata corrispondenza del nome, non raggiungibile, timeout o wallet in autocustodia. Ricevi webhook travel_rule.status.updated contrassegnati con environment: sandbox, e nessun messaggio raggiunge una controparte reale.
Per i trasferimenti in entrata, fai inviare al test VASP un trasferimento con Trigger Test VASP Inbound Transfer, oppure registrane uno con POST /v3/travel-rule/inbound/; entrambi vengono decisi in base alla rubrica degli indirizzi dei tuoi wallet: ON_HOLD, UNCONFIRMED_OWNERSHIP, COUNTERPARTY_MISMATCHED_DATA, oppure COMPLETED seguito da FINISHED.
Per uno scambio a due parti con un’altra applicazione reale, usa due tue applicazioni di produzione sul canale INTERNAL: quella ricevente deve essere individuabile e dimostrare il controllo del wallet di destinazione con un messaggio firmato o con un deposito di prova.