Skip to main content

Overview

In the sandbox environment, customer KYC is mocked: no upstream KYC or screening provider is called. Customer onboarding still goes through the same review as production. Only the provider answers are local: a business’s KYC checks clear after one hour, and an individual’s sanctions screen clears at once, as it does for a clean person on live. The document review is not local. Sandbox reads your documents as live does, with one difference: it does not check if a person’s ID document is authentic, because a sandbox person has no real ID. A sample file that reads as a passport, national ID card or driver’s licence counts as the person’s ID. Your organization does KYB in production. Your sandbox organization is ready at once.

Customer-onboarding lifecycle

Business

When you submit a business customer onboarding application in sandbox:
  1. The application enters "processing".
  2. The mock marks the same fields pending that a live KYC check would (business website, classification report, adverse-media report, associated persons, TIN — depending on the submitted data and country).
  3. A 1-hour timer starts. When it fires, the mock KYC checks clear. The timer does not approve the application.
  4. Call one of the simulate endpoints below to approve or reject the application. An undecided application does not wait forever: it cancels automatically after 14 days. Watch for reviewStage: "operator" on the application — that is the signal to call simulate/decision.

Individual

An individual onboards under KYC reliance, so sandbox decides it the same way live does:
  1. The application enters "processing".
  2. The account holder’s sanctions screen clears. The one exception is an account holder with the first name Ivan and the last name Sanctionov: the screen finds a sanctions match, so the application stays "processing", as a match waits for Conduit compliance on live. Decide it with the simulate endpoint below.
  3. The pipeline compares the identity verification attestation you uploaded with the person you submitted, and checks that you attached the original ID document.
  4. If the attestation names the same person and shows a labelled verification date, for example Verification date: 2026-10-01, and the ID document is attached, the application is approved with no call from you, usually within a few minutes of the submit. Listen for the webhook rather than poll on a short timer. application.approved and customer.created fire.
  5. If the attestation does not match, for example a different name or birth date, a verification date older than one year or no readable verification date, a name that looks like a test marker such as ZZZTEST, a file that is not an attestation, or a missing ID document, the application stays "processing", as it waits for a Conduit operator on live. Drive it with the simulate endpoint below.
To test a rejection, upload an attestation that does not match the person, then reject the application with the simulate endpoint. The first decision wins. A second call with a different outcome returns 409 APPLICATION_ALREADY_DECIDED.

Simulate endpoints

POST /v2/sandbox/applications/:id/simulate/decision forces a sandbox application to a terminal status on demand, regardless of the application’s current review stage. The body’s outcome field selects approved or rejected.

Works for any application type

This endpoint is not limited to customer onboarding. It accepts every application type your sandbox API key can create: outcome: "rejected" publishes the matching *.rejected event for the application’s type. Rejected applications never reach a provisioning branch.

Request shape

The endpoint requires your sandbox API key and a JSON body with an outcome field. The simplest approval call:
Returns 200 OK with the application at its new state. A call with the outcome the application already has returns 200 with the application unchanged, so a call made after an individual auto-approves still succeeds. A call with the other outcome returns 409 APPLICATION_ALREADY_DECIDED. A call that arrives while the application is being decided can return 409 APPLICATION_INVALID_STATUS. Read the application to see its decision.

Rejection options

The same endpoint with outcome: "rejected" accepts optional fields to shape the rejection: Structured category is only meaningful for the KYB-pipeline application types your sandbox API key can create: customer_onboarding and customer_update. Sending category on a non-KYB type (e.g. a virtual_account application) returns 422 REJECTION_CATEGORY_NOT_APPLICABLE. Sending category with outcome: "approved" returns 400 VALIDATION_ERROR. Within category: generic an optional reason is accepted (this is how integrators simulate a manual operator rejection); for all other categories reason cannot be combined with category. Categories: document_mismatch (optional field: tax_id, date_of_incorporation, business_name, business_entity_id, and for an individual application’s own fields account_holder_birth_date, account_holder_address, account_holder_tax_id), data_sourcing_mismatch (optional field: business_entity_id, ubo_first_name, ubo_last_name, ubo_phone, ubo_email, ownership_list; on an individual application the ubo_* fields point at the account holder), compliance (no field), generic (no field; accepts an optional reason). The category value is not case-sensitive. To run an individual application from discovery to a payout, see the Individual quickstart. On an individual application, failureMessage names the account holder where a business application names an owner, for example “The account holder’s phone number couldn’t be matched against our records.”

Errors

Wallet provisioning

Submitting the crypto_wallet feature application alone enables the feature but does not provision an account. For a non-custodial organization, the customer’s wallets are provisioned via POST /v2/customers/:id/wallets/claim-non-custodial, which mints a non-custodial wallet account, sets up the signer roster, and creates the wallets in one shot. See the Multi-signer wallets recipe for the full copy-paste curl flow. For an organization enabled for custodial wallets, no claim is required — the account is provisioned on the customer’s first POST /v2/customers/:id/wallets call.

Notes

  • Customer KYC data submitted to sandbox is not transferred to production. Sandbox and production are isolated environments — end-user customers re-onboard in production.
  • The mock produces the same verification shape your client code sees in production, whether it’s running against sandbox or live.
  • For happy-path tests you can ignore simulation: submit, wait, then observe approved. A business customer_onboarding application does not auto-approve: call simulate/decision. An individual whose attestation matches and shows a verification date, with the ID document attached, approves with no call, usually within a few minutes. virtual_account and crypto_wallet applications usually approve at submission too, with no call needed. customer_update does not auto-resolve: drive it with simulate/decision { outcome: "approved" | "rejected" }.

See also