API Docs · Vision Score

Vision Score

POST/portal/ekyc/vision_score

Synchronously runs Vision Score — face liveness and selfie quality — for a set of selfie images, and returns the score with the eKYC application state.

Request

MethodPOST
Path/portal/ekyc/vision_score
Content-Typeapplication/json
Auth requiredYes — Bearer JWT

Each image may be supplied inline as base64 or by id (returned from API Upload Image). Vision Score can also be called standalone via the eKYC Core API endpoint; both return a Vision Score, and this one is JWT/encrypted_token-authenticated and returns the same TS-native application shape used across the rest of the eKYC Platform Service API.

The Authorization header carries the JWT access token as Bearer <JWT>, to support request authentication.

NameTypeRequiredDescription
images[]ImageDataRequiredSelfie images. The last element is treated as the primary selfie.
gesture_images[]ImageDataOptionalGesture (active liveness) images.
videos[]ImageDataOptionalVideo frames captured during the liveness flow.
metadatajsonOptionalContextual data about the loan application and applicant. See The metadata parameter.
selfie_typestringOptionalSelfie liveness type. Common values: passive, flash, active. See The selfie_type parameter.
flow_idstringOptionalRoutes the request to the lender config mapped to this flow via the encryption key's flow_lender_config_mapping. Defaults to vision_score_only.
lender_idintOptionalAdmin-only override that scopes the call to a specific tenant. Non-admin callers always resolve the lender from their JWT and any supplied value is ignored.

Where each ImageData object accepts either id (preferred — references a pre-uploaded image) or base64 (inline upload):

NameTypeRequiredDescription
idstringOptionalimage_id returned by API Upload Image. Use this to avoid re-sending large payloads.
base64stringOptionalBase64-encoded image content without the data:image/jpeg;base64, prefix. Required when id is not supplied.
metadatastringOptionalPer-image metadata string forwarded to eKYC. Example: "{\"frame_index\":0}".

Modes:

Modeimagesgesture_imagesvideosselfie_typeflow_id
Vision Score only1 imagevision_score_only
Vision Score with Passive Liveness1–3 imagesoptionalpassivevision_score_sanity_liveness

Request Body:

JSON
{
  "images": [
    {
      "id": "8fdcb17e-5d41-4814-8d4f-8c1bfb51df20"
    },
    {
      "base64": "<base64_string>",
      "metadata": "{\"frame_index\":1}"
    }
  ],
  "gesture_images": [
    {
      "id": "fa9a4fee-41c3-4988-a126-1431c130aa94"
    }
  ],
  "videos": [
    {
      "id": "b5a23e55-773f-4cf2-985b-835b9b3d0077"
    }
  ],
  "metadata": {
    "applicant_name": "e3b0c44298fc1c149afb...a1b2c3",
    "id_number": "a665a45920422f9d417e...f4c8b1",
    "dob": "9f86d081884c7d659a2f...3d5c2a",
    "gender": "male",
    "phone_number": "b14a7b8059d9c055954c...8e7f12",
    "email": "2cf24dba5fb0a30e26e8...9d1c4a",
    "application_time": "2025-05-02T10:30:00+07:00",
    "loan_amount": 5000000,
    "loan_currency": "VND",
    "loan_product_type": "personal_loan",
    "acquisition_channel": "agent",
    "is_existing_customer": false,
    "device_type": "android",
    "device_model": "Samsung Galaxy A54"
  },
  "selfie_type": "passive",
  "flow_id": "vision_score_only",
  "lender_id": 0
}

The metadata parameter

The metadata field accepts a dictionary of contextual data associated with the loan application and applicant. Providing this information enables TS to improve model performance over time and unlocks eligibility for model fine-tuning. All fields are optional. Keys outside the list below are accepted and stored but carry no guaranteed semantic interpretation.

PII Notice

Fields marked Encrypt: Yes contain personally identifiable information. Data must be hashed (SHA-256) or encrypted (AES-256) before transmission, in compliance with applicable data protection regulations (GDPR, PDPA, and equivalent local laws).

