The Service API is a JWT-authenticated set of backend endpoints for pulling eKYC application results and files, and for running supporting checks (face indexing, full eKYC checks, image upload) directly against the eKYC Platform backend.
Base endpoint:
The client authenticates using username and password to receive a JWT access token.
Method Path Content-Type Auth Required POST /auth/users/loginapplication/json No
Request Body:
Name Type Required Description user_namestring Yes Account username. passwordstring Yes Account password.
Name Description Status code Response Body Success Login successfully 200 {"data":{"access_token":"<JWT>"},"message":"login success","time":"2024-10-31T07:34:52Z","verdict":"success"}Bad Request Invalid username pattern 400 {"data":{"invalid_parameters":["user_name"],"parameter_formats":{"user_name":"[regex: ^[a-z0-9_]{1,63}$]"}},"message":"some parameters has invalid format","time":"2024-11-06T03:30:42Z","verdict":"invalid_parameters"}Unauthorized Incorrect username or password 401 {"data":{},"message":"username or password is incorrect","time":"2024-10-31T07:50:22Z","verdict":"invalid_credential"}Invalid Method Invalid URL or method 405 {"data":{},"message":"method is not correct for the requested route","time":"2024-11-06T03:23:26Z","verdict":"invalid_method"}Too many requests Too many failed login attempts 429 {"data":{},"message":"too many failed login attempts","time":"2024-11-06T03:33:43Z","verdict":"limit_exceeded"}Internal Server Error Internal Server Error 500 {"data":{},"message":"Unexpected error. Error ID: ff4d5572d9df4560bb6dabc2eadd5a1e","time":"2024-11-06T03:32:09Z","verdict":"failure"}
Use the access token JWT to call GET /application/detail.
Method Path Content-Type Auth Required GET /portal/application/detail— Yes
Header key Header Value Description AuthorizationBearer <JWT>Include the JWT access token to support request authentication
Parameter key Description application_idcorresponding with the application_id in the callback result idcorresponding with the application_user_id in the callback result
Name Description Status code Response Body Success request successfully 200 See the sample success response below Bad Request Invalid parameters 400 {"data":{},"message":"","verdict":"invalid_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 Not found 404 {"data":{},"message":"applications not available","time":"2024-10-31T08:27:27Z","verdict":"record_not_found"}Invalid Method Invalid URL or method 405 {"data":{},"message":"method is not correct for the requested route","time":"2024-11-06T03:23:26Z","verdict":"invalid_method"}Too many requests Too many failed login attempts 429 {"data":{},"message":"too many failed login attempts","time":"2024-11-06T03:33:43Z","verdict":"limit_exceeded"}Internal Server Error Internal Server Error 500 {"data":{},"message":"Unexpected error. Error ID: ff4d5572d9df4560bb6dabc2eadd5a1e","time":"2024-11-06T03:32:09Z","verdict":"failure"}
On success case: 200 OK
The response payload varies based on the flow configuration. Select a scenario below to see the relevant fields.
ID Only Selfie Only Full Flow
{
"data" : {
"verdict" : "pending|approve|review|reject" ,
"application_id" : 10 ,
"application_unique_token" : "ad083945-9620-486c-be7d-c3f5dab870a1" ,
"application_user_id" : "01234567889" ,
"file_ids" : {
"id_front_img_uuid" : "8fdcb17e-5d41-4814-8d4f-8c1bfb51df20" ,
"id_back_img_uuid" : "93cef1cd-2782-4264-9c65-cce78ce3f549" ,
"qr1_img_uuid" : ""
},
"ekyc_ocr" : {
"card_info" : {
"card_info" : [
{ "confidence_score" : 0 , "confidence_verdict" : "" , "field" : "crn" , "value" : "0123456789" },
{ "confidence_score" : 0 , "confidence_verdict" : "" , "field" : "last_name" , "value" : "SANTOS" },
{ "confidence_score" : 0 , "confidence_verdict" : "" , "field" : "first_name" , "value" : "JOSE" },
{ "confidence_score" : 0 , "confidence_verdict" : "" , "field" : "middle_name" , "value" : "CRUZ" },
{ "confidence_score" : 0 , "confidence_verdict" : "" , "field" : "date_of_birth" , "value" : "1990/01/01" },
{ "confidence_score" : 0 , "confidence_verdict" : "" , "field" : "gender" , "value" : "F" },
{ "confidence_score" : 0 , "confidence_verdict" : "" , "field" : "address" , "value" : "CABAROAN SAN ESTEBAN ILOCOS SUR PHL 2706" },
{ "confidence_score" : 0 , "confidence_verdict" : "" , "field" : "id" , "value" : "0123456789" },
{ "confidence_score" : 0 , "confidence_verdict" : "" , "field" : "card_type" , "value" : "ph.ump" },
{ "confidence_score" : 0 , "confidence_verdict" : "" , "field" : "card_label" , "value" : "ph.ump.front" },
{ "confidence_score" : 0 , "confidence_verdict" : "" , "field" : "name" , "value" : "JOSE CRUZ SANTOS" }
],
"converted_card_info" : {
"address" : "CABAROAN SAN ESTEBAN ILOCOS SUR PHL 2706" ,
"birth_date" : "1990/01/01" ,
"card_label" : "ph.ump.front" ,
"card_type" : "ph.ump" ,
"gender" : "F" ,
"id_number" : "0123456789" ,
"name" : "JOSE CRUZ SANTOS"
}
},
"process_status" : "success" ,
"processed_at" : "2024-09-26T18:11:29+07:00" ,
"sanity_check_result" : "good" ,
"sanity_check_score" : 1 ,
"sanity_check_status" : "success" ,
"search_face_result" : null ,
"search_face_status" : "disabled"
},
"id_tampering" : {
"score" : 1 ,
"verdict" : "good"
},
"form_data" : {
"contactInfo" : {
"familyAddress" : "CABAROAN SAN ESTEBAN ILOCOS SUR PHL 2706"
},
"personalInfo" : {
"birthday" : "1990/01/01" ,
"fullName" : "JOSE CRUZ SANTOS" ,
"gender" : "" ,
"idCard" : "0123456789"
}
},
"time" : "2024-09-27T09:50:32+07:00"
}
}
verdict Description pending The user has not completed the flow approve Our recommendation to approve this application review Our recommendation to review this application reject Our recommendation to reject this application
key Description Present in id_front_img_uuid The image id of front side ID Only, Full Flow id_back_img_uuid The image id of back side ID Only, Full Flow qr1_img_uuid The image id of QR code ID Only, Full Flow selfie_image_uuid The image id of selfie that use to compare faces Selfie Only, Full Flow gesture_images List images during user do liveness Selfie Only, Full Flow sequence_frames List frames video during user do liveness Selfie Only, Full Flow liveness_transformed_video_id The video id merge from sequence frames Selfie Only, Full Flow
{
"contactInfo" : {
"familyAddress" : "CABAROAN SAN ESTEBAN ILOCOS SUR PHL 2706"
},
"personalInfo" : {
"birthday" : "1990/01/01" ,
"fullName" : "JOSE CRUZ SANTOS" ,
"gender" : "" ,
"idCard" : "0123456789"
}
}
Method Path Content-Type Auth Required GET /portal/document/download_ekyc_file— Yes
Header key Header Value Description AuthorizationBearer <JWT>Include the JWT access token to support request authentication
Parameter key Description application_idcorresponding with the application_id in the callback result idcorresponding with the file_ids in the callback result
Name Description Status code Response Body Success request successfully 200 See the sample success response below Bad Request Invalid parameters 400 {"data":{},"message":"","verdict":"invalid_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 Not found 404 {"data":{},"message":"applications not available","time":"2024-10-31T08:27:27Z","verdict":"record_not_found"}Invalid Method Invalid URL or method 405 {"data":{},"message":"method is not correct for the requested route","time":"2024-11-06T03:23:26Z","verdict":"invalid_method"}Too many requests Too many failed login attempts 429 {"data":{},"message":"too many failed login attempts","time":"2024-11-06T03:33:43Z","verdict":"limit_exceeded"}Internal Server Error Internal Server Error 500 {"data":{},"message":"Unexpected error. Error ID: ff4d5572d9df4560bb6dabc2eadd5a1e","time":"2024-11-06T03:32:09Z","verdict":"failure"}
On success case: the HTTP status code will be 200, and server will send the file as binary content.
Method Path Content-Type Auth Required POST /portal/ekyc/index_facesapplication/json Yes
Header key Header Value Description AuthorizationBearer <JWT>Include the JWT access token to support request authentication
Request Body:
{
"image_base64" : string,
"collection" : string,
"label" : string,
"metadata" : JSON
}
Name Type Required Description image_base64string Yes Encode base64 of binary image without prefix, e.g. data:image/jpeg;base64, labelstring Yes Label of the image as described at Label table metadatajson Yes More information of the image, e.g. client_uid, phone_number, dob, name. client_uid must not be empty collectionstring No Index faces to this collection. Case-sensitive.
metadata accepts:
Name Type Required Description client_uidstring Yes ID of a user or application or any unique token national_idstring No ID number of the user's ID card unique_tokenstring No The application_unique_token token from Application Detail
Name Description Status code Response Body Success request successfully 200 See the sample success response below Bad Request Invalid parameters 400 {"data":{},"message":"","verdict":"invalid_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 Not found 404 {"data":{},"message":"applications not available","time":"2024-10-31T08:27:27Z","verdict":"record_not_found"}Invalid Method Invalid URL or method 405 {"data":{},"message":"method is not correct for the requested route","time":"2024-11-06T03:23:26Z","verdict":"invalid_method"}Too many requests Too many failed login attempts 429 {"data":{},"message":"too many failed login attempts","time":"2024-11-06T03:33:43Z","verdict":"limit_exceeded"}Internal Server Error Internal Server Error 500 {"data":{},"message":"Unexpected error. Error ID: ff4d5572d9df4560bb6dabc2eadd5a1e","time":"2024-11-06T03:32:09Z","verdict":"failure"}
On success case: the HTTP status code will be 200, and server will send the file as binary content.
Method Path Content-Type Auth Required POST /portal/ekyc/full_checksapplication/json Yes
Header key Header Value Description AuthorizationBearer <JWT>Include the JWT access token to support request authentication
Request Body:
{
"card_type" : string,
"image1" : {
"base64" : string,
"label" : string,
"metadata" : JSON
},
"image2" : {
"base64" : string,
"label" : string,
"metadata" : JSON
},
"selfies" : [
{
"base64" : string,
"label" : string,
"metadata" : JSON
},
...
{
"base64" : string,
"label" : string,
"metadata" : JSON
}
]
"metadata" : JSON
}
Name Type Required Description card_typestring Yes Card type of the image as described at Card types table image1ImageData Yes Image of the identity card's front side image2ImageData No Image of the identity card's back side selfies[]ImageData No List of selfie images of the customer. Max 3 images. metadatajson Yes More information of the identity, e.g. client_uid, phone_number, dob, name. client_uid must not be empty
Each image object accepts:
Name Type Required Description base64string Yes Base64 encoded text of image data labelstring No Label of the image as described at Label table metadatajson No Key-value string; keys must be strings, values may be string, int, float, or bool. Example "{\"id\":\"123456789\",\"type\":1}"
metadata accepts:
Name Type Required Description client_uidstring Yes ID of a user or application or any unique token national_idstring No ID number of the user's ID card unique_tokenstring No The application_unique_token token from Application Detail
Name Description Status code Response Body Success request successfully 200 See the sample success response below Bad Request Invalid parameters 400 {"data":{},"message":"","verdict":"invalid_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"}Invalid Method Invalid URL or method 405 {"data":{},"message":"method is not correct for the requested route","time":"2024-11-06T03:23:26Z","verdict":"invalid_method"}Too many requests Too many failed login attempts 429 {"data":{},"message":"too many failed login attempts","time":"2024-11-06T03:33:43Z","verdict":"limit_exceeded"}Internal Server Error Internal Server Error 500 {"data":{},"message":"Unexpected error. Error ID: ff4d5572d9df4560bb6dabc2eadd5a1e","time":"2024-11-06T03:32:09Z","verdict":"failure"}
On success case: 200 OK
{
"data" : {
"request_id" : "538cdfe9-7009-4bcf-b514-6faf8904e82c" ,
"card_information" : [
{
"field" : "id" ,
"value" : "123456789012" ,
"confidence_verdict" : "" ,
"confidence_score" : 0
},
{
"field" : "name" ,
"value" : "FULL NAME" ,
"confidence_verdict" : "" ,
"confidence_score" : 0
},
{
"field" : "date_of_birth" ,
"value" : "2005/03/02" ,
"confidence_verdict" : "" ,
"confidence_score" : 0
},
{
"field" : "gender" ,
"value" : "F" ,
"confidence_verdict" : "" ,
"confidence_score" : 0
},
{
"field" : "address" ,
"value" : "RD 1000 NDC COMPOUND,, SITH DISTRICT" ,
"confidence_verdict" : "" ,
"confidence_score" : 0
},
{
"field" : "last_name" ,
"value" : "LAST NAME" ,
"confidence_verdict" : "" ,
"confidence_score" : 0
},
{
"field" : "first_name" ,
"value" : "FIRST NAME" ,
"confidence_verdict" : "" ,
"confidence_score" : 0
},
{
"field" : "middle_name" ,
"value" : "MIDDLE NAME" ,
"confidence_verdict" : "" ,
"confidence_score" : 0
},
{
"field" : "card_type" ,
"value" : "ph.philhealth" ,
"confidence_verdict" : "" ,
"confidence_score" : 0
},
{
"field" : "card_label" ,
"value" : "ph.philhealth.qr.front" ,
"confidence_verdict" : "" ,
"confidence_score" : 0
}
],
"compare_faces" : [
{
"face1_id" : "7d71e6e2-a6bb-4ea6-8826-be0947afd6f4" ,
"face2_id" : "1647fae2-7ff2-4500-89cc-4196e42512ce" ,
"result" : "matched" ,
"score" : 0.8136464
}
],
"liveness_check" : {
"is_live" : true ,
"score" : 0.99999917
},
"portrait_sanity" : {
"verdict" : "good" ,
"score" : 1
},
"card_sanity" : {
"verdict" : "photo_not_qualified" ,
"score" : 0.8199463 ,
"score_details" : [
{
"verdict" : "good" ,
"score" : 1
},
{
"verdict" : "photo_not_qualified" ,
"score" : 0.8199463
}
],
"verdict_details" : {}
},
"card_tampering" : {
"verdict" : "alert" ,
"score" : 1 ,
"details" : [
{
"verdict" : "non_liveness" ,
"score" : 0.99 ,
"name" : "alert_1" ,
"info" : "image1"
}
]
}
},
"message" : "fully check eKYC successfully" ,
"time" : "2026-01-27T18:03:56+07:00" ,
"verdict" : "success"
}
verdict Description success Process the request successfully. failure Process the request failure.
Uploads a single image file to eKYC and returns the image_id that can be referenced by other eKYC Platform Service API batch endpoints' images[].id field instead of re-sending the bytes.
Method Path Content-Type Auth Required POST /portal/ekyc/upload/imagemultipart/form-data Yes
Header key Header Value Description AuthorizationBearer <JWT>Include the JWT access token to support request authentication
Form Fields:
Field Type Required Description filefile Yes Image file. Must be non-empty. Maximum size is governed by the server's tv_max_file_size setting. labelstring No Image label as described at Label table . metadatastring No JSON-encoded string with per-image metadata.
{
"data" : {
"image_id" : "8fdcb17e-5d41-4814-8d4f-8c1bfb51df20"
},
"message" : "image uploaded" ,
"time" : "2026-05-04T09:00:00+07:00" ,
"verdict" : "success"
}
Synchronously runs a complete eKYC dossier (ID Verification → Selfie Verification) in a single request. It 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 API 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 the error table below): 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.
Method Path Content-Type Auth Required POST /portal/ekyc/full_verificationapplication/json Yes
Header key Header Value Description AuthorizationBearer <JWT>Include the JWT access token to support request authentication
Request Body:
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>"
}
}
Name Type Required Description card_typestring Yes (for ID) Card type to verify (e.g. vn.national_id). Must be within card_types when that is provided. image1object Yes (for ID) ID front: { "base64": "<base64>", "metadata": "<string>", "qr_code": [{"result": "...", "from_image_type": "..."}] }. image2object No ID back: same structure as image1. qrsarray No Standalone QR images: [{ "base64": "<base64>", "metadata": "<string>" }]. selfiesarray 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 (see API Upload Image ). selfie_typestring No Selfie / liveness type (e.g. passive, passive_v2, flash). videosarray 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. flow_idstring No 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_typesstring No Comma-separated allowed card types (e.g. vn.national_id,vn.passport). langstring No Language code (e.g. vi, en). client_metadataobject 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" : "<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 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).
Name Description Status code Response Body Success Processing completed — read data.verdict 200 See the sample success response above Bad Request Invalid parameters / missing config 400 {"data":{},"message":"eKYC platform URL not configured","verdict":"failure"} / relayed invalid_parameters / missing_parametersUnauthorized 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"}
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).
Runs Vision Score (face liveness + selfie quality) through this same Service API JWT auth. See Vision Score API for the full request/response reference.