---
title: "Selfie2Selfie Biometric Verification"
slug: "selfie2selfie-biometric-verification"
description: "Selfie2Selfie offers privacy-centric biometric verification with real-time facial comparison, ensuring data security without storing templates."
updated: 2025-12-12T10:57:19Z
published: 2025-12-12T10:57:19Z
---

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

# Selfie2Selfie Biometric Verification

| Available via API | Available via SDK | Needs configuration on Veriff’s side | Needs a separate integration | Needs a separate webhook |
| --- | --- | --- | --- | --- |
| ✅ | ✅ | ✅ | ✅ | ❌ |

**Selfie2Selfie Biometric Verification**is a privacy-centric biometric verification feature that **performs real-time facial comparison**between a **customer-provided reference image and a live selfie**captured during the verification session. Unlike standard Biometric Authentication, it processes all facial data ephemerally **without storing biometric templates**, making it ideal solution for you if you have strict data storage limitations or privacy requirements.

Selfie2Selfie Biometric Validation is available via API, web flows and native SDKs.

All session-related **info is returned** **via** decision webhook and can be **polled from different API endpoints**. The results of the verification can also be viewed in the Veriff Customer Portal, on the session view, where the session decision and the reference image are displayed.

> [!NOTE]
> Contact your **solutions engineer** for info and configuration.

---

## Prerequisites