GroupKeyTypeEncryptDescription
Applicant Identityapplicant_namestringYesFull name as captured from ID document
Applicant Identityid_numberstringYesNational ID or passport number
Applicant IdentitydobstringYesDate of birth, ISO 8601 format (e.g. "1990-03-15")
Applicant IdentitygenderstringNoAccepted values: "male", "female", "other"
Applicant Identityphone_numberstringYesRegistered mobile number in E.164 format (e.g. "+84901234567")
Applicant IdentityemailstringYesApplicant email address
Loan Application Contextapplication_timestringNoISO 8601 timestamp of when the loan application was submitted (e.g. "2025-05-02T10:30:00+07:00")
Loan Application Contextloan_amountfloatNoRequested loan amount in local currency
Loan Application Contextloan_currencystringNoISO 4217 currency code (e.g. "VND", "PHP", "USD")
Loan Application Contextloan_product_typestringNoProduct category (e.g. "personal_loan", "bnpl", "salary_advance", "sme_loan")
Loan Application Contextacquisition_channelstringNoChannel through which the applicant was acquired (e.g. "organic", "agent", "referral", "digital_ads")
Loan Application Contextis_existing_customerboolNoWhether the applicant is an existing borrower
Device Contextdevice_typestringNoAccepted values: "android", "ios", "web"
Device Contextdevice_modelstringNoDevice model name (e.g. "Samsung Galaxy A54")

PII fields below are shown as SHA-256 hashes. Plain-text values must never be transmitted.

JSON
{
  "metadata": {
    "applicant_name": "e3b0c44298fc1c149afb...a1b2c3",
    "id_number": "a665a45920422f9d417e...f4c8b1",
    "dob": "9f86d081884c7d659a2f...3d5c2a",
    "gender": "male",
    "phone_number": "b14a7b8059d9c055954c...8e7f12",
    "email": "2cf24dba5fb0a30e26e8...9d1c4a",

    "application_time": "2025-05-02T10:30:00+07:00",
    "loan_amount": 5000000,
    "loan_currency": "VND",
    "loan_product_type": "personal_loan",
    "acquisition_channel": "agent",
    "is_existing_customer": false,

    "device_type": "android",
    "device_model": "Samsung Galaxy A54"
  }
}

The selfie_type parameter

selfie_type is the selfie liveness type. These values are shared with the standalone Vision Score endpoint in the eKYC Core API; the request table above names passive, flash and active as the common ones.

selfie_typeDescription
passivePassive mode
activeActive mode
flashFlash mode with 32 frames
flash_8Flash mode with 8 frames
flash_16Flash mode with 16 framess
flash_32Flash mode with 32 frames

Response

On success the status code is 200 and the top-level verdict is "success"; see Failure codes for the other values. data.application is present only when an application matching unique_token is found for the lender.

JSON
{
  "data": {
    "unique_token": string,        // eKYC application unique token (issued by Platform Init)
    "verify_response": {           // upstream Platform Verify Face Liveness result
      "status": string,            // "success" | "failure"
      "application_state": {
        "current_step": string,            // current step in the eKYC flow, e.g. "success"
        "fully_completed": bool,           // true when every required state is completed
        "required_states": [string],       // states the flow requires the user to complete
        "all_completed_states": [string],  // states the user has completed so far
        "client_custom_settings": {
          "allow_card_types": [string],    // card types permitted for this flow
          "redirect_url": string           // post-flow redirect URL, if configured
        }
      }
    },
    "application": {                        // optional — present only when the application is found
      "verdict": string,                    // "pending" | "approve" | "review" | "reject"
      "application_id": int,
      "application_unique_token": string,
      "application_user_id": string,
      "ekyc_face": {
        "vision_score": number,             // range 0–100; higher = more trustworthy / lower risk
        "vision_score_status": string,      // "success" | "failure"
        "vision_score_request_id": string,  // request id for tracing Vision Score logs
        "liveness_score": number,           // passive-liveness score, range 0–1
        "liveness_status": string,          // "success" | "failure"
        "sanity_check_score": number,       // selfie quality score
        "sanity_check_result": string,      // selfie quality verdict, e.g. "good"
        "sanity_check_status": string,      // "success" | "failure"
        "search_face_result": object,       // face-search hits; null when disabled
        "search_face_status": string,       // e.g. "found"; "" when disabled
        "process_status": string,           // "success" | "failure"
        "processed_at": string,             // ISO 8601 timestamp
        "selfie_image_uuid": string,        // image id of the primary selfie
        "gesture_images": [ { "gesture": string, "image_id": string } ],
        "sequence_frames": [ ... ],         // liveness video frames
        "liveness_transformed_video_id": string  // video merged from sequence frames
      },
      "file_ids": {                         // image/video ids captured during the flow
        "selfie_image_uuid": string,
        "gesture_images": [ { "gesture": string, "image_id": string } ],
        "sequence_frames": [ ... ],
        "liveness_transformed_video_id": string
      },
      "time": string                        // ISO 8601 timestamp
    }
  },
  "message": string,                        // human-readable status, e.g. "vision score check completed"
  "time": string,                           // ISO 8601 timestamp of the response
  "verdict": string                         // "success" on HTTP 200; see the error table above for other values
}
NameTypeDescription
unique_tokenstringThe eKYC application unique token issued by Platform Init. Use it to look up the application via API Application Detail.
verify_responseobjectThe data block returned by the upstream Platform Verify Face Liveness API — same shape as the Selfie Verification API response.
applicationobjectOptional — only present when an application matching unique_token is found for the lender. Same shape as the Application Detail response.

