Service API · API Docs · eKYC Platform
Full verification
Synchronously runs a complete eKYC dossier — ID Verification then Selfie Verification — in a single request, and returns the full application result.
Request
The endpoint imports the ID/selfie assets you already hold, runs the configured ID and selfie checks in sequence (waiting for each), drives the application to a terminal state so the configured Post-check / AML / Government checks run, and returns the full TS-native result — the same shape as Application detail.
This is the Service-API (JWT-authed) equivalent of the Platform Onboard API: same request/response shape, but not the same execution path. The lender is resolved from your JWT access token (like API Vision Score), and the server then generates an encrypted_token on your behalf and drives the request through the same underlying Onboard pipeline. That extra internal step is why this endpoint has two failure modes the Onboard API doesn't (see Failure codes): it can fail to generate that token (500), or fail while calling the underlying pipeline with it (502).
Use this when you already hold a user's ID/selfie assets (e.g. captured on another channel or by another vendor) and want to re-check them through the TrustVision pipeline in one call, without driving Init / Verify ID / Verify Selfie separately.
Note: the request blocks until all checks finish (ID + selfie run sequentially), so allow a generous client timeout.
Send the JWT access token in the Authorization header.
| Name | Type | Required | Description |
|---|---|---|---|
card_type | string | Required for ID | Card type to verify (e.g. vn.national_id). Must be within card_types when that is provided. |
image1 | object | Required for ID | ID front: { "base64": "<base64>", "metadata": "<string>", "qr_code": [{"result": "...", "from_image_type": "..."}] }. |
image2 | object | Optional | ID back: same structure as image1. |
qrs | array | Optional | Standalone QR images: [{ "base64": "<base64>", "metadata": "<string>" }]. |
selfies | array | Required for selfie | Frontal selfie image(s): [{ "base64" \| "id", "metadata" }]. The last element is the primary selfie used for face compare. An element with id references a pre-uploaded image (see Upload image). |
selfie_type | string | Optional | Selfie / liveness type (e.g. passive, passive_v2, flash). |
videos | array | Optional | Liveness video frames: [{ "id"?, "metadata"?, "frames": [{ "base64", "label", "index", "metadata"? }] }] (≤ 10). Required for passive/flash liveness to pass — a still-only selfie gives the engine nothing to score. |
flow_id | string | Optional | Routes the request to the lender config mapped to this flow via the encryption key's flow_lender_config_mapping. Falls back to the lender's active config. |
card_types | string | Optional | Comma-separated allowed card types (e.g. vn.national_id,vn.passport). |
lang | string | Optional | Language code (e.g. vi, en). |
client_metadata | object | Optional | Optional prepared metadata (e.g. applicant identity PII: applicant_name, id_number, dob, gender, phone_number, email), already encrypted by you. JSON ≤ 8 KB. Stored raw and echoed back raw only — never decrypted, and never fed into any check or the verdict. |
At least one of image1 (ID) or selfies (selfie) must be present — supply only one group for an ID-only or selfie-only re-check. Put liveness frames in videos, not in selfies.
The body is identical to the Platform Onboard API minus encrypted_token — authentication is handled by the JWT, so no token is sent in the body.
{
"card_type": "vn.national_id",
"image1": {
"base64": "<base64_string>",
"metadata": "{\"frame_index\":0}",
"qr_code": [{ "result": "...", "from_image_type": "front" }]
},
"image2": {
"base64": "<base64_string>"
},
"selfies": [
{ "base64": "<base64_string>", "metadata": "{\"frame_index\":0}" }
],
"selfie_type": "passive",
"videos": [
{
"frames": [
{ "base64": "<base64_string>", "label": "frontal", "index": 0 }
]
}
],
"flow_id": "full_verification",
"card_types": "vn.national_id,vn.passport",
"lang": "vi",
"client_metadata": {
"applicant_name": "<already-encrypted>",
"id_number": "<already-encrypted>"
}
}
Response
The endpoint blocks until all checks complete, then returns the full result — the same TS-native shape as Application detail (overall verdict plus each module's status). Conditional blocks (ekyc_ocr / ekyc_face / id_tampering / file_ids / form_data / client_metadata) appear only when the corresponding data exists.
Success (200):
{
"data": {
"verdict": "approve",
"application_id": 10,
"application_unique_token": "ad083945-...",
"application_user_id": "0123456789",
"ekyc_ocr": {
"card_info": {},
"process_status": "success",
"sanity_check_status": "success"
},
"ekyc_face": {
"compare_status": "matched",
"compare_score": 0.98,
"liveness_status": "live",
"search_face_status": "not_found"
},
"id_tampering": { "score": 0.01, "verdict": "genuine" },
"client_metadata": {
"applicant_name": "<already-encrypted>",
"id_number": "<already-encrypted>"
},
"access_token": "<JWT>"
},
"message": "onboard completed",
"time": "2026-01-01T00:00:00Z",
"verdict": "success"
}
Response data fields:
| Field | Description |
|---|---|
| data.verdict | Overall application verdict: approve, review, reject, or pending. |
| ekyc_ocr / ekyc_face / id_tampering | Per-module results + status (same as Application detail). Present only when run. |
| client_metadata | The prepared metadata you supplied, echoed back raw (omitted if none). |
| access_token | JWT to re-pull Application detail for this application later. |
See Application detail for the full field reference, and The application result for the verdict, file_ids and form_data mappings.
Dedupe / indexing-only mode: when enabled for the lender (client_custom_settings.onboard_dedupe_only), the endpoint runs only face index/search, leaves data.verdict as pending, and returns the match result on data.ekyc_face.search_face_result / search_face_status (the Post-check / AML / verdict pipeline is skipped).
Failure codes
| Name | Description | Status code | Response Body |
|---|---|---|---|
| Bad Request | Invalid parameters / missing config | 400 | {"data":{},"message":"eKYC platform URL not configured","verdict":"failure"} / relayed invalid_parameters / missing_parameters |
| Unauthorized | Invalid authentication token | 401 | {"data":{},"message":"authorization header is missing","time":"2024-10-31T07:50:22Z","verdict":"missing_authorization"} |
| Token Expired | Token expired. Client should login again | 401 | {"data":{},"message":"Provided token is expired","time":"2024-10-31T07:50:22Z","verdict":"expired_token"} |
| Not Found | Encryption key or lender not found / inactive | 404 | {"data":{},"message":"...","verdict":"record_not_found"} |
| Too Many Requests | Another submission for the same user is in progress, or rate limit reached | 429 | {"data":{},"message":"...","verdict":"limit_exceeded"} |
| Internal Server Error | Cannot create encrypted token | 500 | {"data":{},"message":"cannot create encrypted token","verdict":"failure"} |
| Bad Gateway | Upstream platform call failed (transport) | 502 | {"data":{},"message":"platform onboard failed: ...","verdict":"failure"} |