The Platform API allows clients to drive the eKYC journey programmatically via direct HTTP calls, without using WebView or mobile SDKs.
Base endpoint:
access_token.access_token as a Bearer token in subsequent calls:Authorization: Bearer <access_token>
Initializes an eKYC session from the client-generated encrypted token. This single call handles token parsing, application creation (or lookup), bootstrap configuration, and access token issuance.
| Method | Path | Content-Type | Auth Required |
|---|---|---|---|
| GET | /ekyc/platform/init | — | No |
Query Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
| encrypted_token | string | Yes | The ENCODED_VALUE generated by the Authentication mechanism above (AES-256 CBC encrypted user identity, Base64 URL encoded with key ID prefix) |
| flow_id | string | No | Specific flow to initialize |
| card_types | string | No | Comma-separated list of allowed card types (e.g. vn.national_id,vn.passport) |
| lang | string | No | Language code (e.g. vi, en) |
Success (200):
{
"data": {
"token": "<unique_token>",
"access_token": "<JWT>",
"bootstrap": {
"lender_code": "lender_vn",
"lender_country": "VN",
"lender_language": "vi",
"ui_version": "4.0",
"masked_phone_number": "09*****123",
"required_steps": [],
"flow_selected_at": 1700000000,
"lead_source": "sms",
"client_custom_settings": {}
}
},
"message": "platform init successfully",
"time": "2026-01-01T00:00:00Z",
"verdict": "success"
}
| verdict | Status code | Description |
|---|---|---|
| success | 200 | Session initialized successfully. |
| invalid_parameters | 400 | encrypted_token is missing or has invalid format. |
| record_not_found | 404 | Encryption key, lender, or application not found / expired. |
| limit_exceeded | 429 | Concurrent init request in progress — retry shortly. |
| failure | 500 | Internal server error. |
Uploads ID card images (and optional QR images), runs OCR and tampering checks, and returns the final verification result synchronously.
| Method | Path | Content-Type | Auth Required |
|---|---|---|---|
| POST | /ekyc/platform/verify_id | application/json | Yes |
Request Body:
| Name | Type | Required | Description |
|---|---|---|---|
| card_type | string | Yes | Card type to verify (e.g. vn.national_id, vn.passport, ph.philhealth) |
| image | object | Yes | Front side image: { "base64": "<base64_string>", "metadata": "<string>", "qr_code": [{"result": "...", "from_image_type": "..."}] } |
| image2 | object | No | Back side image: same structure as image |
| qrs | array | No | QR code images: [{ "base64": "<base64_string>", "metadata": "<string>" }] |
Success (200):
{
"data": {
"status": "success",
"error_code": "",
"error_message": {},
"label": "vn.national_id.front",
"next_action": "",
"application_state": ""
},
"message": "verify id card completed",
"time": "2026-01-01T00:00:00Z",
"verdict": "success"
}
Response data fields:
| Field | Type | Description |
|---|---|---|
| status | string | Verification result: success, failure, partial_success, etc. |
| error_code | string | Error code when status is failure (omitted on success) |
| error_message | object | Human-readable error details (omitted on success) |
| label | string | Image label that was processed (e.g. vn.national_id.front) |
| next_action | string | Action the client should take next (e.g. process_qr_code) — if applicable |
| application_state | string | Updated application state after verification |
| verdict | Status code | Description |
|---|---|---|
| success | 200 | Verification completed (check data.status for result). |
| invalid_parameters | 400 | Missing or invalid card_type, image, or base64 data. |
| missing_authorization | 401 | Bearer access_token is missing. |
| expired_token | 401 | Access token expired — call Initialization API again. |
| record_not_found | 404 | Session referenced by the access token no longer exists (expired or reset). |
| limit_exceeded | 429 | A verification is already in progress for this session. |
| failure | 500 | Internal server error or verification timeout. |
Uploads selfie images, runs liveness detection and face matching, and returns the final verification result synchronously. The last image in the images array is treated as the primary selfie.
| Method | Path | Content-Type | Auth Required |
|---|---|---|---|
| POST | /ekyc/platform/verify_selfie | application/json | Yes |
Request Body:
| Name | Type | Required | Description |
|---|---|---|---|
| images | array | Yes | Array of selfie images: [{ "base64": "<base64_string>", "metadata": "<string>" }]. The last element is the primary selfie. |
| selfie_type | string | No | Type of selfie flow (e.g. passive, flash) |
Success (200):
{
"data": {
"status": "success",
"error_code": "",
"error_message": {},
"label": "portrait",
"next_action": "",
"application_state": ""
},
"message": "verify selfie completed",
"time": "2026-01-01T00:00:00Z",
"verdict": "success"
}
Response data fields are identical to the ID Verification API.
| verdict | Status code | Description |
|---|---|---|
| success | 200 | Verification completed (check data.status for result). |
| invalid_parameters | 400 | images is empty or contains invalid base64 data. |
| missing_authorization | 401 | Bearer access_token is missing. |
| expired_token | 401 | Access token expired — call Initialization API again. |
| record_not_found | 404 | Session referenced by the access token no longer exists (expired or reset). |
| limit_exceeded | 429 | A verification is already in progress for this session. |
| failure | 500 | Internal server error or verification timeout. |
Bundles the three calls above (Init → ID Verification → Selfie Verification) into a single synchronous request. It imports a complete dossier, 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 API Application Detail — in the response.
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.
Authentication: unlike Verify ID / Verify Selfie, this endpoint does not require a prior Init or a Bearer
access_token— it authenticates with theencrypted_tokenin the body (the same token as Init). The response still returns anaccess_tokenyou can use to re-pull API Application Detail later.
Note: the request blocks until all checks finish (ID + selfie run sequentially), so allow a generous client timeout.
| Method | Path | Content-Type | Auth Required |
|---|---|---|---|
| POST | /ekyc/platform/onboard | application/json | No |
Request Body:
| Name | Type | Required | Description |
|---|---|---|---|
| encrypted_token | string | Yes | The ENCODED_VALUE from the Authentication mechanism (same as Init). Identifies the user; the user reference inside it is the idempotency key. |
| flow_id | string | No | Specific flow to use. |
| card_types | string | No | Comma-separated allowed card types (e.g. vn.national_id,vn.passport). |
| lang | string | No | Language code (e.g. vi, en). |
| card_type | string | Yes (for ID) | Card type to verify (e.g. vn.national_id). Must be within card_types when that is provided. |
| image1 | object | Yes (for ID) | ID front: { "base64": "<base64>", "metadata": "<string>", "qr_code": [{"result": "...", "from_image_type": "..."}] }. |
| image2 | object | No | ID back: same structure as image1. |
| qrs | array | No | Standalone QR images: [{ "base64": "<base64>", "metadata": "<string>" }]. |
| selfies | array | Yes (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. |
| selfie_type | string | No | Selfie / liveness type (e.g. passive, passive_v2, flash). |
| videos | array | No | 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. |
| client_metadata | object | No | 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 endpoint blocks until all checks complete, then returns the full result — the same TS-native shape as API 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": "Jane Doe",
"gender": "female"
},
"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 API 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 API Application Detail for this application later. |
See API Application Detail for the full field reference (the verdict, file_ids, and form_data mappings).
| verdict | Status code | Description |
|---|---|---|
| success | 200 | Processing completed — read data.verdict for the outcome. |
| missing_parameters | 400 | encrypted_token is missing. |
| invalid_parameters | 400 | Token undecodable, no ID/selfie assets, bad card_type, or invalid base64. |
| record_not_found | 404 | Encryption key or lender not found / inactive. |
| limit_exceeded | 429 | Another submission for the same user is in progress, or rate limit reached. |
| failure | 500 | Internal server error. |
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).