Skip to main content
A sandbox application exchanges Travel Rule data with one counterparty only: the Didit Test VASP, a test VASP built into the platform. It answers each transfer the way you ask it to, through the same code that handles a real counterparty, so you can watch every status, timeline entry and webhook of an exchange before you go live. Nothing you send in sandbox leaves Didit. No network, email recipient or other Didit customer is ever contacted, and nothing is charged.

Before you start

  1. Use a sandbox application’s API key. Live applications never reach the test VASP.
  2. Turn Travel Rule on with a legal name:
  1. Optionally subscribe a webhook destination to travel_rule.status.updated. Sandbox delivers it, marked "environment": "sandbox".

The Didit Test VASP

GET /v1/sandbox/scenarios/ returns the test VASP’s profile and every scenario in its travel_rule object, so your tests can read the trigger values instead of hard-coding them: Every value is test data. The test VASP is not a member of any Travel Rule network, and no result in sandbox shows that a real counterparty or network can be reached.

Outbound scenarios

Every outbound travelRule transaction of a sandbox application that needs an exchange goes to the test VASP. Pick the outcome with the beneficiary wallet address (case does not matter), or with a beneficiary name of the form Didit Test VASP <suffix>; the wallet wins when both are set. With neither, or with a suffix the table does not list, the transfer completes (accept). A transfer that needs no exchange never reaches the test VASP: one below your threshold_amount, one to your user’s own verified wallet, and one whose counterparty wallet you declared self-hosted. A counterparty VASP you or your end user picked by hand from the directory is judged by the routes a live application would have: when its entry has one (a verified TRP endpoint, a network your application sends on, or a compliance contact), the transfer goes to the test VASP; when it has none, the transfer ends COUNTERPARTY_VASP_NOT_FOUND, as it would on a live application.
The transfer’s rail is TEST_VASP, and the transfers list names Didit Test VASP as its beneficiary VASP. Follow it in the travel_rule.status.updated webhooks, or read GET /v3/transactions/{transaction_id}/.
  • name_mismatch compares the beneficiary name you sent with the holder name the test VASP answers with, at your name rule for the beneficiary’s entity type (matching_rules.individual.name or matching_rules.company.name, which follow name_matching_strictness until you set them). The transfer and the timeline entry that decided it carry name_match (with compared_with: "counterparty_vasp") and data_match with mismatched_fields: ["name"].
  • not_reachable keeps the transfer AWAITING_COUNTERPARTY while it retries, with delivery.status RETRYING and last_error test VASP is not answering, then makes it COUNTERPARTY_VASP_NOT_REACHABLE. Send {"action": "resend"} afterwards to run it again.
  • self_hosted has the test VASP answer that the wallet is self-hosted. Record the proof with the wallet ownership widget (minted for you while auto_wallet_verification is on) or POST .../travel-rule/ownership/ with {"confirmed": true}: the wallet is added to your address book under the beneficiary’s name and the name match decides the transfer. A match completes it and marks the wallet verified; {"confirmed": false} declines it.

Inbound transfers from the test VASP

To test the receiving side, have the test VASP send you a transfer with POST /v3/travel-rule/test-vasp/inbound/. Name one of your application’s own address-book wallets: the transfer is decided by the same inbound path as a real one, against your address book, your ownership mode and your name rules.
The 201 response carries transaction_id, txn_id, scenario, travel_rule_status, detail, test_vasp: true and the travel_rule transfer. A live application gets 400 ("The Didit Test VASP is only available on sandbox applications."), another scenario gets 400, and an application with Travel Rule off gets 409. Decide a transfer that waits with POST .../travel-rule/ownership/, as you would a real one: {"confirmed": true} completes it and {"confirmed": false} declines it. A deposit you report yourself with POST /v3/transactions/ is not one the test VASP sent: it stays AWAITING_COUNTERPARTY waiting for its originating VASP, and its timeline names the endpoint above. It fires no webhook until it expires after confirmation_timeout_hours. POST /v3/travel-rule/inbound/ still settles an after-deposit registration against your address book, as on a live application.

Webhooks in sandbox

travel_rule.status.updated fires for sandbox applications on every status change, with "environment": "sandbox". A transfer the test VASP answered also carries rail: "TEST_VASP", test_vasp: true and test_vasp_scenario. The rest of sandbox still behaves as described in Transaction Monitoring in sandbox: rules are not evaluated, transaction.created and transaction.status.updated are not sent, and nothing is billed.

What sandbox does not prove

  • That a real counterparty, a network membership or Didit’s public TRP host works. None of them is contacted.
  • That your network credentials are valid. A connected membership is proven by its first live exchange.
  • The directory routes of real VASPs: on a sandbox application every route reads unavailable with reason: sandbox_application, and every row reachable: false.
See Travel Rule networks for what each rail reaches in production today.