Selfie2Selfie Biometric Verification

Prev Next

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.

Contact your solutions engineer for info and configuration.


Prerequisites

  • You have an integration set up with Veriff

  • The feature is configured for that integration by your Solutions Engineer

  • You have configured the decision webhook to get responses from Veriff (see the how-to in webhooks’ 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 API Documentation and API Reference[↗] how to find these)

  2. Upload the end-user's reference image via POST /sessions/{sessionId}/media[↗] 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 GET sessions/{sessionId}/decision[↗] endpoint.

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 API Documentation and API Reference[↗] how to find these)

    • Veriff strongly recommends you create and send the endUserId or vendorData

Session creation bash example

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 POST /sessions/{sessionId}/media[↗] call.

    • Ensure that the reference image’s image.context is face-reference

Media upload bash example

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 POST /sessions/{sessionId}/media[↗] call.

    • Specify the image.context as appropriate for the image (e.g. face) (see Context types (image, video) for more info about image context types).

Media upload bash example

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 GET sessions/{sessionId}/decision[↗] endpoint. Solution-specific overview of what to expect is provided below in Find decision and/or session related info section.


Find decision and/or session related info

You can get the data from three sources:

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.

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

Webhook payload

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.

Sample request

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

    • 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

    • decisionTime: string  | 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

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 GET sessions/{sessionId}/decision[↗] documentation.

Sample response

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

    • 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

    • decisionTime: string  | 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.

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

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:


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 POST /sessions/{sessionId}/media[↗] 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 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