> ## 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.

# Data Uji Sandbox Didit: Skenario, Nilai Ajaib & Dokumen

> Uji Didit di sandbox: skenario, nilai ajaib, endpoint arm, dokumen contoh, dan kode OTP untuk hasil yang deterministik tanpa PII atau penagihan.

Didit **sandbox** setara dengan kartu uji Stripe atau templat dokumen Sumsub: sandbox memungkinkan Anda mereproduksi hasil verifikasi apa pun secara deterministik, tanpa memanggil penyedia nyata, PII asli, atau saldo Anda.

> [!NOTE]
>
> Sumber kebenaran untuk data ini adalah `serialize_catalog()` di layanan verifikasi, yang disajikan secara langsung di `GET /v1/sandbox/scenarios/`. Salinan yang diuji agar tidak menyimpang dibuat di `docs/sandbox/SANDBOX_REFERENCE.md` di repo `service-didit-verification` melalui `pipenv run python scripts/generate_sandbox_reference.py`. Halaman ini mencerminkan referensi tersebut. Jika ada yang tampak usang, selalu percayai endpoint katalog langsung. Endpoint katalog memerlukan autentikasi: kirimkan kunci API Anda (`x-api-key`) seperti pada panggilan lainnya, atau token sesi jika Anda membacanya dari dalam sesi yang sedang berjalan.

## Model lingkungan

Sandbox adalah **mode per aplikasi** (`ApplicationDetail.mode == SANDBOX`), gagasan yang sama dengan mode pengujian Stripe. Selama sesi berjalan di bawah aplikasi sandbox:

