The Yoti Identity Verification (IDV) Sandbox is an isolated testing environment for validating your integration with mock data and simulated verification outcomes.
What you can do
Test end-to-end flows without real user data
Simulate different verification outcomes (approvals, rejections, extractions)
Use standard Yoti backed SDKs (no separate sandbox SDK)
Manually test using the user view, or automate testing (via built-in agent) by bypassing the user view.
Key differences
Sandbox uses the same SDKs as production but requires:
Sandbox URL: https://api.yoti.com/sandbox/idverify/v1
Sandbox keys from Yoti Hub
Predefined successful responses by default
Optional response configuration (see Configure response)
Before you start
Ensure you have submitted your Yoti Hub organisation for verification and have generated sandbox keys.
Sandbox keys
Install the SDK
Install the Yoti SDK using your language's package manager. The same SDK is used for both production and sandbox environments.
// If you are using Maven, add the following dependency:
<dependency>
<groupId>com.yoti</groupId>
<artifactId>yoti-sdk-api</artifactId>
<version>3.12.0</version>
</dependency>
// If you are using Gradle, add the following dependency:
implementation group: 'com.yoti', name: 'yoti-sdk-api', version: '3.12.0'
// Get the Yoti PHP SDK library via a Composer package
composer require yoti/yoti-php-sdk
// To install the Yoti NuGet package, enter the following command
// from NuGet Package Manager Console in Visual Studio:
Install-Package Yoti
// Add to go.mod:
require github.com/getyoti/yoti-go-sdk/v3
// Or download via terminal:
go get "github.com/getyoti/yoti-go-sdk/v3"
Step 1: Initialise the client
Initialise the Yoti client with your sandbox credentials and point it to the sandbox URL.
Sandbox URL: https://api.yoti.com/sandbox/idverify/v1
const { IDVClient } = require('yoti');
const fs = require('fs');
const SANDBOX_CLIENT_SDK_ID = 'YOUR_SANDBOX_SDK_ID';
const SANDBOX_PEM = fs.readFileSync('/path/to/your-sandbox-pem-file.pem', 'utf8');
// Initialise client with sandbox URL
const idvClient = new IDVClient(
SANDBOX_CLIENT_SDK_ID,
SANDBOX_PEM,
{ apiUrl: 'https://api.yoti.com/sandbox/idverify/v1' }
);
// Point the Doc Scan client at the sandbox by setting environment variable
System.setProperty("yoti.docs.url", "https://api.yoti.com/sandbox/idverify/v1");
import com.yoti.api.client.ClassPathKeySource;
import com.yoti.api.client.docs.DocScanClient;
...
String SANDBOX_CLIENT_SDK_ID = "YOUR_SANDBOX_SDK_ID";
String SANDBOX_PEM_PATH = "/path/to/your-sandbox-pem-file.pem";
DocScanClient docScanClient = DocScanClient.builder()
.withClientSdkId(SANDBOX_CLIENT_SDK_ID)
.withKeyPairSource(ClassPathKeySource.fromClasspath(SANDBOX_PEM_PATH))
.build();
<?php
use Yoti\DocScan\DocScanClient;
$SANDBOX_CLIENT_SDK_ID = 'YOUR_SANDBOX_SDK_ID';
$SANDBOX_PEM_PATH = '/path/to/your-sandbox-pem-file.pem';
$docScanClient = new DocScanClient(
$SANDBOX_CLIENT_SDK_ID,
$SANDBOX_PEM_PATH,
['api.url' => 'https://api.yoti.com/sandbox/idverify/v1']
);
from yoti_python_sdk.doc_scan import DocScanClient
SANDBOX_CLIENT_SDK_ID = 'YOUR_SANDBOX_SDK_ID'
SANDBOX_PEM_PATH = '/path/to/your-sandbox-pem-file.pem'
doc_scan_client = DocScanClient(
SANDBOX_CLIENT_SDK_ID,
SANDBOX_PEM_PATH,
api_url="https://api.yoti.com/sandbox/idverify/v1"
)
using System.IO;
using System.Net.Http;
using Yoti.Auth;
using Yoti.Auth.DocScan;
...
const string SANDBOX_CLIENT_SDK_ID = "YOUR_SANDBOX_SDK_ID";
const string SANDBOX_PEM_PATH = "/path/to/your-sandbox-pem-file.pem";
StreamReader privateKeyStream = System.IO.File.OpenText(SANDBOX_PEM_PATH);
var key = CryptoEngine.LoadRsaKey(privateKeyStream);
var docScanClient = new DocScanClient(
SANDBOX_CLIENT_SDK_ID,
key,
new HttpClient(),
new Uri("https://api.yoti.com/sandbox/idverify/v1")
);
Step 2: Create a session
Create an identity verification session exactly as you would in production. The session configuration determines what checks and tasks will be performed.
const {
SessionSpecificationBuilder,
RequestedDocumentAuthenticityCheckBuilder,
RequestedLivenessCheckBuilder,
RequestedFaceMatchCheckBuilder,
RequestedTextExtractionTaskBuilder,
SdkConfigBuilder
} = require('yoti');
// Define checks
const documentAuthenticityCheck = new RequestedDocumentAuthenticityCheckBuilder().build();
const livenessCheck = new RequestedLivenessCheckBuilder()
.forStaticLiveness()
.withMaxRetries(3)
.build();
const faceMatchCheck = new RequestedFaceMatchCheckBuilder()
.withManualCheckFallback()
.build();
// Define tasks
const textExtractionTask = new RequestedTextExtractionTaskBuilder()
.withManualCheckFallback()
.build();
// Configure SDK
const sdkConfig = new SdkConfigBuilder()
.withAllowsCamera()
.withPresetIssuingCountry('GBR')
.withSuccessUrl('https://yourdomain.com/success')
.withErrorUrl('https://yourdomain.com/error')
.build();
// Build session specification
const sessionSpec = new SessionSpecificationBuilder()
.withClientSessionTokenTtl(900)
.withResourcesTtl(90000)
.withUserTrackingId('some-unique-user-id')
.withRequestedCheck(documentAuthenticityCheck)
.withRequestedCheck(livenessCheck)
.withRequestedCheck(faceMatchCheck)
.withRequestedTask(textExtractionTask)
.withSdkConfig(sdkConfig)
.build();
// Create session
idvClient.createSession(sessionSpec)
.then((session) => {
const sessionId = session.getSessionId();
const clientSessionToken = session.getClientSessionToken();
console.log('Session created:', sessionId);
})
.catch((err) => {
console.error('Error creating session:', err);
});
import com.yoti.api.client.docs.session.create.CreateSessionResult;
import com.yoti.api.client.docs.session.create.SdkConfig;
import com.yoti.api.client.docs.session.create.SessionSpec;
import com.yoti.api.client.docs.session.create.check.RequestedDocumentAuthenticityCheck;
import com.yoti.api.client.docs.session.create.check.RequestedFaceMatchCheck;
import com.yoti.api.client.docs.session.create.check.RequestedLivenessCheck;
import com.yoti.api.client.docs.session.create.task.RequestedTextExtractionTask;
...
// Define checks
RequestedDocumentAuthenticityCheck documentAuthenticityCheck =
RequestedDocumentAuthenticityCheck.builder().build();
RequestedLivenessCheck livenessCheck = RequestedLivenessCheck.builder()
.forStaticLiveness()
.withMaxRetries(3)
.build();
RequestedFaceMatchCheck faceMatchCheck = RequestedFaceMatchCheck.builder()
.withManualCheckFallback()
.build();
// Define tasks
RequestedTextExtractionTask textExtractionTask = RequestedTextExtractionTask.builder()
.withManualCheckFallback()
.build();
// Configure SDK
SdkConfig sdkConfig = SdkConfig.builder()
.withAllowsCamera()
.withPresetIssuingCountry("GBR")
.withSuccessUrl("https://yourdomain.com/success")
.withErrorUrl("https://yourdomain.com/error")
.build();
// Build session specification
SessionSpec sessionSpec = SessionSpec.builder()
.withClientSessionTokenTtl(900)
.withResourcesTtl(90000)
.withUserTrackingId("some-unique-user-id")
.withRequestedCheck(documentAuthenticityCheck)
.withRequestedCheck(livenessCheck)
.withRequestedCheck(faceMatchCheck)
.withRequestedTask(textExtractionTask)
.withSdkConfig(sdkConfig)
.build();
// Create session
CreateSessionResult sessionResult = docScanClient.createSession(sessionSpec);
String sessionId = sessionResult.getSessionId();
String clientSessionToken = sessionResult.getClientSessionToken();
<?php
use Yoti\DocScan\Session\Create\SessionSpecificationBuilder;
use Yoti\DocScan\Session\Create\Check\RequestedDocumentAuthenticityCheckBuilder;
use Yoti\DocScan\Session\Create\Check\RequestedLivenessCheckBuilder;
use Yoti\DocScan\Session\Create\Check\RequestedFaceMatchCheckBuilder;
use Yoti\DocScan\Session\Create\Task\RequestedTextExtractionTaskBuilder;
use Yoti\DocScan\Session\Create\SdkConfigBuilder;
// Define checks
$documentAuthenticityCheck = (new RequestedDocumentAuthenticityCheckBuilder())->build();
$livenessCheck = (new RequestedLivenessCheckBuilder())
->forStaticLiveness()
->withMaxRetries(3)
->build();
$faceMatchCheck = (new RequestedFaceMatchCheckBuilder())
->withManualCheckFallback()
->build();
// Define tasks
$textExtractionTask = (new RequestedTextExtractionTaskBuilder())
->withManualCheckFallback()
->build();
// Configure SDK
$sdkConfig = (new SdkConfigBuilder())
->withAllowsCamera()
->withPresetIssuingCountry('GBR')
->withSuccessUrl('https://yourdomain.com/success')
->withErrorUrl('https://yourdomain.com/error')
->build();
// Build session specification
$sessionSpec = (new SessionSpecificationBuilder())
->withClientSessionTokenTtl(900)
->withResourcesTtl(90000)
->withUserTrackingId('some-unique-user-id')
->withRequestedCheck($documentAuthenticityCheck)
->withRequestedCheck($livenessCheck)
->withRequestedCheck($faceMatchCheck)
->withRequestedTask($textExtractionTask)
->withSdkConfig($sdkConfig)
->build();
// Create session
$session = $docScanClient->createSession($sessionSpec);
$sessionId = $session->getSessionId();
$clientSessionToken = $session->getClientSessionToken();
from yoti_python_sdk.doc_scan import (
SessionSpecBuilder,
RequestedDocumentAuthenticityCheckBuilder,
RequestedLivenessCheckBuilder,
RequestedFaceMatchCheckBuilder,
RequestedTextExtractionTaskBuilder,
SdkConfigBuilder
)
# Define checks
document_authenticity_check = RequestedDocumentAuthenticityCheckBuilder().build()
liveness_check = (
RequestedLivenessCheckBuilder()
.for_static_liveness()
.with_max_retries(3)
.build()
)
face_match_check = (
RequestedFaceMatchCheckBuilder()
.with_manual_check_fallback()
.build()
)
# Define tasks
text_extraction_task = (
RequestedTextExtractionTaskBuilder()
.with_manual_check_fallback()
.build()
)
# Configure SDK
sdk_config = (
SdkConfigBuilder()
.with_allows_camera()
.with_preset_issuing_country('GBR')
.with_success_url('https://yourdomain.com/success')
.with_error_url('https://yourdomain.com/error')
.build()
)
# Build session specification
session_spec = (
SessionSpecBuilder()
.with_client_session_token_ttl(900)
.with_resources_ttl(90000)
.with_user_tracking_id('some-unique-user-id')
.with_requested_check(document_authenticity_check)
.with_requested_check(liveness_check)
.with_requested_check(face_match_check)
.with_requested_task(text_extraction_task)
.with_sdk_config(sdk_config)
.build()
)
# Create session
session = doc_scan_client.create_session(session_spec)
session_id = session.session_id
client_session_token = session.client_session_token
using Yoti.Auth.DocScan.Session.Create;
using Yoti.Auth.DocScan.Session.Create.Check;
using Yoti.Auth.DocScan.Session.Create.Task;
...
// Define checks
var documentAuthenticityCheck = new RequestedDocumentAuthenticityCheckBuilder().Build();
var livenessCheck = new RequestedLivenessCheckBuilder()
.ForStaticLiveness()
.WithMaxRetries(3)
.Build();
var faceMatchCheck = new RequestedFaceMatchCheckBuilder()
.WithManualCheckFallback()
.Build();
// Define tasks
var textExtractionTask = new RequestedTextExtractionTaskBuilder()
.WithManualCheckFallback()
.Build();
// Configure SDK
var sdkConfig = new SdkConfigBuilder()
.WithAllowsCamera()
.WithPresetIssuingCountry("GBR")
.WithSuccessUrl("https://yourdomain.com/success")
.WithErrorUrl("https://yourdomain.com/error")
.Build();
// Build session specification
var sessionSpec = new SessionSpecificationBuilder()
.WithClientSessionTokenTtl(900)
.WithResourcesTtl(90000)
.WithUserTrackingId("some-unique-user-id")
.WithRequestedCheck(documentAuthenticityCheck)
.WithRequestedCheck(livenessCheck)
.WithRequestedCheck(faceMatchCheck)
.WithRequestedTask(textExtractionTask)
.WithSdkConfig(sdkConfig)
.Build();
// Create session
CreateSessionResult createSessionResult = docScanClient.CreateSession(sessionSpec);
string sessionId = createSessionResult.SessionId;
string clientSessionToken = createSessionResult.ClientSessionToken;
Step 3a: Launch the user view (manual testing)
Construct the following URL for manual testing, and render it inside an iFrame:
https://api.yoti.com/sandbox/idverify/v1/web/index.html?sessionID={sessionID}&sessionToken={clientSessionToken}
iFrame example
<iframe
src="https://api.yoti.com/sandbox/idverify/v1/web/index.html?sessionID={sessionID}&sessionToken={clientSessionToken}"
style="height:100vh; width:100%; border:none;"
allow="camera">
</iframe>
Users can upload sample documents and selfies, and the sandbox returns predefined successful responses along with the uploaded image resources.
Step 3b: Use the agent endpoint (automated testing)
Info
The /agent endpoint bypasses the user view and completes sessions programmatically with sample data—ideal for CI/CD and automated tests.
Endpoint
POST https://api.yoti.com/sandbox/idverify/v1/agent
Use Case | Benefit |
|---|
Automated tests | Skip manual document upload |
CI/CD pipelines | Integrate verification in build process |
Payload structure
{
"session_id": "YOUR_SESSION_ID",
"client_session_token": "YOUR_SESSION_TOKEN"
}
const { RequestBuilder, Payload } = require("yoti");
const payload = {
session_id: sessionId,
client_session_token: clientSessionToken
};
const request = new RequestBuilder()
.withBaseUrl("https://api.yoti.com/sandbox/idverify/v1")
.withPemFilePath(SANDBOX_PEM_PATH)
.withEndpoint("/agent")
.withPayload(new Payload(payload))
.withMethod("POST")
.withQueryParam("sdkId", SANDBOX_CLIENT_SDK_ID)
.build();
// Execute request
const response = await request.execute();
import com.yoti.api.client.spi.remote.call.SignedRequest;
import com.yoti.api.client.spi.remote.call.SignedRequestBuilder;
...
String payload = String.format(
"{\"session_id\":\"%s\",\"client_session_token\":\"%s\"}",
sessionId,
clientSessionToken
);
try {
SignedRequest signedRequest = SignedRequestBuilder.newInstance()
.withKeyPair(SANDBOX_PEM_PATH)
.withBaseUrl("https://api.yoti.com/sandbox/idverify/v1")
.withEndpoint("/agent")
.withPayload(payload.getBytes())
.withHttpMethod("POST")
.withQueryParameter("sdkId", SANDBOX_CLIENT_SDK_ID)
.build();
Response response = signedRequest.execute();
} catch (Exception ex) {
ex.printStackTrace();
}
<?php
use Yoti\Http\RequestBuilder;
use Yoti\Http\Payload;
$payload = [
'session_id' => $sessionId,
'client_session_token' => $clientSessionToken
];
$request = (new RequestBuilder())
->withBaseUrl('https://api.yoti.com/sandbox/idverify/v1')
->withPemFilePath($SANDBOX_PEM_PATH)
->withEndpoint('/agent')
->withPayload(Payload::fromJsonData($payload))
->withMethod('POST')
->withQueryParam('sdkId', $SANDBOX_CLIENT_SDK_ID)
->build()
->execute();
from yoti_python_sdk.http import SignedRequest
import json
import requests
payload = {
'session_id': session_id,
'client_session_token': client_session_token
}
payload_string = json.dumps(skip_ui).encode()
signed_request = (
SignedRequest
.builder()
.with_pem_file(SANDBOX_PEM_PATH)
.with_base_url("https://api.yoti.com/sandbox/idverify/v1")
.with_endpoint("/agent")
.with_http_method("POST")
.with_param("sdkId", SANDBOX_CLIENT_SDK_ID)
.with_payload(payload_string)
.build()
)
response = signed_request.execute()
using System.IO;
using System.Net.Http;
using System.Text;
using Yoti.Auth.Web;
HttpClient httpClient = new HttpClient();
StreamReader privateKeyStream = System.IO.File.OpenText(SANDBOX_PEM_PATH);
string payload = Newtonsoft.Json.JsonConvert.SerializeObject(new
{
session_id = sessionId,
client_session_token = clientSessionToken
});
byte[] payloadBytes = Encoding.UTF8.GetBytes(serializedRequest);
Uri baseUrl = new UriBuilder("https", "api.yoti.com", 443, "sandbox/idverify/v1").Uri;
Request agentRequest = new RequestBuilder()
.WithStreamReader(privateKeyStream)
.WithBaseUri(baseUrl)
.WithEndpoint("/agent")
.WithHttpMethod(HttpMethod.Post)
.WithContent(payloadBytes)
.WithQueryParam("sdkId", SANDBOX_CLIENT_SDK_ID)
.Build();
HttpResponseMessage response = agentRequest.Execute(httpClient).Result;
import (
"encoding/json"
"io/ioutil"
"net/http"
"github.com/getyoti/yoti-go-sdk/v3/requests"
)
key, _ := ioutil.ReadFile(SANDBOX_PEM_PATH)
payload, err := json.Marshal(map[string]string{
"session_id": sessionID,
"client_session_token": clientToken,
})
if err != nil {
return fmt.Errorf("marshal payload: %w", err)
}
request, _ := requests.SignedRequest{
HTTPMethod: http.MethodPost,
BaseURL: "https://api.yoti.com/sandbox/idverify/v1",
Endpoint: "/agent",
Params: map[string]string{
"sdkId": SANDBOX_CLIENT_SDK_ID,
},
Headers: map[string][]string{
"Content-Type": {"application/json"},
"Accept": {"application/json"},
},
Body: payload,
}.WithPemFile(key).Request()
response, _ := http.DefaultClient.Do(request)
Step 4: Retrieve session results
After the session is completed (either via user view or agent endpoint), retrieve the results to verify the outcome.
// Retrieve session result
idvClient.getSession(sessionId).then(session => {
// Session state
const state = session.getState();
// Resources (documents, images)
const resources = session.getResources();
const idDocuments = resources.getIdDocuments();
// Checks
const authenticityChecks = session.getAuthenticityChecks();
const livenessChecks = session.getLivenessChecks();
const faceMatchChecks = session.getFaceMatchChecks();
// Tasks
const textExtractionTasks = session.getTextDataChecks();
// Biometric consent
const biometricConsent = session.getBiometricConsentTimestamp();
console.log('Session completed successfully');
}).catch(error => {
console.error('Error retrieving session:', error);
});
// Retrieve session result
GetSessionResult sessionResult = docScanClient.getSession(sessionId);
// Session state
String state = sessionResult.getState();
// Resources (documents, images)
ResourceContainer resources = sessionResult.getResources();
List<? extends IdDocumentResourceResponse> idDocuments = resources.getIdDocuments();
// Checks
List<AuthenticityCheckResponse> authenticityChecks = sessionResult.getAuthenticityChecks();
List<LivenessCheckResponse> livenessChecks = sessionResult.getLivenessChecks();
List<FaceMatchCheckResponse> faceMatchChecks = sessionResult.getFaceMatchChecks();
// Tasks
List<TextDataCheckResponse> textDataChecks = sessionResult.getTextDataChecks();
// Biometric consent
String biometricConsent = sessionResult.getBiometricConsentTimestamp();
<?php
// Retrieve session result
$sessionResult = $docScanClient->getSession($sessionId);
// Session state
$state = $sessionResult->getState();
// Resources (documents, images)
$resources = $sessionResult->getResources();
$idDocuments = $resources->getIdDocuments();
// Checks
$authenticityChecks = $sessionResult->getAuthenticityChecks();
$livenessChecks = $sessionResult->getLivenessChecks();
$faceMatchChecks = $sessionResult->getFaceMatchChecks();
// Tasks
$textDataChecks = $sessionResult->getTextDataChecks();
// Biometric consent
$biometricConsent = $sessionResult->getBiometricConsentTimestamp();
# Retrieve session result
session_result = doc_scan_client.get_session(session_id)
# Session state
state = session_result.state
# Resources (documents, images)
resources = session_result.resources
id_documents = resources.id_documents
# Checks
authenticity_checks = session_result.authenticity_checks
liveness_checks = session_result.liveness_checks
face_match_checks = session_result.face_match_checks
# Tasks
text_data_checks = session_result.text_data_checks
# Biometric consent
biometric_consent = session_result.biometric_consent_timestamp
// Retrieve session result
GetSessionResult sessionResult = docScanClient.GetSession(sessionId);
// Session state
string state = sessionResult.State;
// Resources (documents, images)
ResourceContainer resources = sessionResult.Resources;
List<IdDocumentResourceResponse> idDocuments = resources.GetIdDocuments();
// Checks
List<AuthenticityCheckResponse> authenticityChecks = sessionResult.GetAuthenticityChecks();
List<LivenessCheckResponse> livenessChecks = sessionResult.GetLivenessChecks();
List<FaceMatchCheckResponse> faceMatchChecks = sessionResult.GetFaceMatchChecks();
// Tasks
List<TextDataCheckResponse> textDataChecks = sessionResult.GetTextDataChecks();
// Biometric consent
DateTime biometricConsent = sessionResult.BiometricConsentTimestamp();
Example sandbox response
Here is a sample JSON response from a finished sandbox session:
{
"client_session_token_ttl": 433,
"session_id": "bfaf87e8-51dc-4ee4-be7b-8d4e3d8e9f41",
"state": "COMPLETED",
"resources": {
"id_documents": [
{
"id": "31774db7-8dde-4885-9458-86584f26064b",
"document_type": "DRIVING_LICENCE",
"issuing_country": "GBR",
"pages": [
{
"capture_method": "CAMERA",
"media": {
"id": "74b0437c-e120-4e9f-adb9-56fe71ff09d0",
"type": "IMAGE"
}
}
],
"document_fields": {
"media": {
"id": "3fe2211f-d49d-49c1-9404-c38e9cacc393",
"type": "JSON"
}
},
"document_id_photo": {
"media": {
"id": "c2aa2b94-b987-4077-ba11-bd92abde5455",
"type": "IMAGE"
}
}
}
],
"liveness_capture": [
{
"id": "508826f9-7e30-40fa-a463-d9b243ff86fd",
"liveness_type": "STATIC",
"image": {
"media": {
"id": "4401aff6-b014-4a5a-bf5d-27ce1ce2e27d",
"type": "IMAGE"
}
}
}
]
},
"checks": [
{
"type": "ID_DOCUMENT_AUTHENTICITY",
"id": "309f7e0f-5243-4a1f-b5bb-2c72ec10af21",
"state": "DONE",
"report": {
"recommendation": {
"value": "APPROVE"
},
"breakdown": [
{
"sub_check": "document_in_date",
"result": "PASS"
},
{
"sub_check": "fraud_list_check",
"result": "PASS"
}
]
}
},
{
"type": "LIVENESS",
"id": "67c14a2a-2ec4-4d61-8316-c7569ea56d59",
"state": "DONE",
"report": {
"recommendation": {
"value": "APPROVE"
},
"breakdown": [
{
"sub_check": "liveness_auth",
"result": "PASS"
}
]
}
},
{
"type": "ID_DOCUMENT_FACE_MATCH",
"id": "a0818baa-4641-4f34-89c8-8557805219cd",
"state": "DONE",
"report": {
"recommendation": {
"value": "APPROVE"
},
"breakdown": [
{
"sub_check": "ai_face_match",
"result": "PASS",
"details": [
{
"name": "confidence_score",
"value": "0.95"
}
]
}
]
}
}
],
"user_tracking_id": "12345"
}
Default responses
The sandbox automatically provides approved results for configured checks using sample data, for example:
This lets you test result handling without configuration.
Step 5: (Optional) Configure custom responses
To simulate failures or custom scenarios, refer to the sandbox Configure response guide. This lets you provide mock data such as for text extraction and also simulate partial check approvals or rejections.
You can use the same production SDKs for this as well.
Next steps
Troubleshooting
Session not completing? Verify you're using the sandbox URL: https://api.yoti.com/sandbox/idverify/v1
Authentication errors? Ensure you're using sandbox keys (not production) and haven't opened the PEM file manually.