---
title: "Simulate a sandbox verification result"
method: POST
path: "/verifications/{verification_id}/simulate"
tags: ["Verifications"]
---

# Simulate a sandbox verification result

`POST /verifications/{verification_id}/simulate`

## Request

- Base URL: `https://developers.ozav.io/v2`
- URL: `https://developers.ozav.io/v2/verifications/{verification_id}/simulate`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

Sandbox-only helper for test API keys. Marks a verification as approved
or rejected and updates the linked customer's KYC status so downstream
sandbox flows, including simulated wallet reads, BRL/Pix account reads,
and card issuance, can be exercised without fake identity documents.
Sandbox wallet and account records are projections only; they do not
create an on-chain address or open a real bank account.

## Path parameters

- `verification_id` string, required

## Request body

- object
  - `outcome` 'approved' | 'rejected', required
  - `reason` string

## Response `200`

Updated verification.

- Verification: An identity / business verification session (KYC / KYB) for a customer. Completing or simulating a verification updates the customer's KYC status. In sandbox, approval can materialize simulated wallet and BRL/Pix account projections. Live wallet provisioning and live bank account opening remain separate enabled steps.
  - `id` string, required: Opaque verification identifier, prefixed `ozav_vrf_`.
  - `object` 'verification', required: Resource type discriminator; always the literal `verification`.
  - `customer_id` string, required: The `ozav_cus_` id of the customer being verified.
  - `session_url` string, uri: Hosted verification session URL - redirect the end-user here to complete identity capture (government ID, selfie, liveness; KYB/UBO for a business customer). **In sandbox this field never appears.** A `test` key never starts a hosted session, because a real session bills a third party per attempt. Exercise the outcome with `POST /verifications/{verification_id}/simulate` instead - that is the sandbox affordance, and it lets you drive `approved` or `rejected` yourself. **With a `live` key, two things must both be true**, and the second is not something you control: 1. Your `capabilities` include at least one that hosted capture covers: `kyc_document`, `liveness`, `face_match`, `age_estimation`, `kyb`, `ubo`. Asking only for list/data checks (`aml_name_screening`, `economic_capacity`, ...) never starts a session, because there is nothing for the end-user to do. 2. Hosted capture is switched on at OZAV. This is a single platform-wide setting, **not** something enabled per organization - there is nothing to request for your account. While it is off, no `live` key starts a session. When either condition is missing - or the key is a `test` key - the verification is still created and is a valid record with **no `session_url`**. That is not an error and retrying will not produce one. For an individual on a `live` key with hosted capture off, it is `in_progress` with the hosted checks at `review` and `pending_documents` saying what to upload instead; otherwise it stays `pending` with `checks` at `not_started`. The field is never fabricated: if the session cannot be created, the request fails with a `503` and nothing is persisted, rather than returning a record with a broken link. The `code` says whether retrying helps: `VERIFICATION_SESSION_UNAVAILABLE` (retry shortly), `VERIFICATION_TEMPORARILY_UNAVAILABLE` (on OZAV's side, not caused by your data - retry later with the same data), `VERIFICATION_PROVIDER_REJECTED` or `VERIFICATION_PROVIDER_NOT_CONFIGURED` (contact OZAV support with the `request_id`).
  - `status` 'pending' | 'in_progress' | 'completed' | 'expired', required: Overall state of the verification session: - `pending` - created; checks have not started. - `in_progress` - one or more checks are running. - `completed` - every check reached an outcome. - `expired` - the session expired before completing.
  - `pending_documents` object[]: Only on the `POST /verifications` response, and only when no hosted session was started for an individual: the documents still to send with `POST /customers/{customer_id}/documents`. Absent otherwise.
    - `doc_type` string, required: For example `identity_document`, `selfie`, `proof_of_address`.
    - `state` 'missing' | 'rejected', required
    - `reason` string: Why a rejected file was not accepted.
  - `checks` object: Per-capability check results, keyed by `CapabilityKind`.
  - `created_at` string, date-time: When the verification session was created (RFC 3339 / ISO 8601, UTC).

## Other responses

- `401`: Missing or invalid API key.
- `403`: The organization lacks the entitlement (code ENTITLEMENT_REQUIRED) or the key lacks the scope (code INSUFFICIENT_SCOPE). On money-moving requests (POST /transfers, POST /wallets/{wallet_id}/transfers) a compliance hold on the customer answers with code COMPLIANCE_HOLD: the hold is reviewed and lifted on OZAV's side; retrying does not clear it. When the only hold is a pause until pending onboarding documents are received, a withdrawal answers CUSTOMER_DOCUMENTS_PENDING instead: send what `requirements` on GET /customers/{id} lists; OZAV lifts the pause after reviewing it. On OZAV Services (live without the platform's KYB), any API outside decisions, screenings, lists and self-custody wallets answers with code PRODUCTION_NOT_ACTIVATED.
- `404`: The resource does not exist, is not visible to the caller, or the id was malformed for this position (see "Resource ids" under Errors). These share one status; `code` and `message` tell them apart.

---

[API](https://skmtc.dev/ozav/apis/ozav-api.md) - [All operations](https://skmtc.dev/ozav/apis/ozav-api/llms.txt) - [OpenAPI document](https://skmtc.dev/ozav/apis/ozav-api/revisions/4133dc2109d7?raw)
