Short answer: A travel rule API is the interface a crypto asset service provider uses to exchange originator and beneficiary data with another provider around a transfer, and no single official API exists. IVMS 101 defines only the data model, so a build also needs discovery, a protocol, a state machine that holds funds and retention. As read on 6 November 2026, the EU sets no minimum between providers, Turkey adds identifiers at TRY 30,000, the UK at GBP 800 across borders, and the US rule applies from USD 3,000.
This guide is general education, not legal advice, and Fincode is a software company, not a crypto asset service provider. Documents were read on 6 November 2026 and appear alphabetically, with no ranking.
Travel rule applicability and requirements by jurisdiction
The rule binds the regulated provider moving crypto for a customer; triggers vary by law.
FATF's Interpretive Note to Recommendation 15, quoted in IVMS 101.2023 (opens in a new tab) and a Government of Jersey paper (opens in a new tab), asks countries to make originating providers submit data "immediately and securely". The EU text excludes person-to-person transfers with no provider, and transfers between providers acting on their own behalf (Art. 2(4)).
| Place and text | Trigger | Message data | Self-hosted or unhosted |
|---|---|---|---|
| EU: Regulation 2023/1113 (opens in a new tab), from 30 December 2024 | No minimum (Art. 14) | Originator: name, ledger address and account, address with country, document and customer numbers or birth details, legal entity identifier (LEI) if a field exists. Beneficiary: name, ledger address and account | Obtain and hold data; above EUR 1,000 assess control (Art. 14(5), 16(2)) |
| Turkey: Measures Regulation, Art. 24/A (opens in a new tab) | Full set at TRY 30,000 or more, since 7 October 2026 | Full set: sender name, wallet or reference, one identifier (address, birth details, customer, citizenship, passport or tax number), verified; recipient name and wallet. Below: names and wallets, unverified | Customer declaration; risk-based extra documents; consider not executing (Art. 24/A(6), (8)) |
| UK: Money Laundering Regulations 2017, Part 7A (opens in a new tab) | Names and accounts always; identifier at GBP 800 or more with linked transfers, since 30 June 2026 (reg. 64C(4) (opens in a new tab)); in UK-only chains, on request within three working days (64C(2)) | Names; account numbers or transaction identifier; one originator identifier | May request from the customer; must not release if requested data does not arrive (reg. 64G) |
| US: 31 CFR 1010.410(f) (opens in a new tab), FinCEN FIN-2019-G001 (opens in a new tab) | USD 3,000 or more | Transmittor name, account, address; amount; date; recipient's institution; recipient data as received | Ask counsel |
Amounts define duties, not design targets: the UK counts linked transfers, and no build should split or shape transfers around a figure. Turkey's figure doubled from TRY 15,000 under Presidential Decision 11845 (Resmî Gazete 33393); the September 2025 guide (opens in a new tab) from MASAK, Turkey's financial intelligence unit, still shows TRY 15,000. The regulation does not say how to value crypto in lira. Article 99/A of Capital Markets Law No. 6362 treats activity by foreign crypto-asset platforms directed at Turkish residents as unauthorized. See is crypto legal in Turkey and Turkish crypto exchange APIs.
What data moves: IVMS 101 and what it leaves out
IVMS 101.2023 standardizes who the parties are and says nothing about how the message travels.
- Out of scope. Section 3 excludes information security, privacy, identifying providers, network protocols and storage.
- ASCII names.
primaryIdentifierallows printable ASCII only, so a name such as Öztürk needs a Latin form there and the original inlocalNameIdentifier. The transliteration table does not cover Turkish letters, so fix a rule and expect name-matching differences. - No JSON binding. The PDF never mentions JSON, and names vary: its dictionary says
naturalPersonNameIdentifierType, its example saysnameIdentifierType, and GTR's 2020-edition page (opens in a new tab) nestsoriginatorPersonsunder a capitalizedOriginatorkey. TRISA (opens in a new tab) warns that its protojson output fails a third-party validator. Normalize at the boundary and keep the raw payload.
A tested IVMS 101 validator in Python
A validator catches malformed payloads before a counterparty does, but a clean result does not mean the message meets your law.
This ran on synthetic data on 6 November 2026 (Python 3.11.3, standard library) and covers parts of constraints C1, C6 and C11 only. No live protocol or vendor API was called.
import copy, math, re
def filled(v): # blanks are not data
if isinstance(v, (dict, list)):
return any(map(filled, v.values() if isinstance(v, dict) else v))
return isinstance(v, str) and bool(v.strip())
def has_id(p): # C1: codes alone do not identify
nat, birth = p.get("nationalIdentification") or {}, p.get("dateAndPlaceOfBirth") or {}
places = [{k: v for k, v in a.items() if k not in ("addressType", "country")}
for a in p.get("geographicAddress") or []]
return (filled([p.get("customerIdentification"), nat.get("nationalIdentifier"), places])
or filled(birth.get("dateOfBirth")) and filled(birth.get("placeOfBirth")))
def lei_ok(lei): # pattern, then ISO 7064 check digits
return isinstance(lei, str) and bool(re.fullmatch("[0-9A-Z]{18}[0-9]{2}", lei)) \
and int("".join(str(int(c, 36)) for c in lei)) % 97 == 1
def persons(payload, side): # 2020-era payloads use plural keys
block = payload.get(side) or {}
return (block.get(side + "Person") or []) + (block.get(side + "Persons") or [])
def person_errors(person, is_originator):
natural, legal = person.get("naturalPerson"), person.get("legalPerson")
p = natural or legal
if not p or natural and legal:
return ["exactly one of naturalPerson, legalPerson"]
errors, names = [], (p.get("name") or {}).get("nameIdentifier") or []
if natural:
if not any(n.get("naturalPersonNameIdentifierType",
n.get("nameIdentifierType")) == "LEGL" for n in names):
errors.append("C6 no legal name")
if not all(re.fullmatch("[ -~]{1,100}", str(n.get("primaryIdentifier") or ""))
for n in names):
errors.append("Max100Text: use localNameIdentifier")
if is_originator and not has_id(p):
errors.append("C1 no identifying data")
else:
national = p.get("nationalIdentification") or {}
if national.get("nationalIdentifierType") == "LEIX" and \
not lei_ok(national.get("nationalIdentifier")):
errors.append("C11 bad LEI")
return errors
def check(payload):
errors = []
for side in ("originator", "beneficiary"):
for person in persons(payload, side) or [{}]:
errors += person_errors(person, side == "originator")
return sorted(set(errors))
def turkey_24a_gaps(payload, amount_try):
"""Art. 24/A(1)-(2); verification is separate."""
if type(amount_try) not in (int, float) or not math.isfinite(amount_try) or amount_try < 0:
raise ValueError(f"bad amount: {amount_try}")
gaps = [f"{side} wallet" for side in ("originator", "beneficiary")
if not filled((payload.get(side) or {}).get("accountNumber"))]
for person in persons(payload, "originator") or [{}]:
p = person.get("naturalPerson") or person.get("legalPerson") or {}
if amount_try >= 30_000 and not has_id(p):
gaps.append("one sender identifier")
return sorted(set(gaps))
good = {
"payloadMetadata": {"payloadVersion": "101.2023"},
"originator": {"accountNumber": ["addr-1"], "originatorPerson": [{"naturalPerson": {
"name": {"nameIdentifier": [{"primaryIdentifier": "Example",
"naturalPersonNameIdentifierType": "LEGL"}]},
"customerIdentification": "C-1001"}}]},
"beneficiary": {"accountNumber": ["addr-2"], "beneficiaryPerson": [{"legalPerson": {
"name": {"nameIdentifier": [{"legalPersonName": "Example Ltd",
"legalPersonNameIdentifierType": "LEGL"}]},
"nationalIdentification": {"nationalIdentifier": "SYNTHETICTEST0000031",
"nationalIdentifierType": "LEIX"}}}]}}
print("valid:", check(good))
bad = copy.deepcopy(good)
person = bad["originator"]["originatorPerson"][0]["naturalPerson"]
person["customerIdentification"] = " "
person["name"]["nameIdentifier"][0].update(primaryIdentifier="Öztürk",
naturalPersonNameIdentifierType="ALIA")
legal = bad["beneficiary"]["beneficiaryPerson"][0]["legalPerson"]
legal["nationalIdentification"]["nationalIdentifier"] = "3M5E1GQKGL17HI8CPN20"
print("broken:", check(bad))
for amount in (10_000, 30_000, float("nan")):
try:
print(f"Art. 24/A at TRY {amount:,}:", turkey_24a_gaps(bad, amount))
except ValueError as e:
print("rejected:", e)Output:
valid: []
broken: ['C1 no identifying data', 'C11 bad LEI', 'C6 no legal name', 'Max100Text: use localNameIdentifier']
Art. 24/A at TRY 10,000: []
Art. 24/A at TRY 30,000: ['one sender identifier']
rejected: bad amount: nan- Turkey versus IVMS. At TRY 10,000 the Art. 24/A check passes while C1 fails: Turkey wants only names and wallets below the limit; a strict IVMS receiver wants an identifier.
- Silent passes. The standard's example LEI fits its own pattern but fails the check digits, and NaN fails every comparison, so an unguarded amount check passes it as small.
- EU versus IVMS. C1 accepts a customer number alone. Art. 14(1)(d) lists more, and European Banking Authority (EBA) Guidelines (opens in a new tab) paragraph 39 asks for the combination that best identifies the person. Have compliance write that rule.
Counterparty discovery and travel rule protocols
Each route finds counterparties its own way, and the EBA warns that providers might need several systems because not all interoperate.
| Route | What its documents describe | Discovery and security |
|---|---|---|
| Binance (opens in a new tab) (platform API) | POST /sapi/v1/localentity/withdraw/apply and deposit questionnaires for local entities; country list "Currently supports AU and BR entities." | For its own users, not a network; Turkey not mentioned |
| GTR (opens in a new tab) | API with callback URL | Provider allowlist; mTLS; end-to-end encryption required |
| Notabene (opens in a new tab) (vendor API) | txCreate, txValidateFull, txNotify | Counterparty DID from its widget or txValidateFull |
| Sumsub (opens in a new tab) (vendor API) | API, SDK, or Fireblocks or DFNS setups, over GTR, CODE, Sygna Bridge, TRP and its own protocol; sandbox test provider | Wallet Address Book, protocol lookups, blockchain analytics |
| TRP (opens in a new tab) | HTTPS and JSON; specification 3.2.1, 29 July 2024 | No directory: a Travel Address from the beneficiary's provider; mTLS; payload encryption only through extensions, per TRISA (opens in a new tab) |
The texts name no protocol: EBA paragraph 25 and Art. 24/A(5) in Turkey both allow APIs and independent messaging. EBA paragraph 26 lists the tests: connectivity, reachability, missing-data detection, and data integration, security and reliability. TRISA documents a partial bridge to TRP. The domain travelruleprotocol.org now serves unrelated content, so take TRP from OpenVASP's GitLab.
Unhosted wallets and self-hosted addresses
You collect the data from your own customer and, in the EU above EUR 1,000, assess who controls the address.
- Detect. EBA paragraphs 77 and 78 point to blockchain analytics, data providers and messaging identifiers, then the customer.
- Limit. Art. 14(5) says "exceeding EUR 1 000" and EBA paragraph 81 says "amounts to or exceeds", so settle exactly EUR 1,000 with compliance. Value the transfer at its exchange rate at that time, regardless of fees (paragraph 82).
- Prove. Paragraph 83 lists attended or unattended verification, a small transfer from and to the address, and a signed message. Paragraph 86 allows whitelisting with monitoring.
Hypothetical EU example. A EUR 1,200 withdrawal to a self-hosted address: hold the originator and beneficiary data and assess control before it runs. A EUR 300 withdrawal needs the data only.
Outbound and inbound states: hold funds on the message
Keep message state separate from chain state, and let the message state decide when funds may move.
| Your state | Meaning | TRP | Notabene (opens in a new tab) |
|---|---|---|---|
SENT | Awaiting counterparty | Inquiry POST | SENT |
APPROVED | May broadcast | approved | ACCEPTED |
REFUSED | Do not broadcast | rejected | REJECTED, DECLINED |
BROADCAST | Hash shared | txid | txhash added |
- Outbound. EU Art. 14(8) bars executing before compliance, and EBA paragraph 25 says data goes no later than initiation of the blockchain transaction. A timeout goes to review, never to release.
- Inbound. A deposit can land before its data, so hold it (Art. 16(3), 17(1)): Notabene's
txNotifythen opens anINCOMPLETEmessage, and Binance'stravelRuleStatusV2field definesPENDINGas frozen. Ask through the same channel (paragraph 58). - Deadlines. EBA paragraph 56 caps a request at three working days within the Union and five from outside, or up to seven for longer or non-EU chains. Then reject or return (Art. 17(1)); paragraph 55 points to a secure, segregated account when a return is impossible. In Turkey, ask and then return (Art. 24/A(3)).
Retries, idempotency and repeat failures
Documents differ on retries, so put each route behind one internal transfer ID and its own policy.
- GTR (opens in a new tab): requests run once, except three HTTP 500 errors, which it suggests retrying with the same
requestIdevery 30 seconds, up to 5 times. - Notabene: a repeated
transactionRefreturns 409 while the first call is processing and 200 with the existing message afterward. - TRP: a new UUID per call, retries left undefined, and approval shown both as an immediate reply and as a callback.
Use an outbox, deduplicate inbound messages on a non-empty message ID and count failures per counterparty: EU Art. 17(2) requires action and reporting on repeat failures, UK reg. 64D(5) reporting to the FCA, and Turkey's Art. 24/A(3) points to rejecting transfers or ending the relationship.
Storage, privacy and audit
Keep what proves each decision as long as the law requires, and no longer.
- Retention. EU Art. 26 sets five years, then deletion unless national law allows more. Turkey sets eight years (Measures Regulation Art. 46).
- Record. Raw and normalized payload, protocol, counterparty, timestamps, checks, decision and person. Turkish platforms also collect a transfer description of at least 20 characters (MASAK General Communiqué 29, Art. 4(5) (opens in a new tab)).
- Privacy. EU Art. 14(4) ties submission to security and the GDPR. Keep personal data in a separate encrypted store and only references in logs.
Transaction screening is covered in crypto payment API integration. For integration work in general, see Fincode's exchange API integration and Turkish exchange connectors pages; naming Binance or a vendor here does not mean Fincode integrates it or has built on it. Licensing and compliance decisions stay with the regulated provider.
Frequently asked questions
Does the travel rule cover person-to-person transfers?
Not in the EU text when no provider is involved: Article 2(4) excludes them.
What is the travel rule threshold in Turkey?
TRY 30,000 since 7 October 2026 for the full data set, with the sender's details verified. Below it, names and wallet addresses still travel.
What do the Sumsub, Notabene and Binance travel rule APIs do?
Sumsub and Notabene document vendor layers for exchanging data with other providers. Binance documents endpoints for its own local entities.
Is IVMS 101 a JSON schema?
No. IVMS 101.2023 is a data model with no JSON binding, so field names vary between implementations.
Sources
- Regulation (EU) 2023/1113 on information accompanying transfers of funds and certain crypto-assets (opens in a new tab)
- EBA Travel Rule Guidelines, EBA/GL/2024/11 (opens in a new tab)
- interVASP: IVMS 101.2023 data model standard (opens in a new tab)
- Mevzuat: Measures Regulation, Articles 24/A and 46, consolidated (Turkish) (opens in a new tab)
- Mevzuat: Capital Markets Law No. 6362, Article 99/A (Turkish) (opens in a new tab)
- UK Money Laundering Regulations 2017, Part 7A (opens in a new tab)
- US 31 CFR 1010.410, July 2025 edition (opens in a new tab)
- FinCEN Guidance FIN-2019-G001, 9 May 2019 (opens in a new tab)
- OpenVASP: TRP core specification 3.2.1 (opens in a new tab)
- TRISA: OpenVASP and TRP integration (opens in a new tab)
- GTR: error handling and retries (opens in a new tab)
- Notabene: Travel Rule statuses (opens in a new tab)
- Sumsub: Travel Rule overview (opens in a new tab)
- Binance: Travel Rule wallet REST API (opens in a new tab)
- MASAK: compliance guide for crypto asset service providers, September 2025 (Turkish) (opens in a new tab)
This guide is general information about software and markets, not investment, legal or tax advice. Automated trading can lose money, past or backtested performance does not guarantee future results, and the rules that apply depend on your jurisdiction and your exchange's terms. Sources, checks and corrections: see the editorial policy.