Ringkasan
Pengiriman transaksi dari sisi klien dibangun di atas tiga jaminan:- Pengikatan subjek yang tahan spoofing. Token dibatasi ke satu
vendor_data(ID pengguna Anda) saat dibuat. Identitas subjek dari setiap transaksi yang dikirim dengan token tersebut ditegakkan di sisi server berdasarkan pengikatan ini, sehingga klien yang dimanipulasi tidak dapat mengirim atas nama pengguna lain, dan payload tidak perlu membawa kredensial. - Intelijen perangkat otomatis. SDK mengumpulkan sidik jari perangkat dan mengirimkannya bersama permintaan. Didit menurunkan alamat IP dan user agent di sisi server. Konteks perangkat gabungan dilampirkan ke subjek transaksi tanpa pustaka tambahan, tanpa token perangkat terpisah, dan tanpa integrasi tambahan di pihak Anda. Konteks ini mendukung aturan berbasis perangkat serta korelasi berdasarkan perangkat lintas sesi dan transaksi.
- Pembuktian kepemilikan dompet yang diluncurkan otomatis. Ketika transaksi yang dibuat mengharuskan pengguna akhir membuktikan kontrol atas dompet, respons membawa blok
action_requiredbertipewallet_ownership. SDK langsung membuka alur tersebut, lalu menyegarkan transaksi setelah selesai, tanpa loop polling atau pengiriman tautan yang harus Anda bangun sendiri. Tindakanverification_sessionyang diperlukan berbeda: tindakan itu tidak pernah diluncurkan otomatis dan dikembalikan dalam blok yang sama agar aplikasi Anda meluncurkannya dengan integrasi verifikasi Didit miliknya sendiri.
POST /v3/transactions/ di sisi server tetap menjadi pilihan yang tepat ketika tidak ada pengguna akhir: transfer back-office, impor batch, atau event yang dilaporkan oleh sistem Anda sendiri.
Kedua jalur membuat rekaman transaksi yang sama, menjalankan aturan yang sama, dan mengirim webhook yang sama.Alur
1
Buat token transaksi
Backend Anda memanggil
POST /v3/transactions/sdk-token/ dengan kunci API Anda dan vendor_data pengguna, lalu menyerahkan sdk_token yang dikembalikan ke aplikasi Anda.2
Kirim dari perangkat
Aplikasi memanggil
submitTransaction pada SDK. Pemanggilan ini mengirim payload ke POST /v1/transactions/ dengan header X-Transaction-Token dan pengayaan perangkat otomatis.3
Tangani tindakan yang diperlukan
Jika
action_required.type adalah wallet_ownership, SDK otomatis meluncurkan widget, lalu menyegarkan transaksi melalui GET /v1/transactions/{transaction_id}/.
Jika tipenya verification_session, SDK tidak meluncurkan apa pun. Baca action_required dan mulai alur verifikasi Anda sendiri dengan session_token-nya (atau url di web).Membuat token transaksi
Buat token dari backend Anda denganPOST /v3/transactions/sdk-token/. Autentikasinya menggunakan kunci API yang sama dengan endpoint transaksi /v3/ lainnya.
Alias camelCase (
vendorData, ttlSeconds, maxUses) juga diterima, seperti pada API /v3/ lainnya.
Mengirim dari perangkat
SDK mengirim kePOST /v1/transactions/ dengan token di header X-Transaction-Token.
Payload wire menggunakan camelCase. Metode submitTransaction membangunnya untuk Anda, jadi Anda hanya perlu menanganinya langsung saat memanggil endpoint dari klien HTTP Anda sendiri:
POST /v3/transactions/-nya:
Respons berisi detail transaksi snake_case yang sama dengan endpoint
/v3/, ditambah blok action_required:
Mendeklarasikan dompet swakelola
Contoh di atas menyatakan tujuan sebagai dompet swakelola milik pengguna:paymentMethod.type pada counterparty adalah unhosted_wallet.
Deklarasi tersebut mengubah cara pertukaran Travel Rule berjalan:
- Didit melewati routing VASP pihak lawan sepenuhnya - tidak ada VASP di balik dompet swakelola - dan membuat transfer langsung dalam status
UNCONFIRMED_OWNERSHIP. - Saat
auto_wallet_verificationaktif di pengaturan Travel Rule Anda (default-nya), sesi widget kepemilikan dompet dibuat otomatis dan dikembalikan dalamaction_required, persis seperti pada respons di atas. - SDK meluncurkan widget secara otomatis; setelah pengguna membuktikan kendali atas dompet, transfer menjalankan pencocokan nama dan beralih ke
COMPLETED, atau keCOUNTERPARTY_MISMATCHED_DATAjika nama tidak cocok dengan pemilik yang tercatat di buku alamat dompet.
Penegakan subjek
Tiga hal berikut selalu ditentukan oleh token, tidak pernah oleh payload:- Aplikasi tempat transaksi dibuat.
- Identitas subjek:
subject.externalUserIddalam payload diabaikan dan digantikan denganvendor_datadari token. - Konteks perangkat subjek (lihat di bawah); kolom yang diturunkan dari server selalu menang jika terjadi konflik dengan apa pun yang dikirim dalam
subject.device.
401 dari endpoint ini berarti token ditolak: token tidak ada, tidak dikenal, dicabut, melebihi max_uses-nya, atau kedaluwarsa.
Respons token kedaluwarsa selalu memuat kata expired dalam detail error, dan itulah cara SDK membedakan error expired_token dari error invalid_token.
Membaca transaksi kembali
GET /v1/transactions/{transaction_id}/ mengembalikan detail yang sama dengan autentikasi X-Transaction-Token yang sama.
SDK memanggilnya secara otomatis setelah alur tindakan yang diluncurkan selesai atau jendela waktunya tertutup, sehingga status akhir tidak pernah bergantung pada satu event atau notifikasi saja.
Anda dapat memanggilnya sendiri untuk memeriksa ulang status dan action_required kapan pun selama token masih berlaku. Dari backend Anda, GET /v3/transactions/{transaction_id}/ mengembalikan catatan yang sama.
Intelijen perangkat otomatis
Setiap pengiriman membawa intelijen perangkat tanpa pekerjaan integrasi apa pun di sisi Anda:- SDK mengumpulkan sidik jari perangkat yang menjaga privasi (skema
didit-fp-v2: sinyal platform dan navigator, ID perangkat yang persisten, skor bot, dan hash gabungan) lalu mengirimkannya bersama permintaan. - Didit menurunkan alamat IP, user agent, dan accept-language di sisi server dari koneksi itu sendiri, sehingga nilai-nilai tersebut tidak dapat dipalsukan lewat payload.
/v3/ yang dikirim dari server dapat tetap meneruskan objek device_context eksplisit untuk setiap peserta. Pada jalur SDK, Anda mendapatkan versi yang lebih kuat dari data yang sama tanpa biaya tambahan.
Tindakan yang diperlukan pengguna
Beberapa transaksi memerlukan tindakan pengguna akhir sebelum dapat diselesaikan: sebuah aturan dapat mensyaratkan sesi verifikasi, atau transfer Travel Rule dapat mensyaratkan bukti bahwa dompet tujuan benar-benar milik pengguna. Kedua kasus ini muncul di tempat yang sama, yaitu blokaction_required pada respons submit (dan pada setiap pembacaan transaksi berikutnya):
Jika keduanya dapat berlaku pada transaksi yang sama,
wallet_ownership didahulukan, karena bukti kepemilikan yang belum ada akan memblokir pertukaran Travel Rule itu sendiri.
action_required menjadi null setelah tindakan yang tertunda diselesaikan.
Kolom remediation yang ada tetap dipertahankan demi kompatibilitas ke belakang; action_required adalah blok kanonis.
Kontrak peluncuran otomatis
autoLaunchAction (default true) secara otomatis hanya meluncurkan tindakan wallet_ownership:
- Web - dibuka di modal overlay milik SDK, dengan penyelesaian dideteksi melalui pesan yang divalidasi asal-usulnya ditambah polling transaksi yang terbatas (tidak pernah bergantung pada satu event saja).
- iOS / Android (dan pembungkus React Native serta Flutter, yang meneruskan ke SDK native) - ditampilkan sebagai pengalaman kepemilikan dompet native milik SDK (SwiftUI / Jetpack Compose) ketika
useNativeWalletOwnershipbernilaitrue(default), dengan cadangan keSFSafariViewController/ Chrome Custom Tab, dan terakhir ke browser default. Setelah alur ditutup atau aplikasi kembali ke latar depan, SDK membaca ulang transaksi secara otomatis.
verification_session tidak pernah diluncurkan otomatis: tindakan itu selalu muncul di action_required agar aplikasi Anda memulainya dengan integrasi verifikasi Didit milik Anda sendiri.
Setelah alur kepemilikan dompet yang diluncurkan otomatis oleh SDK selesai atau ditutup, SDK membaca ulang transaksi dan menyerahkan hasil yang diperbarui ke callback onActionCompleted Anda.
Tindakan verification_session tidak termasuk dalam siklus itu, karena aplikasi Anda yang meluncurkannya - lihat bagian berikutnya.
Meluncurkan sesi verifikasi
Ketikaaction_required.type bernilai verification_session, baca blok dari result.actionRequired dan serahkan ke integrasi verifikasi Didit yang sudah ada:
GET /v1/transactions/{transaction_id}/ (atau tunggu webhook transaksi) untuk mengambil status transaksi yang diperbarui.
Contoh: biometrik tambahan untuk penarikan bernilai tinggi
Ini adalah alur terbaik: batasi transaksi berisiko - jumlah besar, penerima baru, perangkat baru - dengan pemeriksaan ulang biometrik dari orang yang sama yang Anda verifikasi saat onboarding. Pengambilalihan akun terlihat persis seperti ini: kata sandi benar, kode 2FA benar (hasil phishing atau SIM swap), dan penarikan ke dompet yang belum pernah Anda lihat. Setiap pertahanan berbasis kredensial sudah gagal pada titik itu. Namun, wajah tidak demikian: penyerang tidak dapat lolos dari swafoto dengan pemeriksaan liveness yang harus cocok dengan wajah yang direkam selama KYC onboarding pemilik sah.1
Buat aturan sekali, di konsol
Transactions → Rules → Create Rule: kondisi
amount gte 5000, tindakan Change status → AWAITING_USER, dan pilih alur kerja Autentikasi Biometrik Anda pada tindakan tersebut.
Tambahkan kondisi risiko lain yang Anda inginkan - pihak lawan yang baru pertama kali, sidik jari perangkat baru, perubahan negara IP - sebagai kondisi tambahan atau aturan tambahan.2
Kirim penarikan seperti biasa
Tidak ada yang berubah pada kode submit Anda. Ketika aturan terpicu, respons kembali dengan
status: "AWAITING_USER" dan blok action_required bertipe verification_session:3
Luncurkan pemeriksaan ulang
Serahkan
session_token (atau url) ke integrasi verifikasi Didit Anda yang sudah ada, persis seperti di Meluncurkan sesi verifikasi.
Karena sesi dibuat untuk vendor_data yang sama dengan subjek transaksi, Didit sudah memiliki wajah referensi terverifikasi pengguna dari onboarding - swafoto liveness yang disetujui, foto chip paspor, atau potret dokumen.
Pengguna mengambil satu swafoto langsung; Didit menjalankan liveness plus pencocokan wajah 1:1 terhadap referensi yang tersimpan itu. Tidak ada pemindaian ulang dokumen, tidak ada onboarding ulang - proses yang hanya memerlukan beberapa detik, dan hanya pada transaksi yang memang memerlukannya.4
Selesaikan berdasarkan hasil
Ketika sesi selesai, transaksi dievaluasi ulang secara otomatis:
APPROVED jika pemeriksaan ulang berhasil, DECLINED jika gagal, dengan webhook transaction.status.updated dalam kedua kasus (reason: remediation_completed pada linimasa transaksi).
Aplikasi Anda menerima hasilnya melalui callback bergaya onActionCompleted, GET /v1/transactions/{transaction_id}/, atau webhook.SDK Web
submitTransaction tersedia di singleton Web SDK saat ini:
{ transactionId, status, travelRuleStatus?, actionRequired? }.
Di payload tingkat SDK, Anda menulis category, details, dan customProperties; SDK memetakannya ke alias wire (type, info, props) untuk Anda.
Error memiliki tipe DiditTransactionError:
SDK Native
API
submitTransaction native tersedia di iOS dan Android SDK 4.1.0 (serta rilis React Native dan Flutter yang menggunakan versi tersebut).
Berbeda dengan Web SDK, payload native langsung menggunakan nama field wire: type, info, dan props.getTransaction(transactionToken, transactionId) untuk membaca ulang transaksi dengan token yang sama. SDK memanggilnya untuk Anda setelah alur tindakan dimulai, dan Anda dapat memanggilnya sendiri kapan saja.
Di perangkat mobile, mekanisme pengiriman sidik jari perangkat sudah diterapkan pada semua panggilan jaringan SDK, sehingga pengiriman transaksi otomatis membawa intelijen perangkat yang sama.
Tanpa SDK
Semua yang dilakukan SDK adalah HTTPS biasa, jadi tidak ada yang mewajibkan penggunaan SDK. Ada dua bentuk integrasi yang setara: Hanya sisi server (tanpa token sama sekali). Kirim denganPOST /v3/transactions/ dari backend Anda menggunakan kunci API Anda. Respons (dan setiap GET /v3/transactions/{transaction_id}/ berikutnya) membawa blok action_required yang sama. Anda juga dapat menyertakan konteks device eksplisit per peserta, karena tidak ada SDK yang mengumpulkannya untuk Anda.
Sisi klien dengan HTTP stack Anda sendiri. Buat token dengan POST /v3/transactions/sdk-token/, lalu panggil POST /v1/transactions/ dan GET /v1/transactions/{transaction_id}/ dari perangkat dengan header X-Transaction-Token. Pengikatan subjek yang sama dan penurunan IP/user-agent di sisi server juga berlaku.
Lalu tangani action_required sendiri:
Dan deteksi penyelesaian tanpa callback dari klien:
- Webhook (direkomendasikan).
transaction.status.updateddipicu saat tindakan yang tertunda menyelesaikan transaksi, dantravel_rule.status.updateddipicu pada setiap transisi pertukaran. Keduanya memuat informasi yang cukup untuk memperbarui catatan Anda tanpa polling. - Polling. Baca ulang transaksi (
/v3/dari backend Anda, atau/v1/dengan token selama token masih berlaku):action_requiredkembali menjadinullsetelah diselesaikan, danstatus/travel_rule.statusmemuat hasilnya.
Webhook
Backend Anda tidak memerlukan aplikasi untuk mengirimkan laporan balik. Ketika transaksi yang dikirim memerlukan tindakan pengguna, webhook transaksi (transaction.created atau transaction.status.updated) menyertakan blok action_required yang sama, sehingga sistem Anda mengetahui tindakan yang tertunda meskipun aplikasi ditutup sebelum alur selesai.
Tindakan verification_session disertai status AWAITING_USER, tetapi tindakan wallet_ownership tidak mengubah status transaksi dengan sendirinya, jadi baca action_required alih-alih status.
Transisi Travel Rule juga mengirimkan travel_rule.status.updated.
Langkah berikutnya
Mengirim transaksi
API Create Transaction di sisi server dan referensi payload lengkap.
Travel Rule
Pertukaran pengirim-penerima terkelola, pengaturan, dan siklus hidupnya.
Widget kepemilikan dompet
Alur bukti kontrol yang di-hosting untuk tindakan wallet_ownership.
Webhook
transaction.created, transaction.status.updated, dan verifikasi tanda tangan.
Aturan
Tindakan aturan, termasuk yang membuat sesi verifikasi.
Status
Arti AWAITING_USER dalam siklus hidup transaksi.