* Setiap penyedia eksternal (OCR, AML, Pencocokan Wajah, liveness, NFC, telepon, email, IP, POA, Validasi Database, document AI) di-**simulasikan**; tidak ada pihak ketiga yang dipanggil.
* **Liveness berjalan persis seperti di lingkungan produksi.** Alur kerja liveness aktif menjalankan pengambilan aktif yang sesungguhnya di sandbox, baik dalam alur yang di-hosting maupun melalui handoff web dari SDK native, sehingga Anda dapat menguji pengalaman yang akan didapatkan pengguna Anda. Hanya *hasil* liveness yang disimulasikan, oleh skenario atau nilai khusus, dan laporan mencatat metode yang dikonfigurasi dalam alur kerja Anda.
* **Domain kustom hanya untuk produksi.** Aplikasi sandbox tidak dapat menambahkan [domain kustom](https://docs.didit.me/id/console/custom-domain.md); sesi sandbox selalu berjalan di domain verifikasi yang di-hosting bawaan.
* Sesi **tidak pernah ditagih** dan pemeriksaan saldo dilewati.
* Kuota per aplikasi sebesar **500 pembuatan sesi / 24 jam** diberlakukan.
* Webhook membawa `"environment": "sandbox"` (sesi produksi membawa `"environment": "live"`).
* Alur yang di-hosting menampilkan lingkungan sesi agar UI dapat memperingatkan pengguna untuk tidak mengunggah PII asli.
* **Hasil tidak pernah bergantung pada piksel**: data yang diekstrak dan status berasal dari skenario atau nilai khusus. Media yang diambil (dokumen, swafoto, video, file POA) benar-benar disimpan, sama seperti sesi produksi.

## Pemantauan Transaksi di sandbox

**Sandbox berbentuk sesi**: sandbox meniru penyedia yang dipanggil oleh sesi verifikasi. Pemantauan Transaksi tidak memiliki penyedia untuk ditiru, jadi aplikasi sandbox menggunakan jalur lain: transaksi disimpan, tetapi **tidak ada proses yang memutuskan, menyaring, memberi notifikasi, atau menagih atas transaksi tersebut**.

Transaksi yang dibuat pada aplikasi sandbox disimpan dan dikembalikan seperti biasa, dan tidak ada hal berikut yang terjadi padanya:

* **Tidak ada evaluasi aturan.** `rule_runs` kosong, apa pun mode aturan Anda. Aturan `ACTIVE` pada aplikasi sandbox tidak pernah terpicu, sehingga transaksi tetap `APPROVED` dengan skor `0` dan tidak ada alert atau kasus yang dibuka.
* **Tidak ada skrining AML / dompet.** `provider_results` kosong, bahkan untuk transaksi kripto pada aplikasi yang pemantauannya diaktifkan.
* **Tidak ada webhook.** Baik `transaction.created` maupun `transaction.status.updated` tidak dikirim untuk transaksi sandbox.
* **Tidak ada penagihan.** Sebuah event penggunaan dicatat dengan harga `0.0000`, dan saldo Anda tidak berubah.

Setiap respons transaksi memuat kolom `environment` (`"live"` atau `"sandbox"`), sehingga `rule_runs` yang kosong tidak pernah membingungkan: `"sandbox"` berarti aturan tidak dievaluasi, bukan berarti tidak ada yang cocok. Business Console menyampaikan hal yang sama pada kartu *Risk & decision* transaksi, alih-alih hanya menampilkan "No rules evaluated".

> [!NOTE]
>
> **Travel Rule adalah satu-satunya pengecualian dari "tidak ada yang berjalan".** Pada aplikasi dengan Travel Rule diaktifkan, transaksi sandbox `travelRule` tetap menjalankan mesin pertukaran: catatan transfer dibuat dan mengalami perubahan status.
> Yang tidak pernah dilakukan sandbox adalah berkomunikasi dengan pihak di luar Didit.
> Satu-satunya pihak lawan adalah [Didit Test VASP](https://docs.didit.me/id/transaction-monitoring/travel-rule-sandbox.md), yang sudah tersedia di dalam platform: tidak ada pesan kepatuhan yang sampai ke VASP pihak lawan yang sungguhan melalui jalur mana pun (`TRP`, keanggotaan jaringan yang Anda hubungkan, email, atau `INTERNAL`), pemeriksaan atribusi VASP pihak lawan dilewati, dan pembatalan tidak mengirim apa pun ke pihak lawan.
> Webhook `travel_rule.status.updated` tetap dikirim, dengan penanda `"environment": "sandbox"`.
>
> **Keluar** - transaksi `travelRule` yang Anda kirim.
> Pemeriksaan `threshold_amount` berjalan lebih dulu, dan di sandbox pemeriksaan ini hanya berlaku jika Anda mengirim `transaction_details.amount_in_default_currency`, karena sandbox tidak mengonversi mata uang. Tanpa kolom tersebut, setiap transfer sandbox dihitung di atas ambang batas.
> Transfer yang tidak dijawab kedaluwarsa setelah `confirmation_timeout_hours`, dan `timeout_outcome` Anda kemudian berlaku untuk transaksi tersebut.
> Di atas ambang batas, pemeriksaan dompet swakelola berlaku seperti biasa: transfer ke [dompet swakelola yang dideklarasikan](https://docs.didit.me/id/transaction-monitoring/travel-rule.md#dompet-swakelola-yang-dideklarasikan) masuk ke `UNCONFIRMED_OWNERSHIP` tanpa ada yang dikirim, dan Anda dapat menyelesaikannya di sandbox melalui [widget verifikasi kepemilikan dompet](https://docs.didit.me/id/transaction-monitoring/wallet-ownership-widget.md), atau melalui [konfirmasi kepemilikan](https://docs.didit.me/id/management-api/travel-rule/confirm-ownership.md) ketika dompet tujuan sudah ada di buku alamat dompet Anda.
> Transfer lain di atas ambang batas diteruskan ke Didit Test VASP melalui jalur `TEST_VASP`, yang menjawabnya di dalam Didit dengan skenario yang Anda pilih berdasarkan alamat dompet atau nama penerima: transfer selesai, ditolak, tidak cocok, menjadi `COUNTERPARTY_VASP_NOT_REACHABLE`, kedaluwarsa (`timeout_outcome` Anda kemudian berlaku untuk transaksi), atau menunggu kepemilikan dompet.
> Lihat [Uji Travel Rule di sandbox](https://docs.didit.me/id/transaction-monitoring/travel-rule-sandbox.md) untuk setiap skenario.
>
> **Masuk** - `POST /v3/travel-rule/inbound/`. Pendaftaran tidak pernah dikirim melalui jalur mana pun, jadi tidak ada yang disimulasikan di dalamnya: sandbox mencocokkan setoran dengan buku alamat dompet Anda dan menyelesaikannya secara sinkron, persis seperti pada live. Hasilnya selalu hasil nyata, bukan `AWAITING_COUNTERPARTY`: `ON_HOLD` (tidak ada kecocokan di buku alamat), `UNCONFIRMED_OWNERSHIP` (entri yang cocok belum terverifikasi kepemilikannya), `COUNTERPARTY_MISMATCHED_DATA` (nama penerima tidak sesuai dengan pemilik dompet), atau `COMPLETED` lalu `FINISHED` (cocok dengan entri yang sudah terverifikasi).
> Untuk menerima transfer dari Didit Test VASP, gunakan [Pemicu Transfer Masuk Test VASP](https://docs.didit.me/id/management-api/travel-rule/trigger-test-vasp-inbound.md) dengan salah satu dompet di buku alamat Anda sendiri.

### Skenario Test VASP Travel Rule

`travel_rule.scenarios` pada katalog mencantumkan skenario keluar ini. Atur nama penerima di bawah pada transaksi `travelRule` keluar setelah mengaktifkan Travel Rule pada aplikasi sandbox Anda. Pemeriksaan ambang batas dan dompet swakelola yang dideklarasikan, yang dijelaskan di atas, berjalan lebih dulu.

| Skenario | Nama penerima | Hasil |
| - | - | - |
| `accept` | `Didit Test VASP` | `COMPLETED` |
| `decline` | `Didit Test VASP Decline` | `COUNTERPARTY_VASP_GENERAL_DECLINE` |
| `name_mismatch` | `Didit Test VASP Name Mismatch` | `COUNTERPARTY_MISMATCHED_DATA` |
| `not_reachable` | `Didit Test VASP Not Reachable` | `COUNTERPARTY_VASP_NOT_REACHABLE` setelah beberapa kali percobaan ulang pengiriman |
| `timeout` | `Didit Test VASP Timeout` | `EXPIRED` saat pemeriksaan kedaluwarsa berjalan setelah batas waktu satu menit |
| `self_hosted` | `Didit Test VASP Self Hosted` | `UNCONFIRMED_OWNERSHIP` |

Anda juga dapat memilih skenario dengan alamat dompet penerima sebagai ganti nama (alamat dompet yang diutamakan jika keduanya diisi), dan transfer yang tidak menyebutkan keduanya akan selesai sebagai `accept`. [Uji Travel Rule di sandbox](https://docs.didit.me/id/transaction-monitoring/travel-rule-sandbox.md) mencantumkan dompet setiap skenario beserta hasil persisnya.

[Pemicu Test VASP masuk](https://docs.didit.me/id/management-api/travel-rule/trigger-test-vasp-inbound.md) hanya menerima `accept` dan `name_mismatch` pada kolom `scenario`-nya.

> [!NOTE]
>
> **Cara menguji aturan sebelum diterapkan di produksi.** Gunakan
> [Backtest](https://docs.didit.me/id/transaction-monitoring/rules-api.md#buat-backtest-aktifkan): fitur ini memutar ulang
> aturan terhadap riwayat transaksi Anda yang sebenarnya dan melaporkan `evaluated` /
> `matched` / `affected_entities` tanpa mengubah status transaksi mana pun. Kombinasikan
> dengan mode `TEST` pada aplikasi produksi: aturan `TEST` dievaluasi pada setiap transaksi live baru dan mencatat apa yang akan dicocokkannya, tanpa mengubah skor atau status, lalu beralih ke `ACTIVE` setelah selektivitasnya dirasa tepat.

## Cara beralih antara live dan sandbox

Live dan sandbox adalah **aplikasi terpisah**, sehingga trafik pengujian dan data produksi tidak pernah tercampur. Setiap aplikasi memiliki `mode` berupa `live` atau `sandbox`:

* Gunakan kunci API dari aplikasi **mode sandbox** untuk mendapatkan sesi tiruan yang tidak ditagih dan dapat disimulasikan.
* Gunakan kunci API dari aplikasi **mode live** untuk verifikasi sungguhan.

Kolom `sandbox_scenario` (pada pembuatan sesi dan pada API AML mandiri) serta endpoint simulasi hanya diterima pada aplikasi sandbox. Keduanya ditolak pada aplikasi live.

## Sandbox dalam alur verifikasi yang di-hosting

Sesi yang dibuat di bawah aplikasi sandbox menampilkan UI tambahan dalam alur verifikasi yang di-hosting (`url` yang dikembalikan oleh `POST /v3/session/`):

* **Banner sandbox di dalam kartu.** Setiap layar menampilkan banner di dalam kartu - "Hanya data uji - tidak ada panggilan nyata". Dengan demikian, selalu jelas bahwa sesi tidak pernah memanggil penyedia sungguhan dan tidak pernah menyentuh saldo Anda. Media yang ditangkap disimpan seperti sesi lainnya, jadi gunakan dokumen contoh dan data uji, bukan dokumen identitas asli atau informasi pribadi.
* **Pemilih skenario sebelum alur.** Sebelum pengambilan dimulai, pemilih di dalam kartu memandu pengguna memilih hasil uji: pilih hasil, lalu pilih pemicu untuk hasil tersebut. Konfirmasi memanggil `POST /v3/session/{session_id}/sandbox/arm/` (lihat [Mengaktifkan (atau mengaktifkan ulang) sesi sebelum alur dimulai](#3-aktifkan-atau-aktifkan-ulang-sesi-sebelum-alur-dimulai) di bawah), lalu melanjutkan ke alur dengan nilai khusus dari skenario tersebut sudah diterapkan.
* **Strip dokumen contoh.** Satu baris dokumen contoh sandbox (hingga 3) berada tepat di bawah komponen pengunggahan dan pengambilan dokumen. Ketuk salah satu untuk menggunakannya sebagai pengganti unggahan asli.

Sesi sandbox menyimpan media **asli** yang ditangkap: dokumen, swafoto, video liveness, dan file bukti alamat diunggah dan disimpan persis seperti pada sesi live. Data *yang diekstrak* (kolom verifikasi identitas, skor pencocokan wajah, hasil liveness, dan sejenisnya) serta hasil sesi itu sendiri (Disetujui / Dalam Peninjauan / Ditolak) disimulasikan oleh skenario atau nilai khusus, dan tidak pernah berasal dari media yang ditangkap. Business Console menandai bagian data yang diekstrak pada sesi sandbox dengan chip **Data simulasi**, sehingga peninjau dapat melihat sekilas bagian mana dari sesi yang merupakan tangkapan asli dan bagian mana yang digerakkan oleh skenario.

## Scenarios

Setiap skenario adalah kumpulan nilai khusus yang diberi nama. Teruskan slug-nya sebagai `sandbox_scenario` saat membuat sesi (atau ke endpoint simulasi) untuk mereproduksi hasilnya.

| Slug | Judul | Status default | Deskripsi |
| - | - | - | - |
| `approve` | Jalur ideal: semua fitur disetujui | Disetujui | Perilaku default sandbox: setiap fitur mock mengembalikan hasil APPROVED yang bersih. Status sesi berakhir sebagai APPROVED. |
| `decline_aml_hit` | AML: Politically Exposed Person (PEP) | Ditolak | Mock AML mengembalikan satu hit dan sesi ditolak pada fitur AML. Hit menggunakan [skema Hit](https://docs.didit.me/id/core-technology/aml-screening/report-aml-screening.md#kolom-per-hit) yang sama dengan penyedia AML produksi: `url`, `match_score`, `risk_score`, `review_status`, `properties`, `pep_matches[]`, dan `score_breakdown` semuanya terisi, dan Log peringatan POSSIBLE\_MATCH\_FOUND ditulis. |
| `decline_document_expired` | Verifikasi identitas: dokumen kedaluwarsa | Ditolak | Mock verifikasi identitas mengembalikan paspor dengan tanggal kedaluwarsa yang sudah lewat. Sesi ditolak pada verifikasi identitas dengan Log peringatan DOCUMENT\_EXPIRED. |
| `decline_minimum_age` | Verifikasi identitas: di bawah usia minimum sesuai kebijakan | Ditolak | Mock verifikasi identitas mengembalikan tanggal lahir yang membuat pengguna berusia sekitar 10 tahun. Pemeriksaan usia produksi mengeluarkan MINIMUM\_AGE\_NOT\_MET dan alur kerja menolak. |
| `decline_mrz_validation` | Verifikasi identitas: kegagalan checksum MRZ | Ditolak | Mock verifikasi identitas mengembalikan paspor dengan checksum MRZ yang rusak. Validator MRZ produksi mengeluarkan MRZ\_VALIDATION\_FAILED dan sesi ditolak. |
| `decline_could_not_recognize_document` | Verifikasi identitas: dokumen tidak terbaca | Ditolak | Mock verifikasi identitas mengembalikan respons kosong. Produksi memunculkan COULD\_NOT\_RECOGNIZE\_DOCUMENT dan meneruskannya ke SDK. |
| `decline_face_match_low_similarity` | Pencocokan wajah: kemiripan di bawah ambang penolakan | Ditolak | Mock pencocokan wajah mengembalikan skor rendah. Produksi mengeluarkan LOW\_FACE\_MATCH\_SIMILARITY dan pemetaan tindakan node alur kerja menolak. |
| `decline_database_no_match` | Validasi database: tidak ada kecocokan di semua layanan | Ditolak | Setiap layanan database yang dipilih mengembalikan NO\_MATCH. Produksi mengeluarkan DATABASE\_VALIDATION\_NO\_MATCH dan alur kerja menolak. |
| `decline_phone_high_risk` | Telepon: nomor uji berisiko tinggi yang dicadangkan | Ditolak | Mock verifikasi telepon memblokir verifikasi (rentang uji yang dicadangkan). Verifikasi telepon berakhir sebagai BLOCKED dan mengeluarkan HIGH\_RISK\_PHONE\_NUMBER. |
| `decline_email_breach` | Email: hit dari database kebocoran | Ditolak | Mock kebocoran email mengembalikan satu hit kebocoran pada alamat tersebut. Verifikasi email mengeluarkan BREACHED\_EMAIL\_DETECTED. |
| `decline_ip_blocklist` | Analisis IP: alamat ada dalam daftar blokir | Ditolak | Mock analisis IP menolak lokasi dengan IP\_ADDRESS\_IN\_BLOCKLIST. Sesi ditolak pada analisis IP. |
| `decline_poa_address_mismatch` | POA: alamat tidak sesuai dengan yang diberikan | Ditolak | Mock POA menolak bukti alamat dengan ADDRESS\_MISMATCH\_WITH\_PROVIDED. Sesi ditolak pada POA. |
| `decline_liveness_attack` | Liveness: serangan wajah terdeteksi | Ditolak | Mock liveness pasif mendeteksi sinyal serangan wajah dan mengeluarkan LIVENESS\_FACE\_ATTACK. Sesi ditolak pada liveness. |
| `decline_nfc_chip_not_verified` | NFC: chip ePassport tidak terverifikasi | Ditolak | Mock ePassport mengembalikan chip yang tanda tangan SOD/DG-nya gagal pemeriksaan integritas. Produksi mengeluarkan NFC\_CHIP\_NOT\_VERIFIED dan sesi ditolak pada NFC saat alur kerja menolak chip yang tidak terverifikasi. |
| `decline_nfc_trust_anchor_missing` | NFC: jangkar kepercayaan penerbit tidak tersedia | Ditolak | Mock ePassport mengembalikan chip yang ditandatangani oleh DSC yang CSCA penerbitnya tidak ada di penyimpanan kepercayaan. Produksi mengeluarkan NFC\_TRUST\_ANCHOR\_MISSING dan sesi ditolak saat alur kerja menolak chip yang tidak terverifikasi. |
| `decline_document_ai_unreadable` | Document AI: dokumen tidak terbaca | Ditolak | Mock Document AI tidak mengembalikan kolom yang dapat dibaca. Produksi mengeluarkan DOCUMENT\_AI\_UNREADABLE\_DOCUMENT dan status dokumen menjadi ditolak setelah anggaran percobaan ulang habis. |
| `review_aml_possible_match` | AML: kemungkinan kecocokan perlu ditinjau | Dalam peninjauan | Mock AML mengembalikan hit dengan keyakinan lebih rendah. Sesi berstatus Dalam peninjauan dengan Log peringatan POSSIBLE\_MATCH\_FOUND untuk diselesaikan oleh analis. |
| `review_face_match_borderline` | Pencocokan wajah: kemiripan di ambang batas | Dalam peninjauan | Mock pencocokan wajah mengembalikan skor di antara ambang peninjauan dan ambang penolakan. Sesi berstatus Dalam peninjauan pada pencocokan wajah. |
| `review_document_borderline_age` | Verifikasi identitas: usia di bawah batas, dikirim ke peninjauan | Dalam peninjauan | Mock verifikasi identitas mengembalikan tanggal lahir di bawah usia minimum yang dikonfigurasi alur kerja. minimum\_age\_action alur kerja diatur ke REVIEW, bukan DECLINE, sehingga sesi berstatus Dalam peninjauan pada verifikasi identitas alih-alih ditolak. |
| `review_poa_partial_match` | POA: kecocokan alamat sebagian | Dalam peninjauan | Mock POA mengembalikan alamat yang hanya cocok sebagian dengan alamat yang diberikan. Sesi berstatus Dalam peninjauan pada bukti alamat. |
| `review_database_partial_match` | Validasi database: kecocokan sebagian | Dalam peninjauan | Layanan database mengembalikan kecocokan sebagian pada nama dan tanggal lahir. Sesi berstatus Dalam peninjauan pada validasi database. |
| `decline_kyb_registry_mismatch` | KYB: data registri tidak cocok | Ditolak | Mock registri mengembalikan perusahaan yang data registrasinya tidak cocok dengan detail yang diharapkan. Sesi bisnis ditolak pada pemeriksaan registri. |
| `review_kyb_registry_partial` | KYB: data registri cocok sebagian | Dalam peninjauan | Mock registri mengembalikan perusahaan yang namanya hanya cocok sebagian. Sesi bisnis berstatus Dalam peninjauan pada pemeriksaan registri. |

Skenario `review_*` ada agar Anda dapat menguji UX peninjauan manual (antrean peninjauan di konsol, webhook `In Review`, dan tindakan persetujuan/penolakan oleh peninjau) tanpa memerlukan input yang menghasilkan penolakan. Dua skenario `kyb_*` di atas mengatur `expected_details.registration_number` alih-alih `expected_details.first_name`: keduanya hanya berlaku untuk sesi Verifikasi Bisnis (KYB).

## Nilai magic

Nilai magic adalah input spesifik yang membuat satu fitur tiruan menghasilkan risiko tertentu. Atur kolom input ke nilai magic (langsung, atau melalui skenario) untuk memicunya.

| Fitur | Kolom input | Nilai magic | Risiko | Deskripsi |
| - | - | - | - | - |
| AML | `user_email` | `sandbox+aml_hit@didit.test` | `POSSIBLE_MATCH_FOUND` | AML: Politically Exposed Person (PEP); AML tiruan mengembalikan satu hasil kecocokan, sesi ditolak pada AML. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_DOCUMENT_EXPIRED` | `DOCUMENT_EXPIRED` | OCR: dokumen kedaluwarsa; sesi ditolak pada verifikasi identitas. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_MINIMUM_AGE_NOT_MET` | `MINIMUM_AGE_NOT_MET` | OCR: tanggal lahir menunjukkan bahwa pengguna berusia di bawah usia minimum yang dikonfigurasi; sesi ditolak. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_MAXIMUM_AGE_EXCEEDED` | `MAXIMUM_AGE_EXCEEDED` | OCR: DOB yang diekstrak melebihi kebijakan usia maksimum yang dikonfigurasi. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_DOCUMENT_NUMBER_FORMAT_MISMATCH` | `DOCUMENT_NUMBER_FORMAT_MISMATCH` | OCR: nomor dokumen yang diekstrak tidak sesuai dengan regex format dokumen yang diharapkan dari registri dokumen. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_PERSONAL_NUMBER_FORMAT_MISMATCH` | `PERSONAL_NUMBER_FORMAT_MISMATCH` | OCR: nomor pribadi yang diekstrak gagal pemeriksaan format registri dokumen. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_DOCUMENT_NOT_SUPPORTED_FOR_APPLICATION` | `DOCUMENT_NOT_SUPPORTED_FOR_APPLICATION` | OCR: jenis dokumen yang diekstrak berada di luar kebijakan `documents_allowed` aplikasi. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_FULL_NAME_MISMATCH_WITH_PROVIDED` | `FULL_NAME_MISMATCH_WITH_PROVIDED` | OCR: nama pada dokumen tidak cocok dengan nama yang sebelumnya diisi pelanggan di `expected_details`; ketidakcocokannya melebihi ambang batas pencocokan nama. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_GENDER_MISMATCH_WITH_PROVIDED` | `GENDER_MISMATCH_WITH_PROVIDED` | OCR: gender yang diekstrak tidak sesuai dengan `expected_details.gender`. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_DOB_MISMATCH_WITH_PROVIDED` | `DOB_MISMATCH_WITH_PROVIDED` | OCR: tanggal lahir yang diekstrak tidak sesuai dengan `expected_details.date_of_birth`. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_COUNTRY_MISMATCH_WITH_PROVIDED` | `COUNTRY_MISMATCH_WITH_PROVIDED` | OCR: negara penerbit tidak sesuai dengan `expected_details.country` (atau `id_country`). |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_NATIONALITY_MISMATCH_WITH_PROVIDED` | `NATIONALITY_MISMATCH_WITH_PROVIDED` | OCR: kewarganegaraan yang diekstrak tidak sesuai dengan `expected_details.nationality`. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_IDENTIFICATION_NUMBER_MISMATCH_WITH_PROVIDED` | `IDENTIFICATION_NUMBER_MISMATCH_WITH_PROVIDED` | OCR: nomor dokumen, nomor pribadi, atau nomor pajak yang diekstrak tidak sesuai dengan `expected_details.identification_number`. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_COULD_NOT_RECOGNIZE_DOCUMENT` | `COULD_NOT_RECOGNIZE_DOCUMENT` | OCR: pipeline mengembalikan hasil kosong atau tidak dapat dikenali; produksi memunculkan COULD\_NOT\_RECOGNIZE\_DOCUMENT. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_MRZ_NOT_DETECTED` | `MRZ_NOT_DETECTED` | OCR: dokumen memerlukan MRZ, tetapi pipeline tidak dapat menemukannya. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_MRZ_VALIDATION_FAILED` | `MRZ_VALIDATION_FAILED` | OCR: MRZ ditemukan, tetapi gagal validasi checksum atau format. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_MRZ_AND_DATA_EXTRACTED_FROM_OCR_NOT_SAME` | `MRZ_AND_DATA_EXTRACTED_FROM_OCR_NOT_SAME` | OCR: kolom identitas MRZ tidak sama dengan kolom yang diekstrak dari VIZ. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_BARCODE_NOT_DETECTED` | `BARCODE_NOT_DETECTED` | OCR: dokumen memerlukan barcode, tetapi tidak ditemukan. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_BARCODE_VALIDATION_FAILED` | `BARCODE_VALIDATION_FAILED` | OCR: barcode berhasil didekode, tetapi gagal validasi lintas kolom. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_QR_NOT_DETECTED` | `QR_NOT_DETECTED` | OCR: dokumen memerlukan kode QR, tetapi tidak ditemukan. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_QR_VALIDATION_FAILED` | `QR_VALIDATION_FAILED` | OCR: kode QR berhasil didekode, tetapi gagal validasi lintas kolom. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_DATA_INCONSISTENT` | `DATA_INCONSISTENT` | OCR: pemeriksaan konsistensi internal pada kolom VIZ menunjukkan adanya ketidaksesuaian. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_DOCUMENT_SIDES_MISMATCH` | `DOCUMENT_SIDES_MISMATCH` | OCR: document\_name pada sisi depan dan sisi belakang tidak berpasangan sebagai dokumen yang sama. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_NAME_NOT_DETECTED` | `NAME_NOT_DETECTED` | OCR: nama depan maupun nama belakang tidak dapat diekstrak dari dokumen. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_DATE_OF_BIRTH_NOT_DETECTED` | `DATE_OF_BIRTH_NOT_DETECTED` | OCR: kelas dokumen memerlukan DOB, tetapi ekstraksi tidak menghasilkan apa pun. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_EXPIRATION_DATE_NOT_DETECTED` | `EXPIRATION_DATE_NOT_DETECTED` | OCR: kelas dokumen memerlukan tanggal kedaluwarsa, tetapi ekstraksi tidak menghasilkan apa pun. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_DOCUMENT_NUMBER_NOT_DETECTED` | `DOCUMENT_NUMBER_NOT_DETECTED` | OCR: nomor dokumen maupun nomor pribadi tidak dapat diekstrak. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_COULD_NOT_DETECT_DOCUMENT_TYPE` | `COULD_NOT_DETECT_DOCUMENT_TYPE` | OCR: pengklasifikasi tidak dapat memetakan hasil tangkapan ke jenis dokumen yang didukung. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_PORTRAIT_IMAGE_NOT_DETECTED` | `PORTRAIT_IMAGE_NOT_DETECTED` | OCR: pipeline tidak dapat mengisolasi area potret pada dokumen. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_UNPARSED_ADDRESS` | `UNPARSED_ADDRESS` | OCR: dokumen memiliki kolom alamat, tetapi geocoding / parsing tidak menghasilkan data yang dapat digunakan. |
| DATABASE\_VALIDATION | `expected_details.first_name` | `SANDBOX_DB_NO_MATCH` | `DATABASE_VALIDATION_NO_MATCH` | Validasi database: setiap layanan pemerintah/registri mengembalikan NO\_MATCH; sesi ditolak pada validasi database. |
| FACEMATCH | `expected_details.first_name` | `SANDBOX_FACE_LOW_MATCH` | `LOW_FACE_MATCH_SIMILARITY` | Pencocokan wajah: skor kemiripan berada di bawah ambang batas penolakan; sesi ditolak pada pencocokan wajah. |
| PHONE | `phone_number` | `+15005550009` | `HIGH_RISK_PHONE_NUMBER` | Telepon: nomor uji khusus yang tidak dapat dikirimkan atau berisiko tinggi; mock verifikasi telepon mengembalikan kegagalan. |
| EMAIL | `user_email` | `sandbox+breach@didit.test` | `BREACHED_EMAIL_DETECTED` | Email: basis data kebocoran mengembalikan kecocokan untuk alamat ini. |
| LOCATION | `expected_details.first_name` | `SANDBOX_IP_BLOCKLIST` | `IP_ADDRESS_IN_BLOCKLIST` | Analisis IP: IP pemanggil terdaftar dalam daftar blokir aplikasi; sesi ditolak pada analisis IP. |
| PROOF\_OF\_ADDRESS | `expected_details.first_name` | `SANDBOX_POA_ADDRESS_MISMATCH` | `ADDRESS_MISMATCH_WITH_PROVIDED` | POA: alamat pada dokumen yang diunggah tidak sesuai dengan alamat yang sudah diisi pelanggan di `expected_details`; sesi ditolak pada POA. |
| LIVENESS | `expected_details.first_name` | `SANDBOX_LIVENESS_ATTACK` | `LIVENESS_FACE_ATTACK` | Liveness: mock liveness pasif mendeteksi sinyal serangan wajah; sesi ditolak pada liveness. |
| NFC | `expected_details.first_name` | `SANDBOX_NFC_CHIP_NOT_VERIFIED` | `NFC_CHIP_NOT_VERIFIED` | NFC: mock e-paspor mengembalikan chip yang tanda tangan SOD/DG-nya gagal pemeriksaan integritas; produksi mengeluarkan NFC\_CHIP\_NOT\_VERIFIED dan menolak ketika alur kerja menolak chip yang tidak terverifikasi. |
| NFC | `expected_details.first_name` | `SANDBOX_NFC_TRUST_ANCHOR_MISSING` | `NFC_TRUST_ANCHOR_MISSING` | NFC: DSC terhubung ke CSCA yang tidak ada di penyimpanan kepercayaan; produksi mengeluarkan NFC\_TRUST\_ANCHOR\_MISSING dan menerapkan tindakan chip tidak terverifikasi yang dikonfigurasi. |
| DOCUMENT\_AI | `expected_details.first_name` | `SANDBOX_DOCUMENT_AI_UNREADABLE` | `DOCUMENT_AI_UNREADABLE_DOCUMENT` | Document AI: ekstraksi tidak menghasilkan kolom yang dapat dibaca; produksi mengeluarkan DOCUMENT\_AI\_UNREADABLE\_DOCUMENT dan dokumen berstatus ditolak setelah batas percobaan ulang habis. |
| AML | `user_email` | `sandbox+aml_review@didit.test` | `POSSIBLE_MATCH_FOUND` | AML: kemungkinan kecocokan yang perlu diselesaikan secara manual; sesi berakhir dalam peninjauan. |
| FACEMATCH | `expected_details.first_name` | `SANDBOX_FACE_BORDERLINE_MATCH` | `LOW_FACE_MATCH_SIMILARITY` | Pencocokan wajah: kemiripan berada di batas antara ambang peninjauan dan ambang penolakan; sesi berakhir dalam peninjauan. |
| ID\_VERIFICATION | `expected_details.first_name` | `SANDBOX_OCR_BORDERLINE_AGE` | `MINIMUM_AGE_NOT_MET` | OCR: tanggal lahir berada di bawah usia minimum, tetapi alur kerja meninjau kegagalan usia minimum alih-alih menolaknya; sesi berakhir dalam peninjauan. |
| DATABASE\_VALIDATION | `expected_details.first_name` | `SANDBOX_DB_PARTIAL_MATCH` | `DATABASE_VALIDATION_PARTIAL_MATCH` | Validasi database: identitas cocok, tetapi nama/tanggal lahir hanya cocok sebagian; sesi berakhir dalam peninjauan. |
| PROOF\_OF\_ADDRESS | `expected_details.first_name` | `SANDBOX_POA_PARTIAL_MATCH` | `ADDRESS_MISMATCH_WITH_PROVIDED` | POA: alamat pada dokumen yang diunggah cocok sebagian dengan alamat yang diberikan; sesi berakhir dalam peninjauan. |
| KYB\_REGISTRY | `expected_details.registration_number` | `SANDBOX-KYB-MISMATCH` | `KYB_REGISTRY_DATA_MISMATCH_WITH_EXPECTED` | KYB: data perusahaan di registri tidak sesuai dengan detail yang diharapkan; sesi ditolak. |
| KYB\_REGISTRY | `expected_details.registration_number` | `SANDBOX-KYB-REVIEW` | `KYB_REGISTRY_DATA_PARTIAL_MATCH_WITH_EXPECTED` | KYB: data perusahaan di registri cocok sebagian dengan detail yang diharapkan; sesi berakhir dalam peninjauan. |

## Pencarian non-dokumen dan dompet identitas

Aplikasi sandbox dapat mengaktifkan setiap dompet identitas dalam katalog negara, termasuk dompet yang tidak tersedia di aplikasi produksi.
Skenario default `approve` mensimulasikan identitas yang terverifikasi tanpa masuk ke dompet eksternal.
Hasilnya disimpan dalam sesi dan mengikuti langkah berikutnya yang normal dari alur kerja.
Sandbox tidak memvalidasi kredensial dompet yang sebenarnya dan tidak menagih percobaan yang disimulasikan.

Permintaan pencarian tetap memvalidasi kolom yang dimasukkan dan menggunakan batas percobaan yang dikonfigurasi, yang secara default adalah satu.
Gunakan skenario berikut untuk menguji aturan coba lagi dan fallback:

| Skenario | Hasil simulasi |
| - | - |
| `lookup_partial_match` | Kecocokan parsial di registri; dihitung terhadap batas percobaan. |
| `lookup_no_match` | Registri menjawab tanpa kecocokan; dihitung terhadap batas percobaan. |
| `lookup_provider_error` | Registri tidak memberikan jawaban; pengguna diminta mencoba lagi, dan setelah tiga kali percobaan tanpa jawaban, fallback kesalahan penyedia diterapkan. |
| `wallet_cancelled` | Pengguna membatalkan masuk ke dompet. |
| `wallet_timeout` | Proses masuk ke dompet kedaluwarsa. |
| `wallet_provider_error` | Proses masuk ke dompet tidak dapat diselesaikan. |

Kegagalan dompet mengikuti pengaturan negara untuk beralih ke pengambilan dokumen atau menolak.
Percobaan pencarian yang selesai dicatat secara terpisah, sehingga dua percobaan yang diizinkan menghasilkan dua hasil sebelum fallback.
Semua penggunaan sandbox tetap gratis.

## Pemeriksaan rekening Bank Verification

Langkah Verifikasi Bank sandbox menawarkan [kedua metode](https://docs.didit.me/id/core-technology/bank-verification/verification-methods.md) di setiap negara, sesuai urutan yang ditetapkan langkah tersebut, pada layanan simulasi tanpa bank dan tanpa biaya.
Dengan urutan default, pengguna memulai dengan masuk ke akun bank dan memilih **Masukkan detail rekening Anda** untuk menjalankan [pemeriksaan rekening](https://docs.didit.me/id/core-technology/bank-verification/account-check.md); atur `bank_method_order` ke `["account_lookup", "open_banking"]` untuk memulai dari pemeriksaan rekening.
Empat karakter terakhir nomor rekening yang diketik menentukan jawabannya; lihat [Uji di sandbox](https://docs.didit.me/id/core-technology/bank-verification/account-check.md#uji-di-sandbox) untuk setiap akhiran dan rekening yang valid untuk setiap format.
[API pemeriksaan rekening](https://docs.didit.me/id/standalone-apis/bank-account-check.md) merespons kunci sandbox dengan akhiran yang sama.

## Dokumen sampel

> [!WARNING]
>
> Jangan pernah mengunggah dokumen identitas asli di sandbox. Gunakan dokumen sampel bawaan sebagai gantinya.

Alur yang di-hosting menyediakan tiga dokumen sampel, masing-masing untuk satu jenis dokumen:

| Negara | Jenis dokumen |
| - | - |
| Spanyol | Kartu identitas nasional |
| Argentina | Paspor |
| Polandia | Lisensi mengemudi |

Ketuk sampel pada bilah sampel untuk menggunakannya sebagai ganti pengambilan asli. Data yang diekstrak dan hasil sesi selalu berasal dari skenario atau nilai khusus yang dipilih, sehingga sampel apa pun dapat digunakan dengan skenario apa pun.

## Identitas sampel: menguji `expected_details`

Setiap dokumen sandbox dibuat secara palsu dari satu **identitas tetap**.
Nilai yang diekstrak sama di setiap sesi dan tidak pernah diturunkan dari tanggal saat ini, sehingga Anda dapat mengisi awal `expected_details` dengan nilai tersebut dan memeriksa penanganan perbandingan kolom serta peringatan secara menyeluruh.
Kirimkan nilai di bawah ini dan pemeriksaan perbandingan akan lolos; kirimkan nilai lain dan peringatan `*_MISMATCH_WITH_PROVIDED` yang sesuai akan muncul dengan sengaja.

Tanggal berikut sama untuk setiap dokumen sampel:

| Kolom | Nilai |
| - | - |
| `date_of_birth` | `1990-06-15` |
| Tanggal penerbitan | `2025-06-15` |
| Tanggal kedaluwarsa | `2035-06-15` |

Identitas lainnya bergantung pada dokumen yang Anda gunakan:

| `sandbox_sample` | Dokumen | `first_name` | `last_name` | `gender` | `nationality` | `id_country` | `identification_number` |
| - | - | - | - | - | - | - | - |
| *(default, tidak ada sampel yang dipilih)* | ePassport Brasil | `GUSTAVO` | `MATSUMOTO` | `M` | `BRA` | `BRA` | `YC531181` |
| `spain-id-card-2021` | Kartu identitas nasional Spanyol | `CARMEN` | `ESPAÑOLA ESPAÑOLA` | `F` | `ESP` | `ESP` | `CAA000000` |
| `argentina-passport-2009` | Paspor Argentina | `MARIA VICTORIA` | `VILLAREAL` | `F` | `ARG` | `ARG` | `AAF794880` |
| `poland-driving-license-2019` | Lisensi mengemudi Polandia | `JAN` | `KOWALSKI` | tidak ada di dokumen ini | `POL` | `POL` | `SP005/89/5` |

```json theme={null}
{
  "workflow_id": "<your-workflow-uuid>",
  "expected_details": {
    "date_of_birth": "1990-06-15",
    "gender": "M",
    "nationality": "BRA",
    "identification_number": "YC531181"
  }
}
```

`first_name` dan `last_name` adalah pengecualian: sandbox menyalin nama yang Anda kirim di `expected_details` ke dokumen yang dibuat, sehingga pencocokan nama lolos dengan nama apa pun.
Gunakan nilai khusus `SANDBOX_OCR_FULL_NAME_MISMATCH_WITH_PROVIDED` untuk menguji ketidakcocokan nama, dan `SANDBOX_OCR_DOB_MISMATCH_WITH_PROVIDED` untuk ketidakcocokan tanggal lahir.

> [!NOTE]
>
> Jika alur kerja Anda membatasi `documents_allowed` ke negara atau jenis dokumen yang tidak mencakup ePassport Brasil, sandbox akan membuat dokumen palsu dari negara yang diizinkan pertama, sehingga `nationality`, `id_country`, dan nama dokumen mengikuti negara tersebut. Tanggal di atas tetap sama.

### Yang tidak dimiliki dokumen palsu

Dokumen palsu adalah templat generik untuk negara dan jenis dokumen yang diizinkan, sehingga kolom yang hanya disediakan oleh dokumen asli yang diterbitkan negara tetap kosong. Yang paling penting untuk perutean adalah **wilayah / negara bagian AS** (`kyc.region`): lisensi mengemudi atau kartu identitas AS palsu tidak memiliki negara bagian, sehingga kondisi cabang seperti `Region equals IL` tidak akan pernah cocok di sandbox. Jika tidak ada cabang lain yang cocok, alur akan mengambil cabang cadangan node tersebut (cabang tanpa kondisi). Ini bukan peninjauan atau kegagalan cabang; kondisinya memang tidak memiliki data untuk dibaca. Kolom yang hilang juga membuat `not equals` dan `not in` gagal; lihat [cara kondisi cabang membaca data sesi](https://docs.didit.me/id/console/workflows.md#cara-kondisi-cabang-membaca-data-sesi) untuk perbedaan antara kolom yang hilang dan string kosong.

Untuk menguji alur yang bergantung pada negara bagian di sandbox, tentukan keputusan dari nilai yang Anda kendalikan pada sesi, bukan dari dokumen:

* Kirim negara bagian di `metadata` saat Anda membuat sesi (misalnya `"metadata": {"credential_state": "IL"}`) dan buat cabang berdasarkan `metadata.credential_state`. Metadata dievaluasi di sandbox persis seperti di produksi.
* Pertahankan kondisi `kyc.region` yang berasal dari dokumen untuk lalu lintas produksi jika Anda juga membutuhkan dokumen untuk membuktikan negara bagian; dalam mode produksi, wilayah dibaca dari dokumen asli.

Semua hal lain tentang perutean sama dengan produksi: grafik alur kerja, kondisi cabang, nilai `metadata` dan `expected_details`, node tindakan, serta node status benar-benar dijalankan. Sandbox tidak pernah memaksa sesi masuk ke peninjauan dengan sendirinya. Sesi sandbox hanya berstatus Dalam peninjauan ketika alur kerja mengarahkannya ke sana (skenario `review_*`, nilai khusus yang dipetakan ke tindakan peninjauan, atau node status dalam grafik).

## Kode OTP dan opt-in email

* **OTP telepon:** pemeriksaan telepon di sandbox menerima kode apa pun dengan format yang benar (4-8 digit; termasuk `123456`). Input dengan format yang salah tetap mengembalikan `400`.
* **OTP email:** pemeriksaan email di sandbox menerima kode apa pun dengan format yang benar (termasuk `123456`). Input dengan format yang salah tetap mengembalikan `400`.

Secara default, sesi sandbox **tidak** mengirim email (alert peninjauan, perubahan status, OTP, pengiriman ulang, tautan sesi baru, dll.). Untuk tetap mengirim email, gunakan salah satu pola opt-in berikut pada alamat penerima:

| Pola opt-in | Contoh |
| - | - |
| `<local>+sandbox@<domain>` | `alice+sandbox@example.com` |
| `*@didit.test` | `alice@didit.test` |

## Mengendalikan hasil: skenario, nilai ajaib, pengaktifan, dan endpoint simulasi

Ada lima cara untuk mengendalikan hasil sandbox.

### 1. `sandbox_scenario` saat membuat sesi

Atur slug skenario saat membuat sesi (`POST /v3/session/`). Alur pembuatan sesi akan memperluas nilai ajaib yang terikat pada skenario ke dalam kolom input sesi, sehingga penyedia tiruan menghasilkan hasil yang dimaksud melalui alur kerja nyata.

```json theme={null}
{
  "workflow_id": "<your-workflow-uuid>",
  "sandbox_scenario": "decline_document_expired"
}
```

### 2. Nilai ajaib yang diketik secara manual

Atur sendiri kolom input (misalnya `expected_details.first_name = "SANDBOX_OCR_DOCUMENT_EXPIRED"`, atau `user_email = "sandbox+aml_hit@didit.test"`). Lihat tabel nilai ajaib di atas untuk daftar lengkapnya.

### 3. Aktifkan (atau aktifkan ulang) sesi sebelum alur dimulai

Atur atau ganti skenario yang diaktifkan pada sesi yang sudah ada, selama sesi belum melewati `Not Started`. Ini adalah endpoint yang dipanggil oleh [pemilih skenario sebelum alur](#sandbox-dalam-alur-verifikasi-yang-di-hosting), dan Anda juga dapat memanggilnya sendiri untuk membuat pemilih kustom atau kerangka pengujian:

```
POST /v3/session/{session_id}/sandbox/arm/
Session-Token: <session_token>
```

```json theme={null}
{
  "scenario": "decline_document_expired"
}
```

Respons 200:

```json theme={null}
{
  "session_id": "<session_id>",
  "scenario": "decline_document_expired",
  "status": "Not Started"
}
```

* Lakukan autentikasi dengan `Session-Token` milik sesi itu sendiri (dikembalikan sebagai `session_token` saat pembuatan sesi), bukan kunci API aplikasi Anda: endpoint ini ditujukan untuk sisi klien.
* Mengembalikan `400` untuk slug skenario yang tidak dikenal, dan `400` setelah sesi melewati `Not Started` (`"Scenario can only be armed before the verification starts."`).
* Mengembalikan `404` ketika `Session-Token` milik aplikasi produksi (bukan sandbox), atau tidak cocok dengan `session_id` di path.
* **Mengaktifkan ulang menggantikan skenario sebelumnya.** Hanya nilai ajaib yang ditulis skenario sebelumnya yang dihapus, dan apa pun yang sudah diketik pengguna secara manual (email, nama depan, dll.) tetap tidak berubah. Contoh: aktifkan `decline_phone_high_risk`, lalu aktifkan `approve`. Nomor telepon kembali menjadi tidak diatur, tetapi email yang dimasukkan pelanggan tetap ada setelah kedua panggilan.

### 4. Endpoint simulasi

Paksa status terminal setelah kejadian:

* Konsol / kunci API (memerlukan hak istimewa `write:sessions`; kunci API dengan cakupan terbatas memerlukan akses tulis ke sesi): `POST /v3/session/{session_id}/simulate/`
* Alur yang di-hosting (header `Session-Token`): `POST /v3/session/{session_id}/sandbox/simulate/`

Keduanya berfungsi pada sesi sandbox KYC dan KYB.
Sesi produksi (bukan sandbox) mengembalikan `404`, begitu juga `Session-Token` yang tidak cocok dengan `session_id` di path.

Setiap kolom dalam body bersifat opsional, tetapi setidaknya salah satu dari `new_status`, `scenario`, atau `risk` wajib diisi:

| Kolom | Tipe | Fungsinya |
| - | - | - |
| `new_status` | string | `Approved`, `Declined`, `In Review`, `Expired` atau `Abandoned`. Jika dibiarkan kosong, nilainya default ke status default dari kasus risiko (`risk`, atau risiko pertama yang dibawa nilai ajaib skenario), atau jika tidak ada, ke status default skenario. |
| `scenario` | string, maksimal 100 karakter | Slug skenario. Tanpa `risk`, risiko pertama yang dibawa oleh nilai ajaib skenario diterapkan. |
| `risk` | string, maksimal 128 karakter | Kasus risiko. Peringatannya ditambahkan ke sesi. |
| `node_id` | string, maksimal 128 karakter | Node alur kerja tempat peringatan dilampirkan. Default ke node saat ini pada sesi. |
| `comment` | string, maksimal 500 karakter | Catatan yang ditambahkan ke entri aktivitas yang dicatat oleh perubahan status. |
| `send_webhooks` | boolean, default `true` | Apakah perubahan status mengirim webhook. |

`send_webhooks: true` mengirim persis webhook yang dikirim oleh perubahan status sungguhan: `status.updated`, ditambah event `user.status.updated` dan `user.data.updated` (atau `business.status.updated` dan `business.data.updated` untuk sesi bisnis) yang disebabkan oleh perubahan itu, ke tujuan yang berlangganan event tersebut.
Dengan `send_webhooks: false`, status tetap berubah, tetapi tidak ada webhook yang dicatat atau dikirim.
Pemulihan webhook yang terlewat tidak pernah mengirim ulang keputusan tersebut, dan konsol tetap diperbarui secara langsung.
Perubahan status berikutnya pada sesi akan mengirim webhook seperti biasa.

```json theme={null}
{
  "scenario": "decline_aml_hit",
  "send_webhooks": false
}
```

Respons 200:

```json theme={null}
{
  "session_id": "<session_id>",
  "previous_status": "In Progress",
  "status": "Declined",
  "scenario": "decline_aml_hit",
  "risk": "POSSIBLE_MATCH_FOUND",
  "send_webhooks": false
}
```

* `status` adalah status yang diatur oleh simulasi, dan `previous_status` adalah status yang dimiliki sesi sebelumnya.
* `scenario` mengembalikan slug Anda dan `risk` adalah kasus risiko yang diterapkan; masing-masing bernilai `null` jika tidak ada.
* `send_webhooks` mengembalikan nilai yang diterapkan.
* Mengembalikan `400` untuk skenario atau risiko yang tidak dikenal, ketika `new_status` tidak dapat ditentukan, untuk `new_status` apa pun selain nilai yang tercantum di atas, dan ketika sesi sudah memiliki status yang diminta (`["The new status is the same as the current status."]`).

### 5. `sandbox_scenario` pada API AML mandiri

Skrining AML di sisi backend tidak memiliki pengguna akhir dan tidak ada sesi yang dapat diaktifkan, sehingga slug ditempatkan pada permintaan skrining itu sendiri (`POST /v3/aml/`):

```json theme={null}
{
  "full_name": "Ada Lovelace",
  "save_api_request": true,
  "sandbox_scenario": "decline_aml_hit"
}
```

* `decline_aml_hit` mengembalikan satu hit dengan format produksi dan menetapkan skrining sebagai `Declined`; `review_aml_possible_match` menetapkannya sebagai `In Review`. Skenario yang tidak mengaktifkan hasil AML apa pun membuat skrining tetap bersih.
* Dengan `save_api_request: true` (default), skrining disimpan persis seperti pada kunci API produksi, sehingga `request_id` yang dikembalikan dapat digunakan pada `GET /v3/session/{request_id}/decision/` dan `GET /v3/session/{request_id}/generate-pdf/`.
* Mengembalikan `400` untuk slug skenario yang tidak dikenal, dan `400` ketika kunci API milik aplikasi produksi.

## Di mana `sandbox_scenario` muncul

Slug skenario yang diaktifkan (`null` jika tidak ada skenario yang diaktifkan) dikembalikan pada beberapa bagian dan sengaja dihilangkan dari bagian lainnya:

| Bagian | Ditampilkan? |
| - | - |
| Payload langkah saat ini (KYC dan KYB) | Ya, sebagai `sandbox_scenario` |
| `GET /v1/session/{id}/decision/` | Ya, sebagai `sandbox_scenario` |
| `GET /v3/session/{id}/decision/` (lihat [Retrieve Session](https://docs.didit.me/id/sessions-api/retrieve-session.md)) | Ya, `sandbox_scenario` tingkat atas (null jika tidak diaktifkan) |
| Webhook sesi (`status.updated`, `data.updated`) | Ya, sebagai `sandbox_scenario`, `null` pada sesi produksi atau sesi sandbox yang tidak diaktifkan |

Jika integrasi Anda perlu bercabang berdasarkan skenario yang diaktifkan di sisi server, baca dari envelope webhook atau salah satu endpoint keputusan (`v1` atau `v3`).

## Penggunaan dan penagihan

Penggunaan sandbox dicatat, tetapi tidak pernah ditagih:

* Setiap panggilan tiruan tetap mencatat event penggunaan (`is_sandbox: true`, dengan harga `0.0000`) sehingga volume sandbox terlihat untuk keperluan debugging. Namun, event ini tidak pernah ditambahkan ke total penggunaan Anda, tidak pernah dikurangkan dari saldo, dan tidak pernah muncul di faktur.
* Saldo, isi saldo, dan tampilan penggunaan produksi di Business Console secara default menyaring penggunaan sandbox. Endpoint penggunaan isi saldo menerima parameter `environment` (`live`, yang merupakan default, atau `sandbox`) sehingga volume sandbox dapat diperiksa secara terpisah, selalu tanpa biaya dan tanpa mengonsumsi paket gratis.
* Verifikasi Email dan Verifikasi Telepon ditagih per permintaan, bukan per hasil sesi, dan sandbox tidak dapat sepenuhnya meniru hal ini di lapisan webhook. Pemeriksaan email dan telepon di sandbox tetap mencatat event penggunaan per permintaan dengan harga `0.0000`, sama seperti fitur tiruan lainnya. Ini adalah perbedaan yang diketahui dan diterima terhadap perilaku penagihan lingkungan produksi, bukan bug.
* Struktur respons Validasi Database di sandbox sengaja berbeda dari struktur respons per penyedia di lingkungan produksi, karena tidak ada penyedia sungguhan yang dapat ditiru. Perlakukan payload Validasi Database di sandbox sebagai pengganti untuk hasilnya (status dan kode peringatan), bukan pratinjau respons penyedia di lingkungan produksi yang identik byte demi byte.


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