• eKYC Platform
    About TrustVision
    SDK Integration
    Trust Central
TrustVision API Documentation

Service API

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:

Authentication mechanism

The client authenticates using username and password to receive a JWT access token.

1. Request

MethodPathContent-TypeAuth Required
POST/auth/users/loginapplication/jsonNo

Request Body:

NameTypeRequiredDescription
user_namestringYesAccount username.
passwordstringYesAccount password.

2. Response

NameDescriptionStatus codeResponse Body
SuccessLogin successfully200{"data":{"access_token":"<JWT>"},"message":"login success","time":"2024-10-31T07:34:52Z","verdict":"success"}
Bad RequestInvalid username pattern400{"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"}
UnauthorizedIncorrect username or password401{"data":{},"message":"username or password is incorrect","time":"2024-10-31T07:50:22Z","verdict":"invalid_credential"}
Invalid MethodInvalid URL or method405{"data":{},"message":"method is not correct for the requested route","time":"2024-11-06T03:23:26Z","verdict":"invalid_method"}
Too many requestsToo many failed login attempts429{"data":{},"message":"too many failed login attempts","time":"2024-11-06T03:33:43Z","verdict":"limit_exceeded"}
Internal Server ErrorInternal Server Error500{"data":{},"message":"Unexpected error. Error ID: ff4d5572d9df4560bb6dabc2eadd5a1e","time":"2024-11-06T03:32:09Z","verdict":"failure"}

Application Detail

Use the access token JWT to call GET /application/detail.

1. Request

MethodPathContent-TypeAuth Required
GET/portal/application/detailYes

Headers

Header keyHeader ValueDescription
AuthorizationBearer <JWT>Include the JWT access token to support request authentication

Query Parameters

Parameter keyDescription
application_idcorresponding with the application_id in the callback result
idcorresponding with the application_user_id in the callback result

2. Response

NameDescriptionStatus codeResponse Body
Successrequest successfully200See the sample success response below
Bad RequestInvalid parameters400{"data":{},"message":"","verdict":"invalid_parameters"}
UnauthorizedInvalid authentication token401{"data":{},"message":"authorization header is missing","time":"2024-10-31T07:50:22Z","verdict":"missing_authorization"}
Token ExpiredToken expired. Client should login again401{"data":{},"message":"Provided token is expired","time":"2024-10-31T07:50:22Z","verdict":"expired_token"}
Not foundNot found404{"data":{},"message":"applications not available","time":"2024-10-31T08:27:27Z","verdict":"record_not_found"}
Invalid MethodInvalid URL or method405{"data":{},"message":"method is not correct for the requested route","time":"2024-11-06T03:23:26Z","verdict":"invalid_method"}
Too many requestsToo many failed login attempts429{"data":{},"message":"too many failed login attempts","time":"2024-11-06T03:33:43Z","verdict":"limit_exceeded"}
Internal Server ErrorInternal Server Error500{"data":{},"message":"Unexpected error. Error ID: ff4d5572d9df4560bb6dabc2eadd5a1e","time":"2024-11-06T03:32:09Z","verdict":"failure"}

On success case: 200 OK

JSON Response

The response payload varies based on the flow configuration. Select a scenario below to see the relevant fields.

{
  "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"
  }
}

Which verdict response mapping:

verdictDescription
pendingThe user has not completed the flow
approveOur recommendation to approve this application
reviewOur recommendation to review this application
rejectOur recommendation to reject this application

Which file_ids response mapping:

keyDescriptionPresent in
id_front_img_uuidThe image id of front sideID Only, Full Flow
id_back_img_uuidThe image id of back sideID Only, Full Flow
qr1_img_uuidThe image id of QR codeID Only, Full Flow
selfie_image_uuidThe image id of selfie that use to compare facesSelfie Only, Full Flow
gesture_imagesList images during user do livenessSelfie Only, Full Flow
sequence_framesList frames video during user do livenessSelfie Only, Full Flow
liveness_transformed_video_idThe video id merge from sequence framesSelfie Only, Full Flow

Which form_data response object:

json
{
  "contactInfo": {
    "familyAddress": "CABAROAN SAN ESTEBAN ILOCOS SUR PHL 2706"
  },
  "personalInfo": {
    "birthday": "1990/01/01",
    "fullName": "JOSE CRUZ SANTOS",
    "gender": "",
    "idCard": "0123456789"
  }
}

Download file

1. Request

MethodPathContent-TypeAuth Required
GET/portal/document/download_ekyc_fileYes

Headers

