> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gu1.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Biometric Check

> Validate a face image against previously approved KYC sessions — in the gu1 KYC API for identity verification flows, with examples for biometric use cases.

## Overview

<Info>
  For **step-up authentication** with hosted liveness capture (iframe), use [Embedded Biometric Session](/en/use-cases/kyc/embedded-biometric) (`POST /api/kyc/biometric/sessions`) instead of this synchronous endpoint. This page documents the **server-side image upload** check.
</Info>

The **Biometric** service is a Gu1 verification that checks whether a face image corresponds to a person who has **already completed an approved KYC validation** in your organization. You send a single face image and the entity to check (by `entityId`, `entityExternalId`, or `entityTaxId`). The API compares that face against the biometric data stored in **previous approved session-based validations** for that entity. If the face matches one of those approved sessions, the response indicates a match and returns the related KYC validation IDs.

<Note>
  **How it works**

  The service looks up approved KYC sessions (created via [session-based validation](/en/use-cases/kyc/create-validation)) for the given entity. It compares the face you send with the biometric information already stored from those approved sessions. No new hosted session is started—this is a one-off check against existing data.
</Note>

## Prerequisites

For this endpoint to work, your organization must have **session-based KYC validation** set up:

1. **KYC Validation integration enabled**: The integration used for session-based validation (e.g. “Gu1 KYC” / validation by session) must be **enabled** for your organization (e.g. in Marketplace / Integrations).
2. **Credentials configured**: The **API key** (and webhook secret) for that **session validation** integration must be set in your organization’s KYC settings. The Biometric endpoint uses the same credentials as session-based validation to perform the check.

If these credentials are not set or the integration is not enabled, the API returns **403** (`NOT_ENABLED` or `NOT_CONFIGURED`).

<Info>
  The Biometric service is a Gu1 service. All verification runs on our infrastructure; no third-party provider names are exposed in responses or errors.
</Info>

## Request

### Endpoint

```
POST https://api.gu1.ai/api/kyc/biometric
```

### Content-Type

Accepts **`multipart/form-data`** or **`application/json`**.

**Multipart** — send the face image in either way (same as Face Match / ID Verification):

1. **As a file part**: field `userImage` or `user_image` (recommended).
2. **As a base64 string**: same field names with a base64-encoded image (with or without `data:image/...;base64,` prefix).

If the image is missing (no file and no base64 string), the API returns **400**.

**JSON** — send `user_image` or `userImage` as a base64/data URL string, or an http(s) URL to fetch the image server-side. Entity identifiers: `entityId`, `entityExternalId`, and/or `entityTaxId`.

You must provide **at least one** of `entityId`, `entityExternalId`, or `entityTaxId` so the API knows which entity to check against.

### Headers

```
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
```

or, for multipart:

```
Authorization: Bearer YOUR_API_KEY
Content-Type: multipart/form-data; boundary=----...
```

The organization is determined from your authentication context; you do not need to send `X-Organization-Id`.

### Body Parameters

<ParamField body="user_image" type="file | string" required>
  Face image. **Multipart:** field `userImage` or `user_image` as a **file part** or **base64 string** (with or without `data:image/...;base64,` prefix). **JSON:** `user_image` or `userImage` as base64, data URL, or http(s) URL. Formats: JPEG, PNG, WebP, TIFF. Max 5MB.
</ParamField>

<ParamField body="entityId" type="string">
  UUID of the person entity in Gu1. At least one of `entityId`, `entityExternalId`, or `entityTaxId` is required.
</ParamField>

<ParamField body="entityExternalId" type="string">
  Your own identifier for the entity (external ID). If you do not send `entityId`, the API resolves the entity by organization + `externalId`. At least one entity identifier is required.
</ParamField>

<ParamField body="externalEntityId" type="string">
  **Deprecated alias** for `entityExternalId`. Still accepted on `POST /api/kyc/biometric` for backward compatibility. Prefer `entityExternalId` in new integrations.
</ParamField>

<ParamField body="entityTaxId" type="string">
  Tax ID of the entity (CUIT, CPF, RFC, etc.). If you do not send `entityId` or `entityExternalId`, the API resolves the entity by organization + normalized `tax_id` (ignores formatting characters such as dashes and dots). At least one entity identifier is required.