- You have an [integration set up](/v1/docs/how-to-create-an-integration) with Veriff
- The **feature is configured** for that integration **by your Solutions Engineer**
- You have configured the [decision webhook](/v1/docs/decision-webhook) to get responses from Veriff (see the how-to in webhooks’ [Set up webhooks](/v1/docs/webhooks-guide#set-up-webhooks) section)
- If using the **API**, you are ready to collect and **send** Veriff your **end-user’s data**
- If using the **API**:
  - Veriff **strongly recommends** you collect and send **additional device/session data** for improved fraud mitigation
  - Veriff **strongly recommends** that you **create and send** us the endUserId or vendorData

---

## Flow overview

The flow is a bit different, depending on the method you are using to verify your end-users with Veriff. The solution works via both SDKs and API, with the SDK automatically handling the selfie capture interface, while the API requires manual collection and submission of the end-user’s images.

### Use via SDKs

1. Generate a verification session using the API keys and the `baseURL` of your Selfie2Selfie Biometric Verification integration (see the <meta charset="utf-8">[API Documentation and API Reference](https://devdocs.veriff.com/apidocs)[↗] how to find these)
2. Upload the **end-user's reference image** via <meta charset="utf-8">[POST /sessions/{sessionId}/media](https://veriff-dev-documentation.document360.io/apidocs/v1sessionsidmedia-3)[↗] API call
  - Ensure that the reference image’s `image.context` is `face-reference`
3. Capture end-user’s **selfie image(s)** with Veriff’s SDKs:
  - Send the end-user through the verification flow to capture the images (using the preferred Veriff SDK).
  - You need the **session URL** generated in step 1 to use the SDKs (found in **response payload** as `verification.url`).
4. The end-user captures their live selfie images with Veriff’s SDKs.
5. Session will be **submitted automatically** once the end-user takes and submits necessary images.
6. Receive the results from Veriff via decision webhook or poll them via <meta charset="utf-8">[GET sessions/{sessionId}/decision](https://veriff-dev-documentation.document360.io/apidocs/v1sessionsiddecision-1)[↗] endpoint.

> [!CAUTION]
> After uploading the end-user’s reference image, **do no use API to patch the session to**`submitted`. This will **happen** **automatically** **after** the end-user has **captured their selfie**.

### Use via API

1. Generate a verification session using the API keys and the `baseURL` of your Selfie2Selfie Biometric Verification integration (see the <meta charset="utf-8">[API Documentation and API Reference](https://devdocs.veriff.com/apidocs)[↗] how to find these)
  - Veriff strongly recommends you create and send the `endUserId` or `vendorData`

**Session creation bash example**

```bash
curl -X POST /v1/sessions/ \
  -H "Content-Type: application/json" \
  -H "X-AUTH-CLIENT: cd938f72-72c8-4a7b-b5c6-2f1b6d5a9c8e" \
  -d '{
    "verification": {
      "person": {
        "firstName": "John",
        "lastName": "Smith"
      }
    },
    "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
    "vendorData": "12345678"
  }'
```

1. Upload the end-user's reference image via <meta charset="utf-8">[POST /sessions/{sessionId}/media](https://veriff-dev-documentation.document360.io/apidocs/v1sessionsidmedia-3)[↗] call.
  - Ensure that the reference image’s `image.context` is `face-reference`

**Media upload bash example**

```bash
curl -X POST \
  --url '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/media \'
  -H "Content-Type: application/json" \
  -H "X-AUTH-CLIENT: cd938f72-72c8-4a7b-b5c6-2f1b6d5a9c8e" \
  -H "X-HMAC-SIGNATURE: 034c6da2bb31fd9e6892516c6d7b90ebe10f79b47cfb3d155d77b4d9b66e1d53" \
  -d '{
    "image": {
      "context": "face-reference",
      "content": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEA...",
      "timestamp": "2025-01-15T10:30:00.000Z"
    }
  }'
```

1. Upload the end-user's selfie image(s) via <meta charset="utf-8">[POST /sessions/{sessionId}/media](https://veriff-dev-documentation.document360.io/apidocs/v1sessionsidmedia-3)[↗] call.
  - Specify the `image.context` as appropriate for the image (e.g. `face`) (see [Context types (image, video)](/v1/docs/context-types-image-video-1) for more info about image context types).

**Media upload bash example**

```bash
curl -X POST \
  --url '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/media' \
  -H 'X-AUTH-CLIENT: cd938f72-72c8-4a7b-b5c6-2f1b6d5a9c8e' \
  -H "X-HMAC-SIGNATURE: 034c6da2bb31fd9e6892516c6d7b90ebe10f79b47cfb3d155d77b4d9b66e1d53" \
  -H 'Content-Type: application/json' \
  -d '{
    "image": {
      "context": "face",
      "content": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEA...",
      "timestamp": "2024-01-15T10:31:00Z"
    }
  }'
```

1. Check the decision data and/or session related info from the decision webhook and/or query the data from the <meta charset="utf-8">[GET sessions/{sessionId}/decision](https://veriff-dev-documentation.document360.io/apidocs/v1sessionsiddecision-1)[↗] endpoint. Solution-specific overview of what to expect is provided below in [Find decision and/or session related](/v1/docs/selfie2selfie-biometric-verification#find-decision-andor-session-related-info) info section.

---

## Find decision and/or session related info

You can get the data from three sources:

- Receive the decision webhook
- Query the results via <meta charset="utf-8">[GET sessions/{sessionId}/decision](https://veriff-dev-documentation.document360.io/apidocs/v1sessionsiddecision-1)[↗]
- View the session in Veriff Customer Portal

### Solution-specific parameters

Info related to Selfie2Selfie Biometric Verification is returned in `faceMatch` string, inside `additionalVerifiedData`. Possible values are: `strong_match`, `possible_match`, `weak_match`.

```json
{
  "verification": {
    "additionalVerifiedData": {
      "faceMatch": "strong_match"
    }
  }
}
```

### Webhook payload

> [!NOTE]
> Below is an **example and an explanation** of the **decision webhook payload**, showing only the **mandatory** parameters for a **Selfie2Selfie Biometric Verification**session**.**
> 
> Depending on your integration configuration, the payload may contain additional parameters. To find more info about those parameters, see the [decision webhook documentation](/v1/docs/decision-webhook#sample-request).

#### Sample request

```json
{
  "status": "success",
  "verification": {
    "id": "f04bdb47-d3be-4b28-b028-a652feb060b5",
    "attemptId": "fd5c1563-1d23-4b1a-ae46-7ba429927ed8",
    "code": 9001,
    "status": "approved",
    "reason": null,
    "reasonCode": null,
    "vendorData": "12345678",
    "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
    "acceptanceTime": "2025-01-15T10:30:00.000Z",
    "submissionTime": "2025-01-15T10:31:00.000Z",
    "decisionTime": "2025-01-15T10:32:22.123Z",
    "person": {
      "firstName": "YAGO",
      "lastName": "FERRERAS",
      "dateOfBirth": null,
      "gender": null,
      "nationality": null,
      "idNumber": null,
      "yearOfBirth": null,
      "placeOfBirth": null,
    },
    "document": {
      "number": null,
      "type": null,            
      "country": null,
      "state": null,
      "remarks": null
    },
    "additionalVerifiedData": {
      "faceMatch": "strong_match"
    },
    "comments": []
  },
  "technicalData": {
        "ip": "186.153.67.122"
  }
}
```

#### Request properties explained

- `status`: `string` Status of the response
- `verification`: `object` Verification request decision object. `null` if decision is not available yet
  - `id`: `string` UUID v4 which identifies the verification session
  - `attemptId`: `string` UUID v4 of the attempt which received a status (as shown in `verification.status` field)
  - `vendorData`: `string | null` The unique identifier that you created for your end-user. `null` if not specified
  - `endUserId`: `string | null` The `UUID` that you created for your end-user. `null` if not specified
  - `status`: `string` Verification status, one of `approved`, `declined`, `resubmission_requested`, `review`, `expired`,` abandoned`
  - `code`: `integer` Verification session decision code, one of `9001`, `9102`, `9103`, `9104`, `9121`. For more info, see the [verification session decision codes](/v1/docs/verification-session-decision-codes-table)
  - `reason`: `string | null` Reason why the verification failed
  - `reasonCode`: `integer | null` Reason code of the failed verification. For more info, see the [possible codes for a failed verification](/v1/docs/verification-session-decision-codes-table)
  - `decisionTime`: `string &nbsp;| null` Timestamp of the decision, represented as `UTC YYYY-MM-DDTHH:MM:SS.SSS+Timezone Offset` (ISO 8601)
  - `acceptanceTime`: `string` Timestamp of the session generation, represented as `UTC YYYY-MM-DDTHH:MM:SS.SSS+Timezone Offset` (ISO 8601)
  - `submissionTime` : string Timestamp of when the session was submitted, represented as `UTC YYYY-MM-DDTHH:MM:SS.SSSSSS+Timezone Offset` (ISO 8601)
  - `person`: `object` Data about the verified person
    - `firstName`: `string | null` Person's first name as written on the document
    - `lastName`: `string | null` Person's last name as written on the document
    - `dateOfBirth`: `string` Person’s date of birth, represented as `YYYY-MM-DD`
    - `gender`: `string | null` Person’s gender, represented as M or F, or `null` if not present
    - `nationality`: `string | null` Person’s nationality, represented as ISO 3166 `alpha-2` or `alpha-3` number
    - `idNumber`: `string | null` National identification number
    - `yearOfBirth`: `string | null` Person’s year of birth, represented as `YYYY`
    - `placeOfBirth`: `string | null` Person’s place of birth
  - `document`: `object` Verified document
    - `number`: `string | null` Document number, `[a-zA-Z0-9]` characters only
    - `type`: `string | null` Document type, one of `PASSPORT`, `ID_CARD`, `RESIDENCE_PERMIT`, `DRIVERS_LICENSE`, `VISA`, `OTHER`
    - `country`: `string | null` Document issuing country, represented as ISO 3166 `alpha-2` code
    - `state`: `string | null` Document issuing state, represented as ISO 3166 `alpha-2` or `alpha-3` code
    - `remarks`: `string` Data extracted from document’s remarks field
  - `additionalVerifiedData`: `object` Data that has been optionally verified for the session
    - `faceMatch`: `string` Indicates the result of the reference image and selfie matching, one of `strong_match`, `possible_match`, `weak_match`
  - `comments`: *(Deprecated) Always returns empty []*
  - `technicalData`: `object` Technical data object
    - `ip`: `string | null` IP of the device from which the verification was made

### API call

> [!NOTE]
> Below is an **example and an explanation** of the **GET /decision API call payload** showing only the **mandatory** parameters for a **Selfie2Selfie Biometric Verification**session.
> 
> Depending on your integration configuration, the payload may contain additional parameters. To find more info about those parameters, see the <meta charset="utf-8">[GET sessions/{sessionId}/decision](https://veriff-dev-documentation.document360.io/apidocs/v1sessionsiddecision-1)[↗] documentation.

#### Sample response

```json
{
  "status": "success",
  "verification": {
    "id": "f04bdb47-d3be-4b28-b028-a652feb060b5",
    "attemptId": "fd5c1563-1d23-4b1a-ae46-7ba429927ed8",
    "code": 9001,
    "status": "approved",
    "reason": null,
    "reasonCode": null,
    "vendorData": "12345678",
    "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
    "acceptanceTime": "2025-01-15T10:30:00.000Z",
    "submissionTime": "2025-01-15T10:31:00.000Z",
    "decisionTime": "2025-01-15T10:32:22.123Z",
    "person": {
      "firstName": "YAGO",
      "lastName": "FERRERAS",
      "dateOfBirth": null,
      "gender": null,
      "nationality": null,
      "idNumber": null,
      "yearOfBirth": null,
      "placeOfBirth": null,
    },
    "document": {
      "number": null,
      "type": null,            
      "country": null,
      "state": null,
      "remarks": null
    },
    "additionalVerifiedData": {
      "faceMatch": "strong_match"
    },
    "comments": []
  },
  "technicalData": {
        "ip": "186.153.67.122"
  }
}
```

#### Response properties explained

- `status`: `string` Status of the response
- `verification`: `object` Verification request decision object. `null` if decision is not available yet
  - `id`: `string` UUID v4 which identifies the verification session
  - `attemptId`: `string` UUID v4 of the attempt which received a status (as shown in `verification.status` field)
  - `vendorData`: `string | null` The unique identifier that you created for your end-user. `null` if not specified
  - `endUserId`: `string | null` The `UUID` that you created for your end-user. `null` if not specified
  - `status`: `string` Verification status, one of `approved`, `declined`, `resubmission_requested`, `review`, `expired`,` abandoned`
  - `code`: `integer` Verification session decision code, one of `9001`, `9102`, `9103`, `9104`, `9121`. For more info, see the [verification session decision codes](/v1/docs/verification-session-decision-codes-table)
  - `reason`: `string | null` Reason why the verification failed
  - `reasonCode`: `integer | null` Reason code of the failed verification. For more info, see the [possible codes for a failed verification](/v1/docs/verification-session-decision-codes-table)
  - `decisionTime`: `string &nbsp;| null` Timestamp of the decision, represented as `UTC YYYY-MM-DDTHH:MM:SS.SSS+Timezone Offset` (ISO 8601)
  - `acceptanceTime`: `string` Timestamp of the session generation, represented as `UTC YYYY-MM-DDTHH:MM:SS.SSS+Timezone Offset` (ISO 8601)
  - `submissionTime` : string Timestamp of when the session was submitted, represented as `UTC YYYY-MM-DDTHH:MM:SS.SSSSSS+Timezone Offset` (ISO 8601)
  - `person`: `object` Data about the verified person
    - `firstName`: `string | null` Person's first name as written on the document
    - `lastName`: `string | null` Person's last name as written on the document
    - `dateOfBirth`: `string` Person’s date of birth, represented as `YYYY-MM-DD`
    - `gender`: `string | null` Person’s gender, represented as M or F, or `null` if not present
    - `nationality`: `string | null` Person’s nationality, represented as ISO 3166 `alpha-2` or `alpha-3` number
    - `idNumber`: `string | null` National identification number
    - `yearOfBirth`: `string | null` Person’s year of birth, represented as `YYYY`
    - `placeOfBirth`: `string | null` Person’s place of birth
  - `document`: `object` Verified document
    - `number`: `string | null` Document number, `[a-zA-Z0-9]` characters only
    - `type`: `string | null` Document type, one of `PASSPORT`, `ID_CARD`, `RESIDENCE_PERMIT`, `DRIVERS_LICENSE`, `VISA`, `OTHER`
    - `country`: `string | null` Document issuing country, represented as ISO 3166 `alpha-2` code
    - `state`: `string | null` Document issuing state, represented as ISO 3166 `alpha-2` or `alpha-3` code
    - `remarks`: `string` Data extracted from document’s remarks field
  - `additionalVerifiedData`: `object` Data that has been optionally verified for the session
    - `faceMatch`: `string` Indicates the result of the reference image and selfie matching, one of `strong_match`, `possible_match`, `weak_match`
  - `comments`: *(Deprecated) Always returns empty []*
  - `technicalData`: `object` Technical data object
    - `ip`: `string | null` IP of the device from which the verification was made

### Veriff Customer Portal

You can find the verification session related info, including the decision, in the Veriff Customer Portal, under the session view tab, where the decision and reference image are displayed.

<meta charset="utf-8">

→ *See*[*Review verification in Veriff Customer Portal*](/v1/docs/how-to-review-verification-in-veriff-customer-portal)*about how to view the session info in the Veriff Customer portal*

---

## Status and reason codes

For an `approved` session, see:

- `verification.code` about verification session decision code, one of `9001`, `9102`, `9103`, `9104`, `9121`
- `verification.status` about verification status, one of `approved`, `declined`, `resubmission_requested`, `expired`, `abandoned`

If the Selfie2Selfie Biometric Verification session was `declined` or `resubmission_requested`, you can find additional information by checking:

- `verification.reason` for the reason why the verification failed
- `verification.reasonCode` for reason code of the failed verification and cross-reference it with [Granular reason codes (table)](/v1/docs/granular-reason-codes)

| `verification.status` | `verification.reasonCode` | `verification.reason` | What does it mean? |
| --- | --- | --- | --- |
| `declined` | 120 | Person on the portrait does not appear to match reference photo | Person on the portrait does not appear to match reference photo. |
| `declined` | 503 | Attempted deceit | Attempted deceit (e.g., presenting a photo of a photo during the liveness check). |
| `declined` | 543 | Reference face image has poor quality | Reference face image has poor quality. |
| `declined` | 545 | Reference image missing | Reference image is missing from the session. |
| `declined` | 546 | Face image quality insufficient | Face is not clearly visible in the live selfie. |
| `declined` | 547 | Face missing | Live selfie image is missing from the session. |
| `declined` | 548 | Attempted deceit, with face reference missing | Liveness check failed on the reference image (e.g., it is a photo of a photo, not a real person). |
| `declined` | 656 | Multiple parties are present in the session | Multiple persons were detected in the live selfie. |

The table above aims to list the most common reasons why you may see the `decline` or `resubmission _requested` reason for a **Selfie2Selfie Biometric Verification** session. However, the session may be rejected due to a reason that is not inherently related to this solution’s flow (e.g. uploaded image’s quality is low). In that case, to find info about the codes you are seeing, refer to:

- [Granular reason codes (table)](/v1/docs/granular-reason-codes)
- [Verification session status codes (table)](/v1/docs/verification-session-status-codes-table)
- [Verification session decision codes (table)](/v1/docs/verification-session-decision-codes-table)

---

## Additional info

### Best practices

1. **Reference image exists**: before starting a session, ensure that end-user’s reference image exists and that you are able to send it to Veriff.
2. **Reference image trustworthiness:**ensure that it is a reliable and valid representation of the end-user.
3. **Reference image quality**: ensure that the image quality is good. This will reduce the possibility of the session going to `resubmission_requested`.
4. **Reference image upload via API**: this must always be done via <meta charset="utf-8">[POST /sessions/{sessionId}/media](https://veriff-dev-documentation.document360.io/apidocs/v1sessionsidmedia-3)[↗] API call, with `image.context` as `face-reference`
5. **Error handling**: implement proper error handling for all possible validation results.
6. **Webhook security**: secure your webhook endpoint and verify request signatures.
7. **User experience**: provide clear feedback to users about validation results.
8. **Ensure**[**backwards compatibility**](/v1/docs/backwards-compatible-changes) for webhooks and API connections.

---

## Changelog

| Date | Description |
| --- | --- |
| Dec 12, 2025 | Broken links fixed, `x-hmac-signature` header restored |
| Dec 11, 2025 | Payload explanation’s formatting updated |
| Dec 10, 2025 | Documentation published |

Veriff customer back-office, a dashboard where you can see your end-users' verification data.

Depending on your setup, you may be required to access the environment via station.veriff.com or hub.veriff.com. Always **check your sign-up email** and make sure that you **log in via correct address**.

A UUID-format unique identifier ([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}) created by you for your end-user to link an end-user to their session(s). Cannot be resolved outside your environment.

Veriff stores it only for identity verification and returns it unchanged in webhooks/API responses or as `null` if not provided.

Strongly recommended if you already use UUID identifiers. Works as an alternative to `vendorData` in Biometric Authentication solution.

A custom unique identifier (max 1,000 characters) created by you, containing only non-semantic data that can't be resolved outside your systems.

Veriff returns it unchanged in webhooks/API responses or as `null` if not provided.

It's referred to as "unique identifier" in Customer Portal and cannot be changed once set.

Required for Fraud solutions (Cross Links check and Velocity Abuse check) and serves as an alternative to `endUserId` in Biometric Authentication when using non-UUID identifiers.

A session during which the end-user is verified. It starts when a session is created, it can contain several attempts (i.e. steps of uploading media, sending additional data etc.) and it ends when a conclusive decision (“approved”, “declined”, “expired”/”abandoned”) is granted.

Each verification session receives an unique ID, aka the **session ID**, which can be added to the API URL when making API requests.

This where the end-user is directed to go through the verification flow, and it is **unique for each verification session**.

It is a combination of the `base URL` and the `sessionToken`, created as soon as a verification session is created. You can find its value in the response payload of your POST /sessions call, as `verification.url`.

The data that you send when you make an API request, or that you receive when you get a response.
