> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Travel Rule FATF API: Kepatuhan VASP

> Didit: pertukaran data pengirim dan penerima Travel Rule FATF untuk VASP dan PSP kripto, pelacakan protokol, $0.02 per pertukaran.

Didit menjalankan pertukaran pengirim-penerima FATF/EU Transfer of Funds Regulation (TFR) untuk transfer aset virtual. Didit mencari jalur yang menjangkau VASP pihak lawan, menegosiasikan data yang diperlukan melalui jalur tersebut, melacak pertukaran melalui siklus hidup 13 status, dan memberi tahu Anda saat pertukaran telah selesai sehingga Anda dapat merilis dana on-chain.

## Ikhtisar

FATF Travel Rule (Rekomendasi 16), yang diterapkan di UE sebagai Transfer of Funds Regulation, mewajibkan Penyedia Layanan Aset Virtual (VASP) pengirim (**VASP pengirim**) untuk mengumpulkan dan mengirimkan informasi pengirim dan penerima kepada VASP penerima (**VASP penerima**) sebelum transfer aset virtual diselesaikan.

Berbeda dengan sebagian besar yurisdiksi, EU TFR berlaku **tanpa jumlah minimum**: setiap transfer kripto termasuk dalam cakupan, bukan hanya transfer di atas ambang pelaporan.

Produk Travel Rule dari Didit adalah pertukaran terkelola, bukan sekadar kolom data:

* Anda mengirimkan transfer dengan `transaction_category: "travelRule"`.
* Didit mencoba jalur sesuai urutan prioritas untuk menjangkau VASP pihak lawan, menjalankan pertukaran melalui jalur pertama yang berhasil menjangkaunya, dan, jika pihak lain mengembalikan nama penerima, mencocokkannya dengan nama yang Anda kirim.
* Anda hanya boleh menyiarkan transfer di on-chain setelah pertukaran mencapai `COMPLETED`.
* Anda kemudian melaporkan hash transaksi on-chain kembali ke Didit untuk menutup pertukaran dengan status `FINISHED`.

Tujuh jalur dirilis dalam versi ini, dicoba sesuai urutan prioritas yang ketat: jalur pertama yang dapat menjangkau VASP pihak lawan akan dipakai.

