> For the complete documentation index, see [llms.txt](https://docs.vida.id/identity-stack/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.vida.id/identity-stack/verify/biometric-verification/biometric-verification-v2/api-reference.md).

# API Reference

Verify that a selfie shows a real, live person and that it matches a reference photo, using the VIDA Verify API V2. The same endpoint can also check the face against a blacklist.

### Choose an operation

| What you need          | Operations to send                                         | Result                                                            |
| ---------------------- | ---------------------------------------------------------- | ----------------------------------------------------------------- |
| Liveness check         | `imageLivenessVerification`                                | Is the selfie a live person?                                      |
| Biometric verification | `imageFaceMatchVerification` + `imageLivenessVerification` | Is it a live person, and does the face match the reference photo? |
| Blacklist check        | Enabled on request                                         | Is the face in the blacklist database?                            |

### How the checks depend on each other

Both operations in Biometric Verification run concurrently, but **face match depends on liveness**. Face matching only happens once a live person is confirmed. This prevents spoofed or unauthorized attempts.

```
imageLivenessVerification
 ├─ Fails → no imageFaceMatchVerification result is returned
 └─ Passes → Blacklist check (only if enabled)
              ├─ Face found → face match is skipped, blacklist response returned
              └─ No match   → imageFaceMatchVerification runs → success response
```

{% hint style="info" %}
The overall result of Biometric Verification depends on passing liveness. For liveness details, see Liveness.
{% endhint %}

### Request format

These fields are shared by every operation.

#### Endpoint

**`POST`** `https://{vida-host}/api/v2/verify`

#### Headers

| Name                | Type   | Description                                          |
| ------------------- | ------ | ---------------------------------------------------- |
| `Authentication` \* | String | `Bearer <Token>`                                     |
| `Content-Type`      | String | Format type of the request body (`application/json`) |

#### Body

| Name             | Type   | Description                                                    |
| ---------------- | ------ | -------------------------------------------------------------- |
| `operations` \*  | Array  | Operations to run, for example `["imageLivenessVerification"]` |
| `payload` \*     | Object | Data for each operation (see below)                            |
| `userConsent` \* | Object | Proof of the user's consent (see below)                        |

#### `payload` fields

| Field                    | Type            | Rule                                             | Description                                                                                       |
| ------------------------ | --------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------- |
| `partnerTrxId`           | String          | Required                                         | A unique ID you generate for this transaction                                                     |
| `groupId`                | String          | Required                                         | An ID that links this request to the rest of the KYC flow                                         |
| `faceImage`              | String (Base64) | Send this **or** `livenessTransactionIds`        | The selfie image                                                                                  |
| `livenessTransactionIds` | Array           | Send this **or** `faceImage`                     | Transaction ID from an earlier Liveness Verification call. Use it instead of sending a new selfie |
| `idFrontSideImage`       | String (Base64) | Send this **or** `croppedFaceImage` (face match) | The front of the ID card                                                                          |
| `croppedFaceImage`       | String (Base64) | Send this **or** `idFrontSideImage` (face match) | A cropped face image from the reference photo                                                     |

{% hint style="warning" %}
Send **one** of `faceImage` or `livenessTransactionIds`, not both.
{% endhint %}

#### `userConsent` fields

| Field        | Type    | Description                                 |
| ------------ | ------- | ------------------------------------------- |
| `userIp`     | String  | IP address of the user                      |
| `country`    | String  | Country code, for example `MYS`             |
| `obtained`   | Boolean | Whether consent was obtained                |
| `obtainedAt` | String  | Unix timestamp of when consent was obtained |

### Liveness check

Checks whether the selfie is a live photo. Send only `imageLivenessVerification` in `operations`.

<details>

<summary>JSON - Sample Request</summary>

```json
{
  "operations": ["imageLivenessVerification"],
  "payload": {
    "partnerTrxId": "{{$guid}}",
    "groupId": "{{$guid}}",
    "faceImage": "Base64 encoded image"
  },
  "userConsent": {
    "userIp": "226.80.211.232",
    "country": "MYS",
    "obtained": true,
    "obtainedAt": "1680700959"
  }
}
```

</details>

<details>

<summary>JSON - Sample Response</summary>

```json
{
  "transactionId": "unique transaction id generated to identify this transaction",
  "partnerTrxId": "partner transaction id submitted by customer in request",
  "groupId": "reference id to track complete KYC flow",
  "imageLivenessVerificationResult": {
    "data": {
      "code": 1043,
      "message": "Selfie photo is a live photo",
      "score": 0.066661
    }
  }
}
```

</details>

### Biometric verification

Checks liveness **and** matches the selfie to a reference photo. Include **both** `imageFaceMatchVerification` and `imageLivenessVerification` in `operations`, plus the reference photo in `payload`.

#### Choose how to send the selfie

|                   | Using `faceImage`                          | Using `livenessTransactionIds`                                  |
| ----------------- | ------------------------------------------ | --------------------------------------------------------------- |
| **What you send** | A new selfie image                         | Transaction ID(s) from an earlier Liveness Verification call    |
| **Use it when**   | Liveness and face match happen in one step | You already ran liveness and don't want to capture a new selfie |

<details>

<summary>JSON - Sample Request Using faceImage</summary>

```json
{
  "requestOrigin": "SDK",
  "kycFlowType": "KYC",
  "operations": [
    "imageFaceMatchVerification",
    "imageLivenessVerification"
  ],
  "payload": {
    "partnerTrxId": "{{$guid}}",
    "groupId": "{{$guid}}",
    "faceImage": "Base64 encoded image",
    "croppedFaceImage": "Base64 encoded cropped face image"
  },
  "userConsent": {
    "userIp": "226.80.211.232",
    "country": "MYS",
    "obtained": true,
    "obtainedAt": "1680700959"
  }
}
```

</details>

<details>

<summary>JSON - Sample Request Using livenessTransactionIds</summary>

```json
{
  "operations": [
    "imageFaceMatchVerification",
    "imageLivenessVerification"
  ],
  "payload": {
    "partnerTrxId": "internal-test-005",
    "groupId": "030920261235",
    "livenessTransactionIds": ["{{liveness_transactionId}}"],
    "idFrontSideImage": "{{id_front_image}}"
  },
  "userConsent": {
    "userIp": "226.80.211.232",
    "country": "MYS",
    "obtained": true,
    "obtainedAt": "1680700959"
  }
}
```

</details>

<details>

<summary>JSON - Success Response</summary>

```json
{
  "transactionId": "unique transaction id generated to identify this transaction",
  "partnerTrxId": "partner transaction id submitted by customer in request",
  "groupId": "reference id to track complete KYC flow",
  "imageFaceMatchVerificationResult": {
    "data": {
      "code": 1042,
      "message": "Selfie photo matches with reference photo",
      "score": 0.941826
    }
  },
  "imageLivenessVerificationResult": {
    "data": {
      "code": 1043,
      "message": "Selfie photo is a live photo",
      "score": 0.198378,
      "imgManipulationScore": 0.091674
    }
  }
}
```

</details>

### Blacklist check

Prevents onboarding or verification of users whose facial images appear in a blacklist database. The check runs **before** face match. If a match is found, the face match step is skipped.

{% hint style="warning" %}
Blacklist Check is **enabled on request**. Contact VIDA to turn it on for your account.
{% endhint %}

**How it works**

{% stepper %}
{% step %}

#### Check if it is enabled

The system checks whether Blacklist Check is enabled for your product. If yes, the check runs.
{% endstep %}

{% step %}

#### Blacklist hit

If the face is found in the blacklist, the system returns a response with the matching code and message, and the face match step is skipped.
{% endstep %}

{% step %}

#### No blacklist match

If no blacklist image is found, the system returns the normal success response, with an empty `faceReferences` list.
{% endstep %}
{% endstepper %}

Blacklist Check can run as part of a Liveness Check or as a standalone check, using the same endpoint: `POST https://{vida-host}/api/v2/verify`.

<details>

<summary>JSON - Success Response No Match</summary>

```json
{
  "transactionId": "unique transaction id generated to identify this transaction",
  "partnerTrxId": "partner transaction id submitted by customer in request",
  "groupId": "reference id to track complete KYC flow",
  "imageFaceMatchVerificationResult": {
    "data": {
      "code": 1042,
      "message": "Selfie photo matches with reference photo",
      "score": 0.992796
    }
  },
  "imageLivenessVerificationResult": {
    "data": {
      "code": 1043,
      "message": "Selfie photo is a live photo",
      "score": 0.066661
    }
  },
  "blacklistCheckResult": {
    "faceReferences": []
  }
}
```

</details>

<details>

<summary>JSON - Success Response Match (Warning)</summary>

```json
{
  "transactionId": "unique transaction id generated to identify this transaction",
  "partnerTrxId": "partner transaction id submitted by customer in request",
  "groupId": "reference id to track complete KYC flow",
  "warnings": [
    {
      "message": "Image is blacklisted.",
      "code": 10501,
      "operations": ["imageFaceMatchVerification"]
    }
  ],
  "imageFaceMatchVerificationResult": {
    "data": {
      "code": 1042,
      "message": "Selfie photo matches with reference photo",
      "score": 0.992796
    }
  },
  "imageLivenessVerificationResult": {
    "data": {
      "code": 1043,
      "message": "Selfie photo is a live photo",
      "score": 0.066661
    }
  },
  "blacklistCheckResult": {
    "faceReferences": [
      {
        "faceId": "f4640eae-5e10-4405-99ea-051826756fb2",
        "matchScore": 1.0
      }
    ]
  }
}
```

</details>

<details>

<summary>JSON - Error Response Match</summary>

```json
{
  "transactionId": "unique transaction id generated to identify this transaction",
  "partnerTrxId": "partner transaction id submitted by customer in request",
  "groupId": "reference id to track complete KYC flow",
  "errors": [
    {
      "message": "Verification failed: Image is blacklisted.",
      "code": 5801,
      "operations": ["imageFaceMatchVerification"]
    }
  ],
  "imageLivenessVerificationResult": {
    "data": {
      "code": 1043,
      "message": "Selfie photo is a live photo",
      "score": 0.066661
    }
  },
  "blacklistCheckResult": {
    "faceReferences": [
      {
        "faceId": "bdc41279-d391-4fc9-8d94-972661fae720",
        "matchScore": 1.0
      }
    ]
  }
}
```

</details>