Header keyHeader ValueDescription
AuthorizationBearer <JWT>Include the JWT access token to support request authentication

Query Parameters

Parameter keyDescription
application_idcorresponding with the application_id in the callback result
idcorresponding with the file_ids in the callback result

2. Response

NameDescriptionStatus codeResponse Body
Successrequest successfully200See the sample success response below
Bad RequestInvalid parameters400{"data":{},"message":"","verdict":"invalid_parameters"}
UnauthorizedInvalid authentication token401{"data":{},"message":"authorization header is missing","time":"2024-10-31T07:50:22Z","verdict":"missing_authorization"}
Token ExpiredToken expired. Client should login again401{"data":{},"message":"Provided token is expired","time":"2024-10-31T07:50:22Z","verdict":"expired_token"}
Not foundNot found404{"data":{},"message":"applications not available","time":"2024-10-31T08:27:27Z","verdict":"record_not_found"}
Invalid MethodInvalid URL or method405{"data":{},"message":"method is not correct for the requested route","time":"2024-11-06T03:23:26Z","verdict":"invalid_method"}
Too many requestsToo many failed login attempts429{"data":{},"message":"too many failed login attempts","time":"2024-11-06T03:33:43Z","verdict":"limit_exceeded"}
Internal Server ErrorInternal Server Error500{"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.

Index Faces

1. Request

MethodPathContent-TypeAuth Required
POST/portal/ekyc/index_facesapplication/jsonYes

Headers

Header keyHeader ValueDescription
AuthorizationBearer <JWT>Include the JWT access token to support request authentication

Request Body:

JSON
{
    "image_base64": string,
    "collection": string,
    "label": string,
    "metadata": JSON
}
NameTypeRequiredDescription
image_base64stringYesEncode base64 of binary image without prefix, e.g. data:image/jpeg;base64,
labelstringYesLabel of the image as described at Label table
metadatajsonYesMore information of the image, e.g. client_uid, phone_number, dob, name. client_uid must not be empty
collectionstringNoIndex faces to this collection. Case-sensitive.

metadata accepts:

NameTypeRequiredDescription
client_uidstringYesID of a user or application or any unique token
national_idstringNoID number of the user's ID card
unique_tokenstringNoThe application_unique_token token from Application Detail

2. Response

NameDescriptionStatus codeResponse Body
Successrequest successfully200See the sample success response below
Bad RequestInvalid parameters400{"data":{},"message":"","verdict":"invalid_parameters"}
UnauthorizedInvalid authentication token401{"data":{},"message":"authorization header is missing","time":"2024-10-31T07:50:22Z","verdict":"missing_authorization"}
Token ExpiredToken expired. Client should login again401{"data":{},"message":"Provided token is expired","time":"2024-10-31T07:50:22Z","verdict":"expired_token"}
Not foundNot found404{"data":{},"message":"applications not available","time":"2024-10-31T08:27:27Z","verdict":"record_not_found"}
Invalid MethodInvalid URL or method405{"data":{},"message":"method is not correct for the requested route","time":"2024-11-06T03:23:26Z","verdict":"invalid_method"}
Too many requestsToo many failed login attempts429{"data":{},"message":"too many failed login attempts","time":"2024-11-06T03:33:43Z","verdict":"limit_exceeded"}
Internal Server ErrorInternal Server Error500{"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.

eKYC full checks (Deprecated)

1. Request

MethodPathContent-TypeAuth Required
POST/portal/ekyc/full_checksapplication/jsonYes

Headers

Header keyHeader ValueDescription
AuthorizationBearer <JWT>Include the JWT access token to support request authentication

Request Body:

JSON
{
  "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
}
NameTypeRequiredDescription
card_typestringYesCard type of the image as described at Card types table
image1ImageDataYesImage of the identity card's front side
image2ImageDataNoImage of the identity card's back side
selfies[]ImageDataNoList of selfie images of the customer. Max 3 images.
metadatajsonYesMore information of the identity, e.g. client_uid, phone_number, dob, name. client_uid must not be empty

Each image object accepts:

NameTypeRequiredDescription
base64stringYesBase64 encoded text of image data
labelstringNoLabel of the image as described at Label table
metadatajsonNoKey-value string; keys must be strings, values may be string, int, float, or bool. Example "{\"id\":\"123456789\",\"type\":1}"

metadata accepts:

NameTypeRequiredDescription
client_uidstringYesID of a user or application or any unique token
national_idstringNoID number of the user's ID card
unique_tokenstringNoThe application_unique_token token from Application Detail

2. Response

NameDescriptionStatus codeResponse Body
Successrequest successfully200See the sample success response below
Bad RequestInvalid parameters400{"data":{},"message":"","verdict":"invalid_parameters"}
UnauthorizedInvalid authentication token401{"data":{},"message":"authorization header is missing","time":"2024-10-31T07:50:22Z","verdict":"missing_authorization"}
Token ExpiredToken expired. Client should login again401{"data":{},"message":"Provided token is expired","time":"2024-10-31T07:50:22Z","verdict":"expired_token"}
Invalid MethodInvalid URL or method405{"data":{},"message":"method is not correct for the requested route","time":"2024-11-06T03:23:26Z","verdict":"invalid_method"}
Too many requestsToo many failed login attempts429{"data":{},"message":"too many failed login attempts","time":"2024-11-06T03:33:43Z","verdict":"limit_exceeded"}
Internal Server ErrorInternal Server Error500{"data":{},"message":"Unexpected error. Error ID: ff4d5572d9df4560bb6dabc2eadd5a1e","time":"2024-11-06T03:32:09Z","verdict":"failure"}

On success case: 200 OK

JSON Response

json
{
  "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"
}

Which verdict response mapping:

verdictDescription
successProcess the request successfully.
failureProcess the request failure.

Upload Image

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.

1. Request

MethodPathContent-TypeAuth Required
POST/portal/ekyc/upload/imagemultipart/form-dataYes

Headers

Header keyHeader ValueDescription
AuthorizationBearer <JWT>Include the JWT access token to support request authentication

Form Fields:

FieldTypeRequiredDescription
filefileYesImage file. Must be non-empty. Maximum size is governed by the server's tv_max_file_size setting.
labelstringNoImage label as described at Label table.
metadatastringNoJSON-encoded string with per-image metadata.

2. Response

json
{
  "data": {
    "image_id": "8fdcb17e-5d41-4814-8d4f-8c1bfb51df20"
  },
  "message": "image uploaded",
  "time": "2026-05-04T09:00:00+07:00",
  "verdict": "success"
}

Full Verification

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.

1. Request

MethodPathContent-TypeAuth Required
POST/portal/ekyc/full_verificationapplication/jsonYes

Headers

Header keyHeader ValueDescription
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.

json
{
  "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>"
  }
}
NameTypeRequiredDescription
card_typestringYes (for ID)Card type to verify (e.g. vn.national_id). Must be within card_types when that is provided.
image1objectYes (for ID)ID front: { "base64": "<base64>", "metadata": "<string>", "qr_code": [{"result": "...", "from_image_type": "..."}] }.
image2objectNoID back: same structure as image1.
qrsarrayNoStandalone QR images: [{ "base64": "<base64>", "metadata": "<string>" }].
selfiesarrayYes (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_typestringNoSelfie / liveness type (e.g. passive, passive_v2, flash).
videosarrayNoLiveness 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_idstringNoRoutes 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_typesstringNoComma-separated allowed card types (e.g. vn.national_id,vn.passport).
langstringNoLanguage code (e.g. vi, en).
client_metadataobjectNoOptional 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.

2. Response

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):

json
{
  "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:

FieldDescription
data.verdictOverall application verdict: approve, review, reject, or pending.
ekyc_ocr / ekyc_face / id_tamperingPer-module results + status (same as API Application Detail). Present only when run.
client_metadataThe prepared metadata you supplied, echoed back raw (omitted if none).
access_tokenJWT 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).

NameDescriptionStatus codeResponse Body
SuccessProcessing completed — read data.verdict200See the sample success response above
Bad RequestInvalid parameters / missing config400{"data":{},"message":"eKYC platform URL not configured","verdict":"failure"} / relayed invalid_parameters / missing_parameters
UnauthorizedInvalid authentication token401{"data":{},"message":"authorization header is missing","time":"2024-10-31T07:50:22Z","verdict":"missing_authorization"}
Token ExpiredToken expired. Client should login again401{"data":{},"message":"Provided token is expired","time":"2024-10-31T07:50:22Z","verdict":"expired_token"}
Not FoundEncryption key or lender not found / inactive404{"data":{},"message":"...","verdict":"record_not_found"}
Too Many RequestsAnother submission for the same user is in progress, or rate limit reached429{"data":{},"message":"...","verdict":"limit_exceeded"}
Internal Server ErrorCannot create encrypted token500{"data":{},"message":"cannot create encrypted token","verdict":"failure"}
Bad GatewayUpstream 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).

Vision Score

Runs Vision Score (face liveness + selfie quality) through this same Service API JWT auth. See Vision Score API for the full request/response reference.