</ParamField>

## Response

### Success (200 OK)

| Field                     | Type      | Description                                                                                 |
| ------------------------- | --------- | ------------------------------------------------------------------------------------------- |
| `match`                   | boolean   | `true` if the face matches at least one **approved** KYC validation for this entity in Gu1. |
| `matchedSessionIds`       | string\[] | Session IDs of the matched approved validations.                                            |
| `matchedKycValidationIds` | string\[] | KYC validation IDs in Gu1 that matched.                                                     |
| `faceSearch`              | object    | Summary: `totalMatches`, `requestId` (for support).                                         |

**Example:**

```json theme={null}
{
  "match": true,
  "matchedSessionIds": ["session-abc-123"],
  "matchedKycValidationIds": ["550e8400-e29b-41d4-a716-446655440000"],
  "faceSearch": {
    "totalMatches": 1,
    "requestId": "req_xyz"
  }
}
```

## Example Request

<CodeGroup>
  ```javascript JSON body (entityTaxId) theme={null}
  const response = await fetch('https://api.gu1.ai/api/kyc/biometric', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      user_image: 'data:image/jpeg;base64,/9j/4AAQ...',
      entityTaxId: '20-41873887-2',
    }),
  });
  const result = await response.json();
  console.log('Match:', result.match, 'KYC validations:', result.matchedKycValidationIds);
  ```

  ```javascript JSON body theme={null}
  const response = await fetch('https://api.gu1.ai/api/kyc/biometric', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      user_image: 'data:image/jpeg;base64,/9j/4AAQ...',
      entityId: '550e8400-e29b-41d4-a716-446655440000',
    }),
  });
  const result = await response.json();
  console.log('Match:', result.match, 'KYC validations:', result.matchedKycValidationIds);
  ```

  ```javascript Multipart (file) theme={null}
  const form = new FormData();
  form.append('userImage', imageFile);
  form.append('entityId', '550e8400-e29b-41d4-a716-446655440000');

  const response = await fetch('https://api.gu1.ai/api/kyc/biometric', {
    method: 'POST',
    headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
    body: form,
  });
  const result = await response.json();
  ```

  ```curl cURL (multipart) theme={null}
  curl -X POST https://api.gu1.ai/api/kyc/biometric \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -F "userImage=@selfie.jpg" \
    -F "entityId=550e8400-e29b-41d4-a716-446655440000"
  ```
</CodeGroup>

## Error Responses

| Code                  | HTTP | Meaning                                                                                                        |
| --------------------- | ---- | -------------------------------------------------------------------------------------------------------------- |
| `NOT_CONFIGURED`      | 403  | Session-based KYC validation credentials are not set in organization KYC settings.                             |
| `NOT_ENABLED`         | 403  | Session-based KYC validation integration is not enabled for this organization.                                 |
| `INVALID_REQUEST`     | 400  | Missing or invalid body (e.g. missing `user_image`, or none of `entityId`, `entityExternalId`, `entityTaxId`). |
| `NOT_FOUND`           | 404  | No entity found for the given `entityId`, `entityExternalId`, or `entityTaxId` in this organization.           |
| `UNAUTHORIZED`        | 401  | Invalid or missing authentication.                                                                             |
| `VERIFICATION_FAILED` | 500  | Verification could not be completed; retry or contact support.                                                 |

## Relation to Session-Based KYC

* **Session-based validation** (`POST /api/kyc/validations`): Creates a KYC session, gives the user a hosted URL, and stores the result (including biometric data) when they complete the flow. Those sessions are what the Biometric endpoint checks against.
* **Biometric** (`POST /api/kyc/biometric`): Sends one face image and checks if it matches any **already approved** session for that entity. Use it when you need to re-verify the same person (e.g. at login or for a new action) without starting a new session.

Both use the same organization credentials for session-based KYC validation. If those credentials are not configured, the Biometric endpoint cannot run.

## Next Steps

<CardGroup cols={2}>
  <Card title="Create KYC Validation" icon="play" href="/en/use-cases/kyc/create-validation">
    Start a session-based verification
  </Card>

  <Card title="Face Match (Document + Selfie)" icon="user-check" href="/en/use-cases/kyc/face-match">
    Compare two images in one call
  </Card>
</CardGroup>
