Overview
The FATF Travel Rule (Recommendation 16), implemented in the EU as the Transfer of Funds Regulation, requires a sending Virtual Asset Service Provider (the originator VASP) to collect and transmit originator and beneficiary information to the receiving VASP (the beneficiary VASP) before a virtual asset transfer settles. Unlike most jurisdictions, the EU TFR applies with no minimum amount - every crypto transfer is in scope, not just transfers above a reporting threshold. Didit’s Travel Rule product is a managed exchange, not just a data field:- You submit a transfer with
transaction_category: "travelRule". - Didit resolves a rail to reach the counterparty VASP, exchanges originator and beneficiary data, and verifies the beneficiary’s identity against the destination wallet.
- Only once the exchange reaches
COMPLETEDshould you broadcast the transfer on-chain. - You then report the on-chain transaction hash back to Didit to close the exchange out as
FINISHED.
GTR, TRUST, VERIFYVASP, SYGNA) run in one of two modes, per network:
- Didit’s platform membership - when Didit’s own membership for a network is active, every Travel Rule application routes over it automatically, with no setup on your side. You can opt out of individual networks with the
disabled_networkssetting (see Setup). - Your own membership - connect your own network membership credentials in the console Marketplace (Travel Rule networks category). A connected membership always takes precedence over Didit’s platform membership, and your transfers travel under your own network identity.
networks object reports each network’s effective mode (didit, own, off, or unavailable), so you can see exactly which rails can fire for your application.
Further networks - CODE (the Korean alliance), TRISA, Notabene, and Veriscope - are listed in the console Marketplace as on-request integrations: their onboarding runs through each network’s own registration or due-diligence process, so request access there and Didit coordinates the connection with you.
When none of the seven rails can resolve a counterparty, Didit runs one more resolution step before giving up: blockchain analytics attribution.
The destination wallet is looked up against blockchain analytics data; when the wallet belongs to a known exchange or custodian, Didit records the attributed VASP on the transfer, adds it to the directory, and re-runs the rails once with the new name.
See Blockchain analytics attribution for the full behavior and pricing.
A transfer whose destination is declared as a self-hosted wallet skips all seven rails - there is no counterparty VASP to exchange with - and goes straight to end-user wallet-ownership proof.
/v3/ endpoints described on this page.What executes when you submit a transfer
Everything below runs synchronously inside the onePOST /v3/transactions/ call - by the time you receive the response, screening has run, routing has been attempted, rules have been evaluated, and the transfer already has a definitive status.
There is no “pending pipeline” to poll for; the only asynchronous parts are the counterparty’s answer and any end-user action.
Step by step:
- Validation and identity binding. The payload is validated (
txn_iddeduplicated - resubmitting the same id returns the existing transaction), and thesubjectis resolved to your user or business profile byvendor_data, linking the transfer to the identity you verified at onboarding. Blocklisted subjects, counterparties, wallets, IPs, and devices are declined immediately. - Device and network enrichment. Party IPs are geo-enriched, and any device context (automatic on SDK submission) is normalized into the device graph - the same graph KYC sessions feed, so “related by device” works across onboarding and transactions.
- Crypto screening. For crypto transfers with monitoring enabled, the relevant wallet (or on-chain hash) is screened against blockchain analytics before anything is exchanged - sanctions exposure, mixer proximity, stolen funds. See Crypto & wallet screening.
- Travel Rule routing. The exchange engine checks the threshold, honors a self-hosted wallet declaration, then walks the seven rails in priority order; if none resolve, blockchain analytics attribution identifies the counterparty and the rails re-run once. Whatever the outcome, the transfer leaves this step with a concrete status -
AWAITING_COUNTERPARTY,COMPLETED(INTERNAL rail),UNCONFIRMED_OWNERSHIP, orCOUNTERPARTY_VASP_NOT_FOUND. - Wallet-ownership minting. If the transfer needs end-user proof of control and
auto_wallet_verificationis on, a wallet-ownership widget session is minted and returned inaction_required. - Rules evaluation. Every active rule runs - the EU TFR bundle reacts to the transfer status set in step 4, your custom rules see the screening output of step 3, and a rule can hold the transaction (
IN_REVIEW), decline it, or demand step-up verification (AWAITING_USER). - Billing and notification. The $0.02 Travel Rule line is recorded, the response returns with the full picture, and
transaction.createdfires to your webhook destinations.
How each step maps to your obligations
APPROVED and nothing is charged.
The Travel Rule exchange itself still executes on sandbox applications when enabled, including real rail dispatch, so use test counterparty data there.Lifecycle
Every transfer has astatus drawn from 13 values.
The exchange starts at AWAITING_COUNTERPARTY in the normal case, at NOT_APPLICABLE when the amount is below your threshold_amount, or at UNCONFIRMED_OWNERSHIP when the destination was declared a self-hosted wallet, and ends in one of the terminal states: FINISHED, CANCELLED, or EXPIRED.
The transfer runs its own state machine, separate from the underlying transaction’s review status. Whenever the exchange transitions, Didit also nudges the transaction: ON_HOLD surfaces the transaction as AWAITING_USER, an expiry applies your configured timeout_outcome, and the EU TFR rules can push it to IN_REVIEW. Read the exchange state from travel_rule.status; read the allow / hold / decline verdict from the transaction’s own status.
Every transition (and every passively reported status) is also mirrored onto the transaction’s custom values so rules can key on it: custom_values.travel_rule_status (canonical status), custom_values.travel_rule_rail (the rail that carried the exchange, empty until one is selected), and custom_values.travel_rule_regime (derived from your settings jurisdiction: SG → singapore, GB → uk, and any EU or EEA member code such as DE or FR → eu; unmapped codes stamp lowercased, e.g. US → us. A props.travel_rule_regime you submit yourself always wins over the derived value).
CANCELLED is additionally reachable from every non-terminal state with action: "cancel"):
Legacy status values
If you were already sendingtravel_rule_details.status before this release, those values still work and are mapped automatically.
camelCase spellings of any status (for example counterpartyVaspNotFound) are accepted too, both on submission and in rule condition values, and normalize to the canonical form:
Setup
Configure your VASP profile and negotiation policy once per application withGET/PUT /v3/travel-rule/settings/.
PUT is a partial update - send only the fields you want to change.
Name matching strictness
Thresholds by jurisdiction
threshold_amount exists because Travel Rule scope varies by regulator.
Didit defaults to 0.00 - the EU position - so every transfer is exchanged unless you raise it deliberately:
threshold_amount to your regulator’s figure; transfers below it resolve to NOT_APPLICABLE without exchanging any identity data.
Thresholds evolve - confirm the current figure with your compliance counsel rather than treating this table as legal advice.
IVMS 101 data model
The industry standard for the data exchanged under the Travel Rule is IVMS 101 (interVASP Messaging Standard).travel_rule_details.originator_data and travel_rule_details.beneficiary_data are IVMS 101-style person payloads: Didit wraps them in each rail’s native envelope - the TRP rail exchanges IVMS101 blocks (ivms101.2023, reported in the transfer’s ivms_version field), the Sygna rail its ECIES-encrypted IVMS variant, and the network rails their own signed envelopes - so one payload shape reaches every counterparty in the format their protocol expects.
Two practical rules:
- Latin script. IVMS 101 requires Latin-script values; transliterate names that are natively written in another script. Didit’s name matching compares normalized token sets, so ordering and casing differences don’t fail an exchange - but different scripts on the two sides will.
- You send data you have verified. Because the subject is bound to your Didit KYC profile by
vendor_data, the originator identity you transmit is the one Didit verified at onboarding - document-extracted, liveness-checked, and face-matched - not an unverified form field. That distinction is exactly what the FATF’s “required and accurate originator information” wording demands.
Travel addresses
A travel address is a compact, encoded string that points at a VASP’s inboundTRP inquiry endpoint - it never exposes a raw URL or any wallet address.
Once your VASP profile is complete, Didit derives your own travel_address (returned read-only in settings) and publishes it so other VASPs can reach you on the TRP rail.
When you know a counterparty’s travel address, store it on the destination wallet address book entry so Didit routes that beneficiary’s transfers straight over TRP instead of falling back to email.
Sending a transfer
Include the transfer onPOST /v3/transactions/ by setting transaction_category to travelRule (or travel_rule) and attaching a travel_rule_details object (alias: travelRule).
When Travel Rule is enabled for your application, Didit ignores any status you send and drives the exchange itself:
- If the amount is below your configured
threshold_amount, the transfer resolves immediately toNOT_APPLICABLEand nothing is negotiated. - If the counterparty’s payment method declares the destination as a self-hosted wallet (
payment_method.method_type: "unhosted_wallet"), no rail is tried - the transfer goes straight toUNCONFIRMED_OWNERSHIPand the wallet-ownership widget is auto-minted (see Declared self-hosted wallets). - Otherwise the rails run in priority order, and the first one that can reach the counterparty carries the exchange:
INTERNAL-beneficiary_data.wallet_addressis registered in another Didit customer’s wallet address book.TRP- the transfer’s asset has a Digital Token Identifier mapping (BTCandETHtoday), and the payload carriesbeneficiary_data.travel_address, the destination’s own address-book entry stores one, or the counterparty resolves in the directory (bycounterparty_vasp_leiorcounterparty_vasp_name) with a TRP endpoint.GTR,TRUST,VERIFYVASP,SYGNA- the network is active for your application (your own connected membership, or Didit’s platform membership when the network is not indisabled_networks), and the counterparty resolves to a network id (explicit field or directory entry - see Counterparty resolution fields).EMAIL-beneficiary_data.counterparty_vasp_emailwas supplied, orcounterparty_vasp_nameresolves to a directory entry with a compliance email.
- If no rail can resolve a counterparty and
vasp_attribution_enabledis on, Didit runs blockchain analytics attribution: the destination wallet is resolved to its owning VASP, the attributed name is written tobeneficiary_data.counterparty_vasp_name(when empty) and to the directory, and the rails re-run once - so a wallet attributed to a VASP whose directory entry carries a TRP endpoint, network id, or compliance email routes on this second pass. - If the counterparty is still unresolved, the transfer is created in
COUNTERPARTY_VASP_NOT_FOUND. On outbound transfers Didit auto-mints the wallet-ownership widget (whenauto_wallet_verificationis on) so the transfer can still complete as a self-hosted-wallet transfer, and you can re-run routing later withaction: "resend"once you have better counterparty data.
Counterparty resolution fields
Everything Didit knows about the counterparty comes fromtravel_rule_details.beneficiary_data.
These fields drive rail resolution; all are optional:
Blockchain analytics attribution
When you pass nothing but a wallet address, Didit can still find out who is on the other side. If no rail can route the transfer, Didit resolves the destination wallet against blockchain analytics attribution data - the same analysis that powers crypto transaction screening knows which wallets belong to which exchanges and custodians. When the wallet is attributed to a known entity, Didit:- Records the attribution on the transfer:
beneficiary_data.counterparty_vasp_nameis filled (when you did not supply one), and the transfer’s metadata carries avasp_attributionblock with the entity name, entity type, country, andsource: "blockchain_analytics". - Adds the entity to your VASP directory (or matches the existing entry), so the attribution is stable across transfers and you can enrich the entry with a travel address, network ids, or a compliance email.
- Re-runs the rails once with the attributed name - a directory entry that already carries a TRP endpoint, network id, or compliance email makes the transfer route immediately instead of landing in
COUNTERPARTY_VASP_NOT_FOUND.
custom_values.aml_screening_trigger is set to travel_rule_attribution so you can see the screening ran because Travel Rule routing required it.
When crypto monitoring already screened the same wallet on this transaction, the stored result is reused - no second analytics call, no second charge.
Attribution never blocks transaction creation: if the analytics lookup fails, the transfer simply proceeds to COUNTERPARTY_VASP_NOT_FOUND and nothing is charged for the attempt.
On action: "resend", a previously recorded attribution is reused instead of re-queried.
Disable the whole step with vasp_attribution_enabled: false in settings.
See Pricing for how the attribution call is billed.
When Travel Rule is disabled, travel_rule_details (including a caller-supplied status, legacy or current) is still recorded on the transaction, but passively - no rail is dispatched.
Use this to backfill compliance data you already tracked with your own process.
holder_name matches, the INTERNAL rail can resolve the whole exchange synchronously - the response above would show "status": "COMPLETED" instead.
travel_rule object is intentionally short (uuid, status, protocol, required, obligations_count, originator_data, beneficiary_data, metadata).
The dedicated transfer endpoints below return a fuller object that also includes direction, rail, ivms_version, ownership_confirmed, deadline_at, timeline, and counterparty_vasp.COMPLETED outbound transfer once you’ve broadcast it on-chain:
COMPLETED status - otherwise the API returns 409.
On success both the outbound transfer and its INTERNAL-rail counterpart move to FINISHED, and the transaction’s payment_txn_id is set to the hash you provided.
To cancel a transfer that hasn’t reached a terminal state yet, send {"action": "cancel"} to the same endpoint instead.
To retry an outbound transfer that could not reach its counterparty - one currently in COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE, or NOT_ENOUGH_COUNTERPARTY_DATA - first improve the counterparty data (for example add a travel_address to the destination wallet entry, or catalogue the VASP in the directory), then send {"action": "resend"} to the same endpoint. Didit re-runs the routing ladder from the start. Any other status returns 409.
Declared self-hosted wallets
When your customer tells you the destination is their own self-hosted (unhosted) wallet, declare it on the transaction instead of letting routing discover there is no VASP behind it: set the counterparty’s payment method type tounhosted_wallet.
- No rail is tried - there is no counterparty VASP to exchange with - and the transfer is created directly in
UNCONFIRMED_OWNERSHIP. - When
auto_wallet_verificationis on (the default), Didit auto-mints a wallet-ownership widget session bound to the transaction and returns it in the transaction’saction_requiredblock; the SDKs launch it automatically on client-side submission. - Once the customer proves control of the wallet, the transfer runs the beneficiary name match and advances to
COMPLETED(orCOUNTERPARTY_MISMATCHED_DATAon a failed match).
UNCONFIRMED_OWNERSHIP is not a resendable state - complete the ownership proof (or cancel) instead of calling action: "resend".
Receiving
Confirming wallet ownership
When theINTERNAL rail resolves a transfer to a wallet address whose address-book entry hasn’t been ownership-verified, the beneficiary side is created in UNCONFIRMED_OWNERSHIP.
The beneficiary’s application confirms or denies it:
confirmed: truemarks the matching wallet address book entry as ownership-verified, then runs the name match on both sides -COMPLETEDif it passes,COUNTERPARTY_MISMATCHED_DATAif it doesn’t.confirmed: falsemoves both sides of the transfer toCOUNTERPARTY_VASP_GENERAL_DECLINE.- Returns
409if the transfer is not currentlyUNCONFIRMED_OWNERSHIP, or if the wallet address book entry it needs was deleted in the meantime.
originator_data/beneficiary_data are omitted entirely until ownership_confirmed is true on an inbound transfer, to avoid leaking counterparty PII before ownership is proven.
Wallet address book
Register the wallets you control so inboundINTERNAL-rail transfers can resolve against them, with POST/GET /v3/travel-rule/wallet-addresses/ and PATCH/DELETE /v3/travel-rule/wallet-addresses/{entry_uuid}/.
PATCH accepts holder_name, holder_vendor_data, entity_type, and travel_address, and returns only those four fields.
DELETE soft-deletes the entry (204) - its address is freed up for re-registration and its ownership proofs are retained for audit, but it immediately stops matching new transfers.
chain.
Avoid registering the same address string for two different chains under one application.Email pickup for unreachable counterparties
When no protocol rail can reach the counterparty, Didit falls back toEMAIL: it sends a one-time pickup link to beneficiary_data.counterparty_vasp_email (or an email resolved from beneficiary_data.counterparty_vasp_name against the VASP directory registry).
The recipient does not need a Didit account or an API key - the link’s token is the authentication.
decision is accept or decline.
On accept, the supplied beneficiary_name is run through the originator’s name_matching_strictness policy - COMPLETED on a match, COUNTERPARTY_MISMATCHED_DATA otherwise.
On decline, the transfer moves to COUNTERPARTY_VASP_GENERAL_DECLINE.
Both endpoints return 404 for an unknown token and 410 once the window closes - either the transfer left AWAITING_COUNTERPARTY, or pickup_expires_at (the same deadline as confirmation_timeout_hours) has passed.
After-deposit sunrise registration
When a crypto deposit settles on-chain before any Travel Rule exchange took place - the sending VASP was unreachable, or you are backfilling historical deposits - register it after the fact withPOST /v3/travel-rule/inbound/.
travelRule transaction (or reuses an unclaimed deposit it already recorded) and resolves the transfer against your wallet address book:
- No matching entry ->
ON_HOLD. - Entry exists but ownership is unproven ->
UNCONFIRMED_OWNERSHIP. - Beneficiary name does not match the entry’s
holder_name->COUNTERPARTY_MISMATCHED_DATA. - Verified entry and the name matches ->
COMPLETED, then immediatelyFINISHED(the deposit has already settled).
created is true when a new transaction was minted (HTTP 201) and false when an existing one was reused (HTTP 200).
On the verified-entry path both transitions happen before the endpoint responds, so the synchronous response already shows the terminal FINISHED status - the intermediate COMPLETED step is still recorded in the transfer’s timeline.
When a new transaction is created, a transaction.created webhook fires for it, followed by a travel_rule.status.updated for each transition (COMPLETED and FINISHED each fire one).
If crypto monitoring is enabled for your application, the deposit is also AML-screened and billed at the standard monitoring rate.
Wallet ownership widget
To move a transfer out ofUNCONFIRMED_OWNERSHIP - or to pre-verify a wallet before any transfer arrives - mint a hosted wallet-ownership widget with POST /v3/travel-rule/widget-session/ and send your customer to the returned url. The widget proves control of the wallet by message signing, a Satoshi test, a screenshot, or self-declaration, then marks the matching address-book entry verified so the exchange can continue.
See Wallet ownership widget for the full flow, the proof methods, and the important note that the widget must be opened in a real browser - never inside a mobile SDK webview.
Directory
GET /v3/travel-rule/vasps/?search=<name> searches a combined directory of discoverable Didit customers and VASPs your compliance team has catalogued in the internal counterparty registry.
limit (default 50) and offset query parameters; count, next, and previous describe the page window.
is_didit_customer: true entries are other Didit applications with Travel Rule enabled and is_discoverable: true - reachable on the INTERNAL rail. Their dd_status is always COMPLETED and dd_score always 0.
is_didit_customer: false entries come from the internal counterparty registry and carry a real dd_status/dd_score.
The dd_score is a single point-banded risk figure (higher is riskier); dd_score_breakdown shows the per-component contributions - licensing and registry standing, sanctions and PEP exposure, jurisdiction risk, and on-chain analytics risk - all derived from checks Didit already runs in-house, with no third-party lookup in the request path. dd_assessed_at is when that assessment last ran.
Gate on the score with the EU TFR rules bundle rather than branching on it inline.
Your own VASP profile never appears in your own directory results.
How entries get into the directory
There is no pre-seeded global VASP list - the directory grows from real activity:- Didit customers appear automatically once they enable Travel Rule and keep
is_discoverable: true. - An inbound
TRPinquiry upserts the initiating VASP (name, LEI, TRP endpoint) into the counterparty registry. - An outbound
TRPexchange records the counterparty identity and endpoint it verified during the handshake. - An after-deposit sunrise registration that names
originating_vaspupserts that VASP, including itstravel_addresswhen supplied. - Didit can catalogue a counterparty for you ahead of any exchange - routing identifiers, jurisdiction, and compliance contact - through support.
Routing identifiers
A directory entry can carry one routing identifier per network. Outbound routing consults them whenever your transfer names the counterparty bycounterparty_vasp_lei or counterparty_vasp_name:
Webhooks
Subscribe a destination totravel_rule.status.updated to get notified on every status transition, on both the outbound and any INTERNAL-rail inbound leg.
Pricing
Outbound Travel Rule exchanges are billed $0.02 per transaction, charged once at creation regardless of how many status transitions the exchange goes through afterward.- The inbound leg Didit creates on the beneficiary’s application via the
INTERNALrail is not billed. - If crypto AML/wallet screening also runs on the same transaction (for example an inbound deposit with
currency_kind: "crypto"and monitoring enabled), that’s billed separately at the standard AML monitoring rate - it is not bundled into the Travel Rule fee. - Travel Rule transactions use this dedicated line item instead of standard transaction-monitoring pricing, not both.
Attribution pricing
Blockchain analytics attribution needs one wallet lookup against the analytics provider, and you always get the full value of that lookup:- Crypto monitoring already screened the wallet on this transaction - the stored result is reused. One analytics call, one AML monitoring charge (the one crypto monitoring already made). Attribution adds nothing.
- Crypto monitoring did not run - Didit makes the required analytics call once and passes its full value on: the transaction is charged the standard crypto AML monitoring rate ($0.15 with Didit-managed analytics) and receives the complete crypto screening output in return - risk score, wallet risk category, network snapshot - not just the VASP name. The usage line item is marked with the
travel_rule_attributiontrigger so the charge is explainable. - Bring-your-own analytics key - the same platform fee that applies to crypto monitoring with your own key applies here ($0.02 per call). Your provider bills you for the underlying lookup directly.
- Failed lookups are never charged, resends reuse the recorded attribution without a new call or charge, and sandbox applications are never charged.
EU TFR rules bundle
Four preset rules ship in thetravel_rule_eu_tfr bundle, purpose-built for EU TFR obligations.
Like every other preset bundle, enable it from the Business Console under Transactions → Rules → Library.
Why this works better on one platform
Travel Rule compliance is an identity problem wearing a payments costume - and Didit already holds the identity:- Verified data on the wire. The originator information you transmit is the KYC profile Didit verified at onboarding (document OCR, liveness, face match) - bound by
vendor_data, not retyped into a form. Standalone Travel Rule vendors transmit whatever you pass them. - Step-up biometrics for risky transfers. A rule can hold any high-value transfer until the user passes a biometric re-check against the face captured at onboarding - the strongest possible answer to account takeover at the moment of withdrawal. See the worked example.
- One device graph. SDK-submitted transfers carry the same device intelligence as KYC sessions, so “new device + high amount + first-time beneficiary” is a single rule, not a data-warehouse join.
- Screening, rules, cases, and the exchange in one place. The wallet screening that attributes the counterparty VASP is the same screening your rules and analysts see - one charge, one console, one audit trail.
- Published pricing. $0.02 per outbound transfer, no volume tiers, no sales call.
FAQ
How the exchange works
Does Didit run the VASP-to-VASP exchange itself, or does it only record Travel Rule data after another network completes the handshake?
Does Didit run the VASP-to-VASP exchange itself, or does it only record Travel Rule data after another network completes the handshake?
travelRule transfer, Didit performs live counterparty discovery, negotiates and verifies the originator and beneficiary data with the receiving VASP, and only clears the transfer once the exchange reaches COMPLETED - it is a managed handshake, not a post-settlement log. Didit also keeps the full record and compliance status of every exchange (a 13-state lifecycle, webhooks, and an audit trail). If you prefer to run Travel Rule through your own process, Didit can instead record the data passively as your single system of record (see the passive-recording question below). Both modes are available; the active exchange is the default.Is the exchange native to Didit, or does it depend on an external interoperability provider (Notabene, Sygna, VerifyVASP, TRP)?
Is the exchange native to Didit, or does it depend on an external interoperability provider (Notabene, Sygna, VerifyVASP, TRP)?
trp.didit.me and implements the industry network protocols directly - GTR (Global Travel Rule), TRUST, VerifyVASP, and Sygna Bridge (spoken natively, including Sygna’s ECIES-encrypted IVMS 101 and signed permission requests). Didit is not a reseller of a single third-party interoperability layer. Reaching a counterparty that lives on a specific membership network necessarily happens over that network - there is no single universal channel in the Travel Rule - but the discovery, handshake, verification, and recordkeeping are all executed by Didit.Which Travel Rule networks and protocols does Didit support?
Which Travel Rule networks and protocols does Didit support?
INTERNAL (both VASPs on Didit), TRP (OpenVASP Travel Rule Protocol), GTR, TRUST, VerifyVASP, Sygna Bridge, and an EMAIL fallback for counterparties with no tooling. CODE, TRISA, Notabene, and Veriscope are available on request through Didit’s Marketplace. See How Didit routes an exchange for the full routing table.Which network should I use, and do I need my own memberships?
Which network should I use, and do I need my own memberships?
TRP is the universal baseline we recommend enabling: it needs no shared membership - publishing a travel address or TRP endpoint lets any Didit VASP reach you - and it is backed by blockchain-analytics attribution when a counterparty is known only by wallet address. For membership networks, choose by where your counterparties operate: GTR offers broad global coverage, TRUST is oriented to US VASPs, and VerifyVASP (which now also operates Sygna Bridge) has strong coverage in Asia. You can route over Didit’s platform membership where available, or connect your own - both are supported, and you are not locked to a single network.How does Didit find the counterparty VASP when I only have a wallet address?
How does Didit find the counterparty VASP when I only have a wallet address?
Pricing and licensing
How much does Travel Rule cost, and is it included in my KYC or verification plan?
How much does Travel Rule cost, and is it included in my KYC or verification plan?
Will I be double-charged when Travel Rule and crypto monitoring both run?
Will I be double-charged when Travel Rule and crypto monitoring both run?
travelRule transactions, and the blockchain-analytics lookup is charged once: if crypto monitoring already screened the destination wallet on the transaction, attribution reuses that stored result at no extra cost. Inbound legs Didit mints on the beneficiary side are never billed the Travel Rule fee.Can Didit provide documentation or a capability statement for my VASP licensing or regulator file?
Can Didit provide documentation or a capability statement for my VASP licensing or regulator file?
Operations and data
What happens to transfers below my threshold?
What happens to transfers below my threshold?
NOT_APPLICABLE: no rail is tried, no identity data leaves Didit, and no Travel Rule fee is charged beyond the transfer’s own creation. The EU TFR has no minimum, so EU CASPs should keep threshold_amount at 0.00.What if the counterparty never responds?
What if the counterparty never responds?
AWAITING_COUNTERPARTY until confirmation_timeout_hours elapses, then a sweeper moves it to EXPIRED and applies your timeout_outcome to the underlying transaction - HOLD for review, REJECT to decline, or PROCEED to leave it untouched. The tr_eu_expired_review preset rule additionally surfaces every expiry to your analysts.My counterparty has no Travel Rule tooling at all. Can I still comply?
My counterparty has no Travel Rule tooling at all. Can I still comply?
EMAIL rail. Their compliance contact receives a one-time pickup link and can confirm or decline the exchange from a hosted page with no Didit account, no API key, and no integration. For deposits that already settled before any exchange was possible, use after-deposit sunrise registration.How do withdrawals to the user's own wallet work?
How do withdrawals to the user's own wallet work?
payment_method.method_type: "unhosted_wallet"). Didit skips VASP routing and instead collects proof that your customer controls the wallet - message signing, Satoshi test, screenshot, or self-declaration - through the wallet-ownership widget. That is the EU TFR self-hosted wallet obligation in API form.Is counterparty PII protected during the exchange?
Is counterparty PII protected during the exchange?
originator_data/beneficiary_data entirely until wallet ownership is confirmed on your side, email pickup pages show only the transfer summary (originator VASP name, amount, destination wallet) - never the person payloads - and rail exchanges run over authenticated HTTPS, with the Sygna rail additionally end-to-end encrypting the IVMS payload.I already track Travel Rule compliance with my own process. Can I just record it?
I already track Travel Rule compliance with my own process. Can I just record it?
travel_rule_details you submit (including a caller-supplied status, current or legacy) is recorded passively on the transaction - no rail is dispatched, nothing is negotiated. Use this to backfill or run your own process while keeping one system of record.How do I test this before going live?
How do I test this before going live?
INTERNAL rail is the easiest full-loop test: register a wallet in a second application’s address book and watch both sides transition.