| Prioritas | Jalur | Cara kerjanya |
| - | - | - |
| 1 | `INTERNAL` | Digunakan saat pelanggan Didit lain telah membuktikan kendali atas dompet penerima dengan pesan bertanda tangan atau deposit uji. Didit membuat transfer masuk yang cocok di aplikasi pelanggan tersebut dan menegosiasikan pertukaran sepenuhnya di dalam platform, tanpa panggilan jaringan keluar. Instan. |
| 2 | `TRP` | Integrasi asli dengan Travel Rule Protocol (TRP / OpenVASP) yang terbuka. Digunakan saat transfer membawa [Travel Address](#travel-address), entri buku alamat dompet tujuan menyimpannya, atau VASP pihak lawan ditemukan di [direktori](#direktori) dengan endpoint TRP. Membawa aset yang tercantum di bawah [identifier aset TRP](#pengidentifikasi-aset-trp). Didit bertukar data pengirim dan penerima secara mesin-ke-mesin, tanpa putaran email. |
| 3 | `GTR` | Jaringan Global Travel Rule (GTR). Pihak lawan ditentukan oleh `counterparty_gtr_vasp_code` yang eksplisit atau entri direktori yang memuatnya. Didit membaca jawaban pihak lawan dari respons GTR, atau dengan melakukan polling status permintaan setiap 5 menit selama transfer menunggu. |
| 4 | `TRUST` | Jaringan TRUST. Pihak lawan ditentukan oleh `counterparty_trust_membership_id` atau entri direktori yang memuatnya. Hanya kirim: TRUST tidak mengirimkan balik apa pun yang dapat dibaca Didit, sehingga transfer menunggu di `AWAITING_COUNTERPARTY` hingga kedaluwarsa. |
| 5 | `VERIFYVASP` | Jaringan VerifyVASP. Pihak lawan ditentukan oleh `counterparty_verifyvasp_id` atau entri direktori yang memuatnya. Didit membaca jawaban pihak lawan dengan melakukan polling status verifikasi setiap 5 menit. |
| 6 | `SYGNA` | Jaringan Sygna Bridge (diakuisisi VerifyVASP pada 2026, masih beroperasi untuk anggota yang sudah ada). Implementasi asli protokol Sygna: IVMS101 terenkripsi ECIES dengan permintaan izin yang ditandatangani. Pihak lawan ditentukan oleh `counterparty_sygna_vasp_code` atau entri direktori yang memuatnya. Jawaban pihak lawan untuk menerima atau menolak akan menyelesaikan atau menolak transfer: Didit melakukan polling status transfer setiap 5 menit, dan juga menerima jawaban tersebut melalui callback Sygna-nya setelah host publik TRP Didit aktif. |
| 7 | `EMAIL` | Jalur cadangan yang digunakan saat tidak ada jalur protokol atau jaringan yang menjangkau pihak lawan dan Anda menyebutkan kontak kepatuhannya di `counterparty_vasp_email`, atau entri direktori pihak lawan memiliki [kontak kepatuhan](#kontak). Didit mengirimkan email ke kontak tersebut berisi tautan pengambilan sekali pakai agar mereka dapat mengonfirmasi atau menolak pertukaran tanpa akun Didit. Ini adalah andalan untuk masalah sunrise: pihak lawan yang belum dapat dijangkau di jaringan mana pun. |

Jalur jaringan (`GTR`, `TRUST`, `VERIFYVASP`, `SYGNA`) memerlukan keanggotaan jaringan di sisi pengirim, dan saat ini keanggotaan tersebut harus **milik Anda sendiri**.
Hubungkan kredensial keanggotaan Anda di **Marketplace** konsol (kategori Travel Rule networks), dan transfer Anda akan berjalan di bawah identitas jaringan Anda sendiri.

**Didit tidak memiliki keanggotaan platform untuk keempat jaringan saat ini, dan sedang melakukan onboarding sebagai penyedia di jaringan tersebut.**
Sampai onboarding itu selesai, `platform_available` bernilai `false` untuk keempatnya, mode pengaturan `didit` (perutean melalui keanggotaan platform Didit) tidak tersedia untuk jaringan mana pun, dan `disabled_networks` tidak memiliki apa pun untuk dinonaktifkan.
Keanggotaan yang Anda hubungkan sendiri selalu didahulukan dibanding keanggotaan platform.
Tidak ada keanggotaan jaringan yang disertakan secara default, termasuk GTR.
Mengaktifkan Travel Rule tidak mengaktifkan GTR, TRUST, VerifyVASP, atau Sygna.
Periksa [Get Travel Rule Settings](https://docs.didit.me/id/management-api/travel-rule/get-settings.md) untuk mode `networks` efektif aplikasi Anda, dan [Travel Rule networks](https://docs.didit.me/id/transaction-monitoring/travel-rule-networks.md) untuk jangkauan setiap jaringan saat ini.
Jika keempatnya melaporkan `unavailable`, tidak ada yang dapat merutekan pertukaran: hubungkan keanggotaan Anda sendiri di **Marketplace**, atau gunakan pihak lawan `INTERNAL`, `TRP`, atau `EMAIL` yang dapat dijangkau.

Saat Anda menyimpan keanggotaan, kode pesertanya harus milik Anda sendiri: permintaan penyimpanan menghasilkan respons `400` jika kodenya adalah kode Didit sendiri di jaringan tersebut, atau kode yang sudah dimiliki keanggotaan aplikasi lain.
Keanggotaan GTR memerlukan kunci privat ed25519 (base64), yang kunci publiknya didaftarkan di portal GTR: kunci ini mengenkripsi data pribadi yang Anda kirim dan mendekripsi data yang Anda terima.
Keanggotaan VerifyVASP mengarah ke Enclave VerifyVASP milik Anda sendiri: URL-nya adalah URL Enclave Anda, dan token-nya adalah token yang disajikan Enclave Anda kepada Didit.

Bahkan dengan keanggotaan Anda sendiri, jalur jaringan hanya merutekan transfer jika `beneficiary_data`-nya memuat id pihak lawan di jaringan tersebut (`counterparty_gtr_vasp_code`, `counterparty_trust_membership_id`, `counterparty_verifyvasp_id`, atau `counterparty_sygna_vasp_code`), atau entri direktori pihak lawan mencantumkannya di jaringan tersebut (lihat [Routes](#rute)).

`platform_available` melaporkan apakah keanggotaan platform telah dikonfigurasi, bukan pemeriksaan status jaringan secara langsung. Demikian pula, `connected` berarti kredensial keanggotaan Anda telah disimpan dan lolos validasi lokal; pertukaran langsung pertama akan memverifikasinya terhadap jaringan. Mode `didit` atau `own` tidak menjamin kemampuan menjangkau pihak lawan maupun keberhasilan pengiriman.

Dengan keanggotaan Anda sendiri, Didit membaca jawaban pihak lawan melalui `GTR`, `VERIFYVASP` dan `SYGNA` dari respons jaringan atau dengan melakukan polling ke jaringan setiap 5 menit, yang kemudian menyelesaikan atau menolak transfer.
`TRUST` hanya untuk pengiriman: transfer yang dikirim melalui jalur ini tetap berada di `AWAITING_COUNTERPARTY` hingga `confirmation_timeout_hours` berlalu, lalu berpindah ke `EXPIRED` dan `timeout_outcome` Anda berlaku.
Penerimaan transfer yang dikirim VASP lain kepada Anda melalui jaringan belum diaktifkan, dan belum ada pertukaran melalui jaringan yang telah diselesaikan dengan jaringan produksi: lihat [Jaringan Travel Rule](https://docs.didit.me/id/transaction-monitoring/travel-rule-networks.md).

Jaringan lain - CODE (aliansi Korea), TRISA, Notabene, dan Veriscope - tercantum di **Marketplace** konsol sebagai kartu permintaan akses.
Didit belum memiliki integrasi dengan jaringan tersebut, sehingga belum ada transfer yang dapat dirutekan melalui jaringan tersebut saat ini.

Ketika ketujuh jalur tidak dapat menentukan pihak lawan, Didit menjalankan satu langkah resolusi lagi sebelum menyerah: atribusi analitik blockchain.
Dompet tujuan dicocokkan dengan data analitik blockchain; ketika dompet tersebut milik bursa atau kustodian yang dikenal, Didit mencatat VASP hasil atribusi pada transfer, menambahkannya ke [direktori](#direktori), dan menjalankan ulang jalur sekali dengan nama baru.
Lihat [Atribusi analitik blockchain](#atribusi-analitik-blockchain) untuk perilaku lengkap dan harganya.

Transfer yang tujuannya [dideklarasikan sebagai dompet swakelola](#dompet-swakelola-yang-dideklarasikan) melewati ketujuh jalur - tidak ada VASP pihak lawan untuk diajak bertukar informasi - dan langsung menuju pembuktian kepemilikan dompet pengguna akhir.

> [!NOTE]
>
> Didit juga mengoperasikan sisi pertukaran untuk pihak lawan: endpoint identitas TRP publik dan endpoint permintaan informasi yang dipanggil VASP lain untuk menjangkau Anda, endpoint callback, dan alur pengambilan email.
> Anda tidak pernah memanggil endpoint tersebut sendiri - itu adalah infrastruktur terkelola - tetapi halaman [Interoperabilitas Travel Rule](https://docs.didit.me/id/transaction-monitoring/travel-rule-interoperability.md) mendokumentasikan setiap endpoint tersebut agar VASP pihak lawan dapat terhubung dengan Anda.
> Anda berinteraksi dengan Travel Rule hanya melalui endpoint `/v3/` yang dijelaskan di halaman ini.

## Apa yang dijalankan saat Anda mengirim transfer

Pemeriksaan berjalan di dalam satu panggilan `POST /v3/transactions/`. Saat Anda menerima respons, skrining sudah dijalankan, transfer sudah disimpan, dan aturan sudah dievaluasi.
Pertukaran data sendiri dimulai setelah respons: Didit memilih rail dan menghubungi pihak lawan di luar permintaan Anda, sehingga tidak ada jaringan atau pihak lawan yang dapat memperlambat atau menggagalkan pembuatan transaksi.
Setiap perubahan status setelah itu dikirim sebagai webhook [`travel_rule.status.updated`](#webhook) yang menyebutkan rail, dan objek transfer yang dikembalikan endpoint transfer Travel Rule memuat field [`delivery`](#pengiriman-dan-coba-lagi) yang menunjukkan apakah pesan berhasil terkirim.
Tidak ada pipeline yang perlu di-polling. Bagian yang asinkron adalah pertukaran data, jawaban pihak lawan, dan tindakan pengguna akhir.

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant You as Your platform
    participant Didit as Didit API
    participant CP as Counterparty VASP
    participant User as Your customer

    You->>Didit: POST /v3/transactions/ (travelRule)
    Note over Didit: Validate + bind subject + blocklist check
    Note over Didit: Device & IP enrichment
    Note over Didit: Crypto screening (when crypto + monitoring on)
    Note over Didit: Threshold check -> transfer stored (AWAITING_COUNTERPARTY)
    Note over Didit: Rules engine (EU TFR bundle + your rules)
    Didit--)You: transaction.created webhook
    Didit-->>You: Transaction + travel_rule.status + action_required
    Note over Didit: After the response: rails in priority order -> analytics attribution
    Didit->>CP: Exchange over the first reachable rail
    Didit--)You: travel_rule.status.updated (each status change)
    User->>Didit: Proves wallet control (when action_required)
    CP-->>Didit: Confirms beneficiary data
    Didit--)You: travel_rule.status.updated (COMPLETED)
    You->>You: Broadcast on-chain
    You->>Didit: PATCH .../travel-rule/ { payment_txn_id }
    Didit--)You: travel_rule.status.updated (FINISHED)
```

Langkah demi langkah:

1. **Validasi dan pengikatan subjek.** Payload divalidasi.
   `transaction_id` yang sudah dipakai di aplikasi Anda akan ditolak dengan `400`, dan jika dua permintaan dengan id yang sama berjalan bersamaan, salah satunya menerima `409`.
   `subject` ditautkan ke profil pengguna atau bisnis Anda melalui `vendor_data`, sehingga transfer muncul di profil tersebut untuk pemantauan.
   `vendor_data` subjek atau pihak lawan yang masuk daftar blokir ditolak dengan `400`, dan tidak ada transaksi yang dibuat.
   Dompet, rekening bank, IP, dan perangkat yang masuk daftar blokir diperiksa pada langkah 6 dan menolak transaksi di sana, setelah routing dijalankan.
2. **Pengayaan perangkat dan jaringan.** IP pihak-pihak diperkaya dengan data geografis, dan konteks perangkat apa pun (otomatis saat [pengiriman melalui SDK](https://docs.didit.me/id/transaction-monitoring/sdk-transaction-submission.md)) dinormalisasi ke dalam graf perangkat. Ini adalah graf yang sama dengan yang diisi sesi KYC, sehingga "terkait berdasarkan perangkat" berlaku lintas onboarding dan transaksi.
3. **Skrining kripto.** Untuk transfer kripto dengan pemantauan aktif, dompet terkait (atau hash on-chain) diskrining terhadap analitik blockchain sebelum ada yang dipertukarkan: paparan sanksi, kedekatan dengan mixer, dana hasil curian. Lihat [Skrining kripto & dompet](https://docs.didit.me/id/transaction-monitoring/aml-screening.md).
4. **Transfer Travel Rule.** Mesin pertukaran memeriksa ambang batas dan menghormati [deklarasi dompet swakelola](#dompet-swakelola-yang-dideklarasikan), lalu menyimpan transfer: `NOT_APPLICABLE` di bawah ambang batas Anda, `UNCONFIRMED_OWNERSHIP` untuk dompet swakelola yang dideklarasikan, `COMPLETED` ketika dompet lawan adalah dompet terverifikasi milik Anda sendiri, dan `AWAITING_COUNTERPARTY` selain itu, dengan rail yang masih kosong.
   Setiap perubahan status memasukkan event `travel_rule.status.updated` ke antrean, dan Didit mengirimkannya setelah `transaction.created` milik transaksi (langkah 7).
5. **Penerbitan widget kepemilikan dompet.** Jika transfer membutuhkan bukti kontrol dari pengguna akhir dan `auto_wallet_verification` aktif, sesi [widget kepemilikan dompet](https://docs.didit.me/id/transaction-monitoring/wallet-ownership-widget.md) diterbitkan dan dikembalikan dalam `action_required`.
6. **Evaluasi aturan.** Setiap aturan aktif dijalankan. [Bundel EU TFR](#paket-aturan-eu-tfr) bereaksi terhadap status transfer yang ditetapkan pada langkah 4, aturan kustom Anda melihat keluaran skrining dari langkah 3, dan sebuah aturan dapat menahan transaksi (`IN_REVIEW`), menolaknya, atau meminta [verifikasi tingkat lanjut](https://docs.didit.me/id/transaction-monitoring/sdk-transaction-submission.md#tindakan-yang-diperlukan-pengguna) (`AWAITING_USER`).
7. **Penagihan dan notifikasi.** Transaksi keluar ditagihkan dalam satu baris: [baris Travel Rule](#harga) ketika transaksi memulai pertukaran data, dan Transaction Screening selain itu. Transfer masuk tidak dikenakan biaya apa pun, dan aplikasi sandbox tidak pernah ditagih.
   Respons dikembalikan, dan event `transaction.created` dikirim ke tujuan webhook Anda, diikuti event `travel_rule.status.updated` dari langkah 4.
8. **Routing, setelah respons.** Didit menelusuri [tujuh rail](#ikhtisar) sesuai urutan prioritas. Jika tidak ada yang berhasil, [atribusi analitik blockchain](#atribusi-analitik-blockchain) mengidentifikasi pihak lawan dan rail dijalankan ulang sekali. Rail pertama yang dapat dijangkau membawa pertukaran data: transfer tetap `AWAITING_COUNTERPARTY` di rail tersebut selama pihak lawan belum menjawab, langsung diselesaikan ketika pihak lawan `INTERNAL` ditemukan (`COMPLETED` atau `COUNTERPARTY_MISMATCHED_DATA`), atau menjadi `COUNTERPARTY_VASP_NOT_FOUND` ketika tidak ada rail yang menjangkau pihak lawan. Setiap perubahan memicu `travel_rule.status.updated`, dan aturan Anda dijalankan ulang setiap kali status atau rail berubah. Transfer yang masih berstatus `COUNTERPARTY_VASP_NOT_FOUND` setelah routing menerima sesi widget kepemilikan dompetnya pada titik itu (jika `auto_wallet_verification` aktif). Bacalah dari `action_required` transaksi dengan [Ambil transaksi](https://docs.didit.me/id/management-api/transactions/get.md).

### Bagaimana setiap langkah memenuhi kewajiban Anda

| Langkah pipeline | Kewajiban yang dipenuhinya |
| - | - |
| Data pengirim yang Anda berikan dalam `originator_data` | Informasi pengirim yang akurat (FATF R.16; EU TFR Pasal 14). Pada rail yang membawa data orang (`INTERNAL`, `TRP`, dan rail jaringan), Didit mengirimkan identitas terverifikasi ketika subjeknya adalah pengguna dengan verifikasi KYC Didit yang disetujui (lihat [Data terverifikasi dan asal-usul](#data-terverifikasi-dan-asal-data)), dan selain itu hanya `originator_data` persis seperti yang Anda kirim. |
| Pertukaran rail sebelum penyelesaian | Informasi pengirim dan penerima dikirimkan ke VASP pihak lawan **sebelum** transfer diselesaikan (FATF R.16; EU TFR Pasal 14-16) |
| Pencocokan nama penerima | Verifikasi bahwa data penerima cocok dengan tujuan (kewajiban CASP penerima menurut EU TFR Pasal 16) |
| Bukti kepemilikan dompet swakelola | Kewajiban dompet swakelola EU TFR: memverifikasi kepemilikan alamat yang tidak di-hosting alih-alih bertukar data dengan VASP |
| Skrining kripto + bundel aturan EU TFR | Prosedur berbasis risiko untuk transfer dengan informasi yang hilang atau tidak lengkap, dan kontrol paparan sanksi |
| Gerbang `COMPLETED` sebelum siaran | Dana tidak dilepaskan sampai pertukaran data selesai. Inilah inti aturannya |
| Penutupan `FINISHED` dengan hash on-chain dan linimasa | Pencatatan: setiap transfer menyimpan linimasa negosiasinya yang lengkap untuk audit |

> [!NOTE]
>
> **Catatan pengujian.** Aplikasi sandbox melewati evaluasi aturan dan penagihan, serta tidak mengirim webhook `transaction.created` atau `transaction.status.updated`. Transaksi sandbox tetap `APPROVED` kecuali `timeout_outcome` Anda diterapkan pada transfer Travel Rule yang kedaluwarsa, dan tidak ada yang ditagih.
> Mesin pertukaran Travel Rule itu sendiri berjalan di aplikasi sandbox ketika Travel Rule diaktifkan, hanya melawan satu pihak lawan: setiap pertukaran **keluar** diarahkan ke [Didit Test VASP](https://docs.didit.me/id/transaction-monitoring/travel-rule-sandbox.md) di rail `TEST_VASP`, yang menjawab di dalam Didit dengan skenario yang Anda pilih, sehingga transfer dapat selesai, ditolak, tidak cocok, tidak dapat dijangkau, kedaluwarsa, atau menunggu kepemilikan dompet.
> Tidak ada pesan kepatuhan yang pernah sampai ke VASP pihak lawan yang sungguhan, dan webhook `travel_rule.status.updated` dikirim dengan `environment: sandbox`.
> Untuk transfer **masuk**, VASP pengujian dapat mengirimkan transfer kepada Anda ([Picu Transfer Masuk Test VASP](https://docs.didit.me/id/management-api/travel-rule/trigger-test-vasp-inbound.md)), dan registrasi (`POST /v3/travel-rule/inbound/`) diselesaikan terhadap buku alamat dompet Anda seperti pada aplikasi produksi: `ON_HOLD`, `UNCONFIRMED_OWNERSHIP`, `COUNTERPARTY_MISMATCHED_DATA`, atau `COMPLETED` lalu `FINISHED`.
> Lihat [Menguji Travel Rule di sandbox](https://docs.didit.me/id/transaction-monitoring/travel-rule-sandbox.md).

## Siklus hidup

Setiap transfer memiliki `status` yang dipilih dari 13 nilai. Pertukaran dimulai dari `AWAITING_COUNTERPARTY` dalam kondisi normal, dari `NOT_APPLICABLE` ketika jumlahnya di bawah `threshold_amount` Anda atau permintaan pembayaran Lightning tidak mencantumkan penerima (lihat [Lightning](#lightning)), atau dari `UNCONFIRMED_OWNERSHIP` ketika tujuan telah [dinyatakan sebagai dompet swakelola](#dompet-swakelola-yang-dideklarasikan). Pertukaran berakhir di salah satu status akhir: `FINISHED`, `CANCELLED`, atau `EXPIRED`.

Transfer menjalankan mesin status sendiri, **terpisah dari** status tinjauan transaksi yang mendasarinya. Status pertukaran tidak pernah mengubah status transaksi dengan sendirinya, dengan satu pengecualian: kedaluwarsa menerapkan `timeout_outcome` yang Anda konfigurasi (atau [kebijakan sunrise atau non-responsif](#kebijakan-sunrise-dan-tidak-responsif) jika berlaku). Sebagai gantinya, aturan Anda dijalankan ulang pada setiap transisi, sehingga [aturan EU TFR](#paket-aturan-eu-tfr) atau aturan apa pun yang menggunakan `travel_rule_status` dapat memindahkan transaksi, misalnya ke `IN_REVIEW`. Transfer yang memerlukan bukti kontrol dompet dari pengguna akhir menambahkan blok `action_required` ke transaksi, tetapi `status`-nya tetap seperti yang ditetapkan aturan Anda. Baca status pertukaran dari `travel_rule.status`, dan baca keputusan izinkan / tahan / tolak dari `status` transaksi itu sendiri.

Setiap transisi (dan setiap status yang dilaporkan secara pasif) juga dicerminkan ke nilai kustom transaksi agar [aturan](https://docs.didit.me/id/transaction-monitoring/rules.md) dapat merujuknya: `custom_values.travel_rule_status` (status kanonis), `custom_values.travel_rule_rail` (jalur yang membawa pertukaran, kosong hingga satu jalur dipilih), dan `custom_values.travel_rule_regime` (diturunkan dari `jurisdiction` di [pengaturan](#pengaturan) Anda: `SG` → `singapore`, `GB` → `uk`, dan kode anggota EU atau EEA apa pun seperti `DE` atau `FR` → `eu`; kode yang tidak dipetakan ditetapkan dalam huruf kecil, misalnya `US` → `us`. `props.travel_rule_regime` yang Anda kirim sendiri selalu didahulukan daripada nilai yang diturunkan).

| Status | Arti |
| - | - |
| `AWAITING_COUNTERPARTY` | Transfer menunggu pihak lawan: pertama selagi Didit memilih jalur dan mengirim pertukaran, tepat setelah pembuatan, lalu selagi pihak lawan merespons. [`delivery`](#pengiriman-dan-coba-lagi) pada transfer menunjukkan apakah pesan tersampaikan. `TRUST` hanya mengirim, sehingga transfer di atasnya tetap di status ini hingga kedaluwarsa. |
| `UNCONFIRMED_OWNERSHIP` | Transfer menunggu bukti kontrol dompet. Status ini tercapai ketika dompet pihak lawan [dinyatakan swakelola](#dompet-swakelola-yang-dideklarasikan) saat pengajuan (keluar atau masuk), atau ketika transfer masuk mengarah ke [entri buku alamat](#buku-alamat-dompet) yang kepemilikannya belum diverifikasi. Berlanjut melalui [widget kepemilikan dompet](https://docs.didit.me/id/transaction-monitoring/wallet-ownership-widget.md) atau [`POST .../travel-rule/ownership/`](#mengonfirmasi-kepemilikan-dompet). |
| `ON_HOLD` | Didit hanya menetapkan status ini pada transfer masuk: dompet tujuan dari [pendaftaran setelah deposit](#pendaftaran-sunrise-setelah-deposit) atau kueri `TRP` masuk tidak ada di [buku alamat](#buku-alamat-dompet) Anda, atau kueri `TRP` masuk menunggu keputusan Anda (terima otomatis nonaktif, atau jawaban otomatis tidak dapat dikirim). Selesaikan dengan [`POST .../travel-rule/ownership/`](#mengonfirmasi-kepemilikan-dompet). Status ini tidak mengubah status transaksi dengan sendirinya; [aturan pustaka](https://docs.didit.me/id/transaction-monitoring/rules-library.md) opt-in `travel-rule-pending-action` memindahkan transaksi seperti itu ke `AWAITING_USER`. |
| `COMPLETED` | Pertukaran berhasil diselesaikan: pihak lawan (atau, pada transfer masuk, Anda) menyetujuinya, atau pemeriksaan yang dijalankan Didit pada jalur tersebut lolos (kecocokan nama penerima, bukti kepemilikan dompet). Aman untuk disiarkan on-chain. |
| `FINISHED` | Pertukaran ditutup dengan hash transaksi on-chain-nya. Pada transfer keluar, Anda melaporkan hash melalui [`PATCH .../travel-rule/`](#mengirim-transfer). Pada transfer masuk, Didit menetapkan status ini ketika deposit sudah diselesaikan ([pendaftaran setelah deposit](#pendaftaran-sunrise-setelah-deposit)), ketika pengirim mengonfirmasi transfer `TRP`, atau ketika sisi keluar `INTERNAL` selesai. |
| `CANCELLED` | Dibatalkan secara manual dengan `action: "cancel"` dari status non-akhir mana pun, atau dibatalkan oleh pengirim transfer `TRP` masuk. |
| `EXPIRED` | `confirmation_timeout_hours` berlalu selagi `AWAITING_COUNTERPARTY`. Proses pembersih (setiap 15 menit) memberi status kedaluwarsa pada transfer dan menerapkan `timeout_outcome` yang Anda konfigurasi ke transaksi yang mendasarinya: `REJECT` menolaknya, `HOLD` memindahkannya ke peninjauan, `PROCEED` membiarkannya tidak tersentuh. [Kebijakan sunrise atau non-responsif](#kebijakan-sunrise-dan-tidak-responsif) Anda menggantikan `timeout_outcome` jika berlaku. |
| `COUNTERPARTY_MISMATCHED_DATA` | Nama penerima tidak memenuhi `name_matching_strictness` yang dikonfigurasi terhadap pihak lainnya: nama yang dikembalikan pihak lawan, atau `holder_name` dari entri buku alamat yang cocok. |
| `COUNTERPARTY_VASP_NOT_FOUND` | Tidak satu pun dari tujuh jalur, maupun mekanisme cadangan [atribusi analitik blockchain](#atribusi-analitik-blockchain), dapat menemukan VASP pihak lawan yang dapat dijangkau untuk transfer ini. Entitas yang diatribusikan tetap dicatat pada transfer dan di direktori. Pada transfer keluar, Didit otomatis membuat sesi [widget kepemilikan dompet](https://docs.didit.me/id/transaction-monitoring/wallet-ownership-widget.md) (jika `auto_wallet_verification` aktif) agar transfer tetap dapat selesai sebagai transfer dompet swakelola. `reason` dan `next_actions` menjelaskan penyebabnya dan apa yang dapat melanjutkannya: lihat [Mengapa transfer tertahan](#mengapa-transfer-macet). |
| `COUNTERPARTY_VASP_NOT_REACHABLE` | VASP pihak lawan telah diidentifikasi, tetapi jalur yang dipilih tidak dapat mengirimkan: identitas `TRP` atau endpoint kuerinya tidak dapat dijangkau, identitas yang dilaporkannya tidak cocok dengan `counterparty_vasp_lei` atau `counterparty_vasp_name`, jaringan menolak pesan atau tidak menerimanya setelah enam percobaan (lihat [Pengiriman dan percobaan ulang](#pengiriman-dan-coba-lagi)), atau penyedia email menolak email kepatuhan. `reason` membedakan hal-hal ini, dan `next_actions` menjelaskan apa yang dapat melanjutkan transfer: lihat [Mengapa transfer tertahan](#mengapa-transfer-macet). Coba lagi dengan `action: "resend"` setelah dapat dijangkau kembali. |
| `COUNTERPARTY_VASP_GENERAL_DECLINE` | Pihak lawan menolak pertukaran: kepemilikan ditolak, pengambilan email ditolak, atau penolakan `TRP` atau Sygna. |
| `NOT_ENOUGH_COUNTERPARTY_DATA` | Kueri `TRP` masuk mengidentifikasi penerima tanpa nama maupun alamat dompet, sehingga Didit tidak dapat mencocokkannya dengan buku alamat Anda. Baik endpoint kepemilikan maupun `resend` tidak menerima transfer masuk seperti ini: Anda hanya dapat membatalkannya, dan pembatalan tidak menjawab kueri pihak lawan. Didit tidak pernah menetapkan status ini pada transfer keluar; jika Anda mencatatnya sendiri pada transfer keluar, `action: "resend"` menjalankan ulang perutean. |
| `NOT_APPLICABLE` | Jumlah transfer berada di bawah `threshold_amount` yang dikonfigurasi, permintaan pembayaran [Lightning](#lightning) keluar tidak mencantumkan penerima (`chain_details.not_applicable_reason` menjelaskan alasannya), atau Anda mencatat status ini sendiri saat Travel Rule dinonaktifkan (termasuk nilai lama `UNKNOWN` dan `EXEMPT`, lihat di bawah). |

> [!WARNING]
>
> **Jangan pernah menyiarkan sebelum `COMPLETED`.**
> Melepaskan dana on-chain saat transfer berstatus `AWAITING_COUNTERPARTY`, `UNCONFIRMED_OWNERSHIP`, atau dalam status ketidakcocokan atau penolakan apa pun akan menggagalkan tujuan pertukaran ini.
> Jalankan langkah siaran Anda hanya jika `status == "COMPLETED"`, lalu panggil `PATCH .../travel-rule/` dengan `payment_txn_id` yang dihasilkan untuk memindahkan transfer ke `FINISHED`.

Transisi secara sekilas (`CANCELLED` juga dapat dicapai dari setiap status non-terminal dengan `action: "cancel"`):

```mermaid theme={null}
stateDiagram-v2
    [*] --> NOT_APPLICABLE: below threshold
    [*] --> UNCONFIRMED_OWNERSHIP: self-hosted wallet declared
    [*] --> AWAITING_COUNTERPARTY: transfer stored, routing queued
    [*] --> COMPLETED: your own verified wallet
    [*] --> ON_HOLD: inbound with no matching wallet entry
    [*] --> NOT_ENOUGH_COUNTERPARTY_DATA: inbound TRP inquiry names no beneficiary
    AWAITING_COUNTERPARTY --> COUNTERPARTY_MISMATCHED_DATA: INTERNAL rail, verified entry, name mismatch
    AWAITING_COUNTERPARTY --> COUNTERPARTY_VASP_NOT_FOUND: no rail resolved
    AWAITING_COUNTERPARTY --> COUNTERPARTY_VASP_NOT_REACHABLE: delivery failed
    AWAITING_COUNTERPARTY --> COMPLETED: counterparty confirmed, names match where checked
    AWAITING_COUNTERPARTY --> COUNTERPARTY_MISMATCHED_DATA: name match failed
    AWAITING_COUNTERPARTY --> COUNTERPARTY_VASP_GENERAL_DECLINE: counterparty declined
    AWAITING_COUNTERPARTY --> EXPIRED: confirmation timeout
    AWAITING_COUNTERPARTY --> COUNTERPARTY_VASP_NOT_REACHABLE: TRP inquiry not delivered
    UNCONFIRMED_OWNERSHIP --> COMPLETED: ownership proven, names match
    UNCONFIRMED_OWNERSHIP --> COUNTERPARTY_MISMATCHED_DATA: name match failed
    UNCONFIRMED_OWNERSHIP --> COUNTERPARTY_VASP_GENERAL_DECLINE: ownership denied
    ON_HOLD --> COMPLETED: you confirm the wallet, names match
    ON_HOLD --> COUNTERPARTY_MISMATCHED_DATA: you confirm the wallet, name mismatch
    ON_HOLD --> COUNTERPARTY_VASP_GENERAL_DECLINE: you deny the wallet
    COUNTERPARTY_MISMATCHED_DATA --> COMPLETED: you approve an inbound TRP inquiry
    COUNTERPARTY_MISMATCHED_DATA --> COUNTERPARTY_VASP_GENERAL_DECLINE: you decline an inbound TRP inquiry
    COUNTERPARTY_VASP_NOT_FOUND --> COMPLETED: wallet ownership proven in the widget
    COUNTERPARTY_VASP_NOT_FOUND --> AWAITING_COUNTERPARTY: action resend
    COUNTERPARTY_VASP_NOT_REACHABLE --> AWAITING_COUNTERPARTY: action resend
    COMPLETED --> FINISHED: payment_txn_id reported or deposit already settled
    FINISHED --> [*]
    EXPIRED --> [*]
```

### Pengiriman dan coba lagi

Didit mengirim setiap pesan yang wajib dikirim oleh sebuah transfer di luar permintaan yang memicunya, dan mencoba lagi hingga pihak lawan menerimanya.
Objek transfer yang dikembalikan oleh [Selesaikan, batalkan, atau kirim ulang](https://docs.didit.me/id/management-api/travel-rule/update-transfer.md), [Konfirmasi kepemilikan](https://docs.didit.me/id/management-api/travel-rule/confirm-ownership.md) dan [pendaftaran sunrise](#pendaftaran-sunrise-setelah-deposit) memuat pesan terbaru di `delivery`, begitu pula objek `travel_rule` yang tertanam pada transaksi. Nilainya `null` jika transfer tidak pernah wajib mengirim pesan.

| Kolom | Keterangan |
| - | - |
| `kind` | `SEND` (pesan pertama ke pihak lawan), `ANSWER` (penerimaan atau penolakan Anda, yang wajib dikirim ke jaringan yang meminta), `TXID` (hash on-chain, setelah Anda menyelesaikan transfer), `CANCEL` (setelah Anda membatalkannya), atau `POLL` (kueri status ke jaringan yang menyediakannya, setiap 5 menit selama transfer menunggu pihak lawan). |
| `status` | `QUEUED`, `SENDING`, `RETRYING`, `DELIVERED`, atau `FAILED`. |
| `rail` | Jalur yang membawa pesan; kosong hingga Didit memilih satu jalur untuk pesan pertama. |
| `attempts` | Jumlah percobaan yang telah dilakukan. |
| `last_error` | Alasan percobaan terakhir gagal, kosong jika tidak ada yang gagal. Ini berupa alasan singkat yang menyebutkan langkah dan jenis kegagalan, misalnya `sygna permission request failed: HTTP 503` atau `sygna status query failed: no answer in time`. Ketika GTR membalas dengan error, kode status dan pesannya sendiri ikut disertakan. Isi respons tidak pernah disertakan. |
| `next_attempt_at` | Kapan percobaan berikutnya dijalankan, selama pesan berstatus `QUEUED` atau `RETRYING`. |
| `delivered_at` | Kapan pihak lawan menerima pesan. |

Kegagalan yang mungkin masih dapat dipulihkan oleh jaringan (tidak ada jawaban tepat waktu, koneksi gagal, HTTP `408`, `429` atau `5xx`) dicoba ulang setelah 30 detik, 2 menit, 10 menit, 30 menit, dan 1 jam.
Ketika pesan pertama gagal permanen, yaitu jaringan menolaknya atau percobaan keenam juga gagal, transfer berpindah ke `COUNTERPARTY_VASP_NOT_REACHABLE` dengan `last_error` di dalam `timeline`, dan Anda dapat mencoba lagi dengan `action: "resend"`.
Pesan lain yang gagal permanen dicatat di `timeline`.
`delivery` tidak pernah menggantikan `status` transfer: baca hasil pertukaran dari `status`, dan gunakan `delivery` untuk melihat mengapa transfer masih menunggu.

### Nilai status lama

Jika Anda sudah mengirim `travel_rule_details.status` sebelum rilis ini, nilai-nilai tersebut tetap berfungsi dan dipetakan secara otomatis.
Varian camelCase dari status apa pun (misalnya `counterpartyVaspNotFound`) juga diterima, baik saat pengiriman data maupun dalam nilai kondisi [aturan](https://docs.didit.me/id/transaction-monitoring/rules.md), dan dinormalisasi ke bentuk kanonis:

| Nilai lama | Dipetakan ke |
| - | - |
| `UNKNOWN` | `NOT_APPLICABLE` |
| `COMPLIANT` | `COMPLETED` |
| `PENDING_ACTION` | `ON_HOLD` |
| `PENDING_COUNTERPARTY` | `AWAITING_COUNTERPARTY` |
| `FAILED` | `CANCELLED` |
| `EXEMPT` | `NOT_APPLICABLE` |

## Pengaturan

Konfigurasi profil VASP dan kebijakan negosiasi Anda sekali per aplikasi dengan `GET`/`PUT /v3/travel-rule/settings/`.

```bash theme={null}
curl -X GET https://verification.didit.me/v3/travel-rule/settings/ \
  -H "x-api-key: YOUR_API_KEY"
```

```json theme={null}
{
  "is_enabled": false,
  "jurisdiction": "EU",
  "name_matching_strictness": "DEFAULT",
  "confirmation_timeout_hours": 48,
  "timeout_outcome": "HOLD",
  "threshold_amount": "0.00",
  "inbound_auto_accept": true,
  "allow_self_declaration": true,
  "allow_screenshot_proof": true,
  "auto_wallet_verification": true,
  "vasp_attribution_enabled": true,
  "counterparty_screening_enabled": false,
  "sunrise_policy": "",
  "sunrise_jurisdictions": ["CO", "KH", "VN"],
  "non_responsive_policy": "",
  "legal_name": "",
  "lei": "",
  "compliance_email": "",
  "is_discoverable": true,
  "travel_address": "",
  "disabled_networks": [],
  "networks": {
    "gtr": { "rail": "GTR", "mode": "unavailable", "platform_available": false, "connected": false },
    "trust": { "rail": "TRUST", "mode": "unavailable", "platform_available": false, "connected": false },
    "verifyvasp": { "rail": "VERIFYVASP", "mode": "unavailable", "platform_available": false, "connected": false },
    "sygna": { "rail": "SYGNA", "mode": "unavailable", "platform_available": false, "connected": false }
  }
}
```

```bash theme={null}
curl -X PUT https://verification.didit.me/v3/travel-rule/settings/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "is_enabled": true,
    "legal_name": "Origin CASP SL",
    "jurisdiction": "EU",
    "name_matching_strictness": "DEFAULT",
    "confirmation_timeout_hours": 48,
    "timeout_outcome": "HOLD",
    "is_discoverable": true
  }'
```

`PUT` adalah pembaruan parsial - kirim hanya kolom yang ingin Anda ubah.

| Kolom | Tipe | Deskripsi |
| - | - | - |
| `is_enabled` | boolean | Mengaktifkan alur negosiasi terkelola untuk transaksi `travelRule` keluar dari aplikasi ini. Membutuhkan `legal_name` yang tidak kosong (sudah tersimpan, atau disertakan dalam permintaan yang sama) - jika tidak, permintaan mengembalikan `400`. |
| `legal_name` | string | Nama resmi VASP Anda. Ditampilkan kepada pihak lawan pada halaman pengambilan email dan dikembalikan di [direktori VASP](#direktori). |
| `lei` | string | Legal Entity Identifier Anda, dikembalikan di direktori VASP. |
| `jurisdiction` | string | Kode yurisdiksi operasional VASP Anda, maksimal 8 karakter (default `"EU"`). |
| `name_matching_strictness` | string | `NONE`, `STRICT`, `CONTAINS`, `DEFAULT`, atau `FUZZY` - lihat di bawah. |
| `confirmation_timeout_hours` | integer | Jumlah jam transfer `AWAITING_COUNTERPARTY` boleh menunggu sebelum kedaluwarsa otomatis. Minimum `1`, default `48`. |
| `timeout_outcome` | string | Apa yang terjadi pada transaksi yang mendasarinya ketika transfer kedaluwarsa: `HOLD` memindahkannya ke peninjauan, `REJECT` menolaknya, `PROCEED` membiarkan statusnya tidak berubah. Default `HOLD`. `sunrise_policy` dan `non_responsive_policy` didahulukan jika salah satunya berlaku. |
| `sunrise_policy` | string | `HOLD`, `REJECT`, `PROCEED`, atau `""` (default) untuk mengikuti `timeout_outcome`: apa yang terjadi pada transfer yang kedaluwarsa ketika pihak lawannya adalah entri direktori di yurisdiksi yang tercantum dalam `sunrise_jurisdictions`. Lihat [Kebijakan sunrise dan non-responsif](#kebijakan-sunrise-dan-tidak-responsif). |
| `non_responsive_policy` | string | `HOLD`, `REJECT`, `PROCEED`, atau `""` (default) untuk mengikuti `timeout_outcome`: apa yang terjadi pada transfer yang kedaluwarsa ketika pihak lawannya adalah entri direktori dengan [responsivitas](#responsivitas) `UNRESPONSIVE`. `sunrise_policy` berlaku lebih dulu jika keduanya cocok. |
| `sunrise_jurisdictions` | string\[] | Hanya baca. Negara yang dianggap Didit sedang berada dalam periode sunrise Travel Rule, saat ini `["CO", "KH", "VN"]`. Yurisdiksi lain mengikuti `timeout_outcome`. |
| `compliance_email` | string | Email kontak kepatuhan untuk profil VASP Anda. [Jaringan Didit](#jaringan-didit) hanya mencantumkan profil Anda setelah alamat ini dikonfirmasi melalui tautan yang dikirim lewat email; mengubahnya membutuhkan konfirmasi baru. |
| `is_discoverable` | boolean | Apakah profil VASP Anda dapat dicantumkan di [jaringan Didit](#jaringan-didit): ditemukan di `GET /v3/travel-rule/vasps/` oleh pelanggan Didit lain dan dihubungi melalui jalur INTERNAL. Pencantuman memiliki syarat tambahan; `didit_network` di pengaturan menunjukkan syarat yang belum terpenuhi. Default `true`. |
| `inbound_auto_accept` | boolean | Jika `true`, permintaan `TRP` masuk yang dompet penerimanya adalah entri terverifikasi di buku alamat Anda dan namanya cocok akan disetujui secara otomatis. Jika `false`, permintaan menunggu di `ON_HOLD` untuk keputusan Anda. Jalur masuk lainnya tidak membaca pengaturan ini. Default `true`. |
| `allow_self_declaration` | boolean | Jika `true`, [widget kepemilikan dompet](https://docs.didit.me/id/transaction-monitoring/wallet-ownership-widget.md) menawarkan deklarasi mandiri sebagai metode pembuktian, dan Anda dapat membuat entri [buku alamat dompet](#buku-alamat-dompet) dengan `self_declared: true`. Default `true`. |
| `allow_screenshot_proof` | boolean | Jika `true`, [widget kepemilikan dompet](https://docs.didit.me/id/transaction-monitoring/wallet-ownership-widget.md) menawarkan unggahan tangkapan layar sebagai metode bukti kepemilikan. Tangkapan layar tidak pernah memverifikasi dompet dengan sendirinya: tim kepatuhan Anda meninjaunya dan mengonfirmasi transfer. Kekuatan buktinya lebih lemah daripada penandatanganan kriptografis - nonaktifkan jika kebijakan Anda mensyaratkan bukti setara tanda tangan. Default `true`. |
| `auto_wallet_verification` | boolean | Jika `true`, transfer keluar yang memerlukan bukti kendali dompet dari pengguna akhir otomatis membuat sesi [widget kepemilikan dompet](https://docs.didit.me/id/transaction-monitoring/wallet-ownership-widget.md) yang terikat pada transaksi dan menampilkannya di blok `action_required` transaksi - SDK Didit meluncurkannya secara otomatis saat [pengiriman sisi klien](https://docs.didit.me/id/transaction-monitoring/sdk-transaction-submission.md). Default `true`. |
| `counterparty_screening_enabled` | boolean | [Skrining VASP pihak lawan terhadap sanksi dan media negatif](#skrining-pihak-lawan) yang bersifat opt-in, ditagihkan per skrining dengan harga Skrining AML Perusahaan. Jika `true`, Didit menyaring pihak lawan yang dituju pertukaran keluar saat pertukaran dimulai, dan menggunakan ulang skrining yang berumur kurang dari 30 hari. Default `false`: tidak ada yang disaring atau ditagihkan. |
| `vasp_attribution_enabled` | boolean | Jika `true`, transfer keluar yang tidak dapat dirutekan oleh jalur mana pun akan diatribusikan melalui [analitik blockchain](#atribusi-analitik-blockchain) - VASP pemilik dompet tujuan ditentukan, entitas tersebut ditambahkan ke direktori, dan jalur dijalankan ulang sekali dengan nama yang sudah diatribusikan. Default `true`. |
| `threshold_amount` | string (decimal) | Jumlah transfer minimum yang memicu pertukaran terkelola, dalam mata uang default aplikasi Anda: Didit membandingkannya dengan jumlah transfer yang dikonversi ke mata uang tersebut (atau dengan `amount_in_default_currency` yang Anda kirim), bukan dengan jumlah dalam mata uang transfer itu sendiri. Transfer di bawahnya langsung berstatus `NOT_APPLICABLE` dan tidak pernah dinegosiasikan. Jika Didit tidak dapat mengonversi jumlahnya, ambang batas tidak diterapkan dan transfer dipertukarkan. Aplikasi sandbox tidak mengonversi jumlah, sehingga di sana ambang batas hanya berlaku jika Anda mengirim `amount_in_default_currency`. Default `0.00` - sesuai dengan kerangka EU TFR yang tidak mengenal jumlah minimum, sehingga setiap transfer diperiksa tanpa memandang besarnya. |
| `ownership_validation_mode` | string | `FULL`, `SIMPLIFIED`, atau `AUTOMATED` - seberapa banyak bukti yang diperlukan untuk memvalidasi kepemilikan dompet. Lihat [Mode validasi kepemilikan](#mode-validasi-kepemilikan). Default `AUTOMATED`. |
| `simplified_validation_threshold` | string (decimal) | Dalam mode `SIMPLIFIED`, transfer di bawah jumlah ini menerima deklarasi mandiri. Default `0.00`. |
| `data_sharing_fields` | object | Kolom yang Anda kirim tentang pengguna Anda sendiri, per jenis entitas. Lihat [Berbagi data](#berbagi-data). |
| `matching_rules` | object | Seberapa ketat setiap kolom data pihak lawan dibandingkan, per jenis entitas. Lihat [Pencocokan per kolom](#pencocokan-per-kolom). |
| `disabled_networks` | string\[] | Jalur jaringan (`GTR`, `TRUST`, `VERIFYVASP`, `SYGNA`) yang tidak boleh dilalui transfer Anda melalui keanggotaan platform Didit. Jaringan yang Anda hubungkan dengan keanggotaan Anda sendiri (Marketplace di konsol) tidak pernah terpengaruh oleh daftar ini. Didit belum memiliki keanggotaan platform, sehingga daftar ini belum berpengaruh pada perutean saat ini (jalur yang tercantum berstatus `mode: off`). Bawaan `[]`. |
| `networks` | object | Hanya baca. Status per jaringan dengan kunci `gtr` / `trust` / `verifyvasp` / `sygna`: `{rail, mode, platform_available, connected}`, dengan `mode` berupa `own` (keanggotaan Anda yang terhubung), `didit` (keanggotaan platform Didit, belum tersedia di jaringan mana pun), `off` (dinonaktifkan oleh Anda), atau `unavailable`. |
| `travel_address` | string | Hanya baca. Travel Address milik VASP Anda sendiri, yaitu endpoint permintaan `TRP` masuk yang telah dienkode dan digunakan VASP lain untuk menjangkau Anda. Terisi setelah Travel Rule diaktifkan, misalnya `ta2ih1MicegQ3JqiKz9xT89KsSuwaDJYw8DgzmeS5uNDp3dGW3bweBWLKws442chRsyNxmmJnyWc7frxjjSeABVsYR11UuBePkw6E`. |

### Keketatan pencocokan nama

| Nilai | Perilaku |
| - | - |
| `NONE` | Nama penerima apa pun diterima - tidak ada perbandingan yang dilakukan. |
| `STRICT` | Kumpulan token ternormalisasi dari kedua nama harus sama persis. |
| `CONTAINS` | Semua kata dari satu nama harus muncul di nama lainnya, berapa pun jumlahnya. |
| `DEFAULT` | Setiap token dari nama yang lebih pendek harus muncul di nama yang lebih panjang (pencocokan subset), dan nama yang lebih pendek memerlukan minimal dua token kecuali kedua nama identik. |
| `FUZZY` | Rasio kemiripan dari seluruh string ternormalisasi harus minimal `0.85`. |

### Mode validasi kepemilikan

`ownership_validation_mode` menentukan seberapa banyak bukti kepemilikan dompet yang diperlukan sebelum transfer dapat mengandalkan dompet tersebut:

| Mode | Perilaku |
| - | - |
| `FULL` | Bukti selalu diperlukan: pesan yang ditandatangani, deposit uji, atau tangkapan layar yang telah ditinjau. Pernyataan pengguna akhir tidak pernah dihitung. Widget tidak menawarkan `SELF_DECLARATION`, memulainya menghasilkan `403`, dan entri buku alamat yang dibuat dengan `self_declared: true` menghasilkan `400`. |
| `SIMPLIFIED` | Deklarasi mandiri diterima selama transfer berada di bawah `simplified_validation_threshold`; di atas ambang tersebut, bukti diperlukan. Transfer masuk (permintaan TRP, pesan jaringan, atau deposit yang Anda laporkan) dihitung berdasarkan jumlahnya yang dikonversi ke mata uang default aplikasi Anda pada kurs saat ini. Aset tanpa kurs, dan setiap transfer dari aplikasi sandbox, dihitung sebagai di atas ambang batas. |
| `AUTOMATED` | Buku alamat dan bukti pengguna akhir sebelumnya secara otomatis menjadi dasar validasi, termasuk deklarasi mandiri selama `allow_self_declaration` bernilai `true`. Ini adalah perilaku bawaan dan merupakan cara kerja setiap aplikasi sebelum mode-mode ini ada. |

Dompet disimpan untuk setiap pengguna akhir setelah terverifikasi.
Pada `FULL` dan `SIMPLIFIED`, transfer berikutnya hanya memakai ulang dompet tersebut jika bukti yang diterima oleh mode tersebut untuk transfer itu mendukungnya.
Ketika `inbound_auto_accept` tidak menemukan dompet yang cocok di buku alamat, dompet kripto yang Anda catat dalam transaksi milik tepat satu pengguna akhir dapat mengidentifikasi pemiliknya.
Didit menambahkan dompet tersebut ke buku alamat pengguna akhir sebagai deklarasi mandiri Anda, dan dianggap terverifikasi kecuali mode-nya `FULL`. Didit tidak pernah menambahkan dompet yang sudah tercantum di buku alamat dengan nama lain pada rantai yang sama (`eth` dan `ethereum`), termasuk dompet yang dicatat sebagai milik VASP lain.
Pemeriksaan alamat yang dilakukan VASP lain sebelum mengirim (melalui `GTR`, `Sygna` dan `VerifyVASP`) juga mengikuti mode ini: pada `FULL`, dompet yang hanya dideklarasikan pengguna akhir tidak dilaporkan sebagai milik Anda.

### Berbagi data

`data_sharing_fields` memilih kolom mana yang dikirim Didit kepada pihak lawan tentang pengguna Anda sendiri, dipisahkan untuk individu dan perusahaan:

```json theme={null}
{
  "data_sharing_fields": {
    "individual": ["name", "wallet_address", "address", "date_of_birth"],
    "company": ["name", "wallet_address", "address"]
  }
}
```

* Individu dapat membagikan `name`, `wallet_address`, `address`, `national_id`, `customer_identification`, `date_of_birth`, dan `place_of_birth`. Perusahaan menggunakan lima yang pertama.
* `name` dan `wallet_address` selalu dikirim.
* Jenis entitas yang tidak pernah Anda pilih membagikan setiap kolom. Daftar kosong juga merupakan pilihan: hanya nama dan dompet yang dibagikan.
* `PUT` digabungkan per jenis entitas, sehingga mengirim `individual` tidak mengubah pilihan `company` yang tersimpan.
* Pilihan yang tidak dapat memenuhi kewajiban pengirim dari rezim `jurisdiction` Anda (EU TFR atau FATF Recommendation 16), termasuk daftar kosong, ditolak dengan `400`. Galatnya berada di bawah `data_sharing_fields`, dengan kunci berdasarkan jenis entitas.

### Pencocokan per kolom

`matching_rules` menentukan seberapa ketat setiap kolom data pihak lawan dibandingkan dengan data yang Anda miliki:

```json theme={null}
{
  "matching_rules": {
    "individual": { "name": "DEFAULT", "date_of_birth": "STRICT", "address": "NONE", "account": "STRICT" },
    "company": { "name": "FUZZY", "address": "NONE", "account": "STRICT" }
  }
}
```

Setiap nilai berupa `NONE`, `STRICT`, `CONTAINS`, `DEFAULT`, atau `FUZZY`.
Bawaan: `name` mengikuti `name_matching_strictness`, `date_of_birth` dan `address` berupa `NONE`, dan `account` berupa `STRICT`.
Kolom yang dihilangkan tetap memakai default-nya, dan kolom yang tidak dibandingkan oleh jenis entitas (perusahaan tidak memiliki `date_of_birth`) ditolak dengan `400`.

### Ambang batas per yurisdiksi

`threshold_amount` ada karena cakupan Travel Rule berbeda-beda menurut regulator.
Didit menetapkan default `0.00` - posisi UE - sehingga setiap transfer dipertukarkan kecuali Anda menaikkannya secara sengaja:

| Rezim | Ambang batas | Catatan |
| - | - | - |
| **Uni Eropa** - Transfer of Funds Regulation (EU) 2023/1113 | **Tanpa minimum** | Setiap transfer kripto CASP-ke-CASP termasuk dalam cakupan. Kepemilikan dompet swakelola harus diverifikasi untuk transfer di atas EUR 1,000. |
| **Rekomendasi FATF 16** (acuan global) | USD/EUR 1,000 | Di bawah angka ini, FATF mengizinkan kumpulan data yang dikurangi (nama dan alamat, tanpa verifikasi). |
| **Amerika Serikat** - BSA Travel Rule | USD 3,000 | Ambang batas transfer dana FinCEN yang sudah lama berlaku, diterapkan pada mata uang virtual yang dapat dikonversi. |
| **Inggris Raya** | Setara EUR 1,000 | Informasi lengkap di atas; data yang dikurangi di bawah (MLRs Part 7A). |
| **Singapura** - MAS PSN02 | SGD 1,500 | Persyaratan yang dikurangi di bawah ambang batas. |
| **Swiss** - FINMA | Tanpa minimum | Informasi wajib untuk semua transfer; bukti kepemilikan diharapkan untuk dompet swakelola. |

Setel `threshold_amount` ke angka yang ditetapkan regulator Anda; transfer di bawah angka tersebut langsung menghasilkan `NOT_APPLICABLE` tanpa pertukaran data identitas apa pun.
Ambang batas terus berubah - konfirmasikan angka terkini dengan penasihat kepatuhan Anda, dan jangan memperlakukan tabel ini sebagai nasihat hukum.

### Model data IVMS 101

Standar industri untuk data yang dipertukarkan di bawah Travel Rule adalah **IVMS 101** (interVASP Messaging Standard).
`travel_rule_details.originator_data` dan `travel_rule_details.beneficiary_data` adalah payload individu dalam gaya IVMS 101: Didit membungkusnya dalam pembungkus asli setiap jalur - jalur TRP menukar blok `IVMS101` (`ivms101.2023`, dilaporkan di kolom `ivms_version` transfer), jalur Sygna menggunakan varian IVMS terenkripsi ECIES, dan jalur `GTR`, `TRUST`, serta `VERIFYVASP` menggunakan pembungkus terenkripsi masing-masing - sehingga satu bentuk payload menjangkau setiap pihak lawan dalam format yang diharapkan protokolnya.

Didit membaca kunci berikut dari setiap payload individu saat menyusun pesan IVMS 101: `first_name` dan `last_name` (atau satu `name` atau `full_name`), `date_of_birth`, `place_of_birth`, `residence_country` (atau `country`), `vendor_data` (atau `customer_identification`), dan `wallet_address`.

Dua aturan praktis:

* **Aksara Latin.** IVMS 101 mensyaratkan nilai dalam aksara Latin; transliterasi nama yang secara asli ditulis dengan aksara lain. [Pencocokan nama](#keketatan-pencocokan-nama) Didit membandingkan kumpulan token yang sudah dinormalisasi, sehingga perbedaan urutan dan huruf besar-kecil tidak menggagalkan pertukaran - tetapi aksara yang berbeda di kedua sisi akan menggagalkannya.
* **Kirimkan data yang sudah Anda verifikasi.** Ketika subjek di balik `vendor_data` adalah pengguna dengan verifikasi KYC Didit yang disetujui, Didit mengirimkan identitas terverifikasi, bukan nilai yang Anda ketik: lihat [Data terverifikasi dan asal data](#data-terverifikasi-dan-asal-data).
  Untuk subjek lain, Didit mengirimkan persis `originator_data` yang Anda kirim, jadi bangunlah dari identitas yang Anda verifikasi saat onboarding, bukan dari kolom formulir yang belum diverifikasi.
  Itulah yang dituntut oleh frasa FATF "required and **accurate** originator information" (informasi pengirim yang wajib dan **akurat**).
  Pada jalur `INTERNAL`, aplikasi penerima juga menerima `subject` yang Anda kirim (nama, `vendor_data`, tanggal lahir, negara, dan alamat) sebagai pihak lawan dari transaksi masuknya.

#### Data terverifikasi dan asal data

Ketika subjek sebuah transfer adalah salah satu pengguna Anda, yaitu individu dengan verifikasi KYC yang disetujui, Didit menyusun sisi pertukaran tersebut dari data terverifikasi:

* pengirim transfer keluar yang Anda buat dengan `POST /v3/transactions/`;
* penerima transfer masuk yang Anda laporkan dengan `POST /v3/transactions/`, atau dengan `POST /v3/travel-rule/inbound/` ketika `holder_vendor_data` pada dompet yang cocok menyebut pengguna tersebut.

Pada `POST /v3/transactions/`, keduanya berlaku untuk transaksi yang `transaction_category`-nya adalah `travel_rule` selama Travel Rule aktif.

Nama terverifikasi, tanggal dan tempat lahir, nomor serta jenis dokumen, alamat, dan negara tempat tinggal (dari alamat tersebut) didahulukan atas nilai yang Anda kirim. Kolom yang tidak dimiliki verifikasi tetap menggunakan nilai Anda, begitu pula alamat lengkap yang Anda kirim ketika alamat terverifikasi tidak cukup lengkap untuk dikirimkan.

`metadata` transfer, pada objek `travel_rule` yang tertanam di transaksi, mencatat asal setiap kolom dan tempat nilai Anda berbeda:

```json theme={null}
{
  "metadata": {
    "originator_provenance": { "name": "verified", "date_of_birth": "verified", "customer_identification": "caller" },
    "originator_verified_differences": {
      "name": { "caller": "Jane Doe", "verified": "Jane Elizabeth Doe" }
    }
  }
}
```

`*_provenance` memetakan setiap kolom ke `verified` atau `caller`, dan `*_verified_differences` mencantumkan setiap kolom tempat Anda mengirim nilai yang berbeda dari nilai terverifikasi, tanpa memperhatikan huruf besar-kecil, spasi, dan kode negara dua atau tiga huruf. Selama data transfer masuk [disamarkan](#data-pihak-lawan-yang-disamarkan), perbedaan tidak disertakan. Didit menghitung keduanya, sehingga salinan kunci ini, atau `name_match`, yang Anda kirim di `travel_rule_details.metadata` akan dibuang.

#### Mengirim IVMS 101 secara langsung

Selain objek datar `originator_data` dan `beneficiary_data`, `travel_rule_details` (pada `POST /v3/transactions/`) dan `POST /v3/travel-rule/inbound/` menerima IVMS 101 asli:

* blok `originator` dan `beneficiary`, dengan `originatorPersons` atau `beneficiaryPersons` yang berisi `naturalPerson` atau `legalPerson`, serta `accountNumber`;
* blok yang sama di dalam objek `ivms101` (atau `IVMS101`);
* satu orang IVMS 101, atau satu blok utuh, sebagai `originator_data` atau `beneficiary_data`.

Setiap sisi menerima satu orang: `naturalPerson`, atau `legalPerson`, yang menjadikan pihak tersebut sebuah perusahaan. `originator_data` atau `beneficiary_data` datar yang tidak kosong didahulukan atas blok untuk sisi yang sama.

```json theme={null}
{
  "travel_rule_details": {
    "status": "AWAITING_COUNTERPARTY",
    "beneficiary": {
      "beneficiaryPersons": [
        {
          "naturalPerson": {
            "name": { "nameIdentifier": [{ "primaryIdentifier": "Ruiz", "secondaryIdentifier": "Carlos", "nameIdentifierType": "LEGL" }] }
          }
        }
      ],
      "accountNumber": ["0xBeneficiaryWallet01"]
    }
  }
}
```

Blok yang tidak valid menghasilkan respons `400` dengan kunci sesuai jalurnya, misalnya `{"travel_rule_details": {"originator.originatorPersons": ["must be a non-empty list of originator persons."]}}`. Pada `POST /v3/travel-rule/inbound/`, kunci yang sama berada di tingkat teratas, di bawah `ivms101.` ketika Anda memakai pembungkus.

#### Data yang wajib diisi per rezim

Ketika Travel Rule aktif, transfer keluar yang mencapai atau melampaui ambang batas Anda harus memuat apa yang diwajibkan rezimnya, atau merespons `400`. Hanya sisi yang Anda kirim yang diperiksa, data terverifikasi dihitung untuk pengirim, dan galatnya berada di bawah `travel_rule_details.originator_data` atau `travel_rule_details.beneficiary_data`, misalnya `"EU TFR requires the originator name."` atau `"FATF Recommendation 16 requires the beneficiary wallet address."`:

| Rezim | Pengirim | Penerima |
| - | - | - |
| EU TFR (`jurisdiction` Anda adalah negara anggota UE, Islandia, Liechtenstein, Norwegia, `EU` atau `EEA`; `EU` adalah nilai default) | Nama, ditambah alamat, nomor dokumen resmi, dan nomor identifikasi pelanggan secara bersamaan, atau tanggal dan tempat lahir. Perusahaan tidak memiliki alternatif tanggal lahir. | Nama dan alamat |
| FATF Recommendation 16 (setiap yurisdiksi lain, termasuk yurisdiksi yang kosong) | Nama, ditambah salah satu dari alamat, nomor dokumen resmi, atau nomor identifikasi pelanggan, atau tanggal dan tempat lahir secara bersamaan. Perusahaan tidak memiliki alternatif tanggal lahir. | Nama dan alamat |

Untuk pengirim, pemeriksaan membaca kolom yang dibagikan aplikasi Anda di [`data_sharing_fields`](#berbagi-data), karena itulah yang dikirim oleh jalur; penerima diperiksa sebagaimana Anda kirimkan. Ketika transfer hanya memenuhi rezim dengan kolom yang tidak Anda bagikan, `400` menyebutkan persyaratan rezim lalu kolom yang dibagikan pengaturan Anda.

Nomor dokumen resmi adalah `national_id` (atau `document_number`), nomor identifikasi pelanggan adalah `customer_identification` (atau `vendor_data`), dan tanggal lahir adalah `date_of_birth`. `beneficiary_data.wallet_address` yang kosong diisi dari `counterparty.payment_method.account_id` sebelum pemeriksaan, dan penarikan UTXO yang output penerimanya disimpulkan Didit dari `travel_rule_details.utxo` dihitung sebagai memuatnya. Transfer Lightning yang tidak berlaku Travel Rule tidak diperiksa.

### Travel Address

**Travel Address** adalah string terkode yang ringkas dan menunjuk ke endpoint inquiry `TRP` masuk milik VASP. Travel Address tidak pernah mengekspos URL mentah atau alamat dompet apa pun.
Setelah Travel Rule diaktifkan, Didit membuat `travel_address` milik Anda (dikembalikan dalam mode baca saja di pengaturan) sehingga Anda dapat membagikannya kepada VASP lain yang menjangkau Anda melalui jalur `TRP`.
Setiap dompet di buku alamat dompet Anda juga memiliki `receiving_travel_address` per dompet: inquiry yang dikirim ke dompet tersebut menyebutkan dompet itu, sehingga Didit tidak perlu mencarinya berdasarkan nomor rekening atau nama pemegang.
Host TRP publik Didit belum merespons VASP lain, sehingga penerimaan melalui `TRP` belum tersedia hingga host tersebut merespons: lihat [Jaringan Travel Rule](https://docs.didit.me/id/transaction-monitoring/travel-rule-networks.md).
Saat Anda mengetahui Travel Address sebuah pihak lawan, simpan di [entri buku alamat dompet](#buku-alamat-dompet) tujuan agar Didit merutekan transfer untuk penerima tersebut langsung melalui `TRP`, bukan beralih ke email.
Didit memvalidasi Travel Address yang Anda simpan pada entri buku alamat dompet atau kirim di `originating_vasp`: setiap alamat harus diawali dengan `ta` dan didekode menjadi URL inquiry yang memuat `t=i`, sehingga placeholder seperti `ta...` akan mengembalikan `400`.
`beneficiary_data.travel_address` pada transaksi tidak divalidasi: jika tidak dapat didekode, jalur `TRP` dilewati.

Enkodingnya adalah Base58Check dengan prefiks `ta`: host dan path endpoint (yang selalu memuat pasangan query `t=i`) ditambah checksum double-SHA-256 empat byte, lalu di-encode dengan base58.
Contoh Travel Address yang valid tampak seperti berikut dan panjangnya sekitar 100 karakter:

```text theme={null}
ta2ih1MicegQ3JqiKz9xT89KsSuwaDJYw8DgzmeSEp1h9tduJcNDZ5SgKLEHeyGMcS1s2HgbM6undFrMQknhM5aTXw3G9KBzi16hx
```

Saat Didit memvalidasi Travel Address, nilai yang tidak berformat benar atau checksum-nya tidak valid akan mengembalikan `400` dengan `"Invalid travel address."`.
Ambil Travel Address yang valid dari respons pengaturan Anda sendiri, atau dari pihak lawan itu sendiri.

## Pengujian tanpa kredensial jaringan

Anda tidak memerlukan keanggotaan GTR, TRUST, VerifyVASP, atau Sygna untuk menguji jalur yang tidak memerlukan keanggotaan. Anda tetap memerlukan kunci API Didit untuk aplikasi yang diuji.

* **Sandbox keluar:** kirim transaksi `travelRule` dari aplikasi sandbox. Setelah pemeriksaan ambang batas dan pemeriksaan dompet swakelola, [Didit Test VASP](https://docs.didit.me/id/transaction-monitoring/travel-rule-sandbox.md) akan meresponsnya di dalam Didit dengan skenario yang Anda pilih berdasarkan dompet atau nama penerima: diterima, ditolak, nama tidak cocok, tidak dapat dijangkau, timeout, atau swakelola. Tidak ada jaringan, email, atau pelanggan Didit lain yang menerima apa pun.
* **Sandbox masuk:** minta VASP pengujian mengirim transfer kepada Anda dengan [Trigger Test VASP Inbound Transfer](https://docs.didit.me/id/management-api/travel-rule/trigger-test-vasp-inbound.md), atau daftarkan sendiri dengan [Register Inbound Travel Rule Transfer](https://docs.didit.me/id/management-api/travel-rule/register-inbound.md). Uji dompet yang tidak dikenal, dompet yang belum diverifikasi, ketidakcocokan nama penerima, dan dompet yang terverifikasi dan cocok. Skenario ini menguji keputusan inbound nyata tanpa menghubungi jaringan.
* **Dua aplikasi produksi yang terkendali:** gunakan rail `INTERNAL` di antara dua aplikasi produksi milik Anda (aplikasi penerima dapat ditemukan dan membuktikan kendali atas dompet tujuan dengan pesan bertanda tangan atau setoran uji), atau pihak lawan TRP yang terkendali, untuk menguji pertukaran dua pihak tanpa kredensial jaringan komersial. Aplikasi produksi dapat menimbulkan biaya dan notifikasi normal; gunakan identitas dan pihak lawan uji yang Anda kendalikan.

Lihat [Uji Travel Rule di sandbox](https://docs.didit.me/id/transaction-monitoring/travel-rule-sandbox.md) untuk setiap skenario dan hasil pastinya. Pengujian sandbox atau protokol lokal yang berhasil tidak memvalidasi kredensial, keanggotaan, atau interoperabilitas produksi jaringan komersial. Hal tersebut memerlukan sandbox jaringan resmi atau pertukaran produksi terkendali dengan kredensial keanggotaan yang valid.

## Mengirim transfer

Sertakan transfer di [`POST /v3/transactions/`](https://docs.didit.me/id/transaction-monitoring/transactions) dengan mengatur `transaction_category` ke `travelRule` (atau `travel_rule`) dan melampirkan objek `travel_rule_details` (alias: `travelRule`).

Blok `travel_rule_details` bersifat opsional, tetapi setelah Anda melampirkannya, `travel_rule_details.status` wajib diisi: blok tanpa field ini akan mengembalikan `400`.
Ketika Travel Rule **diaktifkan** untuk aplikasi Anda, Didit mengabaikan nilai `status` yang Anda kirim dan menjalankan pertukaran data sendiri:

1. Jika jumlahnya di bawah `threshold_amount` yang Anda konfigurasikan, transfer langsung diselesaikan dengan status `NOT_APPLICABLE` dan tidak ada negosiasi yang dilakukan.
2. Jika metode pembayaran pihak lawan menyatakan tujuan sebagai dompet swakelola (`payment_method.method_type: "unhosted_wallet"`), tidak ada jalur yang dicoba. Transfer langsung masuk ke `UNCONFIRMED_OWNERSHIP` dan widget kepemilikan dompet dibuat otomatis (lihat [Dompet swakelola yang dinyatakan](#dompet-swakelola-yang-dideklarasikan)).
3. Jika tidak, jalur dijalankan sesuai urutan prioritas, dan jalur pertama yang dapat menjangkau pihak lawan akan membawa pertukaran data:
   * `INTERNAL`: tepat satu pelanggan Didit lain memegang bukti pesan bertanda tangan atau bukti setoran uji untuk `beneficiary_data.wallet_address`, yang dibuat setelah dompet terakhir kali berganti pemegang. Aplikasi Anda sendiri tidak pernah dihitung, dan jika pengguna akhir Anda memilih anggota jaringan Didit di [widget kepemilikan dompet](https://docs.didit.me/id/transaction-monitoring/wallet-ownership-widget.md), hanya bukti anggota tersebut yang dihitung. Aplikasi pelanggan tersebut harus berstatus produksi (bukan sandbox), Travel Rule aktif, dan `is_discoverable` diatur, serta merupakan VASP yang Anda sebutkan ketika mengirim `counterparty_vasp_lei` atau `counterparty_vasp_name`. Dompet yang hanya dinyatakan sendiri, dibuktikan dengan tangkapan layar, belum diverifikasi, atau hanya tercantum di buku alamat tidak akan pernah menerima apa pun melalui `INTERNAL`.
   * `TRP`: aset transfer memiliki pemetaan Digital Token Identifier untuk jaringan transfer (lihat [Pengidentifikasi aset TRP](#pengidentifikasi-aset-trp)), dan payload membawa `beneficiary_data.travel_address`, atau entri buku alamat tujuan menyimpannya, atau pihak lawan ditemukan di [direktori](#direktori) (melalui `counterparty_vasp_lei` atau `counterparty_vasp_name`) dengan endpoint TRP.
   * `GTR`, `TRUST`, `VERIFYVASP`, `SYGNA`: Anda telah menghubungkan keanggotaan Anda sendiri untuk jaringan tersebut di **Marketplace**, dan pihak lawan dapat diselesaikan menjadi ID jaringan (melalui kolom eksplisit atau entri direktori, lihat [Kolom penyelesaian pihak lawan](#kolom-penentuan-pihak-lawan)).
     Saat ini Didit belum memiliki keanggotaan platform di jaringan-jaringan ini (Didit sedang dalam proses onboarding sebagai penyedia), sehingga `disabled_networks` belum mengubah langkah ini.
   * `EMAIL`: `beneficiary_data.counterparty_vasp_email` telah diisi, atau `counterparty_vasp_name` diselesaikan menjadi entri direktori dengan email kepatuhan.
4. Jika tidak ada jalur yang dapat menyelesaikan pihak lawan, Didit menjalankan rangkaian [penemuan pihak lawan](#penemuan-pihak-lawan). Jika `vasp_attribution_enabled` aktif, rangkaian ini mencakup [atribusi analitik blockchain](#atribusi-analitik-blockchain): dompet tujuan diselesaikan menjadi VASP pemiliknya, nama hasil atribusi ditulis ke `beneficiary_data.counterparty_vasp_name` (jika kosong) dan ke [direktori](#direktori), lalu jalur dijalankan ulang sekali. Dengan demikian, dompet yang diatribusikan ke VASP yang entri direktorinya memiliki endpoint TRP, ID jaringan, atau email kepatuhan akan dirutekan pada putaran kedua ini.
5. Jika pihak lawan masih belum terselesaikan, transfer berpindah ke `COUNTERPARTY_VASP_NOT_FOUND`. Untuk transfer keluar, Didit membuat otomatis [widget kepemilikan dompet](https://docs.didit.me/id/transaction-monitoring/wallet-ownership-widget.md) (jika `auto_wallet_verification` aktif) agar transfer tetap dapat diselesaikan sebagai transfer dompet swakelola, dan Anda dapat menjalankan ulang perutean nanti dengan `action: "resend"` setelah memiliki data pihak lawan yang lebih baik.

Langkah 1 dan 2 terjadi di dalam permintaan. Langkah 3 hingga 5 berjalan tepat setelah respons: transfer kembali dengan status `AWAITING_COUNTERPARTY` dan `protocol: null`, dan setiap hasil tiba sebagai webhook [`travel_rule.status.updated`](#webhook).

### Pengidentifikasi aset TRP

`TRP` menyebut aset yang ditransfer dengan Digital Token Identifier (DTI) ISO 24165.
DTI mengidentifikasi token pada satu blockchain, sehingga token multi-chain memiliki satu DTI untuk setiap jaringan.

Didit mengirim transfer melalui `TRP` untuk aset-aset berikut:

| Aset | Jaringan | DTI |
| - | - | - |
| `BTC` | Bitcoin | `4H95J0R2X` |
| `ETH` | Ethereum | `X9J9K872S` |
| `USDC` | Ethereum | `CK9PW1MFH` |
| `USDC` | Celo | `2ZTG3NNVB` |
| `USDC` | Base | `CP6817N4B` |
| `USDC` | Optimism | `898NNTPZJ` |
| `USDC` | Arbitrum One | `4ZSZS1F4F` |
| `USDC` | Polygon PoS | `LS71LQK3L` |
| `USDC` | Avalanche C-Chain | `45J6XJX7H` |
| `USDC` | Solana | `5R3XFPZSM` |
| `USDC` | Plume | `N064ZKXDM` |

Pengidentifikasi `USDC` adalah yang diterbitkan oleh penerbit token dalam white paper MiCA-nya.

Untuk token multi-chain, transfer harus menyebut jaringannya di `transaction_details.crypto_params.crypto_chain` (misalnya `CELO`, `BASE`, `OP`, `ARB`, atau `POL`).
Tanpa jaringan, atau pada jaringan yang tidak memiliki pemetaan, transfer tidak dikirim melalui `TRP` dan Didit mencoba jalur yang tersisa: jaringan interoperabilitas terlebih dahulu, kemudian email.

`USDT` belum dipetakan.
Token tanpa pemetaan DTI, seperti stablecoin milik perusahaan, memerlukan penerbitnya untuk mendaftarkan DTI ke otoritas registrasi ISO 24165, satu per token per blockchain.
Setelah DTI tersedia, hubungi dukungan Didit dengan setiap DTI, blockchain-nya, dan jumlah angka desimal token, lalu Didit akan menambahkan pemetaannya.

Permintaan `TRP` masuk yang membawa DTI per jaringan yang dipetakan dicatat dengan mata uang token, jumlah dalam desimal token, dan jaringannya.

### Penemuan pihak lawan

Transfer yang hanya membawa alamat dompet tetap dapat mencapai pihak lawannya selama ada pihak yang dapat mengidentifikasinya.
Sebelum transfer keluar dinyatakan tidak dapat dirutekan, Didit memeriksa, sesuai urutan berikut, dan berhenti pada langkah pertama yang menyebut VASP dengan rute:

| Langkah | Fungsinya |
| - | - |
| `internal_address_book` | Pelanggan Didit lain telah membuktikan kendali atas dompet (tanda tangan atau setoran uji), sehingga jalur `INTERNAL` mengirim ke mereka. Entri buku alamat yang belum dibuktikan tidak pernah dihitung. |
| `wallet_attribution` | Atribusi analitik blockchain untuk dompet, dicocokkan dengan VASP di direktori yang memiliki rute. Hasil yang tersimpan digunakan kembali dan hanya dikenakan biaya sekali. Memerlukan `vasp_attribution_enabled`. |
| `network_lookup` | Jaringan Travel Rule yang menjawab "siapa yang memegang alamat ini", ketika aplikasi Anda memiliki aksesnya. Saat ini hanya GTR yang menawarkan fitur ini, dan fitur ini berjalan ketika jalur GTR mengirim. Jika tidak, langkah ini dicatat sebagai `skipped` beserta alasannya. |
| `customer_hint` | Nama VASP, LEI, atau yurisdiksi yang Anda kirim di `beneficiary_data`, dicocokkan dengan VASP dalam direktori yang memiliki rute. `travel_address` atau email kepatuhan dijangkau melalui jalurnya sendiri. |
| `end_user` | Tidak ada yang menyebutkan pihak lawan, maka pengguna akhir diminta. Lihat di bawah. |

Kolom `discovery` pada transfer mencantumkan setiap langkah yang dijalankan beserta `outcome`-nya (`match`, `miss`, atau `skipped`), `reason` yang dapat dibaca mesin, `vasp` dan `rail` yang ditemukan, serta stempel waktu.
VASP yang Anda atau pengguna akhir pilih lebih diutamakan daripada setiap langkah otomatis: discovery tidak pernah menggantinya dengan tebakannya sendiri.

Jika tidak ada langkah yang menyebutkan pihak lawan, transfer berpindah ke `COUNTERPARTY_VASP_NOT_FOUND`, atau `COUNTERPARTY_VASP_NOT_REACHABLE` jika sebuah VASP telah disebutkan tetapi tidak satu pun rutenya tersedia untuk aplikasi Anda.
Transfer kemudian memuat `reason` (`awaiting_end_user`, `no_directory_match`, `directory_match_no_route`, atau `picked_member_without_proven_wallet` ketika anggota yang dipilih pengguna akhir belum membuktikan kepemilikan dompet) dan daftar `next_actions`:

| `action` | Arti |
| - | - |
| `select_counterparty_vasp` | Pengguna akhir memilih VASP tujuan di [widget dompet](https://docs.didit.me/id/transaction-monitoring/wallet-ownership-widget.md), atau Anda menentukannya sendiri dengan `{"action": "beneficiary_vasp", "beneficiary_vasp": "<directory VASP id>"}` pada [endpoint transfer](#mengirim-transfer). Transfer dirutekan ke VASP tersebut dan dikirim ulang. |
| `declare_self_hosted` | Pengguna akhir menyatakan dompet swakelola tersebut di widget yang sama. |
| `add_vasp_hint` | Kirim nama VASP, LEI, atau `travel_address` di `beneficiary_data`, lalu kirim ulang. |
| `update_compliance_email` | Berikan kembali email kepatuhan pihak lawan ketika email pertama ditolak; lihat [Mengapa transfer macet](#mengapa-transfer-macet). |
| `resend` | Jalankan discovery lagi dengan apa pun yang berubah. |

Tautan widget ada di `url` pada tindakan yang dilakukan pengguna akhir.
Ketika tindakan kepemilikan dompet sedang menunggu, blok `action_required` transaksi (tipe `wallet_ownership`) memuat `reason` dan `next_actions` yang sama, sehingga klien yang sudah mengikuti `action_required` menampilkan pemilih tanpa tindakan tambahan.

### Kolom penentuan pihak lawan

Semua yang diketahui Didit tentang pihak lawan berasal dari `travel_rule_details.beneficiary_data`.
Kolom-kolom berikut menentukan resolusi jalur; semuanya bersifat opsional:

| Kolom | Menentukan |
| - | - |
| `wallet_address` | Pencocokan buku alamat `INTERNAL`, pencarian buku alamat `TRP`, dan alur kepemilikan dompet. Jika Anda tidak menyertakannya, Didit menggunakan `counterparty.payment_method.account_id`. |
| `chain` | Membatasi kedua pencarian buku alamat: entri hanya cocok jika `chain`-nya sama dengan nilai ini (tidak peka huruf besar/kecil) atau entri tersebut tidak memiliki `chain`. Jika Anda tidak menyertakannya, Didit mengisinya dari `transaction_details.crypto_params.crypto_chain`, `custom_properties.crypto_chain`, atau mata uang transfer, dalam huruf kapital, tetapi hanya jika nilai itu adalah chain yang dikenali Didit (misalnya `ETH`, `BTC`, `SOL`, `TRX`); jika tidak, transfer tidak memuat chain dan entri cocok di chain mana pun. Untuk transfer `USDT` atau `USDC` tanpa chain eksplisit, Didit menyimpulkannya dari hash transaksi di `transaction_details.payment_reference_id` (hash `0x` menghasilkan `ETH`). |
| `memo` | Destination tag atau memo dari `wallet_address` pada jaringan memo. Menjadi bagian dari dompet setiap kali `wallet_address` dicocokkan (lihat [Jaringan memo dan tag](#jaringan-memo-dan-tag)). Alias: `destinationTag`. |
| `travel_address` | Dirutekan langsung melalui `TRP` - sinyal terkuat yang dapat Anda kirim. |
| `counterparty_vasp_lei` | Pencarian direktori berdasarkan LEI untuk `TRP`, `GTR`, `TRUST`, `VERIFYVASP`, dan `SYGNA`. Juga diverifikasi silang dengan identitas yang dilaporkan endpoint TRP - ketidakcocokan, atau identitas tanpa LEI, membatalkan pertukaran sebagai `COUNTERPARTY_VASP_NOT_REACHABLE`. |
| `counterparty_vasp_name` | Pencarian direktori untuk `TRP`, `GTR`, `TRUST`, `VERIFYVASP`, `SYGNA`, dan `EMAIL`: nama persis, nama yang sama ditulis dengan cara lain (`B.V.` untuk `BV`, atau dengan aksen), lalu alias dari sebuah entri. Diperiksa menggunakan pencocokan fuzzy terhadap identitas TRP jika keduanya ada. |
| `counterparty_vasp_jurisdiction` | Kode negara ISO 3166 dari entitas penerima ketika VASP yang disebutkan adalah merek dengan beberapa entitas teregulasi, atau ketika beberapa entri direktori memiliki nama yang sama - lihat [Merek dan entitasnya](#merek-dan-entitasnya). |
| `counterparty_gtr_vasp_code` | ID jaringan `GTR` eksplisit - melewati direktori. |
| `counterparty_trust_membership_id` | ID jaringan `TRUST` eksplisit - melewati direktori. |
| `counterparty_verifyvasp_id` | ID jaringan `VerifyVASP` eksplisit - melewati direktori. |
| `counterparty_sygna_vasp_code` | Kode VASP `Sygna Bridge` eksplisit - melewati direktori. |
| `counterparty_vasp_email` | Kontak kepatuhan eksplisit untuk jalur `EMAIL` - melewati direktori. |

### Bentuk chain

Pada chain akun (chain EVM, Solana, Tron) transfer memindahkan dana dari satu alamat ke alamat lain, dan Didit membaca kedua dompet langsung dari transaksi.
Tiga bentuk lain memerlukan lebih banyak data, dan hasil resolusi Didit untuk bentuk-bentuk tersebut ada di transfer sebagai `chain_details` (kosong, `{}`, pada chain akun).
`chain_details.originator` dan `chain_details.beneficiary` masing-masing memuat `address`, `memo`, dan `source`, sumber asalnya, dan pencocokan serta perutean membaca dompet dari sana terlebih dahulu.

#### Transfer UTXO

Transaksi Bitcoin, Litecoin, Bitcoin Cash, atau Dogecoin menggunakan input dari sejumlah alamat dan membayar sejumlah output, sebagian di antaranya dikembalikan ke pengirim sebagai kembalian.
Kirim input dan output sebagai `travel_rule_details.utxo` (jumlah dalam satuan koin itu sendiri, sebagai string desimal), dan Didit menyimpulkan apa yang tidak Anda deklarasikan:

* **Pengirim**: `originator_data.wallet_address` jika Anda mengirimkannya, jika tidak, alamat input yang memberikan kontribusi terbesar (`source: largest_input`).
* **Penerima**: dompet yang dideklarasikan, jika tidak, satu-satunya output yang tidak dikirim kembali ke alamat input sebagai kembalian (`only_non_change_output`), jika tidak, satu output yang membayar jumlah transfer (`amount_match`).

```bash theme={null}
curl -X POST https://verification.didit.me/v3/transactions/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "transaction_id": "btc-withdrawal-0042",
    "transaction_category": "travelRule",
    "transaction_details": {
      "direction": "outbound",
      "amount": "0.25",
      "currency": "BTC",
      "currency_kind": "crypto"
    },
    "subject": { "vendor_data": "user-042", "full_name": "Ana Diaz" },
    "counterparty": { "full_name": "Luis Perez" },
    "travel_rule_details": {
      "status": "AWAITING_COUNTERPARTY",
      "beneficiary_data": { "name": "Luis Perez", "counterparty_vasp_name": "Destination Exchange" },
      "utxo": {
        "inputs": [
          { "address": "bc1qsenderhotwallet01", "amount": "0.30" },
          { "address": "bc1qsendercoldwallet02", "amount": "0.05" }
        ],
        "outputs": [
          { "address": "bc1qbeneficiarydeposit01", "amount": "0.25" },
          { "address": "bc1qsenderhotwallet01", "amount": "0.0999" }
        ]
      }
    }
  }'
```

Transfer kemudian memuat:

```json theme={null}
{
  "chain_details": {
    "chain": "BTC",
    "shape": "utxo",
    "originator": { "address": "bc1qsenderhotwallet01", "memo": "", "source": "largest_input" },
    "beneficiary": { "address": "bc1qbeneficiarydeposit01", "memo": "", "source": "only_non_change_output" },
    "utxo": {
      "inputs": [
        { "address": "bc1qsenderhotwallet01", "amount": "0.300000000000000000" },
        { "address": "bc1qsendercoldwallet02", "amount": "0.050000000000000000" }
      ],
      "outputs": [
        { "address": "bc1qbeneficiarydeposit01", "amount": "0.250000000000000000" },
        { "address": "bc1qsenderhotwallet01", "amount": "0.099900000000000000" }
      ],
      "change_output_indexes": [1],
      "beneficiary_output_index": 0
    }
  }
}
```

`chain_details.warnings` menandai hal-hal yang tidak sesuai: `declared_originator_not_an_input`, `declared_beneficiary_not_an_output`, `beneficiary_output_ambiguous` (tidak ada satu output pun yang dapat dibedakan) dan `beneficiary_output_amount_differs`.
`utxo` pada rantai lain mengembalikan `400`, dan setiap daftar memuat paling banyak 1,000 entri.
Deposit yang dilaporkan menggunakan objek `utxo` yang sama (lihat [Pendaftaran sunrise setelah deposit](#pendaftaran-sunrise-setelah-deposit)).

#### Jaringan memo dan tag

Pada XRP, Stellar (XLM), EOS, Cosmos (ATOM), dan Hedera (HBAR), exchange menerima setiap pelanggan di satu alamat bersama dan membedakannya melalui tag tujuan atau memo.
Oleh karena itu, memo menjadi bagian dari dompet: kirimkan sebagai `payment_method.memo` pada peserta, atau sebagai `memo` di `originator_data` / `beneficiary_data` (alias `destinationTag`), dan Didit membandingkan alamat dan memo secara bersamaan.

* Entri buku alamat dengan memo hanya cocok dengan transfer yang menyebutkan memo tersebut. Entri tanpa memo cocok dengan seluruh alamat. Transfer yang tidak menyebutkan memo tidak pernah mencapai entri yang memilikinya: pada alamat bersama, deposit tanpa tag-nya tidak menjadi milik siapa pun.
* Alamat X XRP memuat tag di dalamnya: Didit memisahkannya menjadi alamat klasik dan tag (`source: x_address`), sehingga dompet yang didaftarkan dalam salah satu bentuk akan cocok dengan transfer dalam bentuk lainnya.
* Setiap memo pada alamat bersama merupakan metode pembayaran tersendiri pada transaksi.
* Yang diterima oleh setiap jaringan: tag tujuan XRP adalah bilangan bulat dari 0 hingga 4294967295 (angka JSON diterima); memo Stellar berupa teks hingga 28 byte, id 64-bit, atau hash 32-byte dalam format heksadesimal; EOS menerima hingga 256 byte, Cosmos hingga 256 karakter, Hedera hingga 100 byte. Memo pada rantai yang tidak memilikinya (Bitcoin, rantai EVM, Solana, Tron, Litecoin, Bitcoin Cash, Dogecoin, Lightning) mengembalikan `400`.

#### Lightning

Pembayaran Lightning tidak memiliki alamat penerima on-chain: pembayar memegang permintaan pembayaran.
Pada transfer kripto bitcoin atau Lightning, `payment_method.account_id` dapat berisi permintaan tersebut, dan Didit mengidentifikasi penerima dari permintaan itu tanpa menghubungi jaringan mana pun:

| Yang Anda kirim | Penerima |
| - | - |
| Faktur BOLT11 (`lnbc...`) | Node penerima pembayaran, yang disebutkan dalam faktur atau dipulihkan dari tanda tangannya. |
| Tawaran atau faktur BOLT12 (`lno1...`, `lni1...`) | Node penerbit, kecuali jika tersembunyi di balik blinded path. |
| Lightning Address (`name@domain`) | Alamat itu sendiri. |
| ID node | Node itu sendiri. |
| LNURL (`lnurl1...`, `lnurlp://`) | Tidak ada: LNURL menyebutkan sebuah layanan, bukan penerima pembayaran. |

Penerima pembayaran disimpan sebagai akun dan sebagai `chain_details.beneficiary` (`source: invoice_payee`), pada rantai `LIGHTNING`, dan isi permintaan tersebut tersimpan di `chain_details.lightning`.
Jika permintaan tidak menyebutkan penerima pembayaran, transfer keluar berstatus `NOT_APPLICABLE` dengan alasannya di `chain_details.not_applicable_reason` dan di `timeline`-nya: `LIGHTNING_NO_PAYEE_IDENTIFIER`, `LIGHTNING_BOLT12_BLINDED_PAYEE`, atau `LIGHTNING_LNURL_NAMES_NO_PAYEE`.
Sebuah nilai hanya dibaca sebagai Lightning pada bitcoin, pada `LIGHTNING`, atau ketika tidak ada rantai yang disebutkan (Lightning Address hanya pada bitcoin atau `LIGHTNING`): pada rantai lain, nilai tersebut adalah alamat milik rantai itu sendiri.

> [!NOTE]
>
> Jalur `INTERNAL` hanya mencapai pelanggan Didit lain melalui dompet yang kendalinya telah dibuktikan oleh pelanggan tersebut dengan pesan bertanda tangan atau deposit uji, dan bukti tersebut saat ini tersedia untuk Bitcoin, rantai EVM, Solana, dan Tron.
> Oleh karena itu, pada jaringan memo, Lightning, Litecoin, Bitcoin Cash, dan Dogecoin, transfer tidak pernah mencapai pelanggan Didit lain melalui `INTERNAL`.
> Pencocokan memo, tag, dan Lightning tetap berlaku untuk buku alamat Anda sendiri: transfer masuk, deposit yang dilaporkan, dan permintaan `TRP` ke dompet Anda.

### Memperbarui dompet pengirim

Penarikan sering dideklarasikan dari dompet utama pelanggan Anda, dan disiarkan dari alamat mana pun yang memegang koin tersebut.
Catat dompet tempat dana sebenarnya keluar dengan `PATCH /v3/transactions/{transaction_id}/travel-rule/`:

```bash theme={null}
curl -X PATCH "https://verification.didit.me/v3/transactions/$TRANSACTION_ID/travel-rule/" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "action": "update_originator_wallet", "wallet_address": "bc1qsendercoldwallet02" }'
```

* Hanya transfer keluar, dan tidak pernah transfer yang berstatus `CANCELLED` atau `EXPIRED` (`409`).
* Jika input UTXO transfer diketahui, dompet harus salah satu dari input tersebut (jika tidak, `400`). Kirim juga `memo` pada jaringan memo.
* Hanya catatan yang diubah: tidak ada yang dikirim ulang ke pihak lawan dan statusnya tetap. `chain_details.originator` menjadi dompet baru dengan `source: updated`, `timeline` mencatat dompet sebelumnya dan dompet baru, dan pihak lawan `INTERNAL` dari transfer tersebut diperbarui dengan cara yang sama.

### Atribusi analitik blockchain

Ketika Anda hanya menyertakan alamat dompet, Didit tetap dapat mengetahui siapa pihak di seberangnya.
Jika tidak ada jalur yang dapat merutekan transfer, Didit mencocokkan dompet tujuan dengan data atribusi analitik blockchain - analisis yang sama dengan yang mendukung [skrining transaksi kripto](https://docs.didit.me/id/transaction-monitoring/aml-screening.md) mengetahui dompet mana milik exchange dan kustodian mana.
Atribusi hanya dijalankan pada transfer keluar yang memuat dompet tujuan dan `chain` (lihat [Kolom penentuan pihak lawan](#kolom-penentuan-pihak-lawan)); tanpa rantai, atribusi dilewati.

Ketika dompet diatribusikan ke entitas yang dikenal, Didit:

1. Mencatat atribusi pada transfer: `beneficiary_data.counterparty_vasp_name` diisi (jika Anda tidak memasukkannya), dan metadata transfer memuat blok `vasp_attribution` dengan nama entitas, jenis entitas, negara, dan `source: "blockchain_analytics"`.
2. Menambahkan entitas ke [direktori VASP](#direktori) (atau mencocokkan entri yang sudah ada), sehingga atribusi tetap konsisten di seluruh transfer.
3. Menjalankan ulang jalur sekali dengan nama hasil atribusi - entri direktori yang sudah memuat endpoint TRP membuat transfer dirutekan segera, alih-alih berakhir di `COUNTERPARTY_VASP_NOT_FOUND`.

Panggilan atribusi sekaligus berfungsi sebagai skrining kripto lengkap: transaksi menerima keluaran skrining yang lengkap - skor risiko, kategori risiko dompet, cuplikan jaringan - persis seolah-olah pemantauan kripto telah berjalan, dan `custom_values.aml_screening_trigger` pada transaksi diatur ke `travel_rule_attribution` sehingga Anda dapat melihat bahwa skrining dijalankan karena perutean Travel Rule memerlukannya.
Jika pemantauan kripto sudah melakukan skrining pada dompet yang sama dalam transaksi ini, hasil yang tersimpan digunakan kembali - tidak ada panggilan analitik kedua, dan tidak ada biaya tambahan.
Atribusi tidak pernah memblokir pembuatan transaksi: jika pencarian analitik gagal atau saldo Anda tidak mencukupi, transfer langsung berlanjut ke `COUNTERPARTY_VASP_NOT_FOUND` dan tidak ada biaya yang dikenakan untuk percobaan tersebut.
Pada `action: "resend"`, atribusi yang sudah dicatat sebelumnya digunakan kembali, bukan dikueri ulang.

Nonaktifkan seluruh langkah dengan `vasp_attribution_enabled: false` di [pengaturan](#pengaturan).
Lihat [Harga](#harga) untuk mengetahui bagaimana panggilan atribusi ditagihkan.

Saat Travel Rule **dinonaktifkan**, `travel_rule_details` (termasuk `status` yang diberikan pemanggil, baik status lama maupun status saat ini) tetap dicatat pada transaksi, tetapi secara pasif - tidak ada jalur yang dijalankan.
Gunakan ini untuk mengisi data kepatuhan yang sudah Anda lacak dengan proses Anda sendiri.
Transfer keluar yang pasif tidak memulai pertukaran, sehingga ditagih sebagai Skrining Transaksi, bukan pada [jalur Travel Rule](#harga).

Saat Travel Rule diaktifkan, permintaan ini diarahkan melalui jalur `EMAIL`, karena menyebutkan email kepatuhan pihak lawan dan tidak ada jalur sebelumnya yang dapat menjangkau penerima:

```bash theme={null}
curl -X POST https://verification.didit.me/v3/transactions/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "transaction_id": "trv-2026-07-05-001",
    "transaction_category": "travelRule",
    "transaction_details": {
      "direction": "outbound",
      "action_type": "transfer",
      "amount": "0.25",
      "currency": "ETH",
      "currency_kind": "crypto"
    },
    "subject": {
      "entity_type": "individual",
      "vendor_data": "user-042",
      "full_name": "Jane Doe"
    },
    "travel_rule_details": {
      "status": "AWAITING_COUNTERPARTY",
      "originator_data": {
        "first_name": "Jane",
        "last_name": "Doe",
        "date_of_birth": "1990-04-12",
        "residence_country": "ES",
        "customer_identification": "user-042",
        "wallet_address": "0x135908330861442a814796ae99feac507925782a"
      },
      "beneficiary_data": {
        "wallet_address": "0xede2d7e4f5b097e6391ab6bbcf2f47a53f4778cb",
        "name": "Ana Diaz",
        "counterparty_vasp_email": "compliance@bene-casp.example"
      }
    }
  }'
```

Respons, diringkas hanya pada kolom yang relevan di sini:

```json theme={null}
{
  "uuid": "22222222-3333-4444-5555-666666666666",
  "txn_id": "trv-2026-07-05-001",
  "transaction_type": "travelRule",
  "direction": "OUTBOUND",
  "status": "APPROVED",
  "amount": "0.25",
  "currency": "ETH",
  "currency_type": "crypto",
  "travel_rule": {
    "uuid": "33333333-4444-5555-6666-777777777777",
    "status": "AWAITING_COUNTERPARTY",
    "protocol": null,
    "required": true,
    "obligations_count": 0,
    "originator_data": {
      "first_name": "Jane",
      "last_name": "Doe",
      "date_of_birth": "1990-04-12",
      "residence_country": "ES",
      "customer_identification": "user-042",
      "wallet_address": "0x135908330861442a814796ae99feac507925782a"
    },
    "beneficiary_data": {
      "wallet_address": "0xede2d7e4f5b097e6391ab6bbcf2f47a53f4778cb",
      "name": "Ana Diaz",
      "counterparty_vasp_email": "compliance@bene-casp.example",
      "chain": "ETH"
    },
    "metadata": {
      "compliance_email_source": "caller_supplied"
    }
  },
  "action_required": null
}
```

* `originator_data` adalah data yang Anda kirim, karena subjek contoh tidak memiliki verifikasi KYC yang disetujui; untuk pengguna yang terverifikasi, Didit membangunnya dari data terverifikasi (lihat [Data terverifikasi dan asal-usul data](#data-terverifikasi-dan-asal-data)).
  Jalur `EMAIL` hanya menampilkan kepada penerima kolom pengirim yang Anda bagikan di [`data_sharing_fields`](#berbagi-data).
* `beneficiary_data.chain` bernilai `ETH` karena permintaan tidak menyebutkan jaringan, sehingga Didit mengambilnya dari mata uang.
* `status` bernilai `APPROVED` karena tidak ada aturan yang memproses transaksi; aturan Anda sendiri dapat menetapkan status lain.
* Kontak kepatuhan menerima tautan pengambilan, dan transfer selesai, gagal pada kecocokan nama, atau ditolak saat mereka merespons, atau kedaluwarsa jika mereka tidak merespons (lihat [Pengambilan melalui email](#pengambilan-email-untuk-pihak-lawan-yang-tidak-dapat-dijangkau)).

`protocol` masih `null` karena jalur dipilih setelah respons (misalnya `EMAIL` saat Anda memberikan `counterparty_vasp_email`): [Ambil transaksi](https://docs.didit.me/id/management-api/transactions/get.md) menampilkannya setelah dipilih, dan setiap webhook `travel_rule.status.updated` berikutnya memuatnya di `rail`.
Jika dompet penerima milik pelanggan Didit lain yang telah membuktikan kendali atasnya, jalur `INTERNAL` menyelesaikan seluruh pertukaran tepat setelah respons, dan webhook tersebut sudah melaporkan `COMPLETED` (atau `COUNTERPARTY_MISMATCHED_DATA`). Saat nama tidak cocok, transfer Anda berstatus `COUNTERPARTY_MISMATCHED_DATA` dan pelanggan lain tidak menerima apa pun.
Tanpa `counterparty_vasp_email`, dan ketika baik jalur maupun [atribusi](#atribusi-analitik-blockchain) tidak dapat menjangkau penerima, transfer kemudian berakhir dengan `COUNTERPARTY_VASP_NOT_FOUND` dengan tindakan `wallet_ownership` pada transaksi.

> [!NOTE]
>
> Objek `travel_rule` yang tertanam pada transaksi memuat kolom transfer itu sendiri (`uuid`, `status`, `protocol`, `required`, `obligations_count`, `originator_data`, `beneficiary_data`, `metadata`), yang ditentukan dan dibandingkan oleh Didit (`chain_details`, `name_match`, `data_match`, `mismatched_fields`, dan kolom [maskering](#data-pihak-lawan-yang-disamarkan) `data_masked` dan `data_unmasked`), serta kolom yang menunjukkan posisinya: `direction`, `rail`, `counterparty_vasp`, `delivery`, `discovery`, `reason`, dan `next_actions` (lihat [Mengapa transfer macet](#mengapa-transfer-macet)).
> Setiap baris [`GET /v3/transactions/`](https://docs.didit.me/id/management-api/transactions/list) memuat blok yang sama, atau `null` untuk transaksi tanpa transfer.
> Endpoint transfer khusus di bawah ini juga mengembalikan kolom tersebut, ditambah `ivms_version`, `ownership_confirmed`, `deadline_at`, `timeline`, dan `created_at`, tetapi tanpa `obligations_count` atau `metadata`.

Untuk menutup transfer keluar yang berstatus `COMPLETED` setelah Anda menyiarkannya on-chain:

```bash theme={null}
curl -X PATCH https://verification.didit.me/v3/transactions/22222222-3333-4444-5555-666666666666/travel-rule/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"payment_txn_id": "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060"}'
```

Ini mengharuskan transfer adalah transfer **keluar** dengan status `COMPLETED` - jika tidak, API mengembalikan `409`.
Jika berhasil, transfer keluar dan pasangannya pada jalur `INTERNAL` sama-sama beralih ke `FINISHED`, dan `payment_txn_id` transaksi diisi dengan hash yang Anda berikan.
Pada jalur `TRP`, Didit juga mengirim hash ke callback konfirmasi pihak lawan.

Untuk membatalkan transfer yang belum mencapai status akhir, kirim `{"action": "cancel"}` ke endpoint yang sama sebagai gantinya.
Pasangan pada jalur `INTERNAL` ikut dibatalkan, dan pada jalur `TRP`, setelah pihak lawan menyetujui permintaan, Didit mengirim pembatalan ke callback konfirmasinya.
Transfer yang sudah berstatus `FINISHED`, `CANCELLED`, atau `EXPIRED` mengembalikan `409`.
Permintaan yang tidak memiliki `payment_txn_id` maupun `action` yang didukung mengembalikan `400`.

Pada transfer yang melalui `GTR`, `VERIFYVASP` atau `SYGNA`, Didit melaporkan hash on-chain (atau pembatalan) ke jaringan setelah respons, dengan [percobaan ulang yang sama](#pengiriman-dan-coba-lagi); `delivery` pada respons menunjukkan pesan tersebut.

Untuk mencoba ulang transfer keluar yang tidak dapat menjangkau pihak lawannya - yang saat ini berstatus `COUNTERPARTY_VASP_NOT_FOUND`, `COUNTERPARTY_VASP_NOT_REACHABLE`, atau `NOT_ENOUGH_COUNTERPARTY_DATA` - pertama-tama perbaiki data pihak lawan, misalnya dengan menambahkan `travel_address` pada entri dompet tujuan, [kontak](#kontak) untuk entri direktori pihak lawan, atau dengan mendaftarkan VASP tersebut di [direktori](#direktori).
Kemudian kirim `{"action": "resend"}` ke endpoint yang sama.
Didit memulai ulang tenggat konfirmasi dan memasukkan kembali urutan perutean dari awal, menggunakan data yang tersimpan pada transfer: respons menunjukkan transfer kembali ke `AWAITING_COUNTERPARTY` (dengan `resend queued` pada `timeline`-nya), dan hasilnya dikirim sebagai webhook `travel_rule.status.updated`.
Permintaan pengiriman ulang yang dikirim saat percobaan sebelumnya masih berjalan akan dikirim setelah percobaan tersebut selesai.
Status lain, atau transfer masuk, mengembalikan `409`.

```bash theme={null}
curl -X PATCH https://verification.didit.me/v3/transactions/22222222-3333-4444-5555-666666666666/travel-rule/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action": "resend"}'
```

Untuk menentukan pihak lawan sendiri ketika [penemuan](#penemuan-pihak-lawan) tidak berhasil, kirim `{"action": "beneficiary_vasp", "beneficiary_vasp": "<directory VASP id>"}` (`id` dari `GET /v3/travel-rule/vasps/`).
Transfer diarahkan ke VASP tersebut dan dikirim ulang.
Hanya transfer keluar dengan status `COUNTERPARTY_VASP_NOT_FOUND`, `COUNTERPARTY_VASP_NOT_REACHABLE` atau `NOT_ENOUGH_COUNTERPARTY_DATA` yang menerimanya; status lain mengembalikan `409`, dan id yang tidak dikenal mengembalikan `404`.

### Mengapa transfer macet

Transfer dengan status `COUNTERPARTY_VASP_NOT_FOUND` atau `COUNTERPARTY_VASP_NOT_REACHABLE` menjelaskan mengapa macet dan apa yang membuatnya berjalan lagi, setiap kali transaksinya dibaca.
Blok `travel_rule` dari [`GET /v3/transactions/{transaction_id}/`](https://docs.didit.me/id/management-api/transactions/get), dari respons `201` [`POST /v3/transactions/`](https://docs.didit.me/id/management-api/transactions/create), dan dari setiap baris [`GET /v3/transactions/`](https://docs.didit.me/id/management-api/transactions/list) memuatnya, begitu pula objek transfer yang dikembalikan oleh [endpoint transfer](https://docs.didit.me/id/management-api/travel-rule/update-transfer.md):

* `reason` adalah penyebab yang dapat dibaca mesin, `""` untuk status lainnya.
* `next_actions` berisi tindakan yang memajukan transfer, `[]` untuk status lainnya.
* `delivery` adalah pesan terbaru yang harus dikirimkan transfer kepada pihak lawan: `kind`, `status` (`QUEUED`, `SENDING`, `RETRYING`, `DELIVERED`, atau `FAILED`), `rail`, `attempts`, `last_error`, `next_attempt_at`, dan `delivered_at`, atau `null` jika tidak ada pesan yang harus dikirim.
* `discovery` adalah tempat Didit mencari pihak lawan, dengan satu entri untuk setiap langkah yang dijalankan: `step`, `outcome` (`match`, `miss`, atau `skipped`), `reason`, `vasp`, `rail`, dan `at`.

`email_undeliverable` dan `delivery_failed` berasal dari pengiriman yang gagal dan hanya muncul pada `COUNTERPARTY_VASP_NOT_REACHABLE`.
Pengiriman yang gagal menentukan `reason` terlebih dahulu, sehingga pihak lawan yang berhasil ditemukan Didit tidak pernah dilaporkan sebagai pihak yang tidak dapat ditemukan.
Empat yang lain berasal dari jejak penemuan, pada status mana pun.

| `reason` | Yang terjadi | `next_actions` |
| - | - | - |
| `email_undeliverable` | Penyedia email menolak email kepatuhan dan tidak ada alamat lain untuk dicoba: saat dikirim, pada pengingat, atau sebagai bounce permanen yang dilaporkan kemudian. | `update_compliance_email`, lalu `resend` |
| `delivery_failed` | Rail yang melakukan pengiriman gagal secara permanen: rail jaringan menolak pesan atau kehabisan percobaan ulang, host identitas `TRP` tidak merespons, atau host `TRP` pihak lawan tidak menerima permintaan. | `resend` |
| `awaiting_end_user` | Tidak ada langkah penemuan yang menyebutkan pihak lawan yang dapat dijangkau Didit, sehingga pengguna akhir diminta untuk menyebutkannya. | `select_counterparty_vasp`, `declare_self_hosted`, `add_vasp_hint`, `resend` |
| `directory_match_no_route` | Sebuah langkah menyebutkan entri [direktori](#direktori), tetapi entri tersebut tidak memiliki rute yang dapat digunakan Didit untuk Anda. | Sama seperti `awaiting_end_user` |
| `picked_member_without_proven_wallet` | Pengguna akhir memilih pelanggan Didit lain sebagai pihak lawan, tetapi pelanggan tersebut belum membuktikan kendali atas dompet. | Sama seperti `awaiting_end_user` |
| `no_directory_match` | Jejak penemuan tidak memberikan alasan lain. | Sama seperti `awaiting_end_user` |

| Tindakan berikutnya | Yang harus dilakukan |
| - | - |
| `update_compliance_email` | Berikan kembali email kepatuhan pihak lawan, dengan `{"action": "update_compliance_email", "compliance_email": "..."}` pada endpoint transfer. |
| `resend` | Jalankan ulang perutean dengan `{"action": "resend"}` setelah ada yang berubah. |
| `select_counterparty_vasp` | Pengguna akhir memilih VASP tujuan di [widget kepemilikan dompet](https://docs.didit.me/id/transaction-monitoring/wallet-ownership-widget.md). `url` adalah tautan widget selama transfer memiliki sesi widget yang masih terbuka. |
| `declare_self_hosted` | Pengguna akhir mendeklarasikan dompet sebagai swakelola di dalam widget, pada `url` yang sama. |
| `add_vasp_hint` | Beri tahu Didit siapa pihak lawannya, dengan nama VASP, LEI, atau travel address (misalnya `travel_address` pada [entri buku alamat](#buku-alamat-dompet) dompet tujuan), lalu kirim ulang. |

Pengiriman ulang memindahkan transfer ke tahap berikutnya, sehingga `reason`-nya dihapus.
Entri linimasa dari transisi yang disebabkan pengiriman gagal membawa nilai yang sama pada `reason`.

Jika penyedia email menolak email kepatuhan dari [contoh transfer di atas](#mengirim-transfer), blok `travel_rule` pada transaksinya terbaca sebagai berikut, dalam bentuk ringkas:

```json theme={null}
{
  "uuid": "33333333-4444-5555-6666-777777777777",
  "status": "COUNTERPARTY_VASP_NOT_REACHABLE",
  "protocol": "EMAIL",
  "direction": "OUTBOUND",
  "rail": "EMAIL",
  "counterparty_vasp": null,
  "delivery": {
    "kind": "SEND",
    "status": "FAILED",
    "rail": "EMAIL",
    "attempts": 1,
    "last_error": "email undeliverable",
    "next_attempt_at": null,
    "delivered_at": null
  },
  "reason": "email_undeliverable",
  "next_actions": [
    { "action": "update_compliance_email" },
    { "action": "resend" }
  ]
}
```

Di sini `delivery` sesuai dengan `reason`, karena pengiriman itu sendiri ditolak.
Penolakan pada pengingat, atau bounce yang dilaporkan kemudian, membiarkan `delivery.status` tetap `DELIVERED`: email pertama memang terkirim.
Baca `reason`, bukan `delivery`, untuk mengetahui mengapa transfer tertahan.

Untuk memperbaikinya, berikan kembali email kepatuhan pihak lawan, lalu kirim ulang:

```bash theme={null}
curl -X PATCH https://verification.didit.me/v3/transactions/22222222-3333-4444-5555-666666666666/travel-rule/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action": "update_compliance_email", "compliance_email": "desk@bene-casp.example"}'

curl -X PATCH https://verification.didit.me/v3/transactions/22222222-3333-4444-5555-666666666666/travel-rule/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action": "resend"}'
```

`update_compliance_email` menyimpan alamat tersebut sebagai `beneficiary_data.counterparty_vasp_email` pada transfer ini: alamat itu hanya berlaku untuk transfer ini dan tidak masuk ke entri direktori maupun daftar kontak mana pun.
Status tidak berubah, linimasa mencatat `compliance email updated`, dan transfer tetap memiliki `reason: email_undeliverable` hingga pengiriman ulang mengirim permintaan ke alamat baru.
Hanya transfer keluar dalam `COUNTERPARTY_VASP_NOT_FOUND`, `COUNTERPARTY_VASP_NOT_REACHABLE`, atau `NOT_ENOUGH_COUNTERPARTY_DATA` yang menerima tindakan ini; transfer lain menjawab `409`, dan `compliance_email` yang tidak ada atau formatnya salah menjawab `400`.

### Dompet swakelola yang dideklarasikan

Ketika pelanggan Anda memberi tahu bahwa tujuannya adalah dompet swakelola (unhosted) miliknya sendiri, deklarasikan dompet tersebut pada transaksi, alih-alih membiarkan perutean menemukan bahwa tidak ada VASP di baliknya: atur jenis metode pembayaran pihak lawan menjadi `unhosted_wallet`.

```bash theme={null}
curl -X POST https://verification.didit.me/v3/transactions/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "transaction_id": "trv-2026-07-07-002",
    "transaction_category": "travelRule",
    "transaction_details": {
      "direction": "outbound",
      "action_type": "transfer",
      "amount": "0.25",
      "currency": "ETH",
      "currency_kind": "crypto"
    },
    "subject": {
      "entity_type": "individual",
      "vendor_data": "user-042",
      "full_name": "Jane Doe"
    },
    "counterparty": {
      "entity_type": "external",
      "full_name": "Jane Doe",
      "payment_method": {
        "method_type": "unhosted_wallet",
        "account_id": "0xd3b62acb76fb27a7f8961ec40fa11746b113aca9"
      }
    },
    "travel_rule_details": {
      "status": "AWAITING_COUNTERPARTY",
      "beneficiary_data": {
        "wallet_address": "0xd3b62acb76fb27a7f8961ec40fa11746b113aca9",
        "name": "Jane Doe"
      }
    }
  }'
```

Deklarasi ini melewati perutean sepenuhnya:

* Tidak ada rail yang dicoba - tidak ada VASP pihak lawan untuk bertukar data - dan transfer langsung dibuat dalam `UNCONFIRMED_OWNERSHIP`.
* Ketika `auto_wallet_verification` aktif (nilai default), Didit secara otomatis membuat sesi [widget kepemilikan dompet](https://docs.didit.me/id/transaction-monitoring/wallet-ownership-widget.md) yang terikat pada transaksi dan mengembalikannya dalam blok `action_required` transaksi; SDK akan membukanya secara otomatis pada [pengiriman sisi klien](https://docs.didit.me/id/transaction-monitoring/sdk-transaction-submission.md).
* Setelah pelanggan membuktikan kendali atas dompet, transfer menjalankan pencocokan nama penerima dan maju ke `COMPLETED` (atau `COUNTERPARTY_MISMATCHED_DATA` jika pencocokan gagal).

Ini adalah kewajiban TFR UE untuk dompet swakelola dalam bentuk API: verifikasi kepemilikan dompet unhosted, alih-alih bertukar data dengan VASP pihak lawan.
Deklarasi dibaca dari metode pembayaran di sisi **tujuan** pada transfer keluar dan sisi **sumber** pada transfer masuk - dalam kedua kasus, peserta yang menjadi pihak lawan.
Transfer yang dideklarasikan unhosted sudah berada pada jalur akhir tanpa rail, sehingga `UNCONFIRMED_OWNERSHIP` bukan status yang dapat dikirim ulang - selesaikan pembuktian kepemilikan (atau batalkan) alih-alih memanggil `action: "resend"`.

## Penerimaan

### Mengonfirmasi kepemilikan dompet

Transfer akan menunggu di status `UNCONFIRMED_OWNERSHIP` dalam dua kasus:

* Transfer masuk mengarah ke entri [buku alamat](#buku-alamat-dompet) yang kepemilikannya belum terverifikasi.
* Dompet pihak lawan dinyatakan sebagai dompet swakelola (`counterparty.payment_method.method_type: "unhosted_wallet"`), baik pada penarikan keluar maupun setoran masuk. Lihat [Dompet swakelola yang dinyatakan](#dompet-swakelola-yang-dideklarasikan).

Aplikasi Anda mengonfirmasi atau menolak transfer:

```bash theme={null}
curl -X POST https://verification.didit.me/v3/transactions/{transaction_uuid}/travel-rule/ownership/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"confirmed": true}'
```

Isi permintaan berisi `confirmed` (wajib, boolean) dan `wallet_address` (opsional).

Endpoint ini menerima transfer dalam status berikut, dan mengembalikan `409` dengan `{"detail": "Transfer is not awaiting ownership confirmation."}` untuk status lainnya:

* `UNCONFIRMED_OWNERSHIP`, di kedua arah.
* `ON_HOLD` pada transfer masuk.
* `UNCONFIRMED_OWNERSHIP`, `ON_HOLD` atau `COUNTERPARTY_MISMATCHED_DATA` pada transfer masuk `TRP`, sehingga petugas kepatuhan dapat menyelesaikan pertanyaan pihak lawan secara manual.

Pada transfer yang dibuat sendiri oleh Didit (rel `INTERNAL`, registrasi sunrise, atau dompet swakelola yang dinyatakan):

* `confirmed: true` menandai entri buku alamat dompet yang cocok sebagai kepemilikannya terverifikasi, lalu menjalankan pencocokan nama terhadap `holder_name` entri tersebut. Hasilnya `COMPLETED` jika lolos, dan `COUNTERPARTY_MISMATCHED_DATA` jika tidak.
  Pasangan rel `INTERNAL`, jika ada, mendapat hasil yang sama.
  Untuk dompet swakelola yang dinyatakan, `confirmed: true` mencatat bahwa pelanggan Anda telah memverifikasi siapa yang mengendalikan dompet pihak lawan, dan menyelesaikan transfer (`COMPLETED`), baik keluar maupun masuk.
  Transfer masuk yang depositnya sudah diselesaikan kemudian langsung berlanjut ke `FINISHED`.
* `confirmed: false` memindahkan kedua sisi transfer ke `COUNTERPARTY_VASP_GENERAL_DECLINE`.
* Entri yang cocok dicari di buku alamat Anda hanya berdasarkan alamat dompet, tanpa jaringan blockchain.
  Menyelesaikan `ON_HOLD` masuk tanpa entri yang cocok akan membuat entri dari `beneficiary_data.wallet_address` transfer dan menandainya sebagai terverifikasi.
  Dompet swakelola yang dinyatakan adalah pengecualian: dompet didaftarkan di buku alamat Anda sebagai kepemilikannya terverifikasi, seperti dijelaskan di bawah.
  Dalam kasus lain, entri yang tidak ada mengembalikan `409` dengan `{"detail": "wallet address entry no longer available"}`, yang juga dikembalikan untuk entri yang sudah dihapus.

Pada transfer masuk `TRP`, panggilan yang sama menjawab pertanyaan pihak lawan:

* `confirmed: true` memerlukan alamat pembayaran untuk dikembalikan, yang diambil dari `wallet_address` pada permintaan, lalu dari entri yang cocok, lalu dari `beneficiary_data.wallet_address`.
  Jika ketiganya tidak ada, permintaan mengembalikan `400` dengan `{"wallet_address": ["wallet_address is required to approve."]}`.
  Didit membuat atau memverifikasi entri, mengirim callback penyelesaian pertanyaan ke pihak lawan, menetapkan `ownership_confirmed`, dan memindahkan transfer ke `COMPLETED`.
* `confirmed: false` mengirim respons penolakan dan memindahkan transfer ke `COUNTERPARTY_VASP_GENERAL_DECLINE`.
* Jika endpoint callback pihak lawan tidak dapat dijangkau, permintaan mengembalikan `502` dan transfer tetap berada di status saat ini.
  Pada persetujuan, entri buku alamat dompet tetap dibuat atau ditandai sebagai terverifikasi.

Untuk dompet swakelola yang dinyatakan, dompet yang Anda verifikasi adalah milik pihak lawan: tujuan penarikan keluar, atau sumber (dompet pengirim) setoran masuk.
Didit menambahkannya ke buku alamat dompet sebagai kepemilikannya terverifikasi atas nama pihak lawan, sehingga dompet dicocokkan dengan nama pihak lawan (pengirim, untuk setoran).
Jika buku alamat sudah memuat dompet tersebut di bawah nama pemegang yang berbeda, transfer beralih ke `COUNTERPARTY_MISMATCHED_DATA`.

Jika transfer sama sekali tidak menyebut dompet pihak lawan, sertakan `wallet_address` dalam body permintaan.
Jika transfer maupun permintaan tidak menyediakan alamat dompet, permintaan ditolak dengan `400`.

```json theme={null}
{"confirmed": true, "wallet_address": "0xCounterpartyWallet01"}
```

* Transfer jaringan yang sudah dijawab melalui jaringannya (transfer VerifyVASP, atau transfer GTR atau Sygna Bridge yang sudah diputuskan) mengembalikan `409` (lihat [Transfer dari jaringan](#transfer-dari-jaringan)).

Responsnya adalah objek transfer yang lebih lengkap seperti dijelaskan di atas.
Transfer `INTERNAL` baru tidak pernah menunggu di sini: transfer hanya sampai kepada pelanggan yang sudah membuktikan kendali atas dompet tersebut. Transfer `INTERNAL` lama yang masih menunggu dari sebelum aturan itu tetap menyembunyikan detail pengirim sampai Anda membuktikan kendali atas dompet (pesan yang ditandatangani atau setoran uji), dan mengonfirmasinya mengembalikan `409` sampai Anda melakukannya. Menolaknya tetap berfungsi.
Ketika pihak lawan menjawab bahwa dompetnya adalah dompet swakelola (saat ini [Didit Test VASP](https://docs.didit.me/id/transaction-monitoring/travel-rule-sandbox.md) memberikan jawaban itu di sandbox), mengonfirmasi menambahkan dompet ke buku alamat Anda atas nama penerima dan menjalankan pencocokan nama. Kecocokan menyelesaikan transfer dan menandai dompet sebagai terverifikasi.

### Transfer dari jaringan

Didit juga dapat menerima transfer Travel Rule yang dikirim pihak lawan melalui `GTR`, `VERIFYVASP` atau `SYGNA`.
Penerimaan diaktifkan oleh Didit untuk setiap jaringan secara terpisah, dan **saat ini belum ada yang diaktifkan**: penerimaan juga memerlukan registrasi endpoint Didit di setiap jaringan, dan Didit belum memiliki keanggotaan di jaringan-jaringan ini.
Transfer `TRUST` tidak dapat diterima.

Setelah sebuah jaringan diaktifkan, pesan yang dikirimkannya ditangani sebagai berikut:

* **Perutean.** Pesan sampai ke aplikasi Anda ketika pesan itu menyebut kode peserta dari keanggotaan terhubung Anda sendiri di jaringan tersebut. Pesan yang dialamatkan ke keanggotaan Didit sendiri hanya sampai kepada Anda jika Anda adalah satu-satunya pelanggan Didit aktif yang telah membuktikan kendali atas dompet penerima. Selain itu, pesan ditolak, sehingga tidak ada pelanggan yang pernah menerima transfer pelanggan lain.
* **Keputusan.** Didit membuat transfer masuk di aplikasi Anda dan memutusnya seperti [permintaan TRP](https://docs.didit.me/id/transaction-monitoring/travel-rule-interoperability.md#endpoint-trp): pencocokan dompet, kepemilikan, pencocokan nama, dan `inbound_auto_accept`.
* **Sekali saja.** Jaringan mengirim ulang pesan hingga pesan itu dijawab. Pesan yang dikirim ulang menerima jawaban yang sama dengan yang diterima salinan pertama, dan tidak ada yang dibuat atau diputuskan dua kali.
* **Peninjauan Anda, melalui `GTR` dan `SYGNA`.** Transfer yang menunggu Anda (`UNCONFIRMED_OWNERSHIP`, `ON_HOLD` atau `COUNTERPARTY_MISMATCHED_DATA`) diputuskan dengan [`POST .../travel-rule/ownership/`](#mengonfirmasi-kepemilikan-dompet): `confirmed: true` menyetujuinya (sertakan `wallet_address` jika transfer tidak menyebutkannya) dan `confirmed: false` menolaknya. Didit menjawab jaringan setelah respons, dengan [mekanisme coba lagi yang sama](#pengiriman-dan-coba-lagi). Transfer yang sudah dijawab sebelumnya mengembalikan `409`.
* **Tidak ada jawaban lanjutan melalui `VERIFYVASP`.** VerifyVASP mengambil jawabannya saat ia bertanya, sehingga transfer yang memerlukan peninjauan Anda langsung ditolak dan tidak dapat diputuskan kemudian (`409`).

### Data pihak lawan yang disamarkan

Sampai kepemilikan dompet dikonfirmasi, data pribadi pihak lawan pada transfer masuk dikembalikan dalam bentuk disamarkan, bukan dihilangkan.
Huruf pertama setiap kata tetap ditampilkan, dan routing dompet, chain, serta VASP tetap dapat dibaca.
`data_masked` bernilai `true`, dan pihak lawan dalam detail transaksi, daftar, serta ekspor CSV disamarkan dengan cara yang sama.

Setelah kepemilikan dikonfirmasi, nilai sebenarnya muncul dan `data_unmasked` mencatat entri audit:

```json theme={null}
{
  "data_masked": false,
  "data_unmasked": { "at": "2026-10-17T10:00:00Z", "reason": "wallet_proof", "actor": "" }
}
```

`reason` berisi `ownership_confirmed`, `wallet_proof`, `address_book_match`, `own_verified_wallet`, `inquiry_approved` (Anda menyetujui inkuiri `TRP` atau pesan `GTR` atau `Sygna`), `known_payment_method` (dompet pengguna akhir dalam catatan Anda sendiri memberikan jawaban) atau `travel_address` (Travel Address per dompet menyebutkan dompet tersebut).
Transfer masuk `INTERNAL` membawa `data_unmasked` dengan `reason: wallet_proof` sejak dibuat, karena hanya penerima yang telah membuktikan kepemilikan atau kendali atas dompet yang menerimanya.
`actor` berisi email pengguna konsol atau label kunci API, dan kosong untuk keputusan otomatis.
Laporan **Log transfer Travel Rule** (CSV dan PDF) menyamarkan nama pada transfer masuk dengan cara yang sama sampai kepemilikan dikonfirmasi. Laporan yang Anda serahkan kepada regulator, seperti goAML XML dan laporan PDF untuk regulator, memuat data pihak lawan yang sebenarnya.

### Umpan balik ketidakcocokan

Transfer `COUNTERPARTY_MISMATCHED_DATA` kini menyebutkan kolom yang berbeda.
`data_match` berisi hasil perbandingan dan `mismatched_fields` berisi daftar kolom tersebut.
Keduanya hanya memuat nama kolom dan hasil, tidak pernah nilai, sehingga tetap dapat dibaca saat data disamarkan:

```json theme={null}
{
  "status": "COUNTERPARTY_MISMATCHED_DATA",
  "mismatched_fields": ["date_of_birth"],
  "data_match": {
    "matched": false,
    "mismatched_fields": ["date_of_birth"],
    "fields": {
      "name": { "result": "matched", "strictness": "DEFAULT" },
      "date_of_birth": { "result": "mismatched", "strictness": "STRICT" },
      "address": { "result": "not_compared", "strictness": "NONE" },
      "account": { "result": "matched", "strictness": "STRICT" }
    }
  }
}
```

Entri timeline menyebutkan kolom, misalnya "tanggal lahir penerima tidak cocok dengan pemegang dompet".
Pesan `TRP` penolakan setelah ketidakcocokan memberi tahu VASP pengirim kolom mana yang berbeda, misalnya "Data penerima tidak cocok dengan pemegang dompet: nama".
Yang diketahui VASP lain dibatasi secara sengaja: selama nama belum cocok, nama adalah satu-satunya kolom yang dilaporkan (`mismatched_fields: ["name"]`, setiap kolom lain `not_compared`), dan setelah nama cocok, setiap kolom yang berbeda disebutkan. Ini berlaku untuk sisi pengirim pada pertukaran `INTERNAL` dan untuk penolakan `TRP`.
Nama yang kosong di kedua sisi bernilai `not_compared` dan bukan ketidakcocokan, dan negara dicocokkan berdasarkan negara yang dimaksud, sehingga `ES` dan `ESP` dianggap sama.

#### Skor kecocokan nama

Setiap transfer yang namanya dibandingkan memuat `name_match`, dan entri timeline yang menentukan hasilnya memuat objek yang sama di samping `detail`-nya:

```json theme={null}
{
  "name_match": {
    "score": 90,
    "matched": false,
    "method": "sequence_ratio",
    "strictness": "FUZZY",
    "compared_with": "wallet_holder",
    "transfer_name": "Ana Diaz",
    "compared_name": "Ana Diaz Garcia",
    "matched_names": ["Ana", "Diaz"],
    "mismatched_names": ["Garcia"]
  }
}
```

* `score` adalah kemiripan antara dua nama lengkap, dari 0 sampai 100, dan `0` jika salah satu nama kosong. `matched` adalah hasil pada `strictness`, sehingga keduanya bisa berbeda: `FUZZY` memutuskan berdasarkan rasio kemiripannya sendiri `0.85`.
* `matched_names` adalah kata-kata dari nama transfer yang ditemukan dalam nama lainnya; `mismatched_names` adalah kata-kata yang dimiliki salah satu sisi tetapi tidak dimiliki sisi lainnya.
* `method` bernilai `none`, `exact_token`, `token_subset`, `token_containment` atau `sequence_ratio`, untuk `NONE`, `STRICT`, `DEFAULT`, `CONTAINS` dan `FUZZY`.
* `compared_with` bernilai `wallet_holder` (pemegang yang tercatat untuk dompet) atau `counterparty_vasp` (nama yang diberikan pihak lawan di halaman respons email, atau jawaban Didit Test VASP).
* Hasil transfer mengikuti `data_match`, yang membandingkan setiap kolom, sehingga sebuah transfer dapat berstatus `COUNTERPARTY_MISMATCHED_DATA` sementara `name_match.matched` bernilai `true`.
* `name_match` ada pada objek transfer yang dikembalikan oleh endpoint Travel Rule dan pada `travel_rule` yang tertanam di transaksi, dan bernilai `null` sampai nama dibandingkan. Daftar transfer dan webhook tidak memuatnya.
* Nama disembunyikan selama pihak-pihak [disamarkan](#data-pihak-lawan-yang-disamarkan), dan pada salinan pertukaran `INTERNAL` milik pelanggan lain.

### Pesan dan permintaan dokumen

Dua VASP dapat menyelesaikan transfer yang disengketakan di dalam Didit, bukan lewat email.
`GET` dan `POST /v3/transactions/{transaction_id}/travel-rule/messages/` mencantumkan dan mengirim pesan pada suatu transfer:

```bash theme={null}
curl -X POST https://verification.didit.me/v3/transactions/{transaction_uuid}/travel-rule/messages/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"kind": "DOCUMENT_REQUEST", "body": "Please confirm the beneficiary date of birth.", "requested_documents": ["Proof of address"]}'
```

* `kind` bernilai `MESSAGE` (default) atau `DOCUMENT_REQUEST`. Permintaan dokumen membutuhkan minimal satu entri di `requested_documents` (hingga 10); pesan membutuhkan `body` (hingga 5000 karakter) atau sebuah file.
* `reply_to` menunjuk pesan sebelumnya pada transfer yang sama. Balasan dari pihak seberang yang memuat dokumen memenuhi permintaan dokumen yang dijawabnya, dan `fulfilled_at` diisi pada pesan tersebut. Balasan Anda sendiri tidak pernah memenuhi permintaan Anda sendiri.
* Kirim multipart dengan `files` untuk melampirkan hingga 5 file berukuran masing-masing 10 MB, berupa PDF, PNG, JPEG atau WebP. Didit memeriksa isi setiap file, bukan hanya tipe yang dideklarasikan, dan file lain menyebabkan permintaan mengembalikan `400` pada `files` ("Attach PDF, PNG, JPEG or WebP files only.").
* Sebuah transfer menampung hingga 100 pesan, dengan hingga 20 di antaranya dapat memuat lampiran (masing-masing hingga 5 file), dihitung dari kedua sisi; jika melebihi salah satu batas, permintaan dijawab `400`. Lampiran pesan tidak dihitung sebagai dokumen transaksi itu sendiri.
* Pesan berjalan melalui jalur `INTERNAL` dan `EMAIL`. Pada `INTERNAL`, pelanggan Didit lain melihat pesan di sisinya dalam pasangan tersebut. Pada `EMAIL`, pihak lawan menerima email dan menjawab di portal pengambilan. Jika email pemberitahuan tidak dapat dikirim, pesan tetap disimpan dan permintaan dijawab `201`.
* Permintaan dijawab `409` dengan alasan di `detail` untuk transfer melalui `TRP`, `GTR`, `TRUST`, `VerifyVASP`, atau `Sygna` (protokol tersebut tidak membawa pesan), transfer yang belum memiliki pihak lawan, transfer `INTERNAL` yang datanya tidak cocok dengan pemegang dompet (tidak ada yang sampai ke penerima), transfer `INTERNAL` yang penerimanya belum membuktikan kendali atas dompet (di kedua sisi, sampai hal itu terjadi), transfer `EMAIL` yang pihak lawannya tidak lagi memiliki alamat email kepatuhan, dan transfer `EMAIL` yang tautan pengambilannya sudah kedaluwarsa atau transfernya sudah ditutup.
* Tidak ada webhook yang terpicu saat pihak lawan membalas. Baca endpoint pesan.
* Email yang memberi tahu pihak lawan tentang pesan baru dikirim dalam bahasa Inggris.

### Buku alamat dompet

Daftarkan dompet yang Anda kendalikan agar transfer masuk (jalur `INTERNAL`, inkuiri `TRP` masuk, dan [pendaftaran setelah deposit](#pendaftaran-sunrise-setelah-deposit)) dapat dicocokkan dengan dompet tersebut, dengan `POST`/`GET /v3/travel-rule/wallet-addresses/` dan `PATCH`/`DELETE /v3/travel-rule/wallet-addresses/{entry_uuid}/`.

```bash theme={null}
curl -X POST https://verification.didit.me/v3/travel-rule/wallet-addresses/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "address": "0xede2d7e4f5b097e6391ab6bbcf2f47a53f4778cb",
    "chain": "ETH",
    "holder_name": "Ana Diaz",
    "holder_vendor_data": "user-042",
    "self_declared": true
  }'
```

| Kolom | Tipe | Deskripsi |
| - | - | - |
| `address` | string | Alamat dompet. Unik per aplikasi, `chain`, dan `memo` (alamat dibandingkan tanpa membedakan huruf besar dan kecil), duplikat mengembalikan `400`. Alamat X XRP disimpan sebagai alamat klasik beserta tag-nya. Kosong pada entri yang [diimpor berdasarkan hash-nya](#mengimpor-dompet-secara-massal). |
| `address_hash` | string | Hanya-baca. SHA-256 dari alamat yang sudah diubah menjadi huruf kecil, dalam hex huruf kecil. |
| `memo` | string | Opsional. Tag tujuan atau memo yang menjadi bagian dari dompet pada [jaringan memo](#jaringan-memo-dan-tag); kosong untuk seluruh alamat. Alias: `destinationTag`. |
| `chain` | string | Opsional. Pengidentifikasi chain, hingga 32 karakter. Gunakan token yang sama dengan yang dibawa transfer Anda (misalnya `ETH` atau `BTC`), atau biarkan kosong agar cocok dengan transfer di chain mana pun, lihat catatan di bawah. Penerima Lightning (node id atau Lightning Address) yang didaftarkan di bitcoin disimpan dalam huruf kecil sebagai `LIGHTNING`, tempat transfer [Lightning](#lightning) dicocokkan. |
| `holder_name` | string | Nama pemilik dompet, digunakan untuk pencocokan nama penerima. |
| `holder_vendor_data` | string | Pengenal internal Anda untuk pemilik dompet. |
| `entity_type` | string | Teks bebas hingga 16 karakter, secara default menjadi `"individual"`. |
| `travel_address` | string | Opsional. Travel Address VASP pihak lawan untuk dompet ini, jika Anda mengetahuinya. Memungkinkan Didit merutekan transfer ke penerima ini melalui jalur `TRP`, bukan email. |
| `receiving_travel_address` | string | Hanya-baca. Travel Address Anda sendiri untuk dompet ini. Berikan kepada VASP yang mengirim ke dompet ini: permintaan TRP-nya kemudian menyebut dompet tersebut secara langsung. Kosong untuk dompet yang tercatat sebagai milik VASP lain, saat Travel Rule nonaktif, dan sebelum profil VASP Anda disimpan. Alamat ini berhenti merespons setelah dompet dihapus. |
| `is_ownership_verified` | boolean | Hanya-baca. Apakah kepemilikan alamat ini sudah terbukti (melalui [widget verifikasi kepemilikan dompet](https://docs.didit.me/id/transaction-monitoring/wallet-ownership-widget.md) atau deklarasi mandiri). |
| `self_declared` | boolean | Hanya-tulis, hanya `POST`. Jika `true`, entri dibuat sudah terverifikasi melalui bukti `SELF_DECLARATION`. Transfer masuk ke alamat ini melewati `UNCONFIRMED_OWNERSHIP` sepenuhnya dan langsung ke pencocokan nama. Mengembalikan `400` ketika `allow_self_declaration` nonaktif di pengaturan Anda. |

`PATCH` menerima `holder_name`, `holder_vendor_data`, `entity_type`, dan `travel_address`, dan hanya mengembalikan keempat kolom tersebut.
`DELETE` menghapus entri (`204`). Alamatnya dibebaskan untuk didaftarkan ulang dan segera berhenti mencocokkan transfer baru.

> [!NOTE]
>
> Pencocokan tidak membedakan huruf besar dan kecil pada alamat, mencakup `memo`-nya pada jaringan memo, dan dibatasi oleh `chain`.
> Ketika transfer membawa chain, entri hanya cocok jika `chain`-nya bernilai sama (tanpa membedakan huruf besar dan kecil) atau kosong.
> Nama chain dibandingkan sebagai teks, tidak diterjemahkan, sehingga entri yang tersimpan sebagai `ethereum` tidak cocok dengan transfer yang chain-nya `ETH`.
> Transfer keluar mengambil chain-nya dari `beneficiary_data.chain`, lalu `transaction_details.crypto_params.crypto_chain`, lalu `custom_properties.crypto_chain`, lalu mata uang (misalnya `ETH`, atau untuk `USDT` dan `USDC` chain yang disimpulkan dari `payment_reference_id`). Chain hanya ditetapkan jika merupakan chain yang dikenali Didit. Pendaftaran setelah deposit mengambilnya dari kolom `chain`-nya, dalam huruf kecil.
> Permintaan masuk `TRP` mengabaikan chain: permintaan dicocokkan berdasarkan alamat, atau, jika permintaan tidak menyebut dompet, berdasarkan nama penerima terhadap entri terverifikasi Anda.
> [`POST .../travel-rule/ownership/`](#mengonfirmasi-kepemilikan-dompet) juga mencocokkan berdasarkan alamat saja.
> Ketika beberapa entri cocok, jalur `INTERNAL` dan pendaftaran setelah deposit memprioritaskan entri yang kepemilikannya terverifikasi, lalu yang paling lama. Pencarian `TRP` keluar mengambil entri tertua yang menyimpan travel address.
> Permintaan masuk `TRP` dan endpoint kepemilikan mengambil salah satu entri yang cocok, jadi simpan satu entri per alamat jika memungkinkan.
> Jalur `INTERNAL` tidak mencocokkan entri sama sekali ketika entri terverifikasi untuk alamat tersebut ada di lebih dari satu aplikasi lain.

#### Mengimpor dompet secara massal

Impor hingga 10.000 dompet dalam satu panggilan dengan [`POST /v3/travel-rule/wallet-addresses/import/`](https://docs.didit.me/id/management-api/travel-rule/import-wallet-addresses), dalam format JSON (`{"entries": [...]}` atau array langsung (tanpa pembungkus)) atau sebagai file CSV UTF-8 berukuran maksimal 5 MB dengan baris header.
Satu baris menyebut dompet dengan `address`-nya, dengan `address_hash` (SHA-256 dari alamat yang sudah diubah menjadi huruf kecil, 64 karakter hex atau 44 karakter base64), atau keduanya, serta kolom entri apa pun di atas. Kirim hash saja untuk mendaftarkan dompet tanpa mengungkap alamatnya: hash itu mencocokkan transfer ke alamat tersebut seperti entri lain, dan dapat dibuktikan dengan [widget verifikasi kepemilikan dompet](https://docs.didit.me/id/transaction-monitoring/wallet-ownership-widget.md).

```bash theme={null}
curl -X POST https://verification.didit.me/v3/travel-rule/wallet-addresses/import/ \
  -H "x-api-key: YOUR_API_KEY" \
  -F "file=@wallets.csv;type=text/csv"
```

```text theme={null}
address,address_hash,chain,memo,holder_name,holder_vendor_data
0xBeneficiaryWallet01,,ethereum,,Ana Diaz,user-042
,4f7d2e1c9b8a7f6e5d4c3b2a1f0e9d8c7b6a5f4e3d2c1b0a9f8e7d6c5b4a3f2e,bitcoin,,,user-043
rExchangeSharedAddress01,,XRP,104729,Ana Diaz,user-042
```

Impor bersifat idempoten dan melaporkan setiap baris sesuai urutan pengirimannya: `created`, `existing` (dompet, chain, dan memo yang sama sudah ada dalam daftar dan tidak diubah), `duplicate` (mengulang baris sebelumnya, disebutkan di `duplicate_of_row`), atau `failed` dengan `errors`-nya. Satu baris yang buruk tidak menggagalkan baris lain: responsnya `200` jika tidak ada baris yang gagal dan `207` jika ada, dengan jumlah di `total`, `created`, `existing`, `duplicate`, dan `failed`.
Sel CSV yang kosong dianggap tidak dikirim, dan kolom yang tidak dibaca impor diabaikan, sehingga ekspor dari alat lain dapat diimpor apa adanya.

Pada `GET /v3/travel-rule/transfers/`, setiap baris memuat `originator_memo` dan `beneficiary_memo` di samping kedua dompet.

### Pengambilan email untuk pihak lawan yang tidak dapat dijangkau

Ketika tidak ada jalur protokol yang dapat menjangkau pihak lawan, Didit beralih ke `EMAIL`: Didit mengirim tautan pengambilan sekali pakai ke `beneficiary_data.counterparty_vasp_email` (atau email yang diperoleh dari `beneficiary_data.counterparty_vasp_name` melalui registri direktori VASP).
Penerima tidak memerlukan akun Didit atau kunci API. Token pada tautan itulah autentikasinya.
Berikut cara permintaan dikirim:

* **Ke alamat yang tepat.** `counterparty_vasp_email` yang Anda kirim adalah satu-satunya penerima. Jika tidak, Didit menulis ke hingga tiga alamat: [kontak](#kontak) pihak lawan yang belum memantul (kontak Anda sendiri lebih dulu, lalu kontak platform, yang pernah merespons lebih dulu), kemudian email kepatuhan entri direktori jika masih ada slot tersisa. Setiap alamat menerima emailnya sendiri.
* **Atas nama Anda.** Email berasal dari alamat Didit dengan nama "*nama hukum Anda via Didit*", dalam bahasa yurisdiksi pihak lawan (bahasa Inggris jika tidak diketahui), dan tautan membuka halaman respons dalam bahasa tersebut. Anda tidak menerima salinan: pantau linimasa transfer.
* **Dengan pengingat.** Hingga pihak lawan merespons, Didit mengingatkannya 72, 24, dan 6 jam sebelum batas waktu, setidaknya 12 jam setelah permintaan atau pengingat terakhir, dan tidak pernah setelah batas waktu.
* **Dengan pantulan yang ditangani.** Pantulan atau keluhan spam menandai kontak yang dijangkau sebagai tidak valid beserta alasannya, dan linimasa transfer mencatatnya. Kontak platform kemudian tidak valid untuk setiap pelanggan Didit. Kontak aplikasi Anda sendiri hanya tidak valid untuk aplikasi Anda. Ketika pengiriman email Didit berhenti mengirim ke suatu alamat sama sekali (setelah pantulan permanen, keluhan spam, atau berhenti berlangganan), setiap kontak di alamat itu ditandai tidak valid (`suppressed`), dan kontak tersebut kembali valid ketika pengiriman ke alamat itu dilanjutkan. Ketika tidak ada alamat yang tersisa untuk dikirimi, transfer menjadi `COUNTERPARTY_VASP_NOT_REACHABLE` dengan alasan dari server email penerima di linimasanya. Pantulan permanen atau keluhan spam pada `counterparty_vasp_email` yang Anda kirim langsung menyebabkan hal ini, karena alamat itu satu-satunya penerima. Pantulan sementara (`soft_bounce`) pada alamat itu, atau pada email kepatuhan entri direktori, membiarkan permintaan tetap terbuka untuk pengingat.

Tautan ini membuka halaman yang di-hosting dan menampilkan pertukaran yang tertunda, lalu memanggil dua endpoint publik ini untuk penerima.
Untuk [transfer contoh di atas](#mengirim-transfer), detail pengambilannya adalah:

```bash theme={null}
curl https://verification.didit.me/v3/travel-rule/pickup/{token}/
```

```json theme={null}
{
  "reference": "33333333-4444-5555-6666-777777777777",
  "requested_at": "2026-07-05T10:00:00Z",
  "originator_vasp_name": "Origin CASP SL",
  "originator_vasp_lei": "529900EXAMPLEORIG001",
  "recipient_vasp_name": "Example Counterparty VASP",
  "language": "es",
  "amount": "0.250000000000000000",
  "currency": "ETH",
  "fiat_amount": "",
  "fiat_currency": "",
  "chain": "ETH",
  "beneficiary_wallet": "0xede2d7e4f5b097e6391ab6bbcf2f47a53f4778cb",
  "status": "AWAITING_COUNTERPARTY",
  "ivms_version": "ivms101.2023",
  "deadline_at": "2026-07-07T10:00:00Z",
  "reminders_sent": 0,
  "contact": "",
  "decline_reasons": ["data_mismatch", "not_our_customer", "wallet_not_hosted", "sanctions", "risk_appetite", "jurisdiction", "insufficient_data", "other"],
  "join_invitation": { "eligible": false, "url": "" },
  "originator_data": { "name": "Jane Doe", "wallet_address": "0x77ccff0cc624a53cd8b8d8703ced826710211ec7" },
  "beneficiary_data": { "name": "Ana Diaz", "wallet_address": "0xede2d7e4f5b097e6391ab6bbcf2f47a53f4778cb" },
  "ivms_request": {
    "originator": {
      "originatorPersons": [{ "naturalPerson": { "name": { "nameIdentifier": [{ "primaryIdentifier": "Doe", "secondaryIdentifier": "Jane", "nameIdentifierType": "LEGL" }] } } }],
      "accountNumber": ["0x77ccff0cc624a53cd8b8d8703ced826710211ec7"]
    },
    "beneficiary": {
      "beneficiaryPersons": [{ "naturalPerson": { "name": { "nameIdentifier": [{ "primaryIdentifier": "Diaz", "secondaryIdentifier": "Ana", "nameIdentifierType": "LEGL" }] } } }],
      "accountNumber": ["0xede2d7e4f5b097e6391ab6bbcf2f47a53f4778cb"]
    }
  },
  "data_masked": false
}
```

`reference` adalah `uuid` transfer. `originator_data` dan `ivms_request` IVMS 101 yang dibangun darinya hanya memuat kolom data pengirim yang Anda bagikan di [`data_sharing_fields`](#berbagi-data); nama dan dompet selalu disertakan. `fiat_amount` dan `fiat_currency` kosong jika Anda tidak mengirim nilai yang dikonversi, `contact` mengembalikan nilai `?contact=` pada tautan, dan `decline_reasons` mencantumkan nilai yang dapat diterima oleh `decline_reason`. `join_invitation.eligible` bernilai `true` selama pihak lawan memiliki undangan aktif untuk bergabung ke Didit; tautan undangan itu sendiri hanya dikirim melalui email.

Endpoint ini mengembalikan jumlah yang tersimpan apa adanya, sehingga menyertakan 18 angka desimal penuh, bukan bentuk terpangkas yang digunakan objek detail transaksi.

```bash theme={null}
curl -X POST https://verification.didit.me/v3/travel-rule/pickup/{token}/respond/ \
  -H "Content-Type: application/json" \
  -d '{"decision": "accept", "beneficiary_name": "Ana Diaz"}'
```

`decision` bernilai `accept` atau `decline`.
Pada `accept`, `beneficiary_name` yang dikirim dibandingkan dengan `beneficiary_data.name` pada transfer sesuai aturan nama Anda: `COMPLETED` jika cocok, `COUNTERPARTY_MISMATCHED_DATA` jika tidak.
Pihak lawan dapat mengirim respons IVMS 101 lengkap sebagai `ivms_response` sebagai gantinya; nama penerima di dalamnya kemudian menjadi acuan utama, bukan `beneficiary_name`.
Pada `decline`, transfer berpindah ke `COUNTERPARTY_VASP_GENERAL_DECLINE`. Pihak lawan dapat memberikan `decline_reason` dari `decline_reasons`, dengan `decline_detail` (maksimal 512 karakter, wajib untuk `other`), dan linimasa transfer Anda mencatatnya, misalnya `counterparty declined: The beneficiary is not our customer`.
Respons berupa `{"status": "..."}` yang dihasilkan, ditambah `decline_reason` setelah penolakan. Setelah pihak lawan memberikan jawaban, kedua endpoint mengembalikan `410`.
Kedua endpoint mengembalikan `404` untuk token yang tidak dikenal dan `410` setelah jendela waktunya tertutup, yaitu ketika transfer sudah tidak lagi berstatus `AWAITING_COUNTERPARTY`, atau ketika tenggat konfirmasinya (`confirmation_timeout_hours` setelah pembuatan atau kirim ulang terakhir) sudah lewat.

Pihak lawan membaca dan menjawab melalui tautan pickup dengan `GET` dan `POST /v3/travel-rule/pickup/{token}/messages/`.
Pihak lawan tidak memerlukan kunci API, hanya menerima lampiran PDF, PNG, JPEG, atau WebP, dan mendapatkan `410` setelah tautan kedaluwarsa atau transfer ditutup.
Pesan yang Anda kirim menampilkan nama VASP Anda sebagai `author` dan sebagai `uploaded_by` pada lampiran, tidak pernah menampilkan orang atau kunci API di baliknya.

### Deposit yang belum dipasangkan

Deposit masuk bisa tiba sebelum data Travel Rule dari VASP pengirim.
Deposit seperti itu tetap berstatus `AWAITING_COUNTERPARTY` atau `NOT_ENOUGH_COUNTERPARTY_DATA` sampai data tersebut tiba.
Cantumkan deposit yang masih menunggu dengan kunci API yang memiliki izin transaksi:

```bash theme={null}
curl "https://verification.didit.me/v3/travel-rule/unmatched/" \
  -H "x-api-key: YOUR_API_KEY"
```

Respons menggunakan baris yang sama dengan `GET /v3/travel-rule/transfers/`, dibatasi pada deposit masuk yang menunggu data dari VASP pengirim.

Ketika data sudah tiba sebagai pesan Travel Rule terpisah yang diterima, pasangkan keduanya secara manual:

```bash theme={null}
curl -X POST "https://verification.didit.me/v3/travel-rule/unmatched/{transaction_uuid}/match/" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"transaction_id": "<uuid of the received message transaction>"}'
```

`{transaction_uuid}` adalah deposit.
`transaction_id` adalah transaksi dari pesan Travel Rule yang diterima.
Panggilan ini mengembalikan `{ "deposit": ..., "message": ... }`.
Panggilan ini mengembalikan `404` jika salah satu transaksi sudah tidak ada, dan `409` dengan `travel_rule_match_conflict` ("Deposit ini tidak dapat dicocokkan lagi.") jika salah satu sisi sudah berpindah status.

### Pendaftaran sunrise setelah deposit

Ketika deposit kripto diselesaikan on-chain **sebelum** pertukaran Travel Rule apa pun terjadi, karena VASP pengirim tidak dapat dihubungi atau Anda mendaftarkan deposit historis, daftarkan deposit tersebut setelahnya dengan `POST /v3/travel-rule/inbound/`.

```bash theme={null}
curl -X POST https://verification.didit.me/v3/travel-rule/inbound/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "chain": "eth",
    "txid": "0xf103cfc37f6d390b61827987b9dc631b5e1d2bfeb008a780c1e38047ae5d557b",
    "wallet_address": "0xede2d7e4f5b097e6391ab6bbcf2f47a53f4778cb",
    "amount": "500.00",
    "currency": "USDC",
    "originator_data": { "name": "Carlos Ruiz", "wallet_address": "0x77ccff0cc624a53cd8b8d8703ced826710211ec7" },
    "beneficiary_data": { "name": "Ana Diaz" },
    "originating_vasp": {
      "name": "Northwind Digital Assets Ltd",
      "lei": "5493001KJTIIGC8Y1R12",
      "travel_address": "tareGfwAzkySLkFzcqr7AKno3K4VsT3jayMwPvj3ovbFZHzpayHLmgCrAMoLqjfCYRPpvLqr9dSr2VVTFAncwChcMjL4AheNuHCJM8NRcUg"
    }
  }'
```

`originating_vasp.travel_address` harus berupa [Travel Address](#travel-address) yang nyata dan valid dengan checksum; placeholder akan mengembalikan `400` dengan `"Invalid travel address."`.
`originating_vasp.lei` harus kosong atau 20 karakter dalam format LEI (18 huruf atau angka, diikuti 2 angka); selain itu akan mengembalikan `400` dengan `"Invalid LEI: expected 20 alphanumeric characters (ISO 17442)."`.
Didit hanya memeriksa format ini, bukan digit checksum ISO 17442.

| Kolom | Tipe | Deskripsi |
| - | - | - |
| `chain` | string | Rantai tempat deposit diselesaikan, maksimal 32 karakter. Didit mengubahnya menjadi huruf kecil dan menggunakannya untuk mencocokkan entri [buku alamat](#buku-alamat-dompet) Anda, jadi gunakan token yang sama dengan entri Anda (`eth` cocok dengan entri yang disimpan sebagai `ETH`). Nilai ini juga menentukan apakah deposit dapat menjalani skrining: `bitcoin`/`btc`, `ethereum`/`eth`, `solana`/`sol`, `tron`/`trx`, `polygon`/`matic`, `bsc`/`bnb`, `litecoin`/`ltc`, `ripple`/`xrp`, `bitcoin-cash`/`bch`, dan `dogecoin`/`doge`. |
| `txid` | string | Hash transaksi on-chain. Digunakan untuk menghapus duplikat: `txid` + `wallet_address` yang sama akan mengembalikan transfer yang sudah ada alih-alih membuat duplikat. |
| `wallet_address` | string | Dompet tujuan tempat Anda menerima deposit. Alamat X XRP dipecah menjadi alamat klasik dan tag-nya. |
| `memo` | string | Opsional. Tag tujuan atau memo deposit pada [jaringan memo](#jaringan-memo-dan-tag): pada alamat deposit bersama, nilai ini menyebutkan pelanggan yang memiliki deposit tersebut. |
| `amount` | string (desimal) | Jumlah deposit. |
| `currency` | string | Aset deposit. |
| `originator_data` | object | Detail pengirim dari VASP pengirim, jika diketahui, sebagai objek datar: Didit membaca `name` (atau `full_name`), `first_name`, `last_name`, dan `vendor_data`. |
| `beneficiary_data` | object | Detail penerima (pelanggan Anda), sebagai objek datar: Didit mencocokkan `name`-nya dengan `holder_name` pada entri buku alamat yang cocok, lalu menambahkan `wallet_address` dan `chain` ke dalamnya. |
| `utxo` | object | Opsional, hanya untuk [rantai UTXO](#transfer-utxo). `inputs` dan `outputs` dari transaksi deposit: dompet pengirim adalah `originator_data.wallet_address` jika Anda mendeklarasikannya, jika tidak maka input terbesar. |
| `originating_vasp` | object | `{ name, lei, travel_address }` opsional yang menggambarkan pengirim. `lei` harus sesuai dengan format LEI di atas dan `travel_address` harus berupa Travel Address yang valid, jika tidak permintaan akan mengembalikan `400`. Disimpan pada transfer ini sebagai `metadata.originating_vasp`; tidak pernah membuat atau mengubah entri [direktori](#cara-entri-masuk-ke-direktori) bersama. |

Didit membuat transaksi `travelRule` masuk (atau menggunakan ulang deposit masuk yang sudah Anda kirim dengan hash dan dompet yang sama, jika belum memiliki transfer Travel Rule) dan mencocokkan transfer dengan [buku alamat dompet Anda](#buku-alamat-dompet) berdasarkan alamat dan memo-nya:

* Tidak ada entri yang cocok -> `ON_HOLD`.
  Selesaikan dengan [`POST .../travel-rule/ownership/`](#mengonfirmasi-kepemilikan-dompet): `confirmed: true` menambahkan dompet ke buku alamat Anda sebagai terverifikasi dan menjalankan pencocokan nama; jika cocok, transfer berpindah ke `COMPLETED`, lalu `FINISHED`.
* Entri ada tetapi kepemilikan belum terbukti -> `UNCONFIRMED_OWNERSHIP`.
* Nama penerima tidak cocok dengan `holder_name` pada entri -> `COUNTERPARTY_MISMATCHED_DATA`.
* Entri terverifikasi dan nama cocok -> `COMPLETED`, lalu langsung `FINISHED` (deposit sudah diselesaikan).

Dengan entri buku alamat terverifikasi yang didaftarkan pada [contoh di atas](#buku-alamat-dompet), responsnya adalah:

```json theme={null}
{
  "transaction_id": "44444444-5555-6666-7777-888888888888",
  "txn_id": "tr-in-0xf103cfc37f6d390b61827987b9dc631b5e1d2bfeb008a780c1e38047ae5d557b-6151d81b366e",
  "created": true,
  "travel_rule": {
    "uuid": "55555555-6666-7777-8888-999999999999",
    "status": "FINISHED",
    "direction": "INBOUND",
    "rail": null,
    "protocol": null,
    "ivms_version": "ivms101.2023",
    "required": true,
    "ownership_confirmed": true,
    "deadline_at": null,
    "timeline": [
      { "status": "COMPLETED", "at": "2026-07-06T10:15:02.114208+00:00", "detail": "matched verified wallet address book entry" },
      { "status": "FINISHED", "at": "2026-07-06T10:15:02.131544+00:00", "detail": "on-chain deposit already settled" }
    ],
    "counterparty_vasp": null,
    "originator_data": { "name": "Carlos Ruiz", "wallet_address": "0x77ccff0cc624a53cd8b8d8703ced826710211ec7" },
    "beneficiary_data": { "name": "Ana Diaz", "wallet_address": "0xede2d7e4f5b097e6391ab6bbcf2f47a53f4778cb", "chain": "eth" },
    "created_at": "2026-07-06T10:15:02.087412Z"
  }
}
```

`txn_id` transaksi baru adalah `tr-in-` ditambah 80 karakter pertama dari `txid`, dan hash 12 karakter dari `txid` dan dompet.
`created` bernilai `true` (HTTP `201`) saat panggilan ini mendaftarkan deposit, dan `false` (HTTP `200`) saat `txid` dan `wallet_address` yang sama sudah terdaftar; dalam kasus itu, transfer yang sudah ada dikembalikan tanpa perubahan.
Pada jalur entri terverifikasi, kedua transisi terjadi sebelum endpoint merespons, jadi respons sinkron sudah menampilkan status akhir `FINISHED` - langkah perantara `COMPLETED` tetap tercatat di `timeline` transfer.
Setiap transisi memicu webhook `travel_rule.status.updated` (`COMPLETED` dan `FINISHED` masing-masing memicu satu).
Saat Didit membuat transaksi baru, Didit mengirim [`transaction.created`](https://docs.didit.me/id/integration/webhooks#jenis-event) terlebih dahulu, lalu event-event ini setelahnya.
Pendaftaran tidak dikenakan biaya Travel Rule maupun biaya pemantauan.
Saat pemantauan kripto diaktifkan dan `chain` termasuk yang dapat disaring oleh Didit, deposit yang baru dibuat juga menjalani skrining dan ditagih satu kali dengan tarif Wallet Verification & Screening.

### Widget verifikasi kepemilikan dompet

Untuk memindahkan transfer keluar dari `UNCONFIRMED_OWNERSHIP` - atau untuk memverifikasi dompet terlebih dahulu sebelum transfer apa pun masuk - buat sesi widget verifikasi kepemilikan dompet yang di-hosting dengan `POST /v3/travel-rule/widget-session/` dan arahkan pelanggan Anda ke `url` yang dikembalikan. Widget membuktikan kendali atas dompet melalui penandatanganan pesan (termasuk akun smart contract EVM, melalui ERC-1271 dan ERC-6492), tes Satoshi, tangkapan layar, atau pernyataan mandiri, lalu menandai entri buku alamat yang sesuai sebagai terverifikasi agar pertukaran dapat dilanjutkan.
Tangkapan layar adalah pengecualian: tangkapan layar tidak pernah memverifikasi dompet dengan sendirinya, jadi tim kepatuhan Anda meninjau dan mengonfirmasi transfer di `UNCONFIRMED_OWNERSHIP` dengan [`POST .../travel-rule/ownership/`](#mengonfirmasi-kepemilikan-dompet).

Lihat [Widget verifikasi kepemilikan dompet](https://docs.didit.me/id/transaction-monitoring/wallet-ownership-widget.md) untuk alur lengkap, metode pembuktian, dan catatan penting bahwa widget harus dibuka di browser sungguhan - jangan pernah dibuka di dalam webview SDK seluler.

## Direktori

`GET /v3/travel-rule/vasps/` mencari direktori VASP: entri direktori bersama beserta anggota [jaringan Didit](#jaringan-didit). Setiap baris menunjukkan cara aplikasi Anda dapat menjangkau VASP tersebut saat ini.

```bash theme={null}
curl "https://verification.didit.me/v3/travel-rule/vasps/?search=counterparty" \
  -H "x-api-key: YOUR_API_KEY"
```

```json theme={null}
{
  "count": 1,
  "next": null,
  "previous": null,
  "results": [
    {
      "id": "0d6f3c2a-6a1e-4c55-9a39-1f2b0c7d8e91",
      "kind": "directory",
      "name": "Example Counterparty VASP",
      "lei": "529900EXAMPLECPTY001",
      "jurisdiction": "DE",
      "domains": ["counterparty.example"],
      "reachable": true,
      "aliases": [{ "name": "Example Counterparty", "kind": "trading_name" }],
      "networks": [
        {
          "network": "GTR",
          "code": "EXAMPLE01",
          "listed_name": "Example Counterparty VASP",
          "country": "DE",
          "verified_at": "2026-10-12T09:30:00Z",
          "last_seen_at": "2026-10-12T09:30:00Z",
          "source": "staff"
        }
      ],
      "routes": [
        { "rail": "GTR", "status": "unavailable", "reason": "no_membership", "via": "" },
        { "rail": "EMAIL", "status": "available", "reason": "", "via": "contact" }
      ],
      "umbrella": null,
      "entities": [],
      "contacts": [
        {
          "id": "6c1f9b8e-2d4a-4f7e-8b3c-5a9d0e1f2a3b",
          "email": "travelrule@counterparty.example",
          "name": "Travel Rule desk",
          "source": "staff",
          "scope": "platform",
          "verified_at": null
        }
      ],
      "dd_status": "NOT_STARTED",
      "dd_score": 62,
      "dd_score_breakdown": {
        "jurisdiction": { "points": 25.0, "max": 25, "reason": "jurisdiction_not_high_risk", "detail": "DEU is not on the high-risk jurisdiction list" },
        "verification": { "points": 3.8, "max": 15, "reason": "dd_status_not_started", "detail": "due diligence status NOT_STARTED" },
        "protocol": { "points": 6.0, "max": 15, "reason": "email_only", "detail": "reachable over the email fallback only" },
        "lei": { "points": 10.0, "max": 10, "reason": "lei_valid", "detail": "valid LEI on record" },
        "history": { "points": 5.0, "max": 10, "reason": "no_history", "detail": "no exchange history" },
        "essentials": { "points": 7.5, "max": 15, "reason": "no_essential_checks", "detail": "no decided essential check yet" },
        "responsiveness": { "points": 5.0, "max": 10, "reason": "responsiveness_unknown", "detail": "0 decided recent requests, too few to judge" }
      },
      "dd_assessed_at": "2026-10-12T09:30:00Z",
      "dd_score_semantic": "higher_is_safer",
      "risk_level": "MEDIUM",
      "responsiveness": { "status": "UNKNOWN", "answered": 0, "total": 0, "computed_at": "2026-10-12T09:30:00Z" },
      "essential_checks": {},
      "reachable_rails": ["GTR", "EMAIL"],
      "is_didit_customer": false,
      "decision": {
        "decision": "APPROVED",
        "reason": "Licensed in DE",
        "decided_by": "",
        "updated_at": "2026-10-14T10:05:00Z",
        "inherited_from": null
      },
      "entity_screening": {
        "id": "7a1d2c3b-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
        "status": "Approved",
        "total_hits": 0,
        "score": null,
        "screened_at": "2026-10-14T09:58:00Z",
        "fresh": true,
        "flagged": false
      },
      "questionnaires": []
    }
  ]
}
```

`search` cocok dengan sebagian nama atau alias, LEI yang persis sama, atau domain (`counterparty.example` atau URL di domain tersebut). Persempit hasil dengan:

| Parameter | Efek |
| - | - |
| `network` | `GTR`, `TRUST`, `VERIFYVASP`, `SYGNA` atau `TRISA`: hanya entri yang saat ini tercantum di direktori anggota jaringan tersebut. |
| `jurisdiction` | Kode negara ISO 3166 alpha-2 atau alpha-3. |
| `reachable` | `true`: hanya VASP yang memiliki rute tersedia dari aplikasi Anda. `false`: hanya entri yang saat ini tidak dapat dijangkau. |
| `kind` | `directory` untuk entri bersama, `didit` untuk anggota jaringan Didit. |
| `risk` | `LOW`, `MEDIUM` atau `HIGH`: hanya entri direktori yang `risk_level`-nya berada di tingkat tersebut. Lihat [Skor dan tingkat risiko](#skor-dan-tingkat-risiko). |
| `responsiveness` | `RESPONSIVE`, `UNRESPONSIVE` atau `UNKNOWN`: hanya entri direktori dengan `responsiveness.status` tersebut. Lihat [Responsivitas](#responsivitas). |

Anggota jaringan Didit tidak dinilai, sehingga `risk` dan `responsiveness` hanya mengembalikan entri direktori. Hasil diurutkan berdasarkan nama dan dipaginasi dengan `limit` (default `50`) dan `offset`. Jaringan, kode negara, tingkat risiko, atau status responsivitas yang tidak dikenal merespons `400` dengan menyebut kolomnya. `GET /v3/travel-rule/vasps/{vasp_id}/` mengembalikan satu baris berdasarkan `id`-nya. Profil VASP Anda sendiri tidak pernah muncul dalam hasil Anda sendiri.

`dd_status`, `dd_score`, `dd_score_breakdown`, `dd_assessed_at`, `dd_score_semantic`, `risk_level`, `responsiveness` dan `essential_checks` memuat penilaian uji tuntas bersama untuk entri direktori. `decision`, `entity_screening` dan `questionnaires` adalah catatan aplikasi Anda sendiri tentang VASP, dan tidak ada pelanggan lain yang dapat melihatnya. Lihat [Uji tuntas pihak lawan](#uji-tuntas-pihak-lawan) untuk arti masing-masing, dan gunakan [kolom aturan pihak lawan](#kolom-aturan-dan-preset) untuk membatasi akses berdasarkan kolom tersebut, bukan dengan percabangan inline. Anggota jaringan Didit tidak dinilai: `dd_status` berisi `COMPLETED`, `dd_score` berisi `null`, `risk_level` kosong, dan rinciannya kosong.

### Rute

`routes` mencantumkan cara aplikasi Anda dapat mengirim ke VASP, sesuai urutan yang dicoba oleh mekanisme perutean bertingkat, dan `reachable` bernilai `true` ketika setidaknya satu rute berstatus `available`:

* `TRP` ketika entri memiliki endpoint TRP yang diverifikasi oleh direktori.
* `GTR`, `TRUST`, `VERIFYVASP`, `SYGNA` ketika sebuah jaringan mencantumkan VASP di bawah suatu kode. Rute hanya `available` jika aplikasi Anda dapat mengirim melalui jaringan tersebut saat ini (`via: own_membership` untuk keanggotaan terhubung milik Anda sendiri, `via: didit_membership` untuk keanggotaan Didit). Jika tidak, rute berstatus `unavailable` dengan `reason: no_membership` atau `reason: network_switched_off`, dan tidak pernah ditampilkan sebagai cara untuk menjangkau VASP. Keanggotaan jaringan Didit belum aktif, sehingga saat ini rute jaringan hanya tersedia melalui keanggotaan yang Anda hubungkan di Marketplace.
* `EMAIL` ketika ada kontak kepatuhan untuk entri tersebut.
* `INTERNAL` untuk anggota jaringan Didit.

Entri `TRISA` muncul di bawah `networks` dan memberi tahu Anda siapa VASP tersebut di TRISA, tetapi Didit tidak memiliki jalur TRISA, sehingga tidak pernah menjadi rute.

Aplikasi sandbox hanya mengirim ke [Didit Test VASP](https://docs.didit.me/id/transaction-monitoring/travel-rule-sandbox.md), sehingga tidak ada rute direktori yang tersedia baginya: setiap rute berstatus `unavailable` dengan `reason: sandbox_application`, setiap baris memiliki `reachable: false`, dan `reachable=true` tidak mengembalikan baris apa pun.

### Merek dan entitasnya

Merek yang beroperasi melalui beberapa entitas yang diatur adalah satu baris yang `entities`-nya merupakan entitas hukum penerima transfernya; baris entitas menunjuk kembali ke mereknya di `umbrella`. Transfer yang menyebut merek dikirim ke salah satu entitasnya, dipilih dari semua entitas: entitas di yurisdiksi yang dinyatakan di `beneficiary_data.counterparty_vasp_jurisdiction`, atau jika tidak ada, entitas yang ditautkan [atribusi analitik blockchain](#atribusi-analitik-blockchain) ke dompet tujuan, atau jika tidak ada yurisdiksi yang dinyatakan, satu-satunya entitas merek tersebut. Baru setelah itu entitas tersebut harus dapat dijangkau; jika tidak, transfer tidak pernah dikirim ke entitas lain atau ke merek sebagai gantinya. Ketika tidak ada entitas yang cocok (dua entitas sama-sama cocok, atau tidak ada satu pun entitas yang berada di yurisdiksi yang dinyatakan), rute merek itu sendiri yang digunakan, dan tanpa rute tersebut transfer berstatus `COUNTERPARTY_VASP_NOT_FOUND`. Entitas hukum mana yang menerima data pengirim tidak pernah ditebak, dan tidak pernah ditentukan oleh entitas mana yang kebetulan memiliki kontak.

Beberapa entri yang diberi nama sama, misalnya perusahaan grup yang memakai nama dagang yang sama, dibedakan dengan aturan yang sama: entri di yurisdiksi yang dinyatakan, atau jika tidak, entri yang ditautkan atribusi analitik blockchain. Jika keduanya tidak memilih satu pun, tidak ada yang digunakan, dan detailnya dihitung sebagai tidak menamai entri direktori mana pun.

### Kontak

`contacts` adalah alamat yang menjadi tujuan pengiriman oleh jalur `EMAIL`. Kontak `scope: platform` melayani setiap pelanggan Didit: Didit mengkurasi kontak tersebut (`source: staff`), atau alamat di domain VASP itu sendiri membalas permintaan melalui tautan respons (`source: learned`). Kontak `scope: application` bersifat pribadi bagi aplikasi Anda: yang Anda tambahkan (`source: application`), dan alamat di luar domain VASP yang membalas salah satu permintaan Anda (`source: learned`). Transfer mengirim email ke kontak milik aplikasi Anda terlebih dahulu, lalu ke kontak platform yang pernah membalas (`verified_at` terisi), lalu ke kontak lainnya.

Kelola kontak milik aplikasi Anda dengan API kontak pihak lawan:

```bash theme={null}
curl -X POST https://verification.didit.me/v3/travel-rule/counterparty-contacts/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"counterparty": "0d6f3c2a-6a1e-4c55-9a39-1f2b0c7d8e91", "email": "compliance@counterparty.example", "name": "Compliance desk"}'
```

* `GET /v3/travel-rule/counterparty-contacts/` mencantumkan setiap kontak yang dapat dikirimi email oleh aplikasi Anda, termasuk kontak platform dan kontak yang gagal dikirimi email, dari yang terbaru, dipaginasi dengan `limit` dan `offset`. Filter dengan `?counterparty=` dan `id` entri direktori; nilai yang bukan UUID merespons `400`.
* `POST` menambahkan kontak pribadi (`counterparty`, `email`, dan `name` opsional) dan merespons `201`. Menambahkan alamat yang sudah tercatat untuk entri tersebut di antara kontak Anda akan mengembalikan kontak itu. Entri yang tidak dikenal merespons `400` (`"No directory entry with this id."`).
* `DELETE /v3/travel-rule/counterparty-contacts/{contact_uuid}/` menghapus salah satu kontak milik Anda (`204`). Kontak platform tidak dapat dihapus dan merespons `404`.

Kontak yang gagal terkirim (bounce) atau mengajukan keluhan memiliki `is_invalid: true`, dengan `invalid_reason` (`hard_bounce`, `soft_bounce`, `spam_complaint` atau `suppressed`), `invalid_detail` dan `invalid_at`, dan jalur `EMAIL` akan melewatinya. `created_by` kosong pada kontak platform dan pada kontak yang ditambahkan oleh kunci API.

### Cara entri masuk ke direktori

* Registri interim MiCA dari ESMA untuk penyedia layanan aset kripto, dibaca setiap minggu: nama, LEI, dan negara anggota asal setiap penyedia.
* Direktori publik TRISA, dibaca setiap minggu: identitas setiap anggota, negaranya, dan daftarnya di TRISA. Daftar yang tidak lagi ditampilkan oleh direktori selama tiga minggu akan dihapus.
* Registri LEI global mengisi LEI, nama hukum lain, dan negara sebuah entri, serta menemukan LEI sebuah entri berdasarkan nama hukum persisnya di negaranya.
* [Atribusi analitik blockchain](#atribusi-analitik-blockchain) menambahkan atau mencocokkan VASP yang memiliki dompet tujuan, dan menyimpan nama yang diatribusikan sebagai alias.
* Staf Didit mengkurasi entri: pengenal perutean dan daftar jaringan yang telah mereka verifikasi, kontak kepatuhan, alias, merek beserta entitasnya, duplikat yang digabungkan, dan entri yang disembunyikan.

Data yang dilaporkan pelanggan tentang pihak lawan, seperti `originating_vasp` pada transfer masuk atau Travel Address, tetap berada pada transfer pelanggan tersebut dan tidak pernah mengubah entri bersama. Entri dicocokkan terlebih dahulu berdasarkan LEI, lalu berdasarkan nama atau alias yang persis sama, dan diperkaya, bukan digandakan.

### Jaringan Didit

Profil VASP Anda adalah anggota jaringan Didit, sehingga pelanggan Didit lain dapat menemukannya di direktori dan di pemilih VASP pengguna akhir, hanya jika semua kondisi berikut terpenuhi:

* aplikasi Anda berada di lingkungan produksi (bukan sandbox) dan Travel Rule aktif;
* `is_discoverable` bernilai `true` dan `legal_name` sudah diisi;
* `compliance_email` sudah diisi dan dikonfirmasi: kirim konfirmasi dengan `POST /v3/travel-rule/settings/compliance-email/confirmation/` dan buka tautan yang dikirim lewat email. Mengubah alamat memerlukan konfirmasi baru;
* Didit belum menandai aplikasi sebagai aplikasi uji coba, demo, atau internal.

Jalur `INTERNAL` sendiri mengirimkan dana ke dompet yang telah Anda buktikan kepemilikannya, sebagaimana dijelaskan di [Mengirim transfer](#mengirim-transfer): jalur ini hanya memerlukan aplikasi Anda berada di lingkungan produksi, Travel Rule aktif, dan `is_discoverable`, bukan kondisi lain dalam daftar ini.

`GET /v3/travel-rule/settings/` mengembalikan `didit_network`: `listed`, `compliance_email_confirmed`, dan di `missing` setiap kondisi yang belum terpenuhi (`travel_rule_off`, `sandbox_application`, `not_discoverable`, `legal_name_missing`, `compliance_email_missing`, `compliance_email_unconfirmed`, `excluded_by_staff`, `internal_organization`).

### Pengenal perutean

Perutean keluar memeriksa entri direktori setiap kali transfer Anda menyebut pihak lawan dengan `counterparty_vasp_lei` atau `counterparty_vasp_name` (alias juga berfungsi). Sebuah entri membawa satu pengenal untuk setiap jaringan tempat ia dapat dijangkau, sebuah endpoint TRP yang telah diverifikasi beserta kontak kepatuhannya, dan `routes` menunjukkan mana di antaranya yang dapat digunakan aplikasi Anda. Anda selalu dapat melewati direktori untuk satu transfer dengan menyertakan kolom eksplisit di [Kolom resolusi pihak lawan](#kolom-penentuan-pihak-lawan).

## Uji tuntas pihak lawan

Sebelum dana pelanggan Anda sampai ke VASP lain, Anda perlu tahu siapa VASP tersebut dan apakah Anda menerimanya. Uji tuntas terhadap pihak lawan terdiri dari dua lapisan:

* **Penilaian bersama.** Setiap entri direktori memiliki skor uji tuntas, tingkat risiko, status responsivitas, dan laporan pemeriksaan esensial. Didit menghitungnya dari data platform itu sendiri, sehingga setiap pelanggan melihat nilai yang sama.
* **Catatan Anda sendiri.** Keputusan Anda terhadap VASP, skrining sanksi dan media negatif terhadapnya, serta kuesioner uji tuntas yang Anda pertukarkan dengannya hanya menjadi milik aplikasi Anda. Pelanggan lain tidak pernah melihatnya, dan catatan tersebut tidak pernah mengubah entri bersama.

Catatan Anda sendiri berlaku sama, baik untuk entri direktori maupun untuk anggota [jaringan Didit](#jaringan-didit). Gunakan `id` yang ditampilkan [direktori](#direktori) untuk mengaksesnya.

| Endpoint | Fungsi |
| - | - |
| `GET` / `PUT` / `DELETE /v3/travel-rule/vasps/{vasp_id}/decision/` | Membaca, menetapkan, atau menghapus [keputusan Anda](#keputusan-anda-terhadap-pihak-lawan) terhadap pihak lawan. |
| `GET` / `POST /v3/travel-rule/vasps/{vasp_id}/screening/` | Membaca [skrining pihak lawan](#skrining-pihak-lawan) terbaru Anda, atau menjalankannya. |
| `GET` / `POST /v3/travel-rule/vasps/{vasp_id}/questionnaires/` | Menampilkan [kuesioner uji tuntas](#kuesioner-uji-tuntas) Anda dengan pihak lawan, atau mengirim satu kuesioner. |
| `GET /v3/travel-rule/transfers/?counterparty={vasp_id}` | [Transfer Anda dengan pihak lawan tersebut](#transfer-dengan-satu-pihak-lawan). |

### Skor dan tingkat risiko

`dd_score` berada dalam rentang 0 hingga 100, dan **semakin tinggi semakin aman**. Setiap hasil menyatakannya di `dd_score_semantic`, yang selalu bernilai `higher_is_safer`. `risk_level` adalah kelompok tempat skor tersebut berada:

| `risk_level` | `dd_score` |
| - | - |
| `LOW` | 70 atau lebih |
| `MEDIUM` | 40 hingga 69 |
| `HIGH` | Di bawah 40 |

Skor merupakan jumlah dari tujuh komponen. `dd_score_breakdown` menampilkan setiap komponen sebagai `{points, max, reason, detail}`: `max` adalah bobot komponen tersebut, `reason` adalah kode yang dapat dibaca mesin dan dapat Anda terjemahkan, dan `detail` adalah penjelasan satu baris dalam bahasa Inggris.

| Komponen | Bobot | Cara penilaian | Kode `reason` |
| - | - | - | - |
| `jurisdiction` | 25 | Penuh jika negara entri tidak termasuk dalam daftar yurisdiksi berisiko tinggi bawaan (`IRN`, `PRK`, `SYR`, `AFG`, `RUS`, `MMR`), nol jika termasuk, dan setengah jika negaranya tidak diketahui. | `jurisdiction_not_high_risk`, `jurisdiction_high_risk`, `jurisdiction_unknown` |
| `verification` | 15 | Status verifikasi Didit untuk entri (`dd_status`): penuh untuk `COMPLETED`, setengah untuk `IN_PROGRESS`, seperempat untuk `NOT_STARTED`, nol untuk `REJECTED`. | `dd_status_completed`, `dd_status_in_progress`, `dd_status_not_started`, `dd_status_rejected` |
| `protocol` | 15 | Penuh jika jalur protokol asli menjangkau entri (endpoint TRP atau jalur `INTERNAL`), 40 persen jika hanya jalur email cadangan yang menjangkau entri, dan nol jika tidak ada jalur yang dapat dijangkau. | `native_rail`, `email_only`, `no_rail` |
| `lei` | 10 | Penuh jika ada LEI yang valid dalam catatan, nol jika tidak ada. | `lei_valid`, `lei_missing` |
| `history` | 10 | Proporsi pertukaran yang sudah diputuskan dan berhasil dari entri tersebut, setengah jika belum ada pertukaran yang diputuskan. | `history`, `no_history` |
| `essentials` | 15 | Proporsi [pemeriksaan esensial](#pemeriksaan-esensial) yang sudah diputuskan dan lulus, setengah selama belum ada yang diputuskan. | `essential_checks`, `no_essential_checks` |
| `responsiveness` | 10 | Penuh untuk `RESPONSIVE`, nol untuk `UNRESPONSIVE`, setengah untuk `UNKNOWN`. Lihat [Responsivitas](#responsivitas). | `responsive`, `unresponsive`, `responsiveness_unknown` |

Poin dibulatkan hingga satu desimal, dan total dibulatkan menjadi bilangan bulat. `history` membaca permintaan yang sama dengan [responsivitas](#responsivitas), tanpa jendela waktu: pertukaran dengan `COMPLETED` atau `FINISHED` dihitung sebagai berhasil, sedangkan pertukaran dengan `EXPIRED`, `COUNTERPARTY_MISMATCHED_DATA`, atau `COUNTERPARTY_VASP_GENERAL_DECLINE` dihitung sebagai gagal. Pembatalan adalah tindakan pengirim sendiri dan tidak pernah dihitung.

Didit menghitung ulang penilaian ketika sebuah pertukaran dengan entri tersebut selesai, rampung, kedaluwarsa, mengalami ketidaksesuaian, atau ditolak; ketika entri diperbarui atau dikurasi; dan untuk setiap entri dalam pembaruan direktori mingguan. `dd_assessed_at` menunjukkan kapan penilaian terakhir dijalankan. Entri yang belum pernah dinilai tidak memiliki `dd_assessed_at`, memiliki `dd_score` bernilai `0`, dan `risk_level` kosong, jadi baca `risk_level`, bukan skor mentah. Anggota jaringan Didit tidak dinilai: `dd_score` mereka bernilai `null`, `risk_level` kosong, dan `dd_score_breakdown` kosong.

### Pemeriksaan esensial

`essential_checks` adalah laporan singkat tentang empat pemeriksaan yang dijalankan Didit pada setiap entri direktori, hanya dari sumber terverifikasi platform, tidak pernah dari data yang dilaporkan pelanggan:

| `id` pemeriksaan | Lulus ketika |
| - | - |
| `registration` | Sebuah registri resmi mencantumkan VASP tersebut: registri sementara MiCA Uni Eropa untuk penyedia layanan aset kripto, direktori publik TRISA, atau registri LEI global dengan LEI yang telah diterbitkan. |
| `licence` | Registri MiCA mencatat otorisasi untuk VASP tersebut yang belum berakhir. |
| `domain` | Domain entri cocok dengan endpoint TRP-nya atau dengan situs web yang tercantum dalam registrinya. |
| `lei` | Catatan LEI entri aktif dan telah diterbitkan, dan nama hukum serta negaranya cocok dengan entri. |

Setiap pemeriksaan dalam `checks` menampilkan `status`-nya (`pass`, `fail`, atau `unknown` jika tidak ada sumber dalam catatan yang dapat memutuskannya), `reason` yang dapat dibaca mesin, dan `detail` dalam bahasa Inggris satu baris. `passed`, `failed`, `unknown`, dan `total` menghitung jumlahnya, `level` bernilai `essential`, dan `checked_at` menunjukkan kapan laporan dibuat. Komponen `essentials` menilai proporsi pemeriksaan yang sudah diputuskan dan lulus, sehingga pemeriksaan `unknown` tidak menambah maupun mengurangi nilai entri. Laporan kosong hingga pembaruan direktori mingguan pertama kali memeriksa sebuah entri, dan selalu kosong untuk anggota jaringan Didit.

### Responsivitas

`responsiveness` menunjukkan apakah VASP menanggapi permintaan Travel Rule:

```json theme={null}
{ "status": "UNRESPONSIVE", "answered": 0, "total": 6, "computed_at": "2026-10-12T09:30:00Z" }
```

`total` menghitung permintaan yang dimulai oleh pelanggan Didit kepada VASP dalam 90 hari terakhir dan sudah memiliki hasil yang diputuskan, sedangkan `answered` menghitung permintaan yang dijawab VASP:

* **Dihitung:** permintaan yang dikirim melalui jalur jaringan atau protokol, dan permintaan yang dikirim melalui email ke alamat bersama, yaitu alamat kepatuhan entri atau kontak platform.
* **Tidak pernah dihitung:** permintaan yang dikirim melalui email ke alamat yang dimasukkan oleh seorang pelanggan, atau ke kontak pribadi pelanggan. Pertukaran tersebut tetap berada dalam riwayat transfer pelanggan itu dan tidak pernah memberi label pada VASP untuk pengguna lain.
* **Dijawab:** `COMPLETED`, `FINISHED`, `COUNTERPARTY_VASP_GENERAL_DECLINE`, atau `COUNTERPARTY_MISMATCHED_DATA`. Penolakan atau ketidaksesuaian data adalah jawaban: VASP tersebut telah merespons.
* **Tidak dijawab:** `EXPIRED`.
* **Bukan keduanya:** setiap status lain. Permintaan `CANCELLED` adalah tindakan pengirim sendiri, `COUNTERPARTY_VASP_NOT_REACHABLE` dapat menjadi kegagalan di sisi pengirim, dan permintaan yang masih berjalan belum diputuskan.

| `status` | Kapan |
| - | - |
| `UNKNOWN` | Kurang dari 5 permintaan yang sudah diputuskan dalam periode ini, sehingga satu permintaan kedaluwarsa tidak pernah memberi label pada VASP. |
| `UNRESPONSIVE` | VASP menjawab kurang dari 10 persen dari permintaan yang sudah diputuskan. |
| `RESPONSIVE` | Selain kedua kondisi di atas. |

Anggota jaringan Didit menjawab di dalam Didit dan selalu menampilkan `UNKNOWN` dengan jumlah nol. Tindak lanjuti pihak lawan yang tidak responsif dengan [kebijakan non-responsif](#kebijakan-sunrise-dan-tidak-responsif) atau [preset](#kolom-aturan-dan-preset) `travel-rule-counterparty-unresponsive`.

### Keputusan Anda terhadap pihak lawan

Catat keputusan tim kepatuhan Anda terhadap pihak lawan dengan `PUT /v3/travel-rule/vasps/{vasp_id}/decision/`:

```bash theme={null}
curl -X PUT https://verification.didit.me/v3/travel-rule/vasps/0d6f3c2a-6a1e-4c55-9a39-1f2b0c7d8e91/decision/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"decision": "BLOCKED", "reason": "Unlicensed in its home jurisdiction"}'
```

```json theme={null}
{
  "decision": {
    "decision": "BLOCKED",
    "reason": "Unlicensed in its home jurisdiction",
    "decided_by": "",
    "updated_at": "2026-10-14T10:05:00Z",
    "inherited_from": null
  }
}
```

| `decision` | Arti | Preset yang menindaklanjutinya |
| - | - | - |
| `APPROVED` | Tim Anda menyetujui pihak lawan. | Tidak ada |
| `RESTRICTED` | Transfer ke pihak lawan tersebut boleh dilanjutkan setelah peninjauan. | `travel-rule-counterparty-restricted` menahannya untuk peninjauan. |
| `BLOCKED` | Tim Anda menolak pihak lawan. | `travel-rule-counterparty-blocked` menolak transfernya. |

* Keputusan bersifat privat bagi aplikasi Anda: pelanggan lain tidak pernah melihatnya, dan keputusan itu tidak pernah mengubah entri bersama.
* Keputusan tidak mengubah apa pun dengan sendirinya dan tidak pernah mengubah cara transfer dirutekan. Keputusan itu sampai ke transaksi Anda melalui [kolom aturan](#kolom-aturan-dan-preset) `counterparty_dd_status`: pasang preset, atau tulis aturan Anda sendiri yang memakai kolom tersebut.
* Keputusan terhadap sebuah merek berlaku untuk setiap [entitas](#merek-dan-entitasnya) miliknya yang belum punya keputusan sendiri, dan entitas tersebut menampilkan merek itu di `inherited_from`. Keputusan terhadap entitas menggantikan keputusan merek untuk entitas tersebut.
* `GET` mengembalikan keputusan yang berlaku, atau `{"decision": null}`. `DELETE` menghapus keputusan Anda sendiri dan mengembalikan keputusan yang berlaku setelahnya: keputusan merek untuk sebuah entitas, jika tidak ada maka `null`. Endpoint ini menjawab `404` ketika aplikasi Anda tidak memiliki keputusan sendiri terhadap pihak lawan tersebut.
* `reason` bersifat opsional, maksimal 255 karakter, dan setiap `PUT` menggantinya. `decided_by` adalah pengguna konsol yang membuat atau terakhir mengubah keputusan, dan kosong jika keputusan dibuat oleh kunci API.

### Skrining pihak lawan

Skrining pihak lawan memeriksa VASP pihak lawan itu sendiri, sebagai sebuah perusahaan, terhadap sanksi dan media negatif. Fitur ini **bersifat opt-in dan dikenakan biaya**: aktifkan dengan `counterparty_screening_enabled` di [pengaturan](#pengaturan) Anda. Selama fitur ini nonaktif, tidak ada yang diskrining atau ditagih.

```bash theme={null}
curl -X POST https://verification.didit.me/v3/travel-rule/vasps/0d6f3c2a-6a1e-4c55-9a39-1f2b0c7d8e91/screening/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"refresh": false}'
```

```json theme={null}
{
  "outcome": "screened",
  "screening": {
    "id": "7a1d2c3b-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
    "status": "In Review",
    "total_hits": 2,
    "score": 85.0,
    "screened_at": "2026-10-14T09:58:00Z",
    "fresh": true,
    "flagged": true
  }
}
```

* **Penagihan.** Setiap skrining baru dikenakan [harga](https://docs.didit.me/id/getting-started/pricing.md) Skrining AML Perusahaan milik organisasi Anda. `GET /v3/travel-rule/vasps/{vasp_id}/screening/` mengembalikan `price`, `fresh_days`, dan apakah skrining `enabled`, tanpa biaya. Skrining yang usianya kurang dari 30 hari dianggap masih baru: `POST` mengembalikannya lagi dengan `200` dan `outcome: reused` serta tidak menagih apa pun, kecuali Anda mengirim `refresh: true`. Skrining baru menjawab `201` dengan `outcome: screened`. Aplikasi sandbox tidak pernah diskrining atau ditagih.
* **Skrining otomatis.** Ketika skrining aktif, Didit juga menskrining pihak lawan yang dituju oleh pertukaran keluar saat pertukaran itu dimulai, sebelum aturan Anda dievaluasi terhadap transaksi, dengan penggunaan ulang dan penagihan yang sama. Penolakan atau kegagalan di tahap ini tidak pernah menggagalkan transfer.
* **Hasil.** `status` bernilai `Approved` ketika tidak ada kecocokan yang mungkin perlu ditinjau, dan `In Review` atau `Declined` untuk kecocokan yang mungkin terkait sanksi atau media negatif. `flagged` bernilai `true` selama skrining baru berstatus `In Review` atau `Declined`.
* **Dampak.** Selama skrining terakhir Anda terhadap pihak lawan ditandai dan skrining tetap aktif, `counterparty_risk_level` bernilai `HIGH` di aturan Anda, sehingga preset `travel-rule-counterparty-high-risk`, setelah dipasang, menahan transfernya. `risk_level` bersama di direktori tidak berubah.
* **Privasi.** Skrining bersifat privat bagi aplikasi Anda: pelanggan lain tidak pernah melihatnya, dan skrining itu tidak pernah mengubah entri bersama. Direktori menampilkan skrining terakhir Anda sebagai `entity_screening`.
* **Penolakan.** `409` ketika skrining nonaktif, untuk aplikasi sandbox, atau ketika skrining pihak lawan yang sama sedang berjalan. `403` dengan `code: insufficient_credits` ketika saldo Anda tidak cukup untuk menutup harga. `502` ketika skrining tidak dapat diselesaikan. Tidak satu pun dari penolakan ini menagih apa pun.

### Kuesioner uji tuntas

Mintalah jawaban uji tuntas dari pihak lawan dengan kuesioner standar Didit. `POST /v3/travel-rule/vasps/{vasp_id}/questionnaires/` mengirimkannya melalui email ke alamat kepatuhan yang tercatat untuk pihak lawan, dengan tautan sekali pakai menuju halaman jawaban:

```bash theme={null}
curl -X POST https://verification.didit.me/v3/travel-rule/vasps/0d6f3c2a-6a1e-4c55-9a39-1f2b0c7d8e91/questionnaires/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sent_to": "travelrule@counterparty.example"}'
```

```json theme={null}
{
  "id": "3f9e8d7c-6b5a-4c3d-9e2f-1a0b9c8d7e6f",
  "status": "SENT",
  "form_version": "1",
  "sent_to": "travelrule@counterparty.example",
  "sent_at": "2026-10-14T10:00:00Z",
  "expires_at": "2026-11-13T10:00:00Z",
  "answered_at": null,
  "valid_until": null,
  "current": false,
  "answers": {}
}
```

* **Tujuan pengiriman.** `sent_to` harus berupa alamat kepatuhan yang tercatat: untuk entri direktori, alamat kepatuhannya atau kontak yang dapat dilihat aplikasi Anda di `contacts`; untuk anggota jaringan Didit, email kepatuhan yang sudah dikonfirmasi. Jika dihilangkan, alamat yang digunakan adalah alamat tempat email Travel Rule ke pihak lawan dikirim: kontak Anda terlebih dahulu, lalu kontak platform, lalu alamat kepatuhan entri tersebut. Didit tidak pernah mengirim kuesioner ke tempat lain, dan mengembalikan `400` ketika pihak lawan tidak memiliki alamat kepatuhan yang tercatat.
* **Menjawab.** Tautan membuka `/v3/travel-rule/questionnaires/{token}/`, sebuah halaman untuk seseorang di pihak lawan yang tidak memerlukan akun maupun kunci API. Mereka menjawab setiap pertanyaan, hingga 2.000 karakter per pertanyaan (`N/A` jika tidak berlaku), dan mengirimkannya satu kali. Pihak lawan juga dapat mengirim `{"answers": {"<question id>": "<answer>"}}` ke tautan yang sama. Tautan yang sudah digunakan, diganti, atau melewati tenggatnya akan menampilkan halaman kedaluwarsa. Email dan halaman diterjemahkan; pertanyaannya sendiri selalu dalam bahasa Inggris, sehingga maknanya tidak berubah antarbahasa.
* **Tenggat waktu.** Pihak lawan memiliki 30 hari untuk menjawab (`expires_at`). Jawaban tetap berlaku selama 365 hari (`valid_until`), dan `current` bernilai `true` sampai saat itu. Kuesioner yang belum dijawab dan melewati tenggatnya, serta jawaban yang melewati masa berlakunya, menjadi `EXPIRED`.
* **Satu kuesioner terbuka per pihak lawan.** Pengiriman baru menggantikan kuesioner Anda sebelumnya yang belum dijawab kepada pihak lawan yang sama: kuesioner itu menjadi `EXPIRED` dan tautannya berhenti berfungsi. Satu email per menit dapat dikirim ke sebuah alamat; pengiriman yang lebih cepat mengembalikan `429`.
* **Membaca jawaban.** `GET /v3/travel-rule/vasps/{vasp_id}/questionnaires/` mencantumkan kuesioner Anda kepada pihak lawan, dari yang terbaru, dengan `answers` yang memiliki kunci berupa ID pertanyaan setelah dijawab. Direktori menampilkannya sebagai `questionnaires`. Data ini bersifat privat bagi aplikasi Anda.

Formulir versi `1` berisi dua belas pertanyaan berikut:

| ID pertanyaan | Pertanyaan |
| - | - |
| `legal_name` | Nama badan hukum dan yurisdiksi pendirian. |
| `licensing` | Lisensi atau registrasi yang dimiliki untuk layanan aset virtual: regulator, nomor lisensi, dan status di setiap yurisdiksi. |
| `jurisdictions` | Yurisdiksi tempat Anda beroperasi, dan yurisdiksi mana pun tempat Anda dikecualikan atau dibatasi. |
| `aml_program` | Ringkasan program AML/CFT Anda: kebijakan, prosedur, dan tanggal audit atau tinjauan independen terakhir. |
| `compliance_officer` | Nama dan peran petugas kepatuhan Anda, serta cara menghubungi mereka. |
| `sanctions_screening` | Cara Anda menyaring pelanggan dan pihak lawan terhadap sanksi dan media negatif: penyedia atau daftar, frekuensi, dan eskalasi. |
| `transaction_monitoring` | Cara Anda memantau transaksi untuk aktivitas mencurigakan: alat, ambang batas, dan praktik pelaporan. |
| `travel_rule` | Cara Anda mematuhi Travel Rule: protokol dan jaringan yang digunakan, serta waktu respons Anda yang biasa terhadap permintaan. |
| `custody` | Pengaturan kustodi untuk aset pelanggan: kustodian yang memenuhi syarat, asuransi, dan pemisahan. |
| `ownership` | Pemilik manfaat yang memegang 25 persen atau lebih, dan entitas induk atau payung mana pun. |
| `record_keeping` | Praktik pencatatan dan periode retensi data Travel Rule dan transaksi. |
| `data_protection` | Cara Anda melindungi data pribadi yang dibagikan untuk kepatuhan, dan di mana data tersebut disimpan. |

### Transfer dengan satu pihak lawan

[`GET /v3/travel-rule/transfers/?counterparty={vasp_id}`](https://docs.didit.me/id/management-api/travel-rule/list-transfers) menampilkan daftar transfer Travel Rule aplikasi Anda dengan satu pihak lawan, dari yang terbaru, berdasarkan `id` yang ditampilkan direktori: transfer Anda yang pihak lawannya adalah entri direktori tersebut, atau pertukaran `INTERNAL` Anda dengan anggota jaringan Didit tersebut. Nilai yang bukan id yang valid menghasilkan respons `400`.
Setiap baris memuat `reason` tepat setelah `status`: [`reason`](#mengapa-transfer-macet) milik transfer itu sendiri, sehingga daftar dapat membedakan email kepatuhan yang terpental dari pihak lawan yang tidak memiliki rute, tanpa membuka setiap transfer.

### Kebijakan sunrise dan tidak responsif

Saat transfer kedaluwarsa (`confirmation_timeout_hours` terlewati ketika statusnya `AWAITING_COUNTERPARTY`), `timeout_outcome` menentukan apa yang terjadi pada transaksinya. Dua pengaturan memungkinkan Anda memperlakukan dua alasan umum timeout secara berbeda:

| Pengaturan | Berlaku ketika pihak lawan adalah entri direktori yang |
| - | - |
| `sunrise_policy` | Berada di yurisdiksi yang tercantum di `sunrise_jurisdictions`: negara yang belum menegakkan Travel Rule, sehingga VASP tidak wajib merespons. |
| `non_responsive_policy` | Memiliki `responsiveness.status` `UNRESPONSIVE`. |

Keduanya menerima `HOLD`, `REJECT`, atau `PROCEED`, dengan arti yang sama seperti untuk `timeout_outcome`, atau string kosong untuk mengikuti `timeout_outcome`. Keduanya kosong secara default, sehingga tidak ada yang berubah sampai Anda mengatur salah satunya:

```bash theme={null}
curl -X PUT https://verification.didit.me/v3/travel-rule/settings/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sunrise_policy": "PROCEED", "non_responsive_policy": "HOLD"}'
```

Yang pertama dari berikut ini yang berlaku menentukan hasilnya:

1. `sunrise_policy`, jika diatur dan yurisdiksi pihak lawan ada di `sunrise_jurisdictions`.
2. `non_responsive_policy`, jika diatur dan pihak lawan berstatus `UNRESPONSIVE`.
3. `timeout_outcome` dalam kasus lainnya, termasuk transfer ke anggota jaringan Didit atau ke pihak lawan yang tidak memiliki entri direktori.

`sunrise_jurisdictions` bersifat hanya-baca dan saat ini berisi `["CO", "KH", "VN"]`. Hanya negara-negara ini yang dianggap berada dalam periode sunrise: yurisdiksi lain, serta yurisdiksi yang kosong atau tidak dikenal, mengikuti `timeout_outcome`, sehingga pihak lawan tidak pernah menerima kebijakan sunrise Anda secara tidak sengaja. Linimasa transfer yang kedaluwarsa menyebutkan hasil yang berlaku, misalnya `sunrise_policy=PROCEED (counterparty jurisdiction CO does not enforce the Travel Rule yet)`. Aturan Anda tetap berjalan setelah kedaluwarsa, sehingga aturan seperti EU TFR `tr_eu_expired_review` tetap dapat memindahkan transaksi ke peninjauan di bawah `PROCEED`.

### Kolom aturan dan preset

Empat kolom [aturan](https://docs.didit.me/id/transaction-monitoring/rules.md) memuat informasi yang diketahui aplikasi Anda tentang pihak lawan yang dijangkau pertukaran Travel Rule suatu transaksi: entri direktorinya, atau untuk pertukaran `INTERNAL`, pelanggan Didit yang menerimanya. Setiap kolom kosong jika pertukaran tidak menjangkau pihak lawan yang dikenal.

| Kolom | Nilai |
| - | - |
| `counterparty_dd_status` | [Keputusan](#keputusan-anda-terhadap-pihak-lawan) Anda: `APPROVED`, `RESTRICTED`, atau `BLOCKED`, atau entitas yang mengikuti keputusan mereknya. Kosong jika Anda tidak membuat keputusan. Tidak pernah keputusan pelanggan lain. |
| `counterparty_risk_level` | `risk_level` entri (`LOW`, `MEDIUM`, atau `HIGH`), atau `HIGH` ketika [skrining](#skrining-pihak-lawan) Anda terhadap pihak lawan ditandai. Kosong untuk entri yang belum dinilai, dan untuk anggota jaringan Didit kecuali skrining Anda terhadapnya ditandai. |
| `counterparty_jurisdiction` | Negara pihak lawan, dari entri direktori atau profil anggota jaringan Didit. Kode ISO-2 dan ISO-3 sama-sama dibandingkan, seperti kolom negara lainnya. |
| `counterparty_responsiveness` | `responsiveness.status` entri: `RESPONSIVE`, `UNRESPONSIVE`, atau `UNKNOWN`. Kosong untuk anggota jaringan Didit. |

Lima preset dalam bundel `travel_rule` bekerja pada kolom-kolom tersebut. Pasang dari **Transactions → Rules → Library** di Business Console atau dengan [API pustaka aturan](https://docs.didit.me/id/management-api/transactions/rules-install.md):

| `library_key` | Pemicu | Tindakan default |
| - | - | - |
| `travel-rule-counterparty-blocked` | `counterparty_dd_status` adalah `BLOCKED` | skor +90, `DECLINED` |
| `travel-rule-counterparty-restricted` | `counterparty_dd_status` adalah `RESTRICTED` | skor +50, `IN_REVIEW` |
| `travel-rule-counterparty-high-risk` | `counterparty_risk_level` adalah `HIGH` | skor +40, `IN_REVIEW` |
| `travel-rule-counterparty-high-risk-jurisdiction` | `counterparty_jurisdiction` ada dalam daftar risiko tinggi default (`IRN`, `PRK`, `SYR`, `AFG`, `RUS`, `MMR`) | skor +60, `IN_REVIEW` |
| `travel-rule-counterparty-unresponsive` | `counterparty_responsiveness` adalah `UNRESPONSIVE` | skor +30, `IN_REVIEW` |

Kelima preset ini hanya berlaku untuk transaksi Travel Rule.

## Webhook

Daftarkan tujuan webhook ke `travel_rule.status.updated` untuk menerima notifikasi pada setiap transisi status dari setiap transfer di aplikasi Anda, baik keluar maupun masuk, termasuk leg `INTERNAL`-rail.
Perutean berjalan setelah pembuatan transaksi mengembalikan respons, sehingga hasil seperti `COUNTERPARTY_VASP_NOT_FOUND`, `COUNTERPARTY_VASP_NOT_REACHABLE`, atau pertukaran `INTERNAL` yang langsung diselesaikan sampai kepada Anda melalui event ini, bukan dalam respons pembuatan.

```json theme={null}
{
  "event_id": "9c0c8b8a-1111-4222-9333-666666666666",
  "webhook_type": "travel_rule.status.updated",
  "timestamp": 1774970000,
  "created_at": 1774970000,
  "application_id": "11111111-2222-3333-4444-555555555555",
  "environment": "live",
  "transaction_id": "22222222-3333-4444-5555-666666666666",
  "txn_id": "trv-2026-07-05-001",
  "travel_rule_status": "COMPLETED",
  "rail": "INTERNAL",
  "direction": "OUTBOUND"
}
```

`rail` kosong sampai sebuah rail dipilih.
Untuk satu transaksi, Didit mengirim `travel_rule.status.updated` setelah `transaction.created`: ketika Didit membuat transaksi (`POST /v3/transactions/` Anda, registrasi sunrise, permintaan `TRP` masuk, atau leg masuk `INTERNAL`-rail), Didit mengirim `transaction.created` terlebih dahulu.
Setiap event dikirim dan dicoba ulang secara terpisah, sehingga `transaction.created` yang perlu dicoba ulang tetap bisa tiba setelah event status. Gunakan `transaction_id` sebagai kunci handler Anda, dan baca transaksinya ketika event status menyebutkan transaksi yang belum pernah Anda lihat.
Transfer yang dikirim melalui `TRUST` tidak mendapatkan event `COMPLETED`: TRUST tidak mengirim balik apa pun yang dapat dibaca Didit, sehingga kecuali pengiriman gagal atau Anda membatalkannya, event terakhirnya adalah `EXPIRED`. Melalui `GTR`, `VERIFYVASP`, dan `SYGNA`, event mengikuti jawaban yang dibaca Didit dari jaringan.
Aplikasi sandbox juga mengirim event ini, dengan `"environment": "sandbox"`; transfer yang dijawab oleh [Didit Test VASP](https://docs.didit.me/id/transaction-monitoring/travel-rule-sandbox.md) membawa `rail: "TEST_VASP"`, `test_vasp: true`, dan `test_vasp_scenario`.

Lihat [panduan webhook](https://docs.didit.me/id/integration/webhooks.md#jenis-event) untuk katalog event lengkap, verifikasi tanda tangan, dan kebijakan coba ulang.

## Harga

Biaya Travel Rule adalah **\$0.02 per pertukaran keluar yang dimulai**, dikenakan satu kali saat transaksi dibuat, terlepas dari berapa banyak transisi status yang dilalui pertukaran tersebut setelahnya. `resend` tidak pernah mengenakan biaya ini lagi.

* Berlaku untuk transaksi `travelRule` keluar pada aplikasi dengan Travel Rule aktif, yang jumlahnya sama dengan atau lebih besar dari `threshold_amount` Anda, sehingga Didit memulai pertukaran terkelola untuknya. Transfer ke dompet swakelola, atau ke dompet terverifikasi milik pengguna Anda, juga termasuk, karena bukti kepemilikan adalah pertukarannya.
* Setiap transaksi keluar lain yang membawa data Travel Rule ditagih sebagai Skrining Transaksi standar, yang disertakan dalam paket Anda hingga [batas transaksi bulanan](https://docs.didit.me/id/getting-started/pricing.md#pemantauan-transaksi-kyt) dan dihargai \$0.001 di atas batas tersebut: transfer di bawah ambang batas Anda, pembayaran Lightning yang tidak berlaku bagi Travel Rule, dan transfer yang dicatat secara pasif ketika Travel Rule nonaktif. Sebuah transaksi hanya ditagih pada salah satu dari dua baris, tidak pernah keduanya.
* Transaksi `travelRule` masuk tidak membawa biaya Travel Rule maupun biaya pemantauan: leg masuk yang Didit buat pada aplikasi penerima melalui `INTERNAL` rail, permintaan `TRP` masuk, dan [registrasi setelah deposit](#pendaftaran-sunrise-setelah-deposit).
* Aplikasi yang bergabung dengan Travel Rule secara gratis tidak membayar kedua biaya untuk transaksi `travelRule` keluar sampai Anda mengaktifkan penagihan keluar dengan `POST /v3/travel-rule/workspace/billing/`; menerima transfer tetap gratis.
* Aplikasi sandbox tidak pernah dikenakan biaya.
* Biaya Travel Rule tercantum sebesar $0.02 dan Skrining Transaksi sebesar $0.001 di atas batas Anda. Setiap transaksi dikenakan harga dari baris yang ditagihnya.
* Jika skrining AML/Skrining Dompet juga berjalan pada transaksi yang sama (misalnya deposit masuk dengan `currency_kind: "crypto"` dan pemantauan aktif), biaya tersebut ditagih terpisah dengan tarif standar Wallet Verification & Screening, dan tidak termasuk dalam biaya Travel Rule.
* [Skrining pihak lawan](#skrining-pihak-lawan) bersifat opsional dan ditagih terpisah, dengan harga Company AML Screening per skrining; skrining yang berusia kurang dari 30 hari digunakan kembali tanpa biaya. Keputusan, kuesioner, dan penilaian uji tuntas di direktori tidak dikenakan biaya.

### Harga atribusi

[Atribusi analitik blockchain](#atribusi-analitik-blockchain) memerlukan satu pencarian dompet ke penyedia analitik, dan Anda selalu mendapatkan nilai penuh dari pencarian tersebut:

* **Pemantauan kripto sudah memindai dompet pada transaksi ini** - hasil yang tersimpan digunakan kembali. Satu panggilan analitik, satu biaya Wallet Verification & Screening (biaya yang sudah dikenakan oleh pemantauan kripto). Atribusi tidak menambah apa pun.
* **Pemantauan kripto tidak berjalan** - Didit melakukan panggilan analitik yang diperlukan sekali dan meneruskan nilai penuhnya: transaksi dikenakan tarif standar Wallet Verification & Screening (\$0.15 dengan analitik yang dikelola Didit) dan menerima keluaran skrining kripto lengkap sebagai imbalannya, yaitu skor risiko, kategori risiko dompet, dan snapshot jaringan, bukan hanya nama VASP. Item penggunaan ditandai dengan pemicu `travel_rule_attribution` agar biaya tersebut dapat dijelaskan.
* **Kunci analitik milik Anda sendiri** - biaya platform yang sama yang berlaku untuk pemantauan kripto dengan kunci Anda sendiri juga berlaku di sini (\$0.02 per panggilan). Penyedia Anda menagih pencarian yang mendasarinya langsung kepada Anda.
* **Pencarian yang gagal tidak pernah dikenakan biaya**, pengiriman ulang menggunakan kembali atribusi yang tercatat tanpa panggilan atau biaya baru, dan aplikasi sandbox tidak pernah dikenakan biaya.

Jadi, transfer keluar yang memerlukan atribusi dikenakan \$0.02 (Travel Rule) ditambah satu biaya Wallet Verification & Screening. Ketika kedua produk diaktifkan, panggilan analitik dan biayanya hanya terjadi satu kali.

## Paket aturan EU TFR

Empat aturan preset disertakan dalam bundel `travel_rule_eu_tfr`, yang dirancang khusus untuk kewajiban EU TFR.
Seperti setiap [bundel preset](https://docs.didit.me/id/transaction-monitoring/rules-library.md) lainnya, aktifkan dari Business Console di **Transactions → Rules → Library**.

| Aturan (`library_key`) | Pemicu | Tindakan |
| - | - | - |
| `tr_eu_mismatch_hold` | Status transfer adalah `COUNTERPARTY_MISMATCHED_DATA` | Skor `+50`, transaksi diatur ke `IN_REVIEW` |
| `tr_eu_unverified_selfhosted_review` | Status transfer adalah `UNCONFIRMED_OWNERSHIP` dan jumlah dalam mata uang default minimal `1000` | Transaksi diatur ke `IN_REVIEW` |
| `tr_eu_vasp_not_found_score` | Status transfer adalah `COUNTERPARTY_VASP_NOT_FOUND` | Skor `+25`, diberi tag `travel-rule-sunrise` |
| `tr_eu_expired_review` | Status transfer adalah `EXPIRED` | Transaksi diatur ke `IN_REVIEW` |

Aturan ini dipicu pada setiap transisi yang relevan, yaitu saat pembuatan transfer, saat konfirmasi kepemilikan, saat respons pengambilan email, dan dari proses pembersihan kedaluwarsa. Dengan begitu, transfer yang tidak pernah selesai tetap masuk ke tinjauan kepatuhan dan tidak diselesaikan secara diam-diam.

## Mengapa ini lebih baik di satu platform

Kepatuhan Travel Rule adalah masalah identitas yang menyamar sebagai masalah pembayaran, dan Didit sudah memiliki data identitasnya:

* **Data terverifikasi yang sudah tersedia.** Subjek setiap transfer ditautkan melalui `vendor_data` ke profil KYC yang diverifikasi Didit saat onboarding (OCR dokumen, liveness, pencocokan wajah), sehingga Anda dapat membangun `originator_data` dari kolom yang sudah terverifikasi di platform yang sama.
  Untuk pengguna dengan verifikasi KYC yang disetujui, Didit mengirimkan identitas yang sudah terverifikasi, bukan nilai yang Anda ketik (lihat [Data terverifikasi dan asal-usul data](#data-terverifikasi-dan-asal-data)).
* **Biometrik tambahan untuk transfer berisiko.** [Aturan](https://docs.didit.me/id/transaction-monitoring/rules.md) dapat menahan transfer bernilai tinggi apa pun sampai pengguna lolos pemeriksaan ulang biometrik terhadap wajah yang diambil saat onboarding. Ini adalah jawaban terkuat terhadap pengambilalihan akun pada saat penarikan dana. Lihat [contoh kasus](https://docs.didit.me/id/transaction-monitoring/sdk-transaction-submission.md#contoh-biometrik-tambahan-untuk-penarikan-bernilai-tinggi).
* **Satu graf perangkat.** Transfer yang dikirim melalui SDK membawa informasi perangkat yang sama seperti sesi KYC, sehingga "perangkat baru + jumlah besar + penerima baru" cukup menjadi satu aturan, tanpa perlu join data warehouse.
* **Skrining, aturan, kasus, dan pertukaran di satu tempat.** Skrining dompet yang mengidentifikasi VASP pihak lawan adalah skrining yang sama dengan yang dilihat aturan dan analis Anda, jadi cukup satu biaya, satu konsol, dan satu jejak audit.
* **Harga yang dipublikasikan.** [\$0.02 per pertukaran keluar](#harga), tanpa tingkatan berdasarkan volume, tanpa panggilan penjualan.

## FAQ

### Cara kerja pertukaran

> [accordion] Apakah Didit menjalankan pertukaran antar-VASP sendiri, atau hanya mencatat data Travel Rule setelah jaringan lain menyelesaikan jabat tangan?
>
> Didit menjalankan pertukaran itu sendiri.
> Ketika Anda mengirimkan transfer `travelRule`, Didit melakukan penemuan pihak lawan secara langsung, mengirimkan data pengirim dan penerima ke VASP penerima melalui jalur yang membawanya, dan menandai transfer sebagai `COMPLETED` hanya setelah sisi pihak lawan mengonfirmasinya. Ini adalah jabat tangan terkelola, bukan log pasca-penyelesaian.
> Jawaban dari pihak lawan diproses di setiap jalur kecuali `TRUST`, yang hanya mengirim, sehingga transfer melalui jalur tersebut akan kedaluwarsa, bukan selesai. Melalui `GTR`, `VERIFYVASP`, dan `SYGNA`, Didit membaca jawaban dari respons jaringan atau dengan melakukan polling setiap 5 menit, dan belum ada pertukaran melalui jalur tersebut yang selesai terhadap jaringan yang aktif. Melalui `TRP`, jawaban yang tidak langsung diberikan oleh pihak lawan memerlukan host TRP publik Didit, yang belum aktif (lihat [Jaringan Travel Rule](https://docs.didit.me/id/transaction-monitoring/travel-rule-networks.md)).
> Didit juga menyimpan catatan lengkap dan status kepatuhan setiap pertukaran (sebuah [siklus hidup](#siklus-hidup) dengan 13 status, [webhook](#webhook), dan jejak audit).
> Jika Anda lebih suka menjalankan Travel Rule melalui proses Anda sendiri, Didit dapat mencatat data secara pasif sebagai sistem catatan utama Anda (lihat pertanyaan tentang pencatatan pasif di bawah).
> Kedua mode tersedia: pertukaran aktif berjalan setelah Anda mengatur `is_enabled: true` di [pengaturan](#pengaturan) (nilai default-nya `false`), dan sampai saat itu Didit mencatat data secara pasif.

> [accordion] Apakah pertukaran ini asli dari Didit, atau bergantung pada penyedia interoperabilitas eksternal (Notabene, Sygna, VerifyVASP, TRP)?
>
> Pertukaran ini merupakan fitur bawaan Didit. Didit menjalankan implementasi Travel Rule Protocol (TRP) sendiri, yang akan dilayani di `trp.didit.me` setelah host publik tersebut aktif (saat ini belum merespons, sehingga pihak lawan belum dapat menjangkau Anda melalui TRP). Didit juga mengimplementasikan protokol jaringan industri secara langsung: `GTR` (Global Travel Rule), `TRUST`, `VerifyVASP`, dan `Sygna Bridge` (diimplementasikan secara langsung, termasuk IVMS 101 terenkripsi ECIES dari Sygna dan permintaan izin yang ditandatangani). Didit bukan reseller dari satu lapisan interoperabilitas pihak ketiga. Untuk menjangkau pihak lawan yang berada di jaringan keanggotaan tertentu, komunikasi tentu terjadi melalui jaringan tersebut, karena tidak ada satu saluran universal dalam Travel Rule. Namun penemuan, jabat tangan, verifikasi, dan pencatatan semuanya dijalankan oleh Didit.
> Saat ini setiap jalur jaringan memerlukan keanggotaan Anda sendiri, dan `TRUST` hanya mengirim. Lihat [Ikhtisar](#ikhtisar).

> [accordion] Jaringan dan protokol Travel Rule apa saja yang didukung Didit?
>
> Yang diimplementasikan secara bawaan, dicoba dengan urutan prioritas yang ketat: `INTERNAL` (kedua VASP berada di Didit), `TRP` (OpenVASP Travel Rule Protocol), `GTR`, `TRUST`, `VerifyVASP`, `Sygna Bridge`, dan cadangan `EMAIL` untuk pihak lawan yang tidak memiliki alat pendukung.
> Jalur jaringan memerlukan keanggotaan Anda sendiri saat ini, `TRUST` hanya mengirim, dan penerimaan melalui jaringan belum diaktifkan. Lihat [Jaringan Travel Rule](https://docs.didit.me/id/transaction-monitoring/travel-rule-networks.md).
> CODE, TRISA, Notabene, dan Veriscope muncul di **Marketplace** Didit sebagai kartu permintaan akses, tanpa integrasi saat ini.
> Lihat [Cara Didit merutekan pertukaran](https://docs.didit.me/id/transaction-monitoring/travel-rule-interoperability.md#cara-didit-merutekan-pertukaran) untuk tabel perutean lengkap, dan [Jaringan Travel Rule](https://docs.didit.me/id/transaction-monitoring/travel-rule-networks.md) untuk jangkauan setiap jaringan saat ini.

> [accordion] Jaringan mana yang sebaiknya saya gunakan, dan apakah saya memerlukan keanggotaan sendiri?
>
> `TRP` adalah dasar yang kami rekomendasikan: tidak memerlukan keanggotaan bersama. Dengan membagikan [Travel Address](#travel-address) Anda, VASP mana pun yang menggunakan TRP dapat menjangkau Anda. Ketika pihak lawan hanya diketahui melalui alamat, [atribusi berbasis analisis blockchain](#atribusi-analitik-blockchain) hanya merutekannya melalui TRP jika entri direktori yang diatribusikan sudah memiliki endpoint TRP.
> Untuk transaksi keluar, Didit mengirim aset yang tercantum di bawah [Pengidentifikasi aset TRP](#pengidentifikasi-aset-trp) melalui TRP. Pihak lawan yang tidak langsung merespons memerlukan host TRP publik Didit, yang belum aktif.
> Untuk jaringan keanggotaan, pilih berdasarkan di mana pihak lawan Anda beroperasi: GTR menawarkan cakupan global yang luas, TRUST berorientasi pada VASP di AS, dan VerifyVASP (yang kini juga mengoperasikan Sygna Bridge) memiliki cakupan yang kuat di Asia.
> Ya, saat ini Anda memerlukan keanggotaan sendiri: Didit belum memiliki keanggotaan platform di jaringan-jaringan ini dan sedang melakukan onboarding sebagai penyedia.
> Hubungkan keanggotaan Anda di **Marketplace**; Anda tidak terikat pada satu jaringan saja.
> Ingat bahwa `TRUST` hanya mengirim, sehingga transfer melalui jalur tersebut tidak akan selesai, dan belum ada pertukaran melalui jaringan apa pun yang selesai terhadap jaringan yang aktif.

> [accordion] Bagaimana Didit menemukan VASP pihak lawan ketika saya hanya memiliki alamat?
>
> Melalui rantai resolusi: pelanggan Didit lain yang telah membuktikan kendali atas dompet tersebut (jalur `INTERNAL`), [buku alamat](#buku-alamat-dompet) Anda sendiri untuk Travel Address yang tersimpan, lalu jalur protokol dan jaringan, dan terakhir [atribusi berbasis analisis blockchain](#atribusi-analitik-blockchain).
> Jika transfer hanya membawa dompet tujuan, Didit mencocokkannya dengan data analisis blockchain untuk mengatribusikan bursa atau layanan kustodi pihak lawan, lalu mencatatnya di [direktori VASP](#direktori).
> Transfer kemudian dirutekan secara otomatis hanya jika entri direktori tersebut sudah memiliki rute, seperti endpoint `TRP`. Jika tidak, transfer berakhir dengan `COUNTERPARTY_VASP_NOT_FOUND` dengan nama pihak lawan tercatat, dan Anda dapat mengirim ulang setelah rute tersedia, misalnya setelah Anda menyimpan `travel_address` pihak lawan pada entri buku alamat Anda untuk dompet tersebut (untuk aset yang tercantum di bawah [Pengidentifikasi aset TRP](#pengidentifikasi-aset-trp)).

### Harga dan lisensi

> [accordion] Berapa biaya Travel Rule, dan apakah sudah termasuk dalam paket KYC atau verifikasi saya?
>
> Travel Rule adalah produk terpisah yang ditagih berdasarkan penggunaan.
> Produk ini tidak termasuk dalam verifikasi identitas.
> Biayanya \*\*$0.02 per pertukaran keluar yang dimulai** ([harga yang dipublikasikan](#harga), tanpa tingkatan volume, tanpa panggilan penjualan).
>         Ketika perutean memerlukan pencarian analisis blockchain untuk mengidentifikasi VASP pihak lawan, pencarian tersebut ditagih sekali dengan [tarif atribusi](#harga-atribusi): mulai dari $0.15 yang dikelola Didit, atau \$0.02 dengan kunci penyedia yang sudah ada.
> Biaya ini tidak ditagihkan lagi jika pemantauan kripto sudah menyaring dompet yang sama.
> Transfer di bawah ambang batas Anda, atau transfer yang dicatat saat Travel Rule dinonaktifkan, ditagih sebagai Skrining Transaksi. Transfer masuk, seperti kaki transaksi yang dibuat Didit di sisi penerima, tidak dikenai biaya Travel Rule.

> [accordion] Apakah saya akan dikenakan tagihan ganda ketika Travel Rule dan pemantauan kripto berjalan bersamaan?
>
> Tidak.
> Transaksi `travelRule` ditagih dalam satu baris: biaya Travel Rule (\$0.02) ketika memulai pertukaran keluar, dan Skrining Transaksi standar selain itu. Pencarian analisis blockchain hanya ditagih sekali: jika pemantauan kripto sudah menyaring dompet tujuan pada transaksi tersebut, [atribusi](#atribusi-analitik-blockchain) menggunakan kembali hasil tersimpan itu tanpa biaya tambahan.
> Transfer masuk yang dibuat Didit di sisi penerima tidak pernah dikenai biaya Travel Rule.

> [accordion] Apakah Didit dapat menyediakan dokumentasi atau pernyataan kapabilitas untuk perizinan VASP atau berkas untuk regulator saya?
>
> Ya. Kapabilitas KYT dan pemantauan transaksi, skrining AML dan sanksi, risiko dompet berdasarkan analisis blockchain, serta Travel Rule Didit semuanya didokumentasikan secara publik di docs.didit.me, dan Anda bebas mengutip halaman-halaman ini dalam berkas regulasi. Untuk pernyataan kapabilitas produk formal yang disesuaikan dengan pengajuan tertentu, misalnya aplikasi perizinan VASP AIFC/AFSA, MiCA, atau lainnya, hubungi tim akun Didit Anda dengan format yang diwajibkan regulator Anda.

### Operasional dan data

> [accordion] Apa yang terjadi pada transfer di bawah ambang batas saya?
>
> Transfer tersebut langsung menghasilkan `NOT_APPLICABLE`: tidak ada rail yang dicoba dan tidak ada data identitas yang keluar dari Didit.
> Transaksi ditagih sebagai Transaction Screening standar, bukan dengan biaya Travel Rule.
> Didit membandingkan ambang batas dengan jumlah yang dikonversi ke mata uang default aplikasi Anda.
> Jika Didit tidak dapat mengonversi jumlahnya, ambang batas tidak diterapkan dan transfer diproses untuk pertukaran.
> EU TFR tidak memiliki batas minimum, sehingga CASP di UE sebaiknya mempertahankan `threshold_amount` pada `0.00`.

> [accordion] Bagaimana jika pihak lawan tidak pernah merespons?
>
> Transfer tetap berada di `AWAITING_COUNTERPARTY` hingga `confirmation_timeout_hours` berlalu, lalu sweeper memindahkannya ke `EXPIRED` dan menerapkan `timeout_outcome` Anda ke transaksi yang mendasarinya: `HOLD` untuk peninjauan, `REJECT` untuk menolak, atau `PROCEED` untuk membiarkannya tidak berubah. Aturan preset `tr_eu_expired_review` juga menampilkan setiap kedaluwarsa kepada analis Anda. Pihak lawan yang sama sekali tidak mengambil pesan tersebut merupakan kasus yang berbeda: Didit mencoba kembali, dan setelah percobaan gagal yang keenam, transfer dipindahkan ke `COUNTERPARTY_VASP_NOT_REACHABLE` (lihat [Pengiriman dan coba lagi](#pengiriman-dan-coba-lagi)).

> [accordion] Pihak lawan saya tidak memiliki alat Travel Rule sama sekali. Apakah saya tetap bisa mematuhi ketentuan?
>
> Bisa. Itu adalah rail `EMAIL`. Kontak kepatuhan mereka menerima tautan pengambilan satu kali dan dapat mengonfirmasi atau menolak pertukaran dari halaman yang di-hosting tanpa akun Didit, tanpa kunci API, dan tanpa integrasi. Untuk deposit yang sudah diselesaikan sebelum pertukaran apa pun dimungkinkan, gunakan [pendaftaran sunrise setelah deposit](#pendaftaran-sunrise-setelah-deposit).

> [accordion] Bagaimana cara kerja penarikan ke dompet pengguna sendiri?
>
> Nyatakan tujuan sebagai dompet swakelola (`payment_method.method_type: "unhosted_wallet"`). Didit melewati perutean VASP dan sebagai gantinya mengumpulkan bukti bahwa pelanggan Anda mengendalikan dompet tersebut, melalui penandatanganan pesan, tes Satoshi, tangkapan layar, atau pernyataan mandiri, melalui [widget kepemilikan dompet](https://docs.didit.me/id/transaction-monitoring/wallet-ownership-widget.md). Itulah kewajiban EU TFR terkait dompet swakelola dalam bentuk API.

> [accordion] Apakah data pribadi pihak lawan terlindungi selama pertukaran?
>
> Ya.
> Sampai kepemilikan dompet dikonfirmasi di sisi Anda, data pribadi pihak lawan pada transfer masuk disamarkan, baik di objek transfer maupun di pihak lawan dalam transaksi (lihat [Data pihak lawan yang disamarkan](#data-pihak-lawan-yang-disamarkan)).
> Halaman pengambilan melalui email hanya menampilkan ringkasan transfer (nama VASP pengirim, jumlah, dompet tujuan), tidak pernah payload data pribadi.
> Pertukaran rail berjalan melalui HTTPS, dan jaringan rail (`GTR`, `TRUST`, `VERIFYVASP`, `SYGNA`) juga mengenkripsi payload IVMS dengan kunci publik VASP penerima.

> [accordion] Saya sudah melacak kepatuhan Travel Rule dengan proses saya sendiri. Bisakah saya langsung mencatatnya?
>
> Bisa. Dengan Travel Rule dinonaktifkan, `travel_rule_details` apa pun yang Anda kirimkan (termasuk `status` yang disediakan oleh pemanggil, baik yang berlaku saat ini maupun yang lama) dicatat secara pasif pada transaksi. Tidak ada rail yang dijalankan dan tidak ada yang dinegosiasikan. Gunakan ini untuk mengisi data historis atau menjalankan proses Anda sendiri sambil tetap menggunakan satu sistem pencatatan.

> [accordion] Bagaimana cara menguji ini sebelum beroperasi penuh?
>
> Gunakan aplikasi sandbox dengan Travel Rule aktif. Sandbox melewati aturan, penagihan, dan webhook `transaction.created` serta `transaction.status.updated`, dan setiap pertukaran **keluar** dikirim ke [Didit Test VASP](https://docs.didit.me/id/transaction-monitoring/travel-rule-sandbox.md) pada rail `TEST_VASP`, yang menjawab di dalam Didit dengan skenario yang Anda pilih: terima, tolak, ketidaksesuaian nama, tidak dapat dijangkau, waktu habis, atau dompet swakelola. Anda menerima webhook `travel_rule.status.updated` yang ditandai `environment: sandbox`, dan tidak ada pesan yang sampai ke pihak lawan sungguhan.
> Untuk transfer **masuk**, minta VASP penguji mengirimkan transfer kepada Anda dengan [Trigger Test VASP Inbound Transfer](https://docs.didit.me/id/management-api/travel-rule/trigger-test-vasp-inbound.md), atau daftarkan satu dengan `POST /v3/travel-rule/inbound/`. Keduanya diputuskan berdasarkan buku alamat dompet Anda: `ON_HOLD`, `UNCONFIRMED_OWNERSHIP`, `COUNTERPARTY_MISMATCHED_DATA`, atau `COMPLETED` lalu `FINISHED`.
> Untuk pertukaran dua pihak dengan aplikasi sungguhan lain, gunakan dua aplikasi **produksi** milik Anda sendiri pada rail `INTERNAL`: aplikasi penerima harus dapat ditemukan dan harus membuktikan kendali atas dompet tujuan dengan pesan yang ditandatangani atau deposit uji.

## Langkah berikutnya

> [card] [Widget kepemilikan dompet](https://docs.didit.me/id/transaction-monitoring/wallet-ownership-widget.md)
>
> Buktikan bahwa pelanggan mengendalikan dompet dengan penandatanganan, tes Satoshi, tangkapan layar, atau pernyataan mandiri.

> [card] [Interoperabilitas](https://docs.didit.me/id/transaction-monitoring/travel-rule-interoperability.md)
>
> Endpoint yang menghadap pihak lawan, yang digunakan VASP lain untuk menjangkau Anda: TRP, callback, pengambilan email, sunrise.

> [card] [Jaringan](https://docs.didit.me/id/transaction-monitoring/travel-rule-networks.md)
>
> Apa yang dapat dijangkau setiap rail dan jaringan saat ini, dan apa yang masih menunggu keanggotaan.

> [card] [Uji di sandbox](https://docs.didit.me/id/transaction-monitoring/travel-rule-sandbox.md)
>
> Uji setiap skenario terhadap Didit Test VASP sebelum Anda beroperasi penuh.

> [card] [Mengirimkan transaksi](https://docs.didit.me/id/transaction-monitoring/transactions.md)
>
> Cara menyertakan data Travel Rule dalam payload Create Transaction.

> [card] [Pustaka aturan](https://docs.didit.me/id/transaction-monitoring/rules-library.md)
>
> Katalog lengkap aturan preset, termasuk paket Travel Rule.

> [card] [Webhook](https://docs.didit.me/id/integration/webhooks.md)
>
> Berlangganan travel\_rule.status.updated dan setiap jenis event lainnya.

> [card] [Panduan konsol](https://docs.didit.me/id/transaction-monitoring/console.md)
>
> Melihat status Travel Rule pada tampilan detail transaksi.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.