application.verdict follows the same mapping as API Application Detailpending, approve, review or reject.

The remaining ekyc_face and file_ids fields (compare_score, search_face_result, gesture_images, sequence_frames, liveness_transformed_video_id, …) follow the same shape as the API Application Detail response.

verify_response.application_state reports the flow's progress:

NameTypeDescription
current_stepstringCurrent step in the eKYC flow, e.g. "success".
fully_completedbooltrue when every required state has been completed.
required_states[]stringStates the flow requires the user to complete.
all_completed_states[]stringStates the user has completed so far.
client_custom_settingsobjectPer-client flow settings, e.g. allow_card_types, redirect_url.

The scoring outputs of this endpoint live under application.ekyc_face. vision_score is the primary output; the liveness and sanity-check fields describe the quality of the captured selfie.

Primary output

vision_score (0–100). A higher score means a more trustworthy / lower-risk profile.

GroupFieldTypeDescription
Vision Scorevision_scorenumberVision Score, range 0100. Higher = more trustworthy / lower risk.
Vision Scorevision_score_statusstring"success" when the score was computed, otherwise "failure".
Vision Scorevision_score_request_idstringRequest id used to trace Vision Score processing in logs.
Livenessliveness_scorenumberPassive-liveness score, range 01.
Livenessliveness_statusstring"success" or "failure".
Sanity checksanity_check_scorenumberSelfie quality score.
Sanity checksanity_check_resultstringSelfie quality verdict, e.g. "good".
Sanity checksanity_check_statusstring"success" or "failure".

A successful check, with a Vision Score of 86 and an approve verdict:

JSON
{
  "data": {
    "application": {
      "application_id": 100010221,
      "application_unique_token": "7ae4e342-6cec-4a4e-bd6e-831784391d40",
      "application_user_id": "5b506b16-7928-44ea-b690-1ef61d39ed08",
      "ekyc_face": {
        "gesture_images": [
          {
            "gesture": "frontal",
            "image_id": "186c1ca9-cc99-4fc7-8742-036a2ea8e244"
          }
        ],
        "liveness_score": 0.99999034,
        "liveness_status": "success",
        "liveness_transformed_video_id": "",
        "process_status": "success",
        "processed_at": "2026-06-17T03:17:22Z",
        "sanity_check_result": "good",
        "sanity_check_score": 1,
        "sanity_check_status": "success",
        "search_face_result": null,
        "search_face_status": "",
        "selfie_image_uuid": "186c1ca9-cc99-4fc7-8742-036a2ea8e244",
        "sequence_frames": [],
        "vision_score": 86,
        "vision_score_request_id": "eec55581-33a0-4d3a-8247-81202609f75b",
        "vision_score_status": "success"
      },
      "file_ids": {
        "gesture_images": [
          {
            "gesture": "frontal",
            "image_id": "186c1ca9-cc99-4fc7-8742-036a2ea8e244"
          }
        ],
        "liveness_transformed_video_id": "",
        "selfie_image_uuid": "186c1ca9-cc99-4fc7-8742-036a2ea8e244",
        "sequence_frames": []
      },
      "time": "2026-06-17T03:17:22Z",
      "verdict": "approve"
    },
    "unique_token": "7ae4e342-6cec-4a4e-bd6e-831784391d40",
    "verify_response": {
      "application_state": {
        "all_completed_states": ["ekyc.selfie.passive_v2"],
        "client_custom_settings": {
          "allow_card_types": ["vn.national_id"],
          "redirect_url": ""
        },
        "current_step": "success",
        "fully_completed": true,
        "required_states": ["ekyc.selfie.passive_v2"]
      },
      "status": "success"
    }
  },
  "message": "vision score check completed",
  "time": "2026-06-17T03:17:22Z",
  "verdict": "success"
}

Failure codes

data is empty on every error below; the top-level verdict carries the reason.

NameDescriptionStatus codeResponse Body
Bad RequestInvalid parameters / missing config400{"data":{},"message":"eKYC platform URL not configured","verdict":"failure"}
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"}
Bad GatewayUpstream Platform Init / Verify failed502{"data":{},"message":"platform init failed: ...","verdict":"failure"} / {"data":{},"message":"platform verify selfie failed: ...","verdict":"failure"}
Internal Server ErrorCannot create encrypted token500{"data":{},"message":"cannot create encrypted token","verdict":"failure"}