NAV

Introduction

Welcome to Veriff's developers documentation!

If you have any questions, use the Intercom button at the bottom of the screen or write to support@veriff.com to get in contact with us.

Getting Started With Veriff

Signing up

Fill in the form at veriff.com [↗] and a confirmation email with further instructions is sent to you.

Logging in

To log in to the Veriff environment, please use the link sent in the confirmation email and follow the instructions.

New user accounts

Once you have logged in and wish to create new user accounts for other members of your team, navigate to the Team page. You must have the Administrator rights to do it. Check out this article [↗] in the Knowledge Base for more info (requires a login to the Veriff environment).

Creating an integration

Integration is a collection of settings and is distinguished by the API keys. In short, it means that an integration is a way to exchange data with Veriff.

Integrations are created in the Veriff environment. In case it has not already been created for you, or you would like to create another one, follow these steps.

  1. Log in via the link sent to you in your signup email
  2. Navigate to Integrations tab on the top-bar menu
  3. Click on the Add integration button
  4. Choose a suitable name and environment for the integration (either Test or Live)

Test integrations

These are used for development. Verification sessions done in the test integrations do not count towards paid usage. Stress testing without prior agreement with Veriff is not allowed.

Veriff does not provide decisions for sessions created in the test integration, you need to trigger the decisions yourself.

One option is to do it in the Veriff environment. See the article here [↗] about how to do that (requires a login to the Veriff environment).

The other is to generate a session using the POST /sessions call and pass "Approve", "Decline" or "Resubmit" in the firstName field. You can read more about it in this article [↗] in the Knowledge Base (requires a login to the Veriff environment).

Live integrations

These are used for production. Sessions created will count towards paid usage and Veriff provides a decisions for those.

To find more information about Integrations, please see the articles [↗] in the Knowledge Base (requires a login to the Veriff environment).

Quick guide of IDV using the SDKs

This section is a quick intro into doing identity verification (IDV) when using the Software Development Kits (SDKs).

You may want to opt for the SDKs when you prefer using Veriff's front-end solution and built-in verification flow, and have no plans to independently collect end-user media.

Quick overview of the steps

  1. Add the relevant Veriff SDK to your project
  2. Create an integration (guide above)
  3. Configure webhooks (guide below)
  4. Create a verification session to get the session URL (guide below)
  5. Pass the session URL to the SDK
  6. Direct the end-user to the verification flow, where they submit their data and media
  7. End-user's data and media passed to Veriff
  8. Veriff verifies the end-user
  9. Veriff returns the decision via webhook

Using the API to generate a session for the SDK

First refer to the Prerequisites to create API requests and the Backwards compatible changes sections to make sure you have all you need to start sending API requests.

  1. Make a POST /sessions call:
    • Send the object to https://<BaseURL>/v1/sessions
    • Include the Content-Type application/json header
    • Include the X-AUTH-CLIENT header containing your integration's API key
    • Include the callback URL in verification.callback for Redirect end-users
    • Include the vendorData parameter (optional, but strongly recommended)
  2. From the response you need to take:
    • The unique session ID in verification.id, important for webhooks and for identifying the session later on
    • The unique session URL in verification.url, required to bring the end-user into the flow
    • Also, we recommend storing the unique vendorData parameter, which is important for improved fraud detection, webhooks, and for identifying the session later on

Request example

{
    "verification": {
       "callback": "https://veriff.com",
       "vendorData": "2bf528f7-4b9c-44f0-b928-fdc7afc5ca1b"
  }
}

Response example

{
    "status": "success",
    "verification": {
        "id": "b27afb60-1455-4927-afb6-fc27a60e1455",
        "url": "https://....",
        "vendorData": "2bf528f7-4b9c-44f0-b928-fdc7afc5ca1b",
        "host": "https://....veriff.com",
        "status": "created",
        "sessionToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9....."
    }
}

What happens after the end-user leaves the verification flow?

When the end-user leaves the verification flow, the following scenarios apply.

Android, iOS, Flutter and React Native

When a session is canceled or finished, the Veriff SDK is closed. The end-user is taken back to your application.

Also, the end-user flow completion status is returned to the host application via callback or delegate method, depending on the SDK type. Note that this status shows whether the end-user was able to complete all the steps in the verification flow or not. It is not the verification session status.

Refer to each SDK for more info about the callback or delegate methods:

InContext JS (Iframe and Embedded)

When a session is canceled or finished, the InContext SDK emits the CANCELED or FINISHED events. It is up to you to decide what happens (close, redirect) in the SDK when the events are triggered.

See here for more info about the onEvent callback that will return the end-user flow completion status.

Redirect

When a session is canceled or finished, we try to redirect the end-user to the callback URL, or close the browser if the callback URL is not present.

SDK sessions lifecycle diagram


SDK sessions lifecycle diagram

Quick guide of the IDV using the API

This section is a quick intro into doing identity verification (IDV) when using the Application Programming Interface (API) calls.

In case of using the API, you are collecting the end-user's data and/or media yourself via your own solution, and then use Veriff's API endpoints to pass us relevant data for verification.

The most important prerequisite to send end-user's data to Veriff is the session ID aka the value in the POST /sessions response verification.id field. This is used in all the calls made for the specific session (refer to the Endpoints), and it is used to get the webhook responses for the session.

Quick overview of the steps

  1. Create an integration (guide above)
  2. Configure webhooks (guide below)
  3. Create a verification session to get the session ID (guide below)
  4. Using the session ID, pass end-user's media via POST sessions/{sessionId}/media
  5. Patch the session to submitted using PATCH sessions/{sessionId}
  6. Veriff verifies the end-user
  7. Veriff returns the decision via webhook

Note that collecting end-user's data beforehand or during the flow is optional, as Veriff can extract this data from the media sent to us.

Using the API to generate a session for API

First refer to the Prerequisites to create API requests and the Backwards compatible changes sections to make sure you have all you need to start sending API requests.

  1. Make a POST /sessions call:
    • Send the object to https://<BaseURL>/v1/sessions (required)
    • Include the Content-Type application/json header (required)
    • Include the X-AUTH-CLIENT header containing your integration's API key (required)
    • Include the end-user's data/media you have collected (refer to the Request properties explained in POST /sessions) (optional)
    • Include the vendorData parameter (optional, but strongly recommended)
  2. In the response, you will receive a JSON with:
    • The unique session ID in verification.id, important for webhooks and for identifying the session later on

Request example

{
     "verification": {
          "person": {
               "firstName": "John",
               "lastName": "Smith",
               "idNumber": "12-03-1989"
            },
          "document": {
               "number": "B01234567",
               "type": "PASSPORT",
               "country": "EE"
            },
          "address": {
               "fullAddress": "Lorem Ipsum 30, 12345 Tallinn, Estonia"
            },
         "vendorData": "2bf528f7-4b9c-44f0-b928-fdc7afc5ca1b"
  }
}

Response example

{
    "status": "success",
    "verification": {
        "id": "b27afb60-1455-4927-b155-0260ffe0947a",
        "url": "https://....",
        "vendorData": "2bf528f7-4b9c-44f0-b928-fdc7afc5ca1b",
        "host": "https://....veriff.com",
        "status": "created",
        "sessionToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9....."
    }
}

API sessions lifecycle diagram


API sessions lifecycle diagram

Generating session manually

It is possible to manually generate a verification session in the Veriff environment. This option can be used to test or debug sessions, or as a manual fallback option.

Using this option, you can generate a link and a QR code, and share them with the end-user.

  1. Go to the Veriff environment
  2. Click on the Verifications on the top menu
  3. Click on the Add Verification button
  4. Find and open the relevant integration
  5. Fill in the first name, last name
  6. Click Generate Verification
  7. Click on Share to copy the URL or QR image onto a clipboard

Setting up webhooks

In order to receive responses from Veriff services, you need to configure webhooks. Refer to the Webhooks section for a thorough overview.

To configure the webhook endpoint:

  1. Go to the Veriff environment
  2. Click on the Integrations on the top menu
  3. Find and open the relevant integration
  4. Navigate to the Settings tab on the integration's page
  5. Fill in the webhook URL input field with the URL where your endpoint is accepting payloads from Veriff

There are several types of webhooks. Veriff will post payloads to respective webhook URLs.

Note that the image below does not contain all the possible webhook URLs. The list available depends on your integration.

Verification session statuses

Once the end-user has gone through the flow, we return the session status and the status code.

Session statuses explained

Identity verification session status is one of:

For the aforementioned verification statuses, the status code is one of 9001, 9102, 9103, 9104, 9121. All codes and explanations can be found in the Verification session decision codes table.

Responses 9001, 9102, 9121 and 9104 are conclusive responses. The session is closed and the URL is not available for the end-user.

Response 9103 is an inconclusive response. The session remains open until you receive one of the above conclusive responses. The session is re-opened for the end-user, accepting a new attempt.

Fetching the session statuses

The session status is available in the verification.status parameter in:

Verification decisions

Once the end-user has gone through the verification flow and the verification process is complete, the session receives a decision. The end user is approved, declined, or asked to resubmit.

Decisions explained

We share with you the reasons why the end-user was declined or asked to resubmit:

Triggering decisions manually for testing

There are two ways to trigger decisions for test integration sessions.

  1. In the Veriff environment. Refer to this article [↗] in the Knowledge Base (requires a login to the Veriff environment).

  2. Generate a session using the POST /sessions call and pass "Approve", "Decline" or "Resubmit" in the firstName field. Refer to this article [↗] in the Knowledge Base (requires a login to the Veriff environment).

Fetching the decision

There are several options to fetch the decision(s) of a verification session:

Full Auto solution with insights and extractions

Use the Full Auto webhook, but note that in this case, the "decision" is the system's suggestion about what to do with the session.

Also, querying GET /sessions/{sessionId}/decision endpoint will not return data about the session, the payload will be empty. Contact your Solutions Engineer for more info.

Verification session events

Event statuses and codes are sent to notify you about the progress of the data gathering process during the verification session. For more info, see the Event webhook section.

Backwards compatible changes

All the changes listed below are considered to be backwards compatible by Veriff. Make sure to set up your systems in such flexible manner that it is able to handle these changes.

*As a general note on the order of properties in the responses, keep in mind that the order is not static. This means that the order you see in your API call responses may differ from the order you see in Veriff documentation.

**This means data that your system should be able to just transmit or store, not interpret.

Try our demos

Web

To try out the end-user facing verification flow, navigate to Veriff Demo [↗]. Opening the link will start the verification flow in your browser.

Mobile SDKs

Our mobile SDKs can be tested by downloading the demo versions: iOS / Android [↗]

Review Verifications

To review the submitted verification and its results, visit the Veriff environment and open the individual verification session to see the details.

Browser support for verification flow

Supported browsers

Desktop

In addition to the listed browsers other Chromium based browsers may work.

iOS

Android

In addition to the listed browsers other Chromium based browsers may work.

Not supported browsers

A list of browsers which are not supported currently and that we can not support unless there are browser side changes implemented by the browser provider:

Android

iOS

Allowlisted URLs and IP addresses

To ensure uninterrupted access to our services, it is important that your network firewall configurations permit communication with our servers. This involves allowing specific IP addresses and URLs to establish a secure and reliable connection.

Allowlisted URLs

To facilitate smooth service operations, we request allowing all traffic coming from the following domains:

Allowlisted IP addresses

IPs for US zone

100.20.120.34
52.25.243.218
54.148.105.103
54.218.205.80

IPs for EU zone

34.254.42.181
34.242.213.89
52.19.226.239

Floating IPs range

3.251.215.160/27

That means the range to be allowed is: 3.251.215.160 to 3.251.215.191

Test the API Collection in Postman

It is possible to test the Veriff API v1.0 Collection in Postman. Click on the button below to get started.

Integrations Test Guide

You will have one Test integration pre-created for you in the Veriff environment. You can create more test integrations if needed. The test integration will be used by you to test the communication between Veriff's and your system and to see how the responses are handled.

To check the quality of Veriff's responses, and you are already set up with Veriff, please talk to you Solutions Engineer. If not, please select plan and subscribe to a free trial on Plans [↗] page. After you activate the free trial and log in to the Veriff environment you are allowed to create Live integrations.

Testing verification sessions checklist

Also see our support article for getting the desired test verification result [↗]

Testing security

Testing responses

Each type of response should be accepted:

Explanations and availability of these have been listed in the session status and decision codes tables > decision codes 9001 to 9121.

Testing process in your app

You should test the handling of best cases as well as edge cases:

Mobile testing

Test our demo app by downloading it in the app store. iOS / Android [↗]

API Upload testing

Required tools

Step by step

  1. Download and install Node.js
  2. Download and extract js-integration-demo-master.zip
  3. Open Command (Windows) or Terminal (Mac) on your local computer.
  4. Navigate to js-integration-demo-master folder cd C:\Users\User\Desktop\Veriff API).
  5. Run command >npm install
  6. Open app.js with your text editing app (Notepad/TextEdit) and update 'API-Public-Key' and 'API-Private-Key' to the values in your Backoffice account (Management -> Vendor). Tokens must be in single quotes. Save the file.
const API_TOKEN = process.env.API_TOKEN || 'API-Public-Key';
const API_SECRET = process.env.API_SECRET || 'API-Private-Key';
const API_URL = process.env.API_URL || 'https://api.staging.vrff.io/v1';
const WEBHOOK_PORT = process.env.WEBHOOK_PORT || 3002;
const IMAGE_DIR = process.env.IMAGE_DIR || 'documents'

Run the app.js node app.js

Now the verification session is created and it is being processed. Check your Backoffice dashboard to review the data extracted and decision made by Veriff.

Batch testing

Batch upload tests are sometimes agreed with our onboarding team and are very use case specific. Therefore, below might be not applicable for the majority of customers. For batch tests, customers will need to prepare dataset that will be used for testing. If you have been asked for dataset, please see batch test data preparation guide [↗].

End-User In The Flow

Flow Diagram

Session Status Diagram

Session Status

SDK Guide

Why use the SDK?

Veriff Software Development Kits (SDKs) can be opted for if you prefer leveraging Veriff's front-end solution, wish to maximize the benefits of our built-in verification flow, and have no plans to independently collect end-user media.

SDKs are quite straightforward to integrate with, as they have pre-built components and libraries. Veriff handles SDKs' updates and maintenance, to ensure improvements and bug fixes.

SDKs allow gathering lots of different data, thus supporting enhanced fraud detection abilities. Examples here are video recording and liveness checks.

Once integrated into your project, the SDK allows you to customize the solution's appearance by adding your unique branding elements and colors.

Veriff supports the following SDKs

Native

Web

SDK customization guides

It is possible to change the look of the end-user flow in both native SDKs and the web flow to be more aligned with your brand.

See the Veriff Native SDKs customization guide [↗] document to see the options, and read the customization guide in each SDKs section for further info.

See the Veriff Web SDKs customization guide [↗] document to see the options.

Prerequisites to use the SDKs

Before you can launch the verification flow for your end-users, make sure you have:

Android SDK

Android SDK Requirements

The Veriff Android SDK has the following constraints and requirements:

List of all direct transitive dependencies:

Adding the Android SDK

Open the root build.gradle file and add a new maven destination to the repositories in the allprojects section:

allprojects {
    repositories {
        maven { url "https://cdn.veriff.me/android/" }
        google()
        mavenCentral()
    }
}

Alternatively, when using Gradle 7+, add the Maven repository to your settings.gradle file:

dependencyResolutionManagement {
    repositories {
        maven { url "https://cdn.veriff.me/android/" }
        google()
        mavenCentral()
    }
}

Add the Veriff SDK dependency to the application build.gradle file:

implementation 'com.veriff:veriff-library:6.+'

Permissions

The SDK will request all the permissions it needs, please make sure that the CAMERA, RECORD_AUDIO permissions are not explicitly removed using tools:node="remove" in your app`s manifest file. Ignore this if you are not explicitly removing any permissions.

Declare foreground service sync for Google Play

The SDK declares and uses the FOREGROUND_SERVICE_DATA_SYNC. If you distribute your application on Google Play, then you must declare the foreground service information in Play Console [↗].

The information required by Play Console is (as listed on the Google Play link above):

  1. Provide a description of the app functionality that is using each foreground service type.
    • The Veriff SDK uses the foreground service to upload end-user data to Veriff's servers for verification purposes.
  2. Describe the user impact if the task is deferred by the system (does not start immediately), and/or the task is interrupted by the system (paused and/or restarted).
    • If the task is deferred or interrupted by the system, the end-user verification will be delayed.
  3. Include a link to a video demonstrating each foreground service feature. The video should demonstrate the steps the user needs to take in your app in order to trigger the feature.
    • Please record a video of your app's Veriff SDK integration.
  4. Choose your specific use case for each foreground service type.
    • "Network transfer: Upload or download / Other"

See also Veriff's note on data collection purposes in your app [↗]

Starting the verification flow

The verification flow must be launched from the vendor Activity class with a unique session. A session is valid for 7 days and expires automatically after that.

import com.veriff.Sdk;

Intent intent = Sdk.createLaunchIntent(activity, sessionUrl);
startActivityForResult(intent, REQUEST_CODE);

Parameters are defined as below;

Parameters Description
sessionUrl Required parameter. sessionUrl can be received from your backend implementation. sessionUrl should be unique for each call. Check /sessions endpoint in the API documentation here to learn how to generate one.
REQUEST_CODE Define an integer constant REQUEST_CODE in your activity which can be used to compare in onActivityResult

Customizing the SDK

Setting a theme (Optional)

You can customize the look and feel of the SDK flow by passing a Branding object via Configuration to createLaunchIntent as shown in the example below.

Branding branding = new Branding.Builder()
        .logo(R.drawable.logo)
        // Screen and dialog background color
        .background(getResources().getColor(R.color.background_color))
        // Non-surface content (such as text, icons) displayed on `background`.
        // Accessibility: Must have a contrast ratio of at least 4.5:1 vs `background`
        .onBackground(getResources().getColor(R.color.on_background_color))
        // Secondary non-surface content (such as text) displayed on `background`.
        // Accessibility: Must have a contrast ratio of at least 4.5:1 vs `background`
        .onBackgroundSecondary(getResources().getColor(R.color.on_background_secondary_color))
        // Tertiary non-surface content (such as text) displayed on `background`.
        // Accessibility: Must have a contrast ratio of at least 4.5:1 vs `background`
        .onBackgroundTertiary(getResources().getColor(R.color.on_background_tertiary_color))
        // Primary surfaces (such as buttons) displayed on `background`.
        // Accessibility: Must have a contrast ratio of at least 3:1 vs `background`
        .primary(getResources().getColor(R.color.primary_color))
        // Non-surface content (such as text) displayed on `primary` surfaces.
        // Accessibility: Must have a contrast ratio of at least 4.5:1 vs `primary`
        .onPrimary(getResources().getColor(R.color.on_primary_color))
        // Secondary surfaces (such as bullet points and illustrations) displayed on `background`.
        // Accessibility: Must have a contrast ratio of at least 3:1 vs `background`
        .secondary(getResources().getColor(R.color.secondary_color))
        // Non-surface content (such as text) displayed on `secondary` surfaces.
        // Accessibility: Must have a contrast ratio of at least 4.5:1 vs `secondary`
        .onSecondary(getResources().getColor(R.color.on_secondary_color))
        // Backgroung color of the overlay area on all the screens with camera
        .cameraOverlay(getResources().getColor(R.color.camera_overlay_color))
        // All UI elements on all the screens with camera on top of camera overlay
        // Accessibility: Must have a contrast ratio of at least 4.5:1 vs `cameraOverlay`
        .onCameraOverlay(getResources().getColor(R.color.on_camera_overlay_color))
        // Color used for various outlines and boundaries of UI elements
        .outline(getResources().getColor(R.color.outline_color))
        // Error indicators (such as text, borders, icons) displayed on `background`
        // Accessibility: Must have a contrast ratio of at least 4.5:1 vs `background`
        .success(getResources().getColor(R.color.success_color))
        // Success indicators (such as borders, icons) displayed on `background`
        // Accessibility: Must have a contrast ratio of at least 3:1 vs `background`
        .error(getResources().getColor(R.color.error_color))
        // Button corner radius, in `dp`
        .buttonRadius(48f)
        .build();

Configuration configuration = new Configuration.Builder()
        .branding(branding)
        .build();


Intent intent = Sdk.createLaunchIntent(activity, sessionUrl, configuration);
startActivityForResult(intent, REQUEST_CODE);

All custom values for branding are optional. If a value is not provided for them the default Veriff color or icon will be used.

More customization options

Customizing the font

You can customize the fonts used in the SDK by passing the resource IDs of the fonts you want to use. Make sure that you have added the font files to the font resource folder in your app. A custom font can be set by passing a com.veriff.Font object to the font method of Branding builder. The com.veriff.Font builder accepts 3 types of fonts via the setRegular setMedium and setBold methods.

brandingBuilder.font(
    new com.veriff.Font.Builder()
        .setRegular(R.font.comic_neue_regular)
        .setMedium(R.font.comic_neue_medium)
        .setBold(R.font.comic_neue_bold)
        .build()
);

Custom intro screen

Veriff supports replacing introduction screen with a custom client developed introduction screen for eligible customers. First, please ask about this possibility from your solutions engineer. In case we can offer it for you then removal process is following:

Configuration configuration = new Configuration.Builder()
        .customIntroScreen(true)
        .build();

Note: Adding the configuration alone in your app is not enough to enable the custom intro screen. Make sure to contact your solutions engineer so they can enable the feature for your integration.

Setting a locale for the SDK (Optional)

You can set a locale(java.util.Locale) for the SDK from the app itself.

Locale appLocale = Locale.ENGLISH;
Configuration configuration = new Configuration.Builder()
        .locale(appLocale)
        .build();

Intent intent = Sdk.createLaunchIntent(activity, sessionUrl, configuration);
startActivityForResult(intent, REQUEST_CODE);

Adding vendor data

Veriff supports the option to override vendor data. Please check with your Solutions Engineer to confirm if this feature can be enabled for your integration. If it is possible, follow these steps:

  1. Veriff will enable vendor data overriding from the backend for your integrations.
  2. Modify the configuration option as specified below.
Configuration configuration = new Configuration.Builder()
        .vendorData("Vendor Data")
        .build();

Note: Enabling this feature alone will not be sufficient to override the vendor data. Ensure that you contact your Solutions Engineer to have the feature enabled for your integration.

Getting the verification status

Veriff SDK sends callbacks to your mobile application. To capture the result override the onActivityResult method in your activity that started the verification flow.

Note that this is the end-user flow completion status, meaning that it shows whether the end-user was able to complete all the steps in the verification flow or not. It is not the verification session status.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_CODE) {
        Result result = Result.fromResultIntent(data);
        if (result != null) {
            handleResult(result); //see below for handling the result
        }
    }
    super.onActivityResult(requestCode, resultCode, data);
}

public void handleResult(Result result) {
    switch (result.getStatus()) {
    case DONE:
        // Session is completed from the end-user's perspective
        break;
    case CANCELED:
        // End-user cancelled the session
        break;
    case ERROR:
        // An error occurred during the flow, Veriff has already shown UI, no need to display
        // a separate error message here
        Log.w(TAG, "Verification error occurred: " + result.getError());
        break;
    }
}

Adding error logging

To turn on logging, simply add your logging implementation instance (instance of com.veriff.Logger class) to the SDK before launching the SDK as shown.

Sdk.setLogger(myLoggerImplementation);
Intent intent = Sdk.createLaunchIntent(activity, sessionUrl);
startActivityForResult(intent, REQUEST_CODE);

Excluding ML Kit support

Veriff Android SDK uses ML Kit [↗] for things like automatic selfie capture and accessibility feedback to improve the end-user experience. It uses on-device models that are pre-downloaded by Play services. If your app cannot use Play services at all then you can exclude the transitive mlkit dependency - this will remove any dependencies on ML Kit and disable the use of these ML modules at runtime:

implementation('com.veriff:veriff-library:7.+') {
    exclude group: 'com.veriff', module: 'mlkit'
}

Android SDK Changelog

Please refer to release notes [↗].

Migrating Veriff Android SDK from 5.x.x to 6.0.0

SDK integration

The following APIs were removed:

The following APIs were renamed:

The following APIs were added:

Migrating Veriff Android SDK from 4.x.x to 5.0.0

SDK integration

The following APIs were removed:

The following APIs were added:

Migrating Veriff Android SDK from 3.x.x to 4.0.0

Follow these steps to migrate from SDK 3.x.x to 4.0.0

Android Gradle Plugin Open the root build.gradle file and change the classpath dependency in the buldscript section if that needed. groovy buildscript { repositories { ... } dependencies { classpath 'com.android.tools.build:gradle:3.4.1' // and above ... } }

Kotlin Open the root build.gradle file and change the classpath dependency in the buldscript section if that needed.

buildscript {
    ext.kotlinVersion = '1.4.0' // and above
    repositories {
      ...
    }
    dependencies {
        ...
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
        ...
    }
}

Proguard Open the root build.gradle file and add the force update to the buildscript section if that needed. groovy buildscript { ... configurations.all { resolutionStrategy { force 'net.sf.proguard:proguard-gradle:6.2.2' } } }

SDK integration Nothing changed in SDK except the public API types, please update the imports to java import com.veriff.Branding; import com.veriff.Configuration; import com.veriff.Font; import com.veriff.Result; import com.veriff.Sdk; and change types from VeriffBranding to Branding VeriffConfiguration to Configuration VeriffFont to Font VeriffResult to Result

Migrating Veriff Android SDK from 2.x.x to 3.0.0

Follow these steps to migrate from SDK 2.x.x to 3.0.0

Switch to AndroidX

Veriff SDK 3.0.0 requires AndroidX 1.0.0 or later. If you haven't switched to AndroidX in your app yet then follow this guide [↗].

Enable Java 8

Veriff SDK 3.0.0 requires Java 8 language features to be enabled in your project. If you don't have this enabled already then add this to your app/build.gradle file under the android {} section:

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}

See more here [↗].

Switch from baseUrl and sessionToken to sessionUrl

The new 3.0.0 SDK requires a single sessionUrl parameter instead of baseUrl and sessionToken. See the documentation here. As a backwards compatibility measure, if a sessionToken value is passed into the sessionUrl parameter then it will still work with an assumed baseUrl of magic.veriff.com.

Use com.veriff.* classes instead of mobi.lab.veriff.data.* ones

The name and location of the main SDK entry class has changed from mobi.lab.veriff.data.Veriff to com.veriff.VeriffSdk. The API is largely similar - instead of Veriff.Builder there's a VeriffSdk.createLaunchIntent method that returns an Intent which you can then use to launch veriff. See example here.

If you are using Branding to customize the look and feel of the SDK then it has a new name - VeriffBranding. The builder interface has been streamlined by removing the set* prefixes from all the methods. Read more about customization here.

Use com.veriff.VeriffResult instead of reading return Intent directly

Starting with 3.0.0 there's a new way to handle the result of the verification flow. Instead of reading INTENT_EXTRA_STATUS directly from the returned data intent, use VeriffResult.fromResultIntent(data) to get a result object with a status field and an optional error field. We've reduced status to just three - CANCELED, ERROR, DONE. In case of ERROR the error field contains more information. See the example here.

Remove usage of deprecated types

While the old SDK entrypoints are still present for backwards compatibility they will be removed in the future. Please remove usage of any SDK type marked with @Deprecated - the easiest way to discover these is to look at your Gradle build log with Java/Kotlin compilation warnings turned on.

Here's a list of old deprecated classes due to be removed in a future release:

mobi.lab.veriff.data.Veriff
mobi.lab.veriff.data.Veriff.Builder
mobi.lab.veriff.data.VeriffConstants
mobi.lab.veriff.data.Branding
mobi.lab.veriff.data.Branding.Builder
mobi.lab.veriff.data.DrawableProvider
mobi.lab.veriff.util.LogAccess
mobi.lab.veriff.util.LogAccess.LogLevel
mobi.lab.veriff.util.LogcatLogAccess
mobi.lab.veriff.service.VeriffStatusUpdatesService

iOS SDK

iOS SDK Requirements

Integration Veriff iOS SDK requires at least iOS version 13.0

Adding the SDK to the project

VeriffSDK requires the latest stable version of Xcode available at the time the release is made. If you would like to use versions that are independent of Swift versions, please integrate .xcframework.

Using Swift Package Manager

To integrate Veriff SDK with Swift Package Manager, open File > Swift Packages > Add Package Dependency and add the Veriff iOS SDK Swift Package repository url as stated below;

https://github.com/Veriff/veriff-ios-spm/

Using Cocoapods

To integrate Veriff SDK with Cocoapods, please add the line below to your Podfile and run pod install. New to Cocoapods? Learn more here [↗].

pod 'VeriffSDK'

After installation is done, use the newly created .xcworkspace file of your project.

Using Carthage

To integrate VeriffSDK into your Xcode project using Carthage, specify the required libraries below in your Cartfile.

binary "https://cdn.veriff.me/ios/carthage/VeriffSDK.json"

Run carthage update --use-xcframeworks and then drag and drop Veriff.xcframework from Carthage/Build folder to the Frameworks, Libraries, and Embedded Content section on your app target's General settings tab.

Using XCFramework

To integrate Veriff SDK into your project manually, please download VeriffSDK [↗].

After the download finishes, drag and drop the unzipped Veriff.xcframework to the Frameworks, Libraries, and Embedded Content section on your app target's General settings tab.

Adding permissions

Add usage descriptions to application Info.plist

Not adding these usage descriptions causes system to kill application when it requests the permissions when needed.

Veriff iOS SDK requires camera, microphone, photo library and optionally NFC reader permissions for capturing photos, video and scanning passport during identification. Your application is responsible to describe the reason why camera, microphone, photo library and NFC reader is used. You must add 3 descriptions listed below to Info.plist of your application with the explanation of the usage.

Add required steps for NFC scanning

  1. Add NFCReaderUsageDescription description to Info.plist.
  2. The application needs to define the list of application IDs or AIDs it can connect to, in the Info.plist file.
  3. The AID is a way of uniquely identifying an application on a ISO 7816 tag, which is usually defined by a standard.

    <key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
    <array>
      <string>A0000002471001</string>
      <string>A0000002472001</string>
      <string>00000000000000</string>
    </array>
    
  4. Introduce a new entitlement for NFC scanning. Xcode automatically adds this entitlement when you activate the Near Field Communication Tag Reading feature in the target Signing & Capabilities. Following the activation of this feature, the *.entitlements file should include the TAG format.

    <key>com.apple.developer.nfc.readersession.formats</key>
    <array>
        <string>TAG</string>
    </array>
    

Note: due to Apple's policies, you may be required to record and share a proof video of using the NFC. You can download and use this pre-recorded video [↓]. If this does not solve the issue, please contact our support team.

Declare the purposes of data collection in your app

See Veriff's note on data collection purposes [↗]

Starting verification flow

Import Veriff in your code

// Swift
import Veriff

// Objective-C
@import Veriff;

In order to use Veriff SDK, please import it to your class that will use the SDK.

Start the verification flow

In order to start the verification flow please call the method below with the defined parameters.

// SwiftUI
let veriff = VeriffSdk.shared
veriff.startAuthentication(sessionUrl: sessionUrl)

// Swift
let veriff = VeriffSdk.shared
veriff.startAuthentication(sessionUrl: sessionUrl, presentingFrom: yourViewController)

// Objective-C
VeriffSdk *veriff = [VeriffSdk shared];
[veriff startAuthenticationWithSessionUrl:sessionUrl presentingFrom:yourViewController];

Parameters are defined as below;

Parameters Description
sessionUrl Required parameter. sessionUrl can be received from your backend implementation. sessionUrl should be unique for each call. Check /sessions endpoint in the API documentation here to learn how to generate one.
configuration Optional VeriffConfiguration object. Refer to Customize user interface (Optional) for how to use it.
presentingFrom Your app's view controller from which our UI will be presented modally. It's optional and shouldn't be used in SwiftUI projects.

Customize user interface (Optional)

You can customize the Veriff user interface through your own application, by letting the SDK know of your brand's main color, font and logo. The Branding class allows customization of the navigation bar title image, button corner radius, font and following colors:

In order to use customization set the branding property of VeriffConfiguration before you start the verification.

See the Veriff SDK customization guide [↗] document to see what it looks like.

// Swift
let branding = VeriffSdk.Branding()
branding.logo = UIImage(named: "logo.png")
branding.background = UIColor.background
branding.onBackground = UIColor.onBackground
branding.onBackgroundSecondary = UIColor.onBackgroundSecondary
branding.onBackgroundTertiary = UIColor.onBackgroundTertiary
branding.primary = UIColor.primary
branding.onPrimary = UIColor.onPrimary
branding.secondary = UIColor.secondary
branding.onSecondary = UIColor.onSecondary
branding.cameraOverlay = UIColor.cameraOverlay
branding.onCameraOverlay = UIColor.onCameraOverlay
branding.outline = UIColor.outline
branding.error = UIColor.error
branding.success = UIColor.success
branding.buttonRadius = CGFloat.cornerRadius
branding.font = VeriffSdk.Branding.Font(regular: "Font", medium: "Font-Medium", bold: "Font-Bold")

// Objective-C
VeriffBranding *branding = [[VeriffBranding alloc] init];
branding.logo = [UIImage imageNamed:@"logo.png"];
branding.background = [UIColor background];
branding.onBackground = [UIColor onBackground];
branding.onBackgroundSecondary = [UIColor onBackgroundSecondary];
branding.onBackgroundTertiary = [UIColor onBackgroundTertiary];
branding.primary = [UIColor primary];
branding.onPrimary = [UIColor onPrimary];
branding.secondary = [UIColor secondary];
branding.onSecondary = [UIColor onSecondary];
branding.cameraOverlay = [UIColor cameraOverlay];
branding.onCameraOverlay = [UIColor onCameraOverlay];
branding.outline = [UIColor outline];
branding.error = [UIColor error];
branding.success = [UIColor success];
branding.buttonRadius = 5;
branding.font = [[VeriffBrandingFont alloc] initWithRegular: @"Font" medium: @"Font-Medium" bold: @"Font-Bold"];

For optimal results, we recommend that the height of your custom logo image be kept under 40 points, and the width under 90 points. If your logo exceeds these dimensions, it will be compressed while preserving its original aspect ratio.

Setting the user interface language

The Veriff iOS SDK allows setting the language of the SDK. In order to use this language, please set the languageLocale property of VeriffSdk.Configuration before you start the verification.

// Swift
let locale = Locale(identifier: "et")

// Objective-C
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"et"];

Create the configuration object

// Swift
let configuration = VeriffSdk.Configuration(branding: branding, languageLocale: locale)

// Objective-C
VeriffConfiguration *configuration = [[VeriffConfiguration alloc] initWithBranding:branding languageLocale:locale];

Custom intro screen

Veriff supports replacing introduction screen with a custom client developed introduction screen for eligible customers. First, please ask about this possibility from your Solutions Engineer. In case we can offer it for you then removal process is following:

configuration.customIntroScreen = true

Note: This step alone is not enough to enable the custom intro screen. Make sure to contact your Solutions Engineer so they can enable the feature for your integration.

Vendor data

Veriff supports the option to override vendor data. Please check with your Solutions Engineer to confirm if this feature can be enabled for your integration. If it is possible, follow these steps:

  1. Veriff will enable vendor data overriding from the backend for your integrations.
  2. Modify the configuration option as specified below.
configuration.vendorData = "Vendor Data"

Note: Enabling this feature alone will not be sufficient to override the vendor data. Ensure that you contact your Solutions Engineer to have the feature enabled for your integration.

Start the verification flow by using the configuration

// Swift
let veriff = VeriffSdk.shared
veriff.startAuthentication(sessionUrl: sessionUrl, configuration: configuration, presentingFrom: yourViewController)

// Objective-C
VeriffSdk *veriff = [VeriffSdk shared];
[veriff startAuthenticationWithSessionUrl:sessionUrl configuration:configuration presentingFrom:yourViewController];

Handling result codes from SDK

To receive session results, you must implement the VeriffSdkDelegate protocol and assign a delegate to the VeriffSdk instance.

Note that this is the end-user flow completion status, meaning that it shows whether the end-user was able to complete all the steps in the verification flow or not. It is not the verification session status.

veriff.delegate = self

The Veriff SDK returns a number of result codes that your application can handle.

// Swift
extension VerificationService: VeriffSdkDelegate {
    func sessionDidEndWithResult(_ result: Veriff.Result) {
        switch result.status {
        case .done:
            // The end-user successfully submitted the session
            break
        case .canceled:
            // The end-user canceled the verification process.
            break
        case .error(let error):
            switch error {
                // ...
            }
        }
    }
}

// Objective-C
- (void)sessionDidEndWithResult:(VeriffResult *)result {
    switch (result.status) {
    case VeriffStatusDone:
        // The end-user successfully submitted the session
        break;
    case VeriffStatusCanceled:
        // The end-user canceled the verification process.
        break;
    case VeriffStatusError:
        if (result.error == nil) { break; }
        switch (result.error.code) {
            // ...
        }
    }
}

You can find the description of status codes below:

Notes

Migrating to Veriff iOS 3.0.0

Switch from baseUrl and sessionToken to sessionUrl

The Veriff object in the SDK 3.0.0 takes a required sessionUrl and an optional VeriffConfiguration instance as parameters into initialisation. The sessionUrl is received from your backend implementation (see the documentation here), it is composed of the baseUrl and sessionToken sent to the VeriffConfiguration object in earlier versions.

Updated VeriffConfiguration object

The VeriffConfiguration struct now takes in branding and languageLocale as initialisation parameters.

The new VeriffDelegate method

You can now receive session results via func sessionDidEndWithResult(_ result: Veriff.Result) instead of the obsolete func onSession(result: VeriffResult, sessionToken: String). The sessionToken is included in the Veriff.Result as an instance variable.

Use Veriff.Result instead of VeriffResult

The new Veriff.Result struct comprises status: Status and sessionToken: String? instance variables. The Status enum can be of three types: done, canceled, error. The description variable on the Veriff.Result returns additional information as a string.

Migrating to Veriff iOS 4.0.0

Rename Veriff instances to VeriffSdk

The name Veriff was used both for our module and public class name. However this blocked us from supporting Swift Package Manager due to Swift compiler bug [↗]. We renamed our public class name to VeriffSdk.

VeriffConfiguration is now VeriffSdk.Configuration

VeriffConfiguration struct is moved under VeriffSdk. Please replace the occurrences of VeriffConfiguration with VeriffSdk.Configuration.

Branding is now VeriffSdk.Branding

Branding struct is moved under VeriffSdk. Please replace the occurrences of Branding with VeriffSdk.Branding.

Rename VeriffDelegate to VeriffSdkDelegate

Please replace the occurrences of VeriffDelegate with VeriffSdkDelegate.

VeriffSdk.Result.description made non-optional

If you were dealing with unwrapping it, feel free to remove it.

VeriffSdk.Result.sessionToken removed and VeriffSdk.Result.sessionUrl added instead

Please remove the occurrences of sessionToken. You can now use sessionUrl to get the full sessionUrl including token.

Migrating to Veriff iOS 5.0.0

Increased min iOS supported version

Now min version is iOS 11.0.

Updated VeriffSdk.Branding object

Following configurations are removed:

Fonts API changes:

logomark customization is added.

Migrating to Veriff iOS 6.0.0

Updated VeriffSdk.Branding object

Following configurations are added:

Following configurations are removed:

Following configurations are deprecated:

Following configurations are renamed:

Migrating to Veriff iOS 7.0.0

Set deployment target to iOS 13

iOS SDK Changelog

Please refer to release notes [↗].

Flutter Plugin

Requirements

Integration with Veriff Flutter Plugin requires the project to target at least iOS version 13.0 and Android version 8.0 (API 26) or higher.

Install the plugin to your project

Follow instructions here [↗] to install the plugin.

Declare foreground service sync for Google Play

The SDK declares and uses the FOREGROUND_SERVICE_DATA_SYNC. If you distribute your application on Google Play, then you must declare the foreground service information in Play Console [↗].

The information required by Play Console is (as listed on the Google Play link above):

  1. Provide a description of the app functionality that is using each foreground service type.
    • The Veriff SDK uses the foreground service to upload end-user data to Veriff's servers for verification purposes.
  2. Describe the user impact if the task is deferred by the system (does not start immediately), and/or the task is interrupted by the system (paused and/or restarted).
    • If the task is deferred or interrupted by the system, the end-user verification will be delayed.
  3. Include a link to a video demonstrating each foreground service feature. The video should demonstrate the steps the user needs to take in your app in order to trigger the feature.
    • Please record a video of your app's Veriff SDK integration.
  4. Choose your specific use case for each foreground service type.
    • "Network transfer: Upload or download / Other"

See also Veriff's note on data collection purposes in your app [↗]

iOS specific configuration

Add usage descriptions to application Info.plist

Not adding these usage descriptions causes system to kill application when it requests the permissions when needed.

Veriff requires camera, microphone, photo library and optionally NFC reader permissions for capturing photos, video and scanning passport during identification. Your application is responsible to describe the reason why camera, microphone, photo library and NFC reader is used. You must add 3 descriptions listed below to Info.plist of your application with the explanation of the usage.

Add required steps for NFC scanning

  1. Add NFCReaderUsageDescription description to Info.plist.
  2. The application needs to define the list of application IDs or AIDs it can connect to, in the Info.plist file. The AID is a way of uniquely identifying an application on a ISO 7816 tag, which is usually defined by a standard.

    <key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
    <array>
      <string>A0000002471001</string>
      <string>A0000002472001</string>
      <string>00000000000000</string>
    </array>
    
  3. Introduce a new entitlement for NFC scanning, a feature made available from iOS 13 onwards. Xcode automatically adds this entitlement when you activate the Near Field Communication Tag Reading feature in the target Signing & Capabilities. Following the activation of this feature, the *.entitlements file should include the TAG format.

    <key>com.apple.developer.nfc.readersession.formats</key>
    <array>
        <string>TAG</string>
    </array>
    

Set the iOS target in Xcode

Make sure that the 'iOS Deployment Target' in Xcode (under Project > target > Info > Deployment Target) is set to iOS 13.0 or later.

Launching the verification flow

Import plugin in your code

In order to use Veriff plugin, please import it to your class that will use it. import 'package:veriff_flutter/veriff_flutter.dart'

Start verification flow

In order to start the verification flow please create a configuration with defined parameters below.

Parameters are defined as below;

Parameters Description
sessionUrl Required parameter. sessionUrl can be received from your backend implementation. sessionUrl should be unique for each call. Check /sessions endpoint in the API documentation here to learn how to generate one.
Configuration config = Configuration(sessionUrl);

Then pass the configuration to Veriff object and start the verification flow;

Veriff veriff = Veriff();

try {
      Result result = await veriff.start(config);
      print(result.status);
      print(result.error);
    } on PlatformException {
      // handle exception
    }

Customize user interface (Optional)

You can customize Veriff SDK user interface in your application by defining your brand's colors, font and logo.

See the Veriff SDK customization guide [↗] document to see what it looks like.

Veriff Flutter plugin allows the customization of your brand's colors, font and logo in the SDK flow by passing the optional parameters when launching Veriff:

String regularFontPath = "fonts/Regular.otf";
String mediumFontPath = "fonts/Medium.otf";
String boldFontPath = "fonts/Bold.otf";
Fonts fonts = Fonts(
    regularFontPath: regularFontPath, 
    mediumFontPath: mediumFontPath, 
    boldFontPath: boldFontPath
);
Branding branding = Branding(
    logo: AssetImage(path_of_image),
    background: "#f2ff00",
    onBackground: "#ff00ff",
    onBackgroundSecondary: "#52b35c",
    onBackgroundTertiary: "#3a593d",
    primary: "#123abc",
    onPrimary: "#ff00ff",
    secondary: "#f2ff00",
    onSecondary: "#ff7700",
    cameraOverlay: "#59496a",
    onCameraOverlay: "#e27e23",
    outline: "#ff00ff",
    error: "#ff0000",
    success: "#00ff00",
    buttonRadius: 5,
    fonts: fonts
);

And pass the branding object with configuration for starting the verification flow:

Configuration config = Configuration(sessionUrl, branding: branding);

When a color isn't defined, the default Veriff theme color is used.

Setting the user interface language

Veriff Flutter plugin supports setting the language of the UI. In order to use this feature, please pass the locale identifier as in example below;

Configuration config = Configuration(sessionUrl, branding: branding, languageLocale: "et");

Custom intro screen

Veriff supports replacing introduction screen with a custom client developed introduction screen for eligible customers. First, please ask about this possibility from your solutions engineer. In case we can offer it for you then removal process is following:

config.useCustomIntroScreen = true;

Vendor data

Veriff supports the option to override vendor data. Please check with your Solutions Engineer to confirm if this feature can be enabled for your integration. If it is possible, follow these steps:

  1. Veriff will enable vendor data overriding from the backend for your integrations.
  2. Modify the configuration option as specified below.
config.vendorData = "Vendor Data";

Handling the results from plugin

The Result returned by start method will have a status that is one of Status.done, Status.canceled and Status.error.

Note that this is the end-user flow completion status, meaning that it shows whether the end-user was able to complete all the steps in the verification flow or not. It is not the verification session status.

In case Status.error is received, you will also have an error description that is one of the list below:

You can check the statuses and errors using switch-case as in example below;

switch (result.status) {
        case Status.done:
          print("Session is completed.");
          break;
        case Status.canceled:
          print("Session is canceled by the end-user.");
          break;
        case Status.error:
          switch (result.error) {
            case Error.cameraUnavailable:
              print("User did not give permission for the camera");
              break;
            case Error.microphoneUnavailable:
              print("User did not give permission for the microphone.");
              break;
            case Error.networkError:
              print("Network error occurred.");
              break;
            case Error.sessionError:
              print("A local error happened before submitting the session.");
              break;
            case Error.deprecatedSDKVersion:
              print(
                  "Version of Veriff SDK used in plugin has been deprecated. Please update to the latest version.");
              break;
            case Error.unknown:
              print("Uknown error occurred.");
              break;
            case Error.nfcError:
              print("Error with NFC");
              break;
            case Error.setupError:
              print("Error with setup");
              break;
            case Error.none:
              print("No error.");
              break;
            default:
              break;
          }
          break;
        default:
          break;
}

React Native SDK

React Native SDK requirements

Integration with Veriff React Native SDK requires the project to target at least iOS version 13.4 and Android version 8.0 (API 26) or higher.

Note: If you have created your react native app using expo, you will have to eject out of expo at this point(if you have not ejected out already) since expo does not support native modules Check the Caveats section here [↗] for more info on that.

Add the SDK to a project

Add the Veriff React Native SDK to your package.json file:

npx yarn add @veriff/react-native-sdk

Or if using npm:

npm install @veriff/react-native-sdk --save

Update Android build.gradle file

Open the root build.gradle file in the android folder and add a new maven destination to the repositories in the allprojects section. The best place is right after the local node_modules repositories and before the google() repository.

allprojects {
    repositories {
        // ... local react native repos
        maven { url "https://cdn.veriff.me/android/" } //veriff
        google()
        jcenter()
    }
}

Declare foreground service sync for Google Play

The SDK declares and uses the FOREGROUND_SERVICE_DATA_SYNC. If you distribute your application on Google Play, then you must declare the foreground service information in Play Console [↗].

The information required by Play Console is (as listed on the Google Play link above):

  1. Provide a description of the app functionality that is using each foreground service type.
    • The Veriff SDK uses the foreground service to upload end-user data to Veriff's servers for verification purposes.
  2. Describe the user impact if the task is deferred by the system (does not start immediately), and/or the task is interrupted by the system (paused and/or restarted).
    • If the task is deferred or interrupted by the system, the end-user verification will be delayed.
  3. Include a link to a video demonstrating each foreground service feature. The video should demonstrate the steps the user needs to take in your app in order to trigger the feature.
    • Please record a video of your app's Veriff SDK integration.
  4. Choose your specific use case for each foreground service type.
    • "Network transfer: Upload or download / Other"

See also Veriff's note on data collection purposes in your app [↗]

iOS Specific setup

Add Swift to the ios module

Veriff SDK requires your ios module to have some Swift code. If you don't have any Swift code yet then add a new empty.swift file in Xcode. If Xcode offers to add a bridging header then add it.

Update iOS Podfile

Open Podfile in the ios folder and make sure that platform is 13.4 or higher:

platform :ios, '13.4'

Also make sure your main target in the Podfile contains use_native_modules! directive:

target 'MyApp' do
  # pod 'foo'...

  config = use_native_modules!
end

Add usage descriptions to application Info.plist

Not adding these usage descriptions causes system to kill application when it requests the permissions when needed.

Veriff requires camera, microphone, photo library and optionally NFC reader permissions for capturing photos, video and scanning passport during identification. Your application is responsible to describe the reason why camera, microphone, photo library and NFC reader is used. You must add 3 descriptions listed below to Info.plist of your application with the explanation of the usage.

Add required steps for NFC scanning

  1. Add NFCReaderUsageDescription description to Info.plist.
  2. The application needs to define the list of application IDs or AIDs it can connect to, in the Info.plist file. The AID is a way of uniquely identifying an application on a ISO 7816 tag, which is usually defined by a standard.

    <key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
    <array>
      <string>A0000002471001</string>
      <string>A0000002472001</string>
      <string>00000000000000</string>
    </array>
    
  3. Introduce a new entitlement for NFC scanning, a feature made available from iOS 13 onwards. Xcode automatically adds this entitlement when you activate the Near Field Communication Tag Reading feature in the target Signing & Capabilities. Following the activation of this feature, the *.entitlements file should include the TAG format.

    <key>com.apple.developer.nfc.readersession.formats</key>
    <array>
        <string>TAG</string>
    </array>
    

Set the iOS target in Xcode

Make sure that the 'iOS Deployment Target' in Xcode (under Project > target > Info > Deployment Target) is set to iOS 13.4 or later.

Using the Veriff React Native SDK

Starting the verification flow

In order to use Veriff SDK, please import it to the file that will use the SDK.

import VeriffSdk from '@veriff/react-native-sdk';

Parameters are defined as below;

Parameters Description
sessionUrl Required parameter. sessionUrl can be received from your backend implementation. sessionUrl should be unique for each call. Check /sessions endpoint in the API documentation here to learn how to generate one.

Once you have the sessionUrl you can launch Veriff using VeriffSdk imported earlier:

var result = await VeriffSdk.launchVeriff({ sessionUrl: SESSION_URL });

User Interface customization

You can customize Veriff SDK user interface in your application by defining your brand's colors, font and logo.

See Veriff SDK customization guide [↗] document on how it looks.

Veriff React Native SDK allows the customization of your brand's colors, font and logo in the SDK flow by passing in these optional properties when launching Veriff:

var result = await VeriffSdk.launchVeriff({
    sessionUrl: SESSION_URL,
    branding: {
      logo: 'parrot', // see alternative options for logo below
      background: '#ff00ff',
      onBackground: '#ffffff',
      onBackgroundSecondary: '#ff00ff',
      onBackgroundTertiary: '#000000',
      primary: '#333333',
      onPrimary: '#444444',
      secondary: '#333333',
      onSecondary: '#444444',
      outline: '#444444',
      cameraOverlay: '#59496a',
      onCameraOverlay: '#e27e23',
      error: '#333333',
      success: '#444444',
      buttonRadius: 28,
      iOSFont: {
        regular: 'Font-Regular',
        medium: 'Font-Medium',
        bold: 'Font-Bold',
      },
      androidFont: {
        regular: 'font_regular',
        medium: 'font-medium',
        bold: 'font_bold',
      }
    },
  });

When a color or a font isn't defined the default Veriff color or font is used. Same applies to the logo - when it isn't defined the default is used. The image assets need to be added into Xcode assets in the iOS project and into drawable folders in the Android project. In the example above you would need to add an image asset named 'parrot' into Xcode assets and 'parrot.png' to Android drawable folders in android/src/main/res.

Instead of using platform-specific image assets you can provide a URI to an image which will then be used:

var result = await VeriffSdk.launchVeriff({
    sessionUrl: SESSION_URL,
    branding: {
      logo: { uri: 'http://example.com/logo/parrot.jpg' },
    },
  });

React Native assets are also supported through resolveAssetSource:

const resolveAssetSource = require('react-native/Libraries/Image/resolveAssetSource');
const parrot = require('./img/parrot.png');

var result = await VeriffSdk.launchVeriff({
    sessionUrl: SESSION_URL,
    branding: {
      logo: resolveAssetSource(parrot),
    },
  });

Setting the user interface language

The Veriff RN SDK allows setting the language of the SDK. In order to use this language, please pass the locale as in example below;

var result = await VeriffSdk.launchVeriff({
    sessionUrl: SESSION_URL,
    locale: 'et'
  });

Custom intro screen

Veriff supports replacing introduction screen with a custom client developed introduction screen for eligible customers. Please request this from your solutions engineer. The removal process is following:

var result = await VeriffSdk.launchVeriff({
    sessionUrl: SESSION_URL,
    locale: 'et',
    customIntroScreen: true
  });

Vendor data

Veriff supports the option to override vendor data. Please check with your Solutions Engineer to confirm if this feature can be enabled for your integration. If it is possible, follow these steps:

  1. Veriff will enable vendor data overriding from the backend for your integrations.
  2. Modify the configuration option as specified below.
var result = await VeriffSdk.launchVeriff({
    sessionUrl: SESSION_URL,
    locale: 'et',
    vendorData: "Vendor Data"
  });

Handling the result from the SDK

The result returned by launchVeriff will have a status field that is one of either VeriffSdk.statusDone, VeriffSdk.statusCanceled or VeriffSdk.statusError.

Note that this is the end-user flow completion status, meaning that it shows whether the end-user was able to complete all the steps in the verification flow or not. It is not the verification session status.

In case of statusError there will be a error code (not human-readable) in the error field.

var result = await VeriffSdk.launchVeriff({ sessionUrl: SESSION_URL });
switch (result.status) {
  case VeriffSdk.statusDone:
    // end-user submitted the images and completed the flow
    // note that this does not mean a final decision yet
    break;
  case VeriffSdk.statusCanceled:
    // end-user canceled the flow before completing
    break;
  case VeriffSdk.statusError:
    // the flow could not be completed due to an error
    console.log("Veriff verification failed with error=" + result.error);
    break;
}

Migrating to React Native SDK 3.0.0

Follow these steps to migrate to React Native SDK 3.0.0 API

Updated Branding API

Following configurations are added:

Following configurations are removed:

Following configurations are renamed:

buttonCornerRadius -> buttonRadius

Migrating to React Native SDK 2.0.0

Follow these steps to migrate to React Native SDK 2.0.0 API

Use new parameter sessionUrl

New API uses sessionUrl instead of a sessionToken. sessionUrl is a combination of base URL and session token.

We renamed the navigationBarImage parameter in configuration to logo.

React Native SDK Changelog

Below is a summary of changes introduced with each version of the React Native SDK. Expand the list by clicking on "Versions" and then on each release version to see the summary.

Cordova Plugin

Cordova requirements

Integration with Cordova plugin requires the project to target at least iOS version 11.0 and Android version 5.0 (API level 21) or higher.

Add the plugin to a project

Add the Veriff Cordova plugin to your project:

cordova plugin add @veriff/cordova-plugin-veriff

Adding this plugin will make the window.cordova.plugins.Veriff global object available once the deviceready event propagates.

Declare foreground service sync for Google Play

The SDK declares and uses the FOREGROUND_SERVICE_DATA_SYNC. If you distribute your application on Google Play, then you must declare the foreground service information in Play Console [↗].

The information required by Play Console is (as listed on the Google Play link above):

  1. Provide a description of the app functionality that is using each foreground service type.
    • The Veriff SDK uses the foreground service to upload end-user data to Veriff's servers for verification purposes.
  2. Describe the user impact if the task is deferred by the system (does not start immediately), and/or the task is interrupted by the system (paused and/or restarted).
    • If the task is deferred or interrupted by the system, the end-user verification will be delayed.
  3. Include a link to a video demonstrating each foreground service feature. The video should demonstrate the steps the user needs to take in your app in order to trigger the feature.
    • Please record a video of your app's Veriff SDK integration.
  4. Choose your specific use case for each foreground service type.
    • "Network transfer: Upload or download / Other"

See also Veriff's note on data collection purposes in your app [↗]

iOS Specific setup

Add usage descriptions to application Info.plist

Not adding these usage descriptions causes system to kill application when it requests the permissions when needed.

Veriff requires camera, microphone, photo library and optionally NFC reader permissions for capturing photos, video and scanning passport during identification. Your application is responsible to describe the reason why camera, microphone, photo library and NFC reader is used. You must add 3 descriptions listed below to ios platform in config.xml of your application with the explanation of the usage.

        <config-file target="*-Info.plist" parent="NSCameraUsageDescription">
            <string>Access to camera is needed for user identification purposes</string>
        </config-file>

        <config-file target="*-Info.plist" parent="NSMicrophoneUsageDescription">
            <string>Access to microphone is needed for video identification</string>
        </config-file>

        <config-file target="*-Info.plist" parent="NSPhotoLibraryUsageDescription">
            <string>Access to photo library is needed uploading proof of address documents</string>
        </config-file>

Add required steps for NFC scanning

  1. Add NFCReaderUsageDescription description to ios platform inside config.xml.
        <config-file target="*-Info.plist" parent="NFCReaderUsageDescription">
            <string>Access to NFC is needed for user identification purposes</string>
        </config-file>
  1. The application needs to define the list of application IDs or AIDs it can connect to, in the Info.plist file. The AID is a way of uniquely identifying an application on a ISO 7816 tag, which is usually defined by a standard.

    <config-file target="*-Info.plist" parent="com.apple.developer.nfc.readersession.iso7816.select-identifiers">
        <array>
            <string>A0000002471001</string>
            <string>A0000002472001</string>
            <string>00000000000000</string>
        </array>
    </config-file>
    
  2. Introduce a new entitlement for NFC scanning, a feature made available from iOS 13 onwards. Xcode automatically adds this entitlement when you activate the Near Field Communication Tag Reading feature in the target Signing & Capabilities. Following the activation of this feature, the *.entitlements file should include the TAG format. If your application is intended to support iOS versions prior to iOS 13, the NDEF format is mandatory. However, for applications targeting iOS 13 and later, there is no need to add the NDEF format to the entitlements.

    <config-file target="**/Entitlements.plist" parent="com.apple.developer.nfc.readersession.formats">
        <array>
            <string>TAG</string>
            <string>NDEF</string>
        </array>
    </config-file>
    

Set the iOS target in Xcode

Make sure that the 'iOS Deployment Target' in Xcode (under Project > target > Info > Deployment Target) is set to iOS 12.4 or later.

Using the Veriff Cordova plugin

Starting the verification flow

The Veriff Plugin has a single function to start a verification attempt: start(callback, sessionUrl, configuration)

User Interface customization

You can customize Veriff SDK user interface in your application by defining your brand's colors, font and logo.

See Veriff SDK customization guide [↗] document on how it looks.

Veriff Cordova plugin allows the customization of your brand's colors, font and logo in the SDK flow by passing in these optional properties when launching Veriff:


window.cordova.plugins.Veriff.start(
    function (result) {
        console.log("Veriff SDK result: status: " + result.status + ", error: " + result.error);
    },
    sessionUrl,
    {
        branding: {
            logo: 'parrot',
            background: '#ff00ff',
            onBackground: '#ffffff',
            onBackgroundSecondary: '#ff00ff',
            onBackgroundTertiary: '#000000',
            primary: '#333333',
            onPrimary: '#444444',
            secondary: '#333333',
            onSecondary: '#444444',
            outline: '#444444',
            cameraOverlay: '#59496a',
            onCameraOverlay: '#e27e23',
            error: '#333333',
            success: '#444444',
            buttonRadius: 28,
            iOSFont: {
                regular: 'Font-Regular',
                medium: 'Font-Medium',
                bold: 'Font-Bold',
            },
            androidFont: {
                regular: 'font_regular.ttf',
                medium: 'font-medium.ttf',
                bold: 'font_bold.ttf',
            }
        }
    },
);

When a color or a font isn't defined the default Veriff color or font is used. Same applies to the logo - when it isn't defined the default is used. The image assets need to be added into Xcode assets in the iOS project and into drawable folders in the Android project. In the example above you would need to add an image asset named 'parrot' into Xcode assets and 'parrot.png' to Android drawable folders in android/src/main/res.

Setting the user interface language

The Veriff Cordova plugin allows setting the language of the SDK. In order to use this language, please pass the locale as in example below;

window.cordova.plugins.Veriff.start(
    function (result) {
        console.log("Veriff SDK result: status: " + result.status + ", error: " + result.error);
    },
    sessionUrl,
    {
        locale: 'et'
    }
);

Custom intro screen

Veriff supports replacing introduction screen with a custom client developed introduction screen for eligible customers. Please request this from your solutions engineer. The removal process is following:

window.cordova.plugins.Veriff.start(
    function (result) {
        console.log("Veriff SDK result: status: " + result.status + ", error: " + result.error);
    },
    sessionUrl,
    {
        customIntroScreen: true
    }
);

Vendor data

Veriff supports the option to override vendor data. Please check with your Solutions Engineer to confirm if this feature can be enabled for your integration. If it is possible, follow these steps:

  1. Veriff will enable vendor data overriding from the backend for your integrations.
  2. Modify the configuration option as specified below.
window.cordova.plugins.Veriff.start(
    function (result) {
        console.log("Veriff SDK result: status: " + result.status + ", error: " + result.error);
    },
    sessionUrl,
    {
        vendorData: 'Vendor Data',
    }
);

Handling the result from the SDK

The result returned by Veriff.start will have a status field that is one of either Veriff.STATUS_DONE, Veriff.STATUS_CANCELED or Veriff.STATUS_ERROR.

Note that this is the end-user flow completion status, meaning that it shows whether the end-user was able to complete all the steps in the verification flow or not. It is not the verification session status.

In case of Veriff.STATUS_ERROR there will be a error code (not human-readable) in the error field.

window.cordova.plugins.Veriff.start(
    function (result) {
        console.log("Veriff SDK result: status: " + result.status + ", error: " + result.error);
        switch (result.status) {
            case STATUS_DONE:
                // end-user submitted the images and completed the flow
                // note that this does not mean a final decision yet
                break;
            case STATUS_CANCELED:
                // end-user canceled the flow before completing
                break;
            case STATUS_ERROR:
                // the flow could not be completed due to an error
                console.log("Veriff verification failed with error=" + result.error);
                switch (result.error) {
                    case UNABLE_TO_ACCESS_CAMERA:
                        // unable to access camera, likely due to no permission
                        break;
                    case UNABLE_TO_ACCESS_MICROPHONE:
                        // unable to access camera, likely due to no permission
                        break;
                    case NETWORK_ERROR:
                        break;
                    case SESSION_ERROR:
                        break;
                    case UNKNOWN_ERROR:
                        break;
                    case UNSUPPORTED_SDK_VERSION:
                        break;
                }
                break;
        }
    },
    sessionUrl
);

Javascript SDK

Veriff JS SDK is a simple and customizable library, making it a convenient way to include Veriff's web flow to your solution.

The purpose of the JS SDK is to create the session URL for your end-user's verification session.

Once you have the URL, you have two options to direct the user to the verification flow:

Install JS SDK

Include as a script tag:

<script src='https://cdn.veriff.me/sdk/js/1.5/veriff.min.js'></script>

or install it via a package manager

  $ npm install --save @veriff/js-sdk
   // CommonJS
  const Veriff = require('@veriff/js-sdk');

  // ES6 style import
  import { Veriff } from '@veriff/js-sdk';

Adding JS SDK

Veriff JS SDK requires one parent element in HTML:

<div id='veriff-root'></div>

It is possible to set the width of js-sdk form through style attribute:

<div id='veriff-root' style="width:400px"></div>

In order to initialize the library, API Key, parentId and onSession callback function is required. Parameters are defined as below:

Parameters Description
apiKey Required parameter. See how to find your API keys here to learn how to generate one.
parentId Required parameter. 'veriff-root'
onSession Required parameter. The end-user can be redirected either to the verification url or incontext SDK can be triggered
  const veriff = Veriff({
    apiKey: 'API_KEY',
    parentId: 'veriff-root',
    onSession: function(err, response) {
      // received the response, verification can be started / triggered now

      // redirect
      window.location.href = response.verification.url;

      // incontext sdk
      createVeriffFrame({url: response.verification.url});
    }
  });

  veriff.mount();

Read more about incontext sdk method or redirection.

By default, the following form will be rendered:

JSSDKDEFAULT

onSession function is executed after the response is received from the API, response body contains a verification object with following schema:

    {
      "status": "success",
      "verification": {
          "id": "UUID V4 Identifying the verification",
          "url": "full url to which a person should be redirected in order to proceed with verification flow",
          "host": "hostname",
          "status": "status of the verification",
          "sessionToken": "JWT encoded verification token"
      }
  }

vendorData: string - customer-specific data string, max 1000 characters long, will be sent back unmodified using webhooks. We require only non-semantic data to be submitted (UUID-s etc., that can not be resolved or used outside the customer's domain). In case the Given name / Last name / Vendor Data or all of them are known, they can be passed to the SDK, therefore text input fields will not be rendered.

  const veriff = Veriff({
    apiKey: 'API_KEY',
    parentId: 'veriff-root',
    onSession: function(err, response) {
      // received the response, verification can be started now
    }
  });
  veriff.setParams({
    person: {
      givenName: 'Foo',
      lastName: 'Bar'
    },
    vendorData: '7eb19312-79d6-11ec-90d6-0242ac120003'
  });
  veriff.mount({
    submitBtnText: 'Get verified'
  });

JSSDKONLYBUTTON

It is possible to disable fields rendering without passing any data by not including anything in corresponding value:

  const veriff = Veriff({
    apiKey: 'API_KEY',
    parentId: 'veriff-root',
    onSession: function(err, response) {
      // received the response, verification can be started now
    }
  });
  veriff.setParams({
    person: {
      givenName: ' ',
      lastName: ' '
    },
    vendorData: ' '
  });
  veriff.mount({
    submitBtnText: 'Get verified'
  });

Additionally the input placeholder and button text value can be customised.

  const veriff = Veriff({
    apiKey: 'API_KEY',
    parentId: 'veriff-root',
    onSession: function(err, response) {
      // received the response, verification can be started now
    }
  });
  veriff.mount({
    formLabel: {
      givenName: 'First name',
      lastName: 'Family name',
      vendorData: 'Unique id of an end-user'
    },
    submitBtnText: 'Get verified',
    loadingText: 'Please wait...'
  });

JSSDKCUSTOM

Adding viewport meta tag

The viewport meta tag is crucial for proper rendering and layout on mobile devices. If this meta tag is missing, the website may be rendered too small on mobile devices.

Make sure to add the following tag to mitigate such issues:

<meta name="viewport" content="width=device-width, initial-scale=1.0">

InContext Javascript SDK

Use this if you would like to use incontext UI.

Install InContext JS SDK

npm install @veriff/incontext-sdk

Adding InContext JS SDK

You need to have a Veriff session URL generated before initializing the SDK. Please see our documentation to learn how to generate one, or use our JavaScript SDK to create it.

// ES6
import { createVeriffFrame } from '@veriff/incontext-sdk';

// CommonJS
const { createVeriffFrame } = require('@veriff/incontext-sdk');

const veriffFrame = createVeriffFrame({ url: VERIFF_SESSION_URL })

This will render a modal with adapted Veriff application in iframe.

createVeriffFrame() returns an object that controls the modal.

Listening for events

Pass onEvent callback function when initializing SDK

import { createVeriffFrame, MESSAGES } from '@veriff/incontext-sdk';

createVeriffFrame({
  url,
  onEvent: function(msg) {
    switch(msg) {
      case MESSAGES.CANCELED:
        //
        break;
    }
  }
})

Note that this sends you the end-user flow completion status, meaning that it shows whether the end-user was able to complete all the steps in the verification flow or not. It does not send the verification session status.

Using with inline script

Include a script tag:

<script src='https://cdn.veriff.me/incontext/js/v1/veriff.js'></script>
window.veriffSDK.createVeriffFrame({ url: VERIFF_SESSION_URL });

Options

createVeriffFrame([options])

Close Veriff modal

Normally modal will be closed due to end-user input, but if you want to control it(e.g. timeout), please use this function.

veriffFrame.close();

onReload

This callback can be called on some browsers when the end-user has denied camera access and to re-request access the host page has to be reloaded.

For best UX we recommend reloading the webpage & reopening Veriff InContext SDK automatically.

Example:

const url = sessionStorage.getItem('@veriff-session-url') || getSessionUrl()

veriffSDK.createVeriffFrame({
  url,
  onReload: () => {
    // Logic to re-open Veriff SDK after page reload
    // e.g. sessionStorage.setItem('@veriff-session-url', url);
    window.location.reload();
  },
});

Adding Content Security Policy to InContext SDK

In order to improve the security, add the following CSP directives headers to index.html file, under the <meta> tag:

Content-Security-Policy default-src 'self' *.veriff.me *.veriff.com;
script-src 'self' *.veriff.me *.veriff.com *.hotjar.com *.probity.io;
img-src blob: 'self' *.probity.io;
frame-src 'self' *.hotjar.com;
connect-src 'self' *.veriff.com *.veriff.me *.probity.io;
style-src 'self' *.veriff.com *.veriff.me;

For example:

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-security-policy"
 content="default-src 'self' *.veriff.me *.veriff.com;
script-src 'self' *.veriff.me *.veriff.com *.hotjar.com *.probity.io *sentry.io;
img-src blob: 'self' *.probity.io;
frame-src 'self' *.hotjar.com;
connect-src 'self' *.veriff.com *.veriff.me *.probity.io;
style-src 'self' *.veriff.com *.veriff.me;">
</head>

Allow camera requests in your Permissions Policy

To avoid any issues, make sure that you allow Veriff to request camera access. If your Permissions Policy denies camera requests by default, you may encounter issues when using the InContext SDK. For more information, please read the W3C Permissions Policy Explainer [↗].

The html document where the InContext Iframe is embedded is explicitly blocking the use of camera and microphone if the following header is present:

Permissions-Policy Header: camera=(), microphone=()

According to MDN Web Docs - Permissions Policy > Allowlists[↗]:

Integrate by Redirection

In case you would like to opt out of modal based approach by using our incontext sdk you can instead redirect end-users to the verification flow.

Using redirection

You need to have a Veriff session URL generated before redirecting the end-user to the flow. See our documentation to learn how to generate one, or use our JavaScript SDK to create it.

// After receiving the url you could redirect end-users there by using following
window.location.href = url;

Query parameters

Available parameters that can be changed;

Parameters Description
lang Optional parameter. lang can be used to override the end-user interface's language.

SDK Support Policy

Support Policy for Veriff SDKs

Identity verification software, practices, and regulations move fast. To keep our software user-friendly, and maintain high conversion rates for our customers, our development team needs to be faster. To deliver an increasingly smarter, better and safer product, it's important to drop backward compatibility layers and update SDKs at least once every three months. Our SDKs are updated every two weeks, and downloading new releases will keep your verification process smooth and error-free. All releases are fully tested by our team and before being deployed, and come with the support from our team in the form of:

SDK release versioning To help you keep track of SDK releases, Veriff uses three numbers to represent the scale of the updates. Each release is assigned either X, Y, or Z according to the following descriptions:

Supported languages

Supported languages are as below;

Language Code Name
ar العربية
bg Български
bn বাংলা
ca Català
cs Čeština
da Dansk
de Deutsch
el Ελληνικά
et Eesti
en English
es Español (España)
es-latam Español (Latinoamérica)
es-mx Español (México)
fi Suomi
fil Filipino
fr Français
hi हिंदी
hr Hrvatski
hu Magyar
id Bahasa Indonesia
it Italiano
ja 日本語
ka ქართული
ko 한국어
lv Latviešu
lt Lietuvių
mk Македонски
ms Bahasa Melayu
nb Norsk (Bokmål)
nl Nederlands
pl Polski
pt Português (Brasil)
pt-pt Português (Portugal)
ro Română
ru Русский
si සිංහල
sk Slovenčina
sl Slovenski
so Af-soomaali
sr Srpski
sv Svenska
tr Türkçe
th ไทย
uk Українська
vi Tiếng Việt
zh 简体中文
zh-hant 繁體中文
hy հայերեն

Sessions lifecycle diagram (SDK)

SDK sessions lifecycle diagram

API Guide

Why use the API?

There are a few scenarios where you may not wish to use Veriff's native or web SDKs to verify your end-users. For example:

In those cases, you can do the whole process using our API and you will not show any Veriff front-end to your end-users.

Customer's API flow in a nutshell

Create a verification session

The goal here is to create a new object (a verification session) that contains one verification, nested inside the session object in the response. Also, you will receive the session ID, which you need for the next step. (Guide: Using the API to generate a session for API)

Send end-user's media

Using the session ID, pass the end-user's media (face, document front, document back, etc.) by uploading all images (and video if applicable) one by one using the POST request to sessions/{sessionId}/media endpoint. The goal here is to upload the required photos and associate them with the verification created in step 1.

Take advantage of the additional collected data

In order to further improve the IDV process, we strongly recommend you collect some additional end-user data and send it to us via POST /sessions/{sessionId}/collected-data. This step is not mandatory, but it is highly recommended.

Submit session for review

Once all the media and additional data has been uploaded, you then submit the verification session by sending the PATCH request to PATCH /sessions/{sessionId} and marking the verification to submitted status. Make sure that all the media has been submitted prior to triggering the PATCH request.

Wait for Veriff to verify the end-user

After these three steps, you have done your part, and the verification will then be taken care of by us.

Wait for webhook response

Veriff sends different types of webhooks for different event types using the POST method. For IDV, we send:

Prerequisites to use the API

In order to start sending media over the API, make sure that you:

Prerequisites to create API requests

API keys

Log in to Veriff's environment via the link in your sign-up email. Navigate to Integrations page via the top menu and open the Integration you need. From there you need to take:

Shared secret key rotation

It is possible to manage your shared secret keys in the Veriff environment. You can add and delete keys, and set the master signature key.

You can have up to 5 shared secret keys.

To manage the keys:

  1. Log in to the Veriff environment
  2. Click on the Integrations on the top menu
  3. Find and open the relevant integration
  4. All the keys are displayed on the main page, under the shared secret keys field
  5. You can add a key using the + Add key button
  6. Use the kebab menu button next to the key to promote it to the master signature key, or to delete it

API URL and Headers

To create the API URL, add v1 to the Base URL value:

https://<Base-URL>/v1/

The list below shows basic Headers. These are often needed to send requests, or are returned in responses:

X-AUTH-CLIENT: string (required) - API key
CONTENT-TYPE: string (required) - Media type of the resource (application/json)
X-HMAC-SIGNATURE: string (required) - HMAC-SHA256 hex encoded keyed hash using your shared secret key

Backwards compatible changes

All the changes listed below are considered to be backwards compatible by Veriff. Make sure to set up your systems in such flexible manner that it is able to handle these changes.

*As a general note on the order of properties in the responses, keep in mind that the order is not static. This means that the order you see in your API call responses may differ from the order you see in Veriff documentation.

**This means data that your system should be able to just transmit or store, not interpret.

API Reference

Endpoints

Available endpoints and methods:

POST /sessions

Creates a session with the data specified in the request body.

The customer sends end-user's data to Veriff, and in return receives a unique sessionId and a unique sessionToken that are related to the verification session initiated for the specific end-user.

The response also returns the session URL value (required in the SDK integrations). You can find this in the verification.url parameter.

You can find the sample implementation for Javascript at https://github.com/Veriff/js-integration-demo

Request

Request method: POST
Media type: application/json
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
Content-Type: application/json

Request properties explained
Sample Request
curl
curl -X POST \
  --url '/v1/sessions/' \
  -H 'Content-Type: application/json' \
  -H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
  -d '{
    "verification": {
        "callback": "https://veriff.com",
        "person": {
            "firstName": "John",
            "lastName": "Smith",
            "idNumber": "123456789"
        },
        "document": {
            "number": "B01234567",
            "type": "PASSPORT",
            "country": "EE"
        },
        "address": {
            "fullAddress": "Lorem Ipsum 30, 13612 Tallinn, Estonia"
        },
        "vendorData": "11111111",
        "endUserId": "fa820aba-019f-455a-ae81-cfca8075bc3f",
        "consents": [
            {
                "type": "ine",
                "approved": true
            }
        ]
    }
}'
Node.js
var request = require('request');

var options = { method: 'POST',
  url: '/v1/sessions/',
  headers:
   { 'Content-Type': 'application/json',
     'X-AUTH-CLIENT': 'API-PUBLIC-KEY' },
  body:
   { verification:
      { callback: 'https://veriff.com',
        person:
         { firstName: 'John',
           lastName: 'Smith',
           idNumber: '123456789' },
        document: { number: 'B01234567', type: 'PASSPORT', country: 'EE' },
        vendorData: '11111111',
        endUserId: 'fa820aba-019f-455a-ae81-cfca8075bc3f',
        consents: [
         {
           type: 'ine',
           approved: true
         }
        ]
      }
   },
  json: true };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
Python3
import requests
import pprint
import json

url = '/v1/sessions/'

payload = json.dumps({
    'verification': {
        'callback': 'https://veriff.com',
        'person': {
          'firstName': 'John',
          'lastName': 'Smith',
          'idNumber': '123456789'
        },
        'document': {
          'number': 'B01234567',
          'type': 'PASSPORT',
          'country': 'EE'
        },
        'vendorData': '11111111',
        'endUserId': 'fa820aba-019f-455a-ae81-cfca8075bc3f',
        'features': [
          'selfid'
        ],
        'consents': [
          {
            'type': 'ine',
            'approved': true
          }
        ]
    }
})

headers = {
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'Content-Type': 'application/json'
}

response = requests.request('POST', url, data=payload, headers=headers)
pprint.pprint(response.json())

Response

Media type: application/json
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Request body signed with the shared secret key
Content-Type: application/json

Response properties explained
Sample response
{ "status": "success",
  "verification":{
    "id":"f04bdb47-d3be-4b28-b028-a652feb060b5",
    "url": "https://alchemy.veriff.com/v/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRoX3Rva2VuIjoiOThiYzdjMjEtZTQ0Yy00MTZiLTkxOTMtMTU5ZGZkMzBmMDg4Iiwic2Vzc2lvbl9pZCI6Ijc2ODhmMzYzLTAyZjctNDE1My1iMzM1LWE0ODQ3OTRkMzZmNyIsImlhdCI6MTUwMTIyODI1MSwiZXhwIjoxNTAxODMzMDUxfQ.bMEF37E6-zT2Aa6Q8UXK3B_ZL51w6D_lxnGgQvhj214",
    "vendorData": "11111111",
    "endUserId": "fa820aba-019f-455a-ae81-cfca8075bc3f",
    "host": "https://alchemy.veriff.com",
    "status": "created",
    "sessionToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRoX3Rva2VuIjoiOThiYzdjMjEtZTQ0Yy00MTZiLTkxOTMtMTU5ZGZkMzBmMDg4Iiwic2Vzc2lvbl9pZCI6Ijc2ODhmMzYzLTAyZjctNDE1My1iMzM1LWE0ODQ3OTRkMzZmNyIsImlhdCI6MTUwMTIyODI1MSwiZXhwIjoxNTAxODMzMDUxfQ.bMEF37E6-zT2Aa6Q8UXK3B_ZL51w6D_lxnGgQvhj214"
  }
}

POST /sessions/{sessionId}/media

Uploads an image (and specifies the type of the image that's being uploaded) for a specific sessionId.

Information about PDF support

Veriff supports PDF file uploads for Identity Verification (IDV) documents and Proof of Address (PoA) documents.

Identity Verification Feature

In IDV, document images can be uploaded in following configurations:

Veriff processes first 5 pages of uploaded PDF file. System removes empty pages from the PDF.

Proof of Address Feature

The file that is uploaded for Proof of Address flow must contain only one PoA document. If you need to send several PoA documents, upload them one-by-one in separate PDF files.

For PoA, documents can be uploaded in following configurations:

Veriff processes first 5 pages of uploaded PDF file. System removes empty pages from the PDF.

Request

Request method: POST
Media type: application/json
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Request body signed with the shared secret key
Content-Type: application/json

Request properties explained
Sample request
curl
curl -X POST \
  --url '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/media' \
  -H 'Content-Type: application/json' \
  -H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
  -H 'X-HMAC-SIGNATURE: 034c6da2bb31fd9e6892516c6d7b90ebe10f79b47cfb3d155d77b4d9b66e1d53' \
  -d '{
    "image": {
    "context": "document-front",
      "content": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA+.../9fgAEAKcxisFjVfn0AAAAASUVORK5CYII="
    }
}'

Node.js
var request = require('request');

var options = { method: 'POST',
  url: '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/media',
  headers:
   { 'Content-Type': 'application/json',
     'X-HMAC-SIGNATURE': '034c6da2bb31fd9e6892516c6d7b90ebe10f79b47cfb3d155d77b4d9b66e1d53',
     'X-AUTH-CLIENT': 'API-PUBLIC-KEY' },
  body:
   { image:
      { context: 'document-front',
        content: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA+.../9fgAEAKcxisFjVfn0AAAAASUVORK5CYII=' } },
  json: true };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});

Python3.py
import requests
import json
import pprint

url='/v1/sessions/{sessionId}/media'

payload = json.dumps({
    'image': {
    'context': 'document-front',
      'content': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA+.../9fgAEAKcxisFjVfn0AAAAASUVORK5CYII='
    }
})


headers = {
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'X-HMAC-SIGNATURE': '034c6da2bb31fd9e6892516c6d7b90ebe10f79b47cfb3d155d77b4d9b66e1d53',
    'Content-Type': 'application/json'
}

response = requests.request('POST', url, data=payload, headers=headers)
pprint.pprint(response.json())

Response

Media type: application/json
Type: object
Headers
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Request body signed with the shared secret key
Content-Type: application/json

Response properties explained
Sample response
{ "status": "success",
  "image":{
     "context": "document-back",
     "id": "39388f8d-c6d6-4e9b-92c6-6978b2e8d664",
     "name": "document-back",
     "timestamp": (Deprecated) null,
     "size": 52268,
     "mimetype": "image/png",
     "url": "/v1/media/39388f8d-c6d6-4e9b-92c6-6978b2e8d664"
   }
}

POST /sessions/{sessionId}/collected-data

Uploads information that has been collected for improved IDV process. The session must be either in created or started status.

Request

Request method: POST
Media type: application/json
Type: object
Headers
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Request body signed with the shared secret key
Content-Type: application/json

Request properties explained
Sample Request
curl

curl -X POST \
 --url '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/collected-data' \
  -H 'Content-Type: application/json' \
  -H 'X-AUTH-CLIENT: API key' \
  -H 'X-HMAC-SIGNATURE: 034c6da2bb31fd9e6892516c6d7b90ebe10f79b47cfb3d155d77b4d9b66e1d53' \ 
  -d '{
        "providerName": "SampleName",
        "person": {
            "email": "firstname.lastname@domain.com",
            "phoneNumber": "+11 222 333 44"
        },
        "network": {
            "mobileCarrier": "RandomTeleCom Inc",
            "ssid": "12345",
            "hostname": "examplehostname.amazonaws.com",
            "location": {
                "countryCode": "US",
                "continentCode": "NA",
                "city": "New York",
                "region": "New York",
                "timezone": "EDT"
            },
            "ip": {
                "addressV4": "192.168.XXX.XXX"
            },
            "asn": {
                "number": "AS12345",
                "organisation": "AWS"
            }
        },
        "device": {
            "fingerprint": "123456asdfg7890hijkl123456asdfg7890hijkl123456asdfg7890hijkl",
            "androidId": "ab1357cd-a1b2-c3d4-f5g6",
            "idfv": "F325G3GB-12FC-352F-C6C3-DZ52F0F690D8",
            "model": "Samsung Galaxy S23 Ultra",
            "vendor": "Samsung",
            "type": "mobile",
            "browser": {
                "languages": ["en-gb"],
                "timezoneOffsetMinutes": -240,
                "isIncognito": false
            },
            "screen": {
                "heightPixels": 3088,
                "widthPixels": 1440,
                "dpi": 500
            },
            "battery": {
                "level": 0.43,
                "charging": true
            },
            "os": {
                "family": "Android",
                "name": "Android",
                "version": "13"
            }
        }
    }'
Node.js
var request = require('request');

var options = {
  url: '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/collected-data',
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
    'X-AUTH-CLIENT': 'API key' \
    'X-HMAC-SIGNATURE': '034c6da2bb31fd9e6892516c6d7b90ebe10f79b47cfb3d155d77b4d9b66e1d53'
  },
  body: {
    "providerName": "SampleName",
    "person": {
      "email": "firstname.lastname@domain.com",
      "phoneNumber": "+11 222 333 44"
    },
    "network": {
      "mobileCarrier": "RandomTeleCom Inc",
      "ssid": "12345",
      "hostname": "examplehostname.amazonaws.com",
      "location": {
        "countryCode": "US",
        "continentCode": "NA",
        "city": "New York",
        "region": "New York",
        "timezone": "EDT"
      },
      "ip": {
        "addressV4": "192.168.XXX.XXX"
      },
      "asn": {
        "number": "AS12345",
        "organisation": "AWS"
      }
    },
    "device": {
      "fingerprint": "123456asdfg7890hijkl123456asdfg7890hijkl123456asdfg7890hijkl",
      "androidId": "ab1357cd-a1b2-c3d4-f5g6",
      "idfv": "F325G3GB-12FC-352F-C6C3-DZ52F0F690D8",
      "model": "Samsung Galaxy S23 Ultra",
      "vendor": "Samsung",
      "type": "mobile",
      "browser": {
        "languages": ["en-gb"],
        "timezoneOffsetMinutes": -240,
        "isIncognito": false
      },
      "screen": {
        "heightPixels": 3088,
        "widthPixels": 1440,
        "dpi": 500
      },
      "battery": {
        "level": 0.43,
        "charging": true
      },
      "os": {
        "family": "Android",
        "name": "Android",
        "version": "13"
      }
    }
  }
},
json: true };

request(options, function (error, response, body) {
  if (error) {
    console.error('Error:', error);
  } else {
    console.log('Response:', body);
  }
});

Response

Media type: application/json
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Request body signed with the shared secret key
Content-Type: application/json

Response properties explained
Sample response
{
  "status": "success",
  "sessionId": "f04bdb47-d3be-4b28-b028-a652feb060b5",
  "attemptId": "f5c68aea-7f4d-478d-80ab-ca9356074f69"
}

PATCH /sessions/{sessionId}

Changes the status of the verification to "submitted".

Request

Request method: PATCH
Media type: application/json
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Request body signed with the shared secret key
Content-Type: application/json

Request properties explained
Sample request
curl
curl -X PATCH \
  --url '/v1/sessions/fd5c1563-1d23-4b1a-ae46-7ba429927ed8' \
  -H 'Content-Type: application/json' \
  -H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
  -H 'X-HMAC-SIGNATURE: dd994f70b1150ae012f9c1d6d20adf7ed69780044835d39de20b00ffae0660a0' \
  -d '{
    "verification": {
      "status": "submitted"
    }
}'
Node.js
var request = require('request');

var options = { method: 'PATCH',
  url: '/v1/sessions/fd5c1563-1d23-4b1a-ae46-7ba429927ed8',
  headers:
   { 'Content-Type': 'application/json',
     'X-HMAC-SIGNATURE': 'dd994f70b1150ae012f9c1d6d20adf7ed69780044835d39de20b00ffae0660a0',
     'X-AUTH-CLIENT': 'API-PUBLIC-KEY' },
  body:
   { verification:
      { status: 'submitted' } },
  json: true };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
Python3.py
import requests
import json
import pprint

url = '/v1/sessions/{sessionId}'

payload = json.dumps({
    'verification': {
      'status': 'submitted'
    }
})

headers = {
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'X-HMAC-SIGNATURE': 'dd994f70b1150ae012f9c1d6d20adf7ed69780044835d39de20b00ffae0660a0',
    'Content-Type': 'application/json'
}

response = requests.request('PATCH', url, data=payload, headers=headers)
pprint.pprint(response.json())

Response

Media type: application/json
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Request body signed with the shared secret key
Content-Type: application/json

Response properties explained
Sample response
{
    "status": "success",
    "verification": {
        "id": "fd5c1563-1d23-4b1a-ae46-7ba429927ed8",
        "url": "https://alchemy.veriff.com/v/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzZXNzaW9uX2lkIjoiZmQ1YzE1NjMtMWQyMy00YjFhLWFlNDYtN2JhNDI5OTI3ZWQ4IiwiaWF0IjoxNTcyMzM4MDIwfQ.3HbNq0YWKAfFrH-P658_WXMwcUMubyC1aXAMo-umfCU",
        "vendorData": "11111111",
        "endUserId": "fa820aba-019f-455a-ae81-cfca8075bc3f",
        "host": "https://alchemy.veriff.com",
        "status": "submitted",
        "sessionToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzZXNzaW9uX2lkIjoiZmQ1YzE1NjMtMWQyMy00YjFhLWFlNDYtN2JhNDI5OTI3ZWQ4IiwiaWF0IjoxNTcyMzM4MDIwfQ.3HbNq0YWKAfFrH-P658_WXMwcUMubyC1aXAMo-umfCU"
    }
}

GET /sessions/{sessionId}/attempts

Returns the list of attempt objects with sessionId = {sessionId}

Returns the user-defined statuses data if those have been set in the Veriff environment.

Request

Request method: GET
Media type: application/json
Type: object
Headers
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = sessionId signed with the shared secret key
Content-Type: application/json

Sample request
curl
curl -X GET \
  --url '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/attempts' \
  -H 'Content-Type: application/json' \
  -H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
  -H 'X-HMAC-SIGNATURE: 334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14' \
Node.js
var request = require('request');

var options = { method: 'GET',
  url: '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/attempts',
  headers:
   { 'Content-Type': 'application/json',
     'X-HMAC-SIGNATURE': '334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14',
     'X-AUTH-CLIENT': 'API-PUBLIC-KEY' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
Python3.py
import requests
import json
import pprint

url = '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/attempts'

headers = {Response
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'X-HMAC-SIGNATURE': '334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14',
    'Content-Type': 'application/json'
}

response = requests.request('GET', url, headers=headers)
pprint.pprint(response.json())

Response

Media type: application/json
Type: object
Headers
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Request body signed with the shared secret key
Content-Type: application/json

Response properties explained
Sample Response (simple)
{
  "status": "success",
  "verifications": [
    {
      "id": "f5c68aea-7f4d-478d-80ab-ca9356074f69",
      "status": "approved"
    },
    {
      "id": "f2270684-8c51-4d03-88eb-dafd43e8b486",
      "status": "resubmission_requested"
    }
  ]
}
Sample Response (user-defined statuses added)

In the sample below the user has added a status for the attempt in the Veriff environment, but has not enabled the "Custom" option for the status.

{
  "status": "success",
  "verifications": [
      {
        "id": "a1c68aea-7f4d-478d-80ab-ca9356074f69",
        "status": "approved",
        "userDefinedData":[
          {
            "status":"Custom status for suspicious attempt",
            "statusCode":"custom_status_for_suspicious_attempt",
            "reason":"Looks like velocity abuse",
            "reasonCode":"looks_like_velocity_abuse",
            "createdAt":"2023-09-18T08:41:41.606636Z"
          }
        ],
        "createdTime":"2023-09-18T08:33:30.047935Z"
      },
      {
        "id": "f2270684-8c51-4d03-88eb-dafd43e8b486",
        "status": "resubmission_requested"
      }
  ]
}

In the sample below the user has added a status for the attempt in the Veriff environment, has enabled the "Custom" option for the status and added an explanation to the text box.

{
  "status": "success",
  "verifications": [
      {
        "id": "a1c68aea-7f4d-478d-80ab-ca9356074f69",
        "status": "approved",
        "userDefinedData":[
          {
            "status":"Custom status for suspicious attempt",
            "statusCode":"custom_status_for_suspicious_attempt",
            "reason":"The document used in this attempt is clearly a cut-out",
            "reasonCode": null,
            "createdAt":"2023-09-18T08:41:41.606636Z"
          }
        ],
        "createdTime":"2023-09-18T08:33:30.047935Z"
      },
      {
        "id": "f2270684-8c51-4d03-88eb-dafd43e8b486",
        "status": "resubmission_requested"
      }
  ]
}

GET /sessions/{sessionId}/decision

Returns the session decision with sessionId = {sessionId}

In order to receive the decision payload from us:

  1. the Integration needs to have the Webhook decisions URL configured
  2. the session related to the sessionId needs to have one of 9000-code statuses, otherwise you will see Decision not available in the response payload

Test integrations

For test integrations, the Webhook decision URL is added automatically.

But you need to manually set the session's status in the Veriff Environment:

Live integrations

For live integrations, you need to define the Webhook decisions URL:

In live integrations, the session statuses are set automatically.

Request

Request method: GET
Media type: application/json
Type: object
Headers
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = sessionId signed with the shared secret key
Content-Type: application/json

Sample request
curl
curl -X GET \
  --url '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/decision' \
  -H 'Content-Type: application/json' \
  -H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
  -H 'X-HMAC-SIGNATURE: 334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14' \
Node.js
var request = require('request');

var options = { method: 'GET',
  url: 'https://<Base-URL>/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/decision',
  headers:
   { 'Content-Type': 'application/json',
     'X-HMAC-SIGNATURE': '334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14',
     'X-AUTH-CLIENT': 'API-PUBLIC-KEY' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});

Python3.py
import requests
import json
import pprint

url = 'https://<Base-URL>/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a/decision'

headers = {
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'X-HMAC-SIGNATURE': '334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14',
    'Content-Type': 'application/json'
}

response = requests.request('GET', url, headers=headers)
pprint.pprint(response.json())

Response

Headers

X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Response body signed with the shared secret key
Content-Type: application/json

Response properties explained
Sample Response
{
  "status": "success",
  "verification": {
    "id": "12df6045-3846-3e45-946a-14fa6136d78b",
    "code": 9001,
    "person": {
      "gender": null,
      "idNumber": null,
      "lastName": "MORGAN",
      "addresses": [
        {
          "fullAddress": "1234 Snowy Ridge Road, Indiana, 56789 USA",
          "parsedAddress": {
            "city": null,
            "unit": null,
            "state": "Indiana",
            "street": "1234 Snowy Ridge Road",
            "country": "USA",
            "postcode": "56789",
            "houseNumber": "null"
          }
        }
      ],
      "firstName": "SARAH",
      "citizenship": null,
      "dateOfBirth": "1967-03-30",
      "nationality": null,
      "yearOfBirth": "1967",
      "placeOfBirth": "MADRID",
      "occupation": "Sales Representative",
      "employer": "Any Company LLC",
      "foreignerStatus": "EXTRANJERO",
      "extraNames": "NOM D'USAGE",
      "pepSanctionMatch": null
    },
    "reason": null,
    "status": "approved",
    "comments": [],
    "document": {
      "type": "DRIVERS_LICENSE",
      "number": "MORGA753116SM9IJ",
      "country": "US",
      "remarks": "WORK PERMITTED",
      "state": "NY",
      "placeOfIssue": "NEW YORK",
      "validFrom": null,
      "validUntil": "2022-04-20",
      "firstIssue": "2015-03-21",
      "issueNumber": "01",
      "issuedBy": "ISSUER",
      "nfcValidated": "true",
      "residencePermitType": "C",
      "portraitIsVisible": "true",
      "signatureIsVisible": "true"
    },
    "reasonCode": null,
    "vendorData": "12345678",
    "endUserId": "fa820aba-019f-455a-ae81-cfca8075bc3f",
    "decisionTime": "2019-11-06T07:18:36.916Z",
    "acceptanceTime": "2019-11-06T07:15:27.000Z",
    "additionalVerifiedData": {
      "driversLicenseCategory": {
        "B": true
      },
      "driversLicenseCategoryFrom": {
        "B": "2019-10-06"
      },
      "driversLicenseCategoryUntil": {
        "B": "2025-10-05"
      },
      "estimatedAge": 32,
      "estimatedGender": 0.613,
      "processNumber": "12345678912 1234",
      "driversLicenseNumber": "1234569",
      "cpfValidated": {
        "status": "CPF is validated"
        "cpfNumber": "123456789",
        "name": "SARAH MORGAN",
        "dateOfBirth": "1967-03-30",
        "yearOfDeath": null
      },
      "ineBiometricRegistryValidation": {
          "faceMatch": true,
          "faceMatchPercentage": 89,
          "responseStatus": "success"
      }
    },
    "riskScore": {
      "score": 0.12
    },
    "riskLabels": [
    {
      "label": "document_integration_level_crosslinked_with_fraud",
      "category": "document",
      "sessionIds": ["5a2358e7-fd31-4fcb-a23f-4d76651ba68a"]
    },
    {
      "label": "document_integration_level_crosslinked_with_multiple_declines",
      "category": "document",
      "sessionIds": ["fd5c1563-1d23-4b1a-ae46-7ba429927ed8"]
    }],
    "biometricAuthentication": {
      "matchedSessionId": "d40edb60-6ae6-4475-be72-84b81669cce6",
      "matchedSessionEndUserId": "a1b2c35d-eš8f7-6d5e-3cd2-a1b2c35db3d4",
      "matchedSessionVendorData": "12345678"
      "details": {
        ...
      }
    }
  },
  "technicalData": {
    "ip": "186.153.67.122"
  }
}

GET /sessions/{sessionId}/person

Returns information objects about a person (hereinafter the Person) associated with the specific sessionId.

Request

Request method: GET
Media type: application/json
Type: object
Headers
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = sessionId signed with the shared secret key
Content-Type: application/json

Sample request
curl
curl -X GET \
  --url '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/person' \
  -H 'Content-Type: application/json' \
  -H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
  -H 'X-HMAC-SIGNATURE: 334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14' \
Node.js
var request = require('request');

var options = { method: 'GET',
  url: '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/person',
  headers:
   { 'Content-Type': 'application/json',
     'X-HMAC-SIGNATURE': '334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14',
     'X-AUTH-CLIENT': 'API-PUBLIC-KEY' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
Python3.py
import requests
import json
import pprint

url = '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/person'

headers = {
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'X-HMAC-SIGNATURE': '334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14',
    'Content-Type': 'application/json'
}

response = requests.request('GET', url, headers=headers)
pprint.pprint(response.json())

Response

Media type: application/json
Type: object
Headers
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Request body signed with the shared secret key
Content-Type: application/json

Response properties explained
Sample response from the data provider
{
    "status": "success",
    "person": {
        "id": "b00a203e-2524-4ded-867b-b4e281a2c96b",
        "firstName": "MUAMMAR GADDAFI",
        "lastName": null,
        "idCode": "062.449.269-94",
        "dateOfBirth": "1942-09-22",
        "gender": null,
        "nationality": null,
        "placeOfBirth": null,
        "citizenships": [],
        "pepSanctionMatches": [
          {
            "provider": "Comply Advantage",
            "numberOfMatches": 1,
            "date": "2022-07-12T12:42:30.573Z",
            "matches": [],
            "hits": [
                {
                    "doc": {
                      "id": "4KJL9THDX9ZNV4W",
                      "lastUpdatedUtc": "2022-07-09T12:50:34Z",
                      "createdUtc": "2020-03-17T19:32:58Z",
                      "fields": [
                        {
                          "name": "Original Country Text",
                          "source": "world-bank-star-asset-recovery-watch",
                          "value": "European Union"
                        },
                        {
                          "name": "Nationality",
                          "source": "complyadvantage",
                          "value": "Libya"
                        },
                        {
                          "name": "Original Place of Birth Text",
                          "source": "hong-kong-special-administrative-region-sanctions-issued-under-the-un-sanctions-ordinance",
                          "value": "Sirte"
                        },
                        {
                          "name": "Original Country Text",
                          "source": "complyadvantage",
                          "value": "East Africa"
                        }
                      ],
                      "types": [
                        "adverse-media",
                        "adverse-media-v2-cybercrime",
                        "adverse-media-v2-financial-aml-cft",
                        "adverse-media-v2-financial-difficulty",
                        "adverse-media-v2-fraud-linked",
                        "adverse-media-v2-general-aml-cft",
                        "adverse-media-v2-narcotics-aml-cft",
                        "adverse-media-v2-other-minor",
                        "adverse-media-v2-other-serious",
                        "adverse-media-v2-property",
                        "adverse-media-v2-terrorism",
                        "adverse-media-v2-violence-aml-cft",
                        "adverse-media-v2-violence-non-aml-cft",
                        "pep",
                        "pep-class-1",
                        "pep-class-2",
                        "sanction",
                        "warning"
                      ],
                      "name": "Mouammar Mohammed Abu Minyar Kadhafi",
                      "entityType": "person",
                      "aka": [
                        {
                          "name": "Moamarr Qaddafi"
                        },
                        {
                          "name": "Moammar Kaddafi"
                        },
                        {
                          "name": "Muammer al Gaddafi"
                        },
                        {
                          "name": "মোৱাম্মাৰ গাড্ডাফি"
                        },
                        {
                          "name": "Moammar Khadafi"
                        }
                      ],
                      "associates": [
                        {
                          "association": "spouse",
                          "name": "Fatiha al-Nuri"
                        },
                        {
                          "association": "spouse",
                          "name": "Fatiha al-Nuri Gaddafi"
                        },
                        {
                          "association": "child",
                          "name": "Qadhafi Muammar Mohammed Abu Minyar"
                        },
                        {
                          "association": "spouse",
                          "name": "Safia el-Brasai"
                        },
                        {
                          "association": "spouse",
                          "name": "Safia el-Brasai Gaddafi"
                        }
                      ],
                      "sources": [
                        "argentina-ministerio-de-relaciones-exteriores-y-culto-sanciones-de-la-onu",
                        "belarus-state-security-agency-list-of-organizations-and-individuals-involved-in-terrorist-activities"
                      ],
                      "keywords": [],
                      "media": [
                        {
                          "date": "2021-11-16T00:00:00Z",
                          "snippet": "Sang Tan Judges in the High Court in London have ruled that Saleh Ibrahim Mabrouk, a former aide of Libyan leader Colonel Muammar Gaddafi, was partly to blame for the murder of PC Yvonne Fletcher. The gunman",
                          "title": "'Justice at Last': Former Gaddafi Aide Found Liable for 1984 Police Officer Murder by UK High Court - 16.11.2021, Sputnik International",
                          "url": "https://sputniknews.com/amp/20211116/justice-at-last-former-gaddafi-aide-found-liable-for-1984-police-officer-murder-by-uk-high-court-1090775876.html"
                        }
                      ],
                      "assets": [
                        {
                          "publicUrl": "http://complyadvantage-asset.s3.amazonaws.com/76993a49-2d1e-4397-9e35-1e20f2b7dfa8.pdf",
                          "source": "world-bank-star-asset-recovery-watch",
                          "type": "pdf"
                        }
                      ],
                      "sourceNotes": {
                        "argentinaMinisterioDeRelacionesExterioresYCultoSancionesDeLaOnu": {
                          "amlTypes": [
                            "sanction"
                          ],
                          "listingStartedUtc": "2019-09-26T00:00:00Z",
                          "name": "Argentina Ministerio de Relaciones Exteriores y Culto Sanciones de la ONU",
                          "url": "https://www.cancilleria.gob.ar/es/politica-exterior/seguridad-internacional/comite-de-sanciones"
                        },
                        "belarusStateSecurityAgencyListOfOrganizationsAndIndividualsInvolvedInTerroristActivities": {
                          "amlTypes": [
                            "sanction"
                          ],
                          "listingStartedUtc": "2019-08-28T00:00:00Z",
                          "name": "Belarus State Security Agency List of Organizations and Individuals Involved in Terrorist Activities",
                          "url": "http://kgb.by/ru/perechen-inf-ru/"
                        },
                        "complyadvantageAdverseMedia": {
                          "amlTypes": [
                            "adverse-media",
                            "adverse-media-v2-cybercrime",
                            "adverse-media-v2-financial-aml-cft",
                            "adverse-media-v2-financial-difficulty",
                            "adverse-media-v2-fraud-linked",
                            "adverse-media-v2-general-aml-cft",
                            "adverse-media-v2-narcotics-aml-cft",
                            "adverse-media-v2-other-minor",
                            "adverse-media-v2-other-serious",
                            "adverse-media-v2-property",
                            "adverse-media-v2-terrorism",
                            "adverse-media-v2-violence-aml-cft",
                            "adverse-media-v2-violence-non-aml-cft"
                          ],
                          "countryCodes": [
                            "AE",
                            "AM",
                            "AR"
                          ],
                          "name": "ComplyAdvantage Adverse Media"
                        },
                        "dfatAustraliaList": {
                          "amlTypes": [
                            "sanction"
                          ],
                          "countryCodes": [
                            "LY",
                            "OM"
                          ],
                          "listingStartedUtc": "2011-02-26T00:00:00Z",
                          "name": "DFAT Australia Consolidated Sanctions List",
                          "url": "https://www.dfat.gov.au/international-relations/security/sanctions/Pages/consolidated-list.aspx"
                        }
                      },
                    },
                  "matchTypes": [
                    "aka_exact",
                    "year_of_birth"
                  ],
                  "matchTypesDetails": {
                    "gaddafiMuammar": {
                      "matchTypes": {
                        "gaddafi": [
                          "name_exact"
                        ],
                        "muammar": [
                          "name_exact"
                        ]
                      },
                      "type": "aka"
                    },
                    "muammarGaddafi": {
                      "matchTypes": {
                        "gaddafi": [
                          "name_exact"
                        ],
                        "muammar": [
                          "name_exact"
                        ]
                      },
                      "type": "aka"
                    }
                  },
                  "matchStatus": "potential_match",
                  "isWhitelisted": false,
                  "score": 24.46217
                }
            ]
         }
      ]
   }
}

GET /sessions/{sessionId}/media

Returns a list of media objects with sessionId = {sessionId}

The list of objects are sorted based on their accuracy (e.g., does an image match the required image type) and their quality. The order is determined by the automation system.

Note that the request will return the media objects of the most recent attempt. If you require the media of a certain attempt, you can call the list of attemptId-s with GET sessions/{sessionId}/attempts and then use the GET attempts/{attemptId}/media to get the media of a specific attempt.

Request

Request method: GET
Media type: application/json
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = sessionId signed with the shared secret key
Content-Type: application/json

Sample request
curl
curl -X GET \
  --url '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/media' \
  -H 'Content-Type: application/json' \
  -H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
  -H 'X-HMAC-SIGNATURE: 334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14'
Node.js
var request = require('request');

var options = { method: 'GET',
  url: '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/media',
  headers:
   { 'Content-Type': 'application/json',
     'X-HMAC-SIGNATURE': '334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14',
     'X-AUTH-CLIENT': 'API-PUBLIC-KEY' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
Python3.py
import requests
import json
import pprint

url = '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/media'

headers = {
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'X-HMAC-SIGNATURE': '334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14',
    'Content-Type': 'application/json'
}

response = requests.request('GET', url, headers=headers)
pprint.pprint(response.json())

Response

Media type: application/json
Type: object
Headers
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Request body signed with the shared secret key
Content-Type: application/json

Response properties explained
Sample response
{
  "status": "success",
  "videos": [
    {
      "context": "{VIDEO_TYPE}",
      "duration": "{DURATION_IN_SECONDS}",
      "id": "{MEDIA_ID}",
      "mimetype": "{MEDIA_MIME_TYPE}",
      "name": "{VIDEO_NAME}",
      "sessionId": "{SESSIOND_ID}",
      "size": "{SIZE_IN_B}",
      "timestamp": (Deprecated) null,
      "url": "{MEDIA_DOWNLOAD_URL}"
    }
  ],
  "images": [
    {
      "context": "{IMAGE_TYPE}",
      "id": "{MEDIA_ID}",
      "name": "{IMAGE_NAME}",
      "url": "{MEDIA_DOWNLOAD_URL}",
      "sessionId": "{SESSIOND_ID}",
      "timestamp": (Deprecated) null,
      "size": "{SIZE_IN_B}",
      "mimetype": "{MEDIA_MIME_TYPE}"
    }
  ]
}

GET /sessions/{sessionId}/watchlist-screening

Returns a list of data objects from PEP and Sanctions services for specific sessionId.

Only available for customers using the Veriff PEP and Sanctions services.

Request

Request method: GET
Media type: application/json
Type: object.
Headers
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = session signed with the shared secret key
Content-Type: application/json

Sample request
curl
curl -X GET \
  --url '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/watchlist-screening' \
  -H 'Content-Type: application/json' \
  -H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
  -H 'X-HMAC-SIGNATURE: 334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14' \
Node.js
var request = require('request');

var options = { method: 'GET',
  url: '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/watchlist-screening',
  headers:
   { 'Content-Type': 'application/json',
     'X-HMAC-SIGNATURE': '334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14',
     'X-AUTH-CLIENT': 'API-PUBLIC-KEY' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});

Python3.py
import requests
import json
import pprint

url = '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/watchlist-screening'

headers = {
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'X-HMAC-SIGNATURE': '334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14',
    'Content-Type': 'application/json'
}

response = requests.request('GET', url, headers=headers)
pprint.pprint(response.json())

Response

Media type: application/json
Type: object
Headers
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Request body signed with the shared secret key
Content-Type: application/json

Response properties explained
Sample response
No match
{
    "status": "success",
     "data": {
         "attemptId": "aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7",
         "sessionId": "f04bdb47-d3be-4b28-b028-a652feb060b5",
         "vendorData": null,
         "endUserId": "fa820aba-019f-455a-ae81-cfca8075bc3f",
         "checkType": "initial_result",
         "matchStatus": "no_match",
         "searchTerm": {
             "name": "Juan Rico"
         },
         "totalHits": 0,
         "createdAt": "2021-06-15T08:27:33.015Z",
         "hits": []
     }
}
Possible match
{
    "status": "success",
    "data": {
        "attemptId": "aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7",
        "sessionId": "f04bdb47-d3be-4b28-b028-a652feb060b5",
        "vendorData": null,
        "endUserId": "fa820aba-019f-455a-ae81-cfca8075bc3f",
        "checkType": "updated_result",
        "matchStatus": "possible_match",
        "searchTerm": {
            "name": "Mirko Kokki",
            "year": "1960"
        },
        "totalHits": 1,
        "createdAt": "2021-07-05T13:23:59.851Z",
        "hits": [{
            "matchedName": "Miro kokkino",
            "countries": [
                "Australia",
                "Brazil"
            ],
            "dateOfBirth": "1963",
            "dateOfDeath": null,
            "matchTypes": [
                "aka_exact",
                "year_of_birth"
            ],
            "aka": [
                "Mirkoni kokki",
                "Mirkor Kokki"
            ],
            "associates": [
                "Desmon Lamela",
                "Fred Austin"
            ],
            "listingsRelatedToMatch": {
                "warnings": [{
                    "sourceName": "FBI Most Wanted",
                    "sourceUrl": "http://www.fbi.gov/wanted",
                    "date": null
                }],
                "sanctions": [{
                    "sourceName": "Argentina Ministerio de Relaciones Exteriores y Culto Sanciones de la ONU",
                    "sourceUrl": "https://www.cancilleria.gob.ar/es/politica-exterior/seguridad-internacional/comite-de-sanciones",
                    "date": null
                }],
                "fitnessProbity": [],
                "pep": [{
                    "sourceName": "United Kingdom Insolvency Service Disqualified Directors",
                    "sourceUrl": "https://www.insolvencydirect.bis.gov.uk/IESdatabase/viewdirectorsummary-new.asp",
                    "date": null
                }],
                "adverseMedia": [{
                    "sourceName": "SNA's Old Salt Award Passed to Adm. Davidson",
                    "sourceUrl": "https://www.marinelink.com/amp/news/snas-old-salt-award-passed-adm-davidson-443093",
                    "date": null
                }]
            }
        }]
    }
}
Failed response
{
    "status": "fail",
    "code": "1818",
    "message": "Signature \"334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14\" does not match the HMAC-SHA256 of query ID and integration API secret."
}

DELETE /sessions/{sessionId}

Method to request deletion of a session, a session is eligible for deletion on created, started, abandoned, expired, approved, resubmission_requested, declined, inflow_completed, review statuses. Attempting to delete the session in other statuses will respond with the Session is not in a completed status. error message. The availability of this feature is optional, depending on integration.

If session status is one of the following created, started or resubmission_requested a decision webhook with expired/abandoned status will be sent. After successful request, session will immediately become unavailable in Station and API. Data will be deleted within 12 hours.

Rate-limit is: 10 sessions per 24 hours and 5 sessions per 1 hour.

Request

Request method: DELETE
Media type: application/json
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = sessionId signed with the shared secret key
Content-Type: application/json

Sample request
curl
curl -X DELETE \
  --url '/v1/sessions/fd5c1563-1d23-4b1a-ae46-7ba429927ed8' \
  -H 'Content-Type: application/json' \
  -H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
  -H 'X-HMAC-SIGNATURE: dd994f70b1150ae012f9c1d6d20adf7ed69780044835d39de20b00ffae0660a0'
Node.js
var request = require('request');

var options = { method: 'DELETE',
  url: '/v1/sessions/fd5c1563-1d23-4b1a-ae46-7ba429927ed8',
  headers: {
     'Content-Type': 'application/json',
     'X-HMAC-SIGNATURE': 'dd994f70b1150ae012f9c1d6d20adf7ed69780044835d39de20b00ffae0660a0',
     'X-AUTH-CLIENT': 'API-PUBLIC-KEY'
  },
 };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
Python3.py
import requests
import json
import pprint

url = '/v1/sessions/{sessionId}'

headers = {
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'X-HMAC-SIGNATURE': 'dd994f70b1150ae012f9c1d6d20adf7ed69780044835d39de20b00ffae0660a0',
    'Content-Type': 'application/json'
}

response = requests.request('DELETE', url, headers=headers)
pprint.pprint(response.json())

Response

Media type: application/json
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Request body signed with the shared secret key
Content-Type: application/json

Successful response

Response HTTP status code: 202 Accepted
Response body:

{
    "status": "success",
    "verification": {
        "id": "fd5c1563-1d23-4b1a-ae46-7ba429927ed8"
    }
}
Failed responses

Response HTTP status code: 400 Bad Request
Response body:

{
    "status": "fail",
    "code": "1305",
    "message": "Session is not in a completed status."
}

Response HTTP status code: 400 Bad Request
Response body:

{
    "status": "fail",
    "code": "1306",
    "message": "Session in progress."
}
Limited access response

Response HTTP status code: 429 Too Many Requests
Response body:

{
    "status": 429,
    "code": "1004",
    "message": "Too many requests",
}

GET /attempts/{attemptId}/media

Returns a list of media objects with attemptId = {attemptId}

The list of objects are sorted based on their accuracy (e.g., does an image match the required image type) and their quality. The order is determined by the automation system.

Request

Request method: GET
Media type: application/json
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = attemptId signed with the shared secret key
Content-Type: application/json

Sample request
curl
curl -X GET \
  --url '/v1/attempts/f5c68aea-7f4d-478d-80ab-ca9356074f69/media' \
  -H 'Content-Type: application/json' \
  -H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
  -H 'X-HMAC-SIGNATURE: acfe1cf21c986edf25cc6bc74fd769954443bbb606500019a4bed46645179b36' \
Node.js
var request = require('request');

var options = { method: 'GET',
  url: '/v1/attempts/f5c68aea-7f4d-478d-80ab-ca9356074f69/media',
  headers:
   { 'Content-Type': 'application/json',
     'X-HMAC-SIGNATURE': 'acfe1cf21c986edf25cc6bc74fd769954443bbb606500019a4bed46645179b36',
     'X-AUTH-CLIENT': 'API-PUBLIC-KEY' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});

Python3.py
import requests
import json
import pprint

url = '/v1/attempts/f5c68aea-7f4d-478d-80ab-ca9356074f69/media'

headers = {
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'X-HMAC-SIGNATURE': 'acfe1cf21c986edf25cc6bc74fd769954443bbb606500019a4bed46645179b36',
    'Content-Type': 'application/json'
}

response = requests.request('GET', url, headers=headers)
pprint.pprint(response.json())

Response

Media type: application/json
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Request body signed with the shared secret key
Content-Type: application/json

Response properties explained
Sample response
{
  "status": "success",
  "videos": [
    {
      "context": "{VIDEO_TYPE}",
      "id": "{MEDIA_ID}",
      "name": "{VIDEO_NAME}",
      "duration": "{DURATION_IN_SECONDS}",
      "url": "{MEDIA_DOWNLOAD_URL}",
      "timestamp": (Deprecated) null,
      "size": "{SIZE_IN_B}",
      "mimetype": "{MEDIA_MIME_TYPE}"
    }
  ],
  "images": [
    {
      "context": "{IMAGE_TYPE}",
      "id": "{MEDIA_ID}",
      "name": "{IMAGE_NAME}",
      "url": "{MEDIA_DOWNLOAD_URL}",
      "timestamp": (Deprecated) null,
      "size": "{SIZE_IN_B}",
      "mimetype": "{MEDIA_MIME_TYPE}"
    }
  ]
}

GET /media/{mediaId}

Returns media file with mediaId = {mediaId}.
To get the mediaId of a specific media file, request a list of media with GET attempts/{attemptId}/media or sessions/{sessionId}/media.

Note about the size of images captured with the end-user flow

Request

Request method: GET
Media type: application/json
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = mediaId signed with the shared secret key
Content-Type: application/json

Sample request
curl
curl -X GET \
  --url '/v1/media/ebbf6434-3bf1-4020-8ac3-1ef51a25c673' \
  -H 'Content-Type: application/json' \
  -H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
  -H 'X-HMAC-SIGNATURE: 452bfca0e02f8ee0f56d97373cc6971067e43149f1b7e58b681d4e57353a2f6b' \
Node.js
var request = require('request');

var options = { method: 'GET',
  url: '/v1/media/ebbf6434-3bf1-4020-8ac3-1ef51a25c673',
  headers:
   { 'Content-Type': 'application/json',
     'X-HMAC-SIGNATURE': '452bfca0e02f8ee0f56d97373cc6971067e43149f1b7e58b681d4e57353a2f6b',
     'X-AUTH-CLIENT': 'API-PUBLIC-KEY' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});

Python3.py
import requests

url = '/v1/media/ebbf6434-3bf1-4020-8ac3-1ef51a25c673'

headers = {
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'X-HMAC-SIGNATURE': '452bfca0e02f8ee0f56d97373cc6971067e43149f1b7e58b681d4e57353a2f6b',
    'Content-Type': 'application/json'
}

response = requests.request('GET', url, headers=headers)
print(response.content)

Response

Headers

X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Response body signed with the shared secret key
TRANSFER-ENCODING: string (required) Form of encoding used to safely transfer the payload body

Sample response
Transfer-Encoding: chunked
Sample chunked data handling /media/{mediaId}

Sample how to store response data to file (image or video)

Headers:
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = mediaId signed with the shared secret key
mediaId: string (required) mediaId To get the mediaId of a specific media file, request a list of media with GET attempts/{attemptId}/media or sessions/{sessionId}/media

Node.js

Here is a simple example how to download media with Node.js, it is applicable for both video and image files. Just make sure to use correct file extension which can be found from /media api response

const fs = require('fs');
const request = require('request');

var options = { method: 'GET',
  url: '/v1/media/ebbf6434-3bf1-4020-8ac3-1ef51a25c673',
  headers:
   { 'Content-Type': 'application/json',
     'X-HMAC-SIGNATURE': '452bfca0e02f8ee0f56d97373cc6971067e43149f1b7e58b681d4e57353a2f6b',
     'X-AUTH-CLIENT': 'API-PUBLIC-KEY' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);
}).pipe(fs.createWriteStream(__dirname+'/myMedia.jpeg'));
Video files sample
media_url = '/v1/media/05cfc122-15d8-4838-bbf1-7b26a736b2d2'

headers = {
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'X-HMAC-SIGNATURE': '452bfca0e02f8ee0f56d97373cc6971067e43149f1b7e58b681d4e57353a2f6b',
    'Content-Type': 'application/json',
}

response = requests.get(media_url, headers=headers)

with open('media_filename.webm', 'wb') as media_file:
    for chunk in response.iter_content():
        media_file.write(chunk)
Image files sample
media_url = '/v1/media/2b3b3a9f-d73d-445a-aabe-9b41c1c1a2ac'

headers = {
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'X-HMAC-SIGNATURE': '452bfca0e02f8ee0f56d97373cc6971067e43149f1b7e58b681d4e57353a2f6b',
    'Content-Type': 'application/json',
}

response = requests.get(media_url, headers=headers)
with open('image_file_name.jpg', 'wb') as write_file:
    write_file.write(response.content)

GET /address/{addressId}/media

Returns a list of media objects with addressId = {addressId} for Proof of Address sessions.

Request

Request method: GET
Media type: application/json
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = addressId signed with the shared secret key
Content-Type: application/json

Sample request
curl
curl -X GET \
  --url '/v1/address/f087f21f-5282-41b8-9857-6f85c28b8122/media' \
  -H 'Content-Type: application/json' \
  -H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
  -H 'X-HMAC-SIGNATURE: acfe1cf21c986edf25cc6bc74fd769954443bbb606500019a4bed46645179b36' \
Node.js
var request = require('request');

var options = { method: 'GET',
  url: '/v1/address/f087f21f-5282-41b8-9857-6f85c28b8122/media',
  headers:
   { 'Content-Type': 'application/json',
     'X-HMAC-SIGNATURE': 'acfe1cf21c986edf25cc6bc74fd769954443bbb606500019a4bed46645179b36',
     'X-AUTH-CLIENT': 'API-PUBLIC-KEY' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});

Python3.py
import requests
import json
import pprint

url = '/v1/address/f087f21f-5282-41b8-9857-6f85c28b8122/media'

headers = {
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'X-HMAC-SIGNATURE': 'acfe1cf21c986edf25cc6bc74fd769954443bbb606500019a4bed46645179b36',
    'Content-Type': 'application/json'
}

response = requests.request('GET', url, headers=headers)
pprint.pprint(response.json())

Response

Media type: application/json
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Request body signed with the shared secret key
Content-Type: application/json

Response properties explained
Sample response
{
  "status": "success",
  "images": [
    {
      "context": "{IMAGE_TYPE}",
      "id": "{MEDIA_ID}",
      "name": "{IMAGE_NAME}",
      "url": "{MEDIA_DOWNLOAD_URL}",
      "timestamp": null,
      "size": "{SIZE_IN_B}",
      "mimetype": "{MEDIA_MIME_TYPE}"
    }
  ]
}

GET /address-media/{mediaId}

Returns the media for Proof of Address with mediaId = {mediaId}

Request

Request method: GET
Media type: application/json
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = mediaId signed with the shared secret key
Content-Type: application/json

Sample request
curl
curl -X GET \
  --url '/v1/address-media/8d79522f-e3ad-4c1f-8e6a-4248db6935a2' \
  -H 'Content-Type: application/json' \
  -H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
  -H 'X-HMAC-SIGNATURE: 452bfca0e02f8ee0f56d97373cc6971067e43149f1b7e58b681d4e57353a2f6b' \
Node.js
var request = require('request');

var options = { method: 'GET',
  url: '/v1/address-media/8d79522f-e3ad-4c1f-8e6a-4248db6935a2',
  headers:
   { 'Content-Type': 'application/json',
     'X-HMAC-SIGNATURE': '452bfca0e02f8ee0f56d97373cc6971067e43149f1b7e58b681d4e57353a2f6b',
     'X-AUTH-CLIENT': 'API-PUBLIC-KEY' } };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});

Python3.py
import requests

url = '/v1/address-media/8d79522f-e3ad-4c1f-8e6a-4248db6935a2'

headers = {
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'X-HMAC-SIGNATURE': '452bfca0e02f8ee0f56d97373cc6971067e43149f1b7e58b681d4e57353a2f6b',
    'Content-Type': 'application/json'
}

response = requests.request('GET', url, headers=headers)
print(response.content)

Response

Headers:
X-AUTH-CLIENT: string (required) API key
X-HMAC-SIGNATURE: string (required) Response body signed with the shared secret key
TRANSFER-ENCODING: string (required) Form of encoding used to safely transfer the payload body.

Sample response
Transfer-Encoding: chunked
Sample chunked data handling /address-media/{mediaId}

Sample how to store response data to file (image or video)

Headers:
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = mediaId signed with the shared secret key

Node.js

Here is a simple example how to download address media with Node.js. Just make sure to use correct file extension, which can be found from /media api response.

const fs = require('fs');
const request = require('request');

var options = {
  method: 'GET',
  url: '/v1/address-media/8d79522f-e3ad-4c1f-8e6a-4248db6935a2',
  headers: {
    'Content-Type': 'application/json',
    'X-HMAC-SIGNATURE': '452bfca0e02f8ee0f56d97373cc6971067e43149f1b7e58b681d4e57353a2f6b',
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY'
  }
};

request(options, function (error, response, body) {
  if (error) throw new Error(error);
}).pipe(fs.createWriteStream(__dirname + '/myMedia.jpeg'));
Image files sample
media_url = '/v1/address-media/8d79522f-e3ad-4c1f-8e6a-4248db6935a2'

headers = {
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'X-HMAC-SIGNATURE': '452bfca0e02f8ee0f56d97373cc6971067e43149f1b7e58b681d4e57353a2f6b',
    'Content-Type': 'application/json',
}

response = requests.get(media_url, headers=headers)
with open('image_file_name.jpg', 'wb') as write_file:
    write_file.write(response.content)

POST /validate-registry

Validates a national ID number (e.g. social security number (SSN)) with the provided data. A verification session will be automatically created and submitted after which the validation result gets sent via Webhook. Note that media upload is not used for registry verification.

You will need a separate integration to do this verification (i.e., the integration you have for IDV will not suffice.)

In order to perform a social security number (SSN) validation the following fields must be provided:

Request

Request method: POST
Media type: application/json
Type: object
Headers
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string = Request body signed with the shared secret key
Content-Type: application/json

Request properties explained
Sample request
curl
curl -X POST \
  --url '/v1/validate-registry/' \
  -H 'Content-Type: application/json' \
  -H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
  -d '{
    "verification": {
        "callback": "https://veriff.com",
        "person": {
            "firstName": "John",
            "lastName": "Smith",
            "idNumber": "123456789",
            "dateOfBirth": "1980-03-06"
        },
        "address": {
            "street": "Street 123",
            "houseNumber": "456"
        },
        "vendorData": "11111111",
        "endUserId": "fa820aba-019f-455a-ae81-cfca8075bc3f"
    }
}'
Node.js
var request = require('request');

var options = { method: 'POST',
    url: '/v1/validate-registry/',
    headers:
            { 'Content-Type': 'application/json',
                'X-AUTH-CLIENT': 'API-PUBLIC-KEY' },
    body:
            { verification:
                        { callback: 'https://veriff.com',
                            person:{
                                firstName: 'John',
                                lastName: 'Smith',
                                idNumber: '123456789',
                                dateOfBirth: "1980-03-06"
                            },
                            address: {
                                street: 'Street 123',
                                houseNumber: '456'
                            },
                            vendorData: '11111111'
                            endUserId: 'fa820aba-019f-455a-ae81-cfca8075bc3f' } },
    json: true };

request(options, function (error, response, body) {
    if (error) throw new Error(error);

    console.log(body);
});
Python3
import requests
import pprint
import json

url = '/v1/validate-registry/'

payload = json.dumps({
    'verification': {
        'callback': 'https://veriff.com',
        'person': {
            'firstName': 'John',
            'lastName': 'Smith',
            'idNumber': '123456789',
            'dateOfBirth': '1980-03-06'
        },
        'address': {
            'street': 'Street 123',
            'houseNumber': '456',
        },
        'vendorData': '11111111',
        'endUserId': 'fa820aba-019f-455a-ae81-cfca8075bc3f',
        'features': [
          'selfid'
        ]
    }
})

headers = {
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'Content-Type': 'application/json'
}

response = requests.request('POST', url, data=payload, headers=headers)
pprint.pprint(response.json())

Response

Media type: application/json
Type: object
Headers
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Request body signed with the shared secret key
Content-Type: application/json

Response properties explained
Sample responses
Success, values in the form match
{
    "status": "success",
    "verification": {
        "id":"f04bdb47-d3be-4b28-b028-a652feb060b5",
        "vendorData": "11111111",
        "endUserId": "fa820aba-019f-455a-ae81-cfca8075bc3f",
        "status": "submitted",
        "sessionToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRoX3Rva2VuIjoiOThiYzdjMjEtZTQ0Yy00MTZiLTkxOTMtMTU5ZGZkMzBmMDg4Iiwic2Vzc2lvbl9pZCI6Ijc2ODhmMzYzLTAyZjctNDE1My1iMzM1LWE0ODQ3OTRkMzZmNyIsImlhdCI6MTUwMTIyODI1MSwiZXhwIjoxNTAxODMzMDUxfQ.bMEF37E6-zT2Aa6Q8UXK3B_ZL51w6D_lxnGgQvhj214"
    }
}
Status 400 "Bad request", firstName + lastName OR fullName not provided
{
    "status": "fail",
    "code": "1309",
    "message": "SSN validation requires person firstName + lastName OR fullName to be provided"
}
Status 400 "Bad request", idNumber not provided
{
  "status": "fail",
  "code": "1308",
  "message": "ID number is missing."
}
Status 400 "Bad request", dateOfBirth OR address not provided
{
  "status": "fail",
  "code": "1310",
  "message": "SSN validation requires person.dateOfBirth or address data to be provided."
}

POST sync-api.veriff.me/v1/validate-registry

Validates a national ID number (e.g. social security number (SSN)) with the provided data. A verification session will be automatically created and submitted after which the validation result gets sent in the API Response. Note that media upload is not used for registry verification.

You will need a separate integration to do this verification (i.e., the integration you have for IDV will not suffice.)

In order to perform a social security number (SSN) validation the following fields must be provided:

Request

Request method: POST
Media type: application/json
Type: object
Headers
X-AUTH-CLIENT: string (required) = API key
X-API-KEY: string (required) = API key
X-HMAC-SIGNATURE: string = Request body signed with the shared secret key
Content-Type: application/json

Request properties explained
Sample request
curl
curl -X POST \
  --url '/v1/validate-registry' \
  -H 'Content-Type: application/json' \
  -H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
  -H 'X-API-KEY: API-PUBLIC-KEY' \
  -H 'X-HMAC-SIGNATURE: 4776e5fb59795da4856c8176efcdeaf6fe15d0bed6a179e75c86a5f5580a250c' \
  -d '{
    "verification": {
        "person": {
            "firstName": "John",
            "lastName": "Smith",
            "idNumber": "123456789",
            "dateOfBirth": "1980-03-06"
        },
        "address": {
            "street": "Street 123",
            "houseNumber": "456",
            "postcode": "12345"
        },
        "vendorData": "11111111",
        "endUserId": "fa820aba-019f-455a-ae81-cfca8075bc3f"
    }
}'
Node.js
var request = require('request');

var options = {
  method: 'POST',
  url: '/v1/validate-registry/',
  headers: {
    'Content-Type': 'application/json',
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'X-API-KEY': 'API-PUBLIC-KEY',
    'X-HMAC-SIGNATURE': '4776e5fb59795da4856c8176efcdeaf6fe15d0bed6a179e75c86a5f5580a250c',
  },
  body: {
    verification: {
      person: {
        firstName: 'John',
        lastName: 'Smith',
        idNumber: '123456789',
        dateOfBirth: '1980-03-06',
      },
      address: {
        street: 'Street 123',
        houseNumber: '456',
        postcode: '12345',
      },
      vendorData: '11111111',
      endUserId: 'fa820aba-019f-455a-ae81-cfca8075bc3f'
    },
  },
  json: true,
};

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
Python3
import requests
import pprint
import json

url = '/v1/validate-registry/'

payload = json.dumps({
    'verification': {,
        'person': {
            'firstName': 'John',
            'lastName': 'Smith',
            'idNumber': '123456789',
            'dateOfBirth': '1980-03-06'
        },
        'address': {
            'street': 'Street 123',
            'houseNumber': '456',
            'postcode': '12345',
        },
        'vendorData': '11111111',
        'endUserId': 'fa820aba-019f-455a-ae81-cfca8075bc3f',
        'features': [
          'selfid'
        ]
    }
})

headers = {
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'X-API-KEY': 'API-PUBLIC-KEY',
    'Content-Type': 'application/json',
    'X-HMAC-SIGNATURE': '4776e5fb59795da4856c8176efcdeaf6fe15d0bed6a179e75c86a5f5580a250c'
}

response = requests.request('POST', url, data=payload, headers=headers)
pprint.pprint(response.json())
Failed request validation scenarios

Two types of validation is done: X-HMAC-SIGNATURE and request payload validation. Below are possible failure scenarios.

X-HMAC-SIGNATURE validation failed

HTTP status code: 401
Message: "MissingAuthentication"

{
status: 'fail',
code: 1812,
message: 'Signature {invalid-hmac-signature value} is not a valid SHA256 hash.'
}

Required field fullName or (firstName + lastName) not provided

HTTP status code: 400
Message: "InvalidRequest"

{
status: 'fail',
code: 1102,
message: 'Request person is missing required field fullName or (firstName + lastName)'
}

Required field dateOfBirth or address not provided

HTTP status code: 400
Message: "InvalidRequest"

{
status: 'fail',
code: 1102,
message: 'Request is missing required field dateOfBirth or address'
}

Required field fullAddress or (street + houseNumber + postcode) not provided

HTTP status code: 400
Message: "InvalidRequest"

{
status: 'fail',
code: 1102,
message: 'Request address is missing required field fullAddress or (street + houseNumber + postcode)'
}

Required field idNumber not provided

HTTP status code: 400
Message: "InvalidRequest"

{
status: 'fail',
code: 1102,
message: 'Request is missing required field idNumber'
}

Response

Media type: application/json
Type: object
Headers
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Response body signed with the shared secret key
Content-Type: application/json

Response properties explained
Sample Response
Approved decision
{
  "status": "success",
  "verification": {
    "id": "09551b48-4d7c-4a30-8437-5301223953fa",
    "code": 9001,
    "person": {
      "gender": null,
      "idNumber": "123456789",
      "lastName": "Smith",
      "firstName": "John",
      "citizenship": null,
      "dateOfBirth": "1980-03-06",
      "nationality": null,
      "yearOfBirth": null,
      "placeOfBirth": null,
      "pepSanctionMatch": null
    },
    "reason": null,
    "status": "approved",
    "comments": [],
    "document": {
      "type": null,
      "number": null,
      "country": null,
      "validFrom": null,
      "validUntil": null
    },
    "reasonCode": null,
    "vendorData": null,
    "endUserId": "fa820aba-019f-455a-ae81-cfca8075bc3f",
    "decisionTime": "2019-11-06T07:18:36.916Z",
    "acceptanceTime": "2019-11-06T07:15:27.000Z",
    "additionalVerifiedData": {}
  },
  "technicalData": {
    "ip": null
  }
}
Declined decision
{
    "status": "success",
    "verification": {
        "id": "5ca9d2b6-3708-4540-928e-4b8e82717c3f",
        "code": 9102,
        "person": {
            "gender": null,
            "idNumber": "123456789",
            "lastName": "Smith",
            "firstName": "John",
            "citizenship": null,
            "dateOfBirth": "1980-03-06",
            "nationality": null,
            "yearOfBirth": null,
            "placeOfBirth": null,
            "pepSanctionMatch": null
        },
        "reason": "Unable to validate National Id data",
        "status": "declined",
        "comments": [],
        "document": {
            "type": null,
            "number": null,
            "country": null,
            "validFrom": null,
            "validUntil": null
        },
        "reasonCode": 529,
        "vendorData": null,
        "endUserId": "fa820aba-019f-455a-ae81-cfca8075bc3f",
        "decisionTime": "2019-11-06T07:18:36.916Z",
        "acceptanceTime": "2019-11-06T07:15:27.000Z",
        "additionalVerifiedData": {
            "failedValidation": "Neither address or date of birth matched"
        }
    },
    "technicalData": {
        "ip": null
    }
}

POST /sessions/{sessionId}/consents

Uploads a consent (and specifies the type of the consent that is being uploaded) for a specific sessionId.

Request

Request method: POST
Media type: application/json
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Request body signed with the shared secret key
Content-Type: application/json

Request properties explained
Sample request
curl
curl -X POST \
  --url '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/consents' \
  -H 'Content-Type: application/json' \
  -H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
  -H 'X-HMAC-SIGNATURE: 034c6da2bb31fd9e6892516c6d7b90ebe10f79b47cfb3d155d77b4d9b66e1d53' \
  -d '{
  "type": "ine",
  "approved": true,
  "text": "User agrees to share their INE details",
}'

Node.js
var request = require('request');

var options = { method: 'POST',
  url: '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/consents',
  headers:
   { 'Content-Type': 'application/json',
     'X-HMAC-SIGNATURE': '034c6da2bb31fd9e6892516c6d7b90ebe10f79b47cfb3d155d77b4d9b66e1d53',
     'X-AUTH-CLIENT': 'API-PUBLIC-KEY' },
  body:
   { image:
      { type: 'ine',
        approved: true,
        text: 'User agrees to share their INE details' } },
  json: true };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});

Python3.py
import requests
import json
import pprint

url='/v1/sessions/{sessionId}/consents'

payload = json.dumps({
  'type': 'ine',
  'approved': True,
  'text': 'User agrees to share their INE details'
})


headers = {
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'X-HMAC-SIGNATURE': '034c6da2bb31fd9e6892516c6d7b90ebe10f79b47cfb3d155d77b4d9b66e1d53',
    'Content-Type': 'application/json'
}

response = requests.request('POST', url, data=payload, headers=headers)
pprint.pprint(response.json())

Response

Media type: application/json
Type: object
Headers
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Request body signed with the shared secret key
Content-Type: application/json

Response properties explained
Sample response
{ "status": "success",
  "image":{
     "context": "consent",
     "id": "12551f8d-d3d6-4e9b-91b2-3978a2e7a553",
     "sessionId": "39388f8d-c6d6-4e9b-92c6-6978b2e8d664"
   }
}

GET /sessions/{sessionId}/decision/ine-registry

INE (Institutio Nacional Electoral - Mexican Electoral Registry) is the organization that issues the voter ID cards and maintains the voters registry.

Returns data about the INE identification number.

Request

Request properties explained

Request method: GET
Media type: application/json
Type: object
Headers
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = sessionId signed with the shared secret key
Content-Type: application/json (required)
Query parameters:
version: string (required) = the version number of the check

Sample request

Note: the examples below are for illustrative purposes only, and are using mock data for API URL and X-HMAC-SIGNATURE, and a placeholder for API-PUBLIC-KEY. You need to replace these with the actual values that you use.

curl
curl -X GET 'v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/decision/ine-registry?version=1.0.0' \
-H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
-H 'X-HMAC-SIGNATURE: 334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14' \
-H 'Content-Type: application/json' \
Node.js
var request = require('request');
var url = '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/decision/ine-registry?version=1.0.0';
var options = {
    method: 'GET',
    url: url,
    headers: {
        'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
        'X-HMAC-SIGNATURE': '334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14',
        'Content-Type': 'application/json'
    }
};
request(options, function (error, response, body) {
    if (error) {
        console.error('Error:', error);
    } else {
        console.log('Response:', body);
    }
});
Python3.py
import requests
import json
import pprint
url = "/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/decision/ine-registry"
headers = {
    "X-AUTH-CLIENT": "API-PUBLIC-KEY",
    "X-HMAC-SIGNATURE": "334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14",
    "Content-Type": "application/json"
}
params = {
    "version": "1.0.0"
}
response = requests.get(url, headers=headers, params=params)
if response.status_code == 200:
    data = json.loads(response.text)
    pprint.pprint(data)
else:
    print(f"Error: {response.status_code}")

Response

Headers

X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = payload signed with the shared secret key
Content-Type: application/json

Response properties explained

Note: in the respective jurisdiction, an active = true credential can be used for identification and related activities; an active = false credential could still be in the database, but it cannot be used for identification and related activities.

Sample Response
{
    "active": false,
    "documentState": "No se obtuvieron datos de la consulta con los parámetros seleccionados"
}

GET /sessions/{sessionId}/decision/curp-registry

The CURP (Unique Key of Population Registry) is the name of the population number/certificate in Mexico.

Returns the check result with CURP identification number and status.

Request

Request method: GET
Media type: application/json
Type: object
Headers
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = sessionId signed with the shared secret key
Content-Type: application/json (required)
Query parameters:
version: string (required) = the version number of the check

Sample request

Note: the examples below are for illustrative purposes only, and are using mock data for API URL and X-HMAC-SIGNATURE, and a placeholder for API-PUBLIC-KEY. You need to replace these with the actual values that you use.

curl
curl -X GET 'v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/decision/curp-registry?version=1.0.0' \
-H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
-H 'X-HMAC-SIGNATURE: 334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14' \
-H 'Content-Type: application/json' \
Node.js
var request = require('request');
var url = '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/decision/curp-registry?version=1.0.0';
var options = {
  method: 'GET',
  url: url,
  headers: {
    'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
    'X-HMAC-SIGNATURE': '334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14',
    'Content-Type': 'application/json'
    }
};
request(options, function (error, response, body) {
  if (error) {
    console.error('Error:', error);
  } else {
    console.log('Response:', body);
  }
});
Python3.py
import requests
import json
import pprint
url = "/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/decision/curp-registry"
headers = {
    "X-AUTH-CLIENT": "API-PUBLIC-KEY",
    "X-HMAC-SIGNATURE": "334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14",
    "Content-Type": "application/json"
}
params = {
    "version": "1.0.0"
}
response = requests.get(url, headers=headers, params=params)
if response.status_code == 200:
    data = json.loads(response.text)
    pprint.pprint(data)
else:
    print(f"Error: {response.status_code}")

Response

Headers

X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = payload signed with the shared secret key
Content-Type: application/json

Response properties explained

Full forms of the statusCurp acronyms

Active CURP: AN (Alta Normal), AH (Alta con Homonimia), CRA CU (CURP Reactivada), RCN (Registro de Cambio no Afectando a CURP), RCC (Registro de Cambio Afectando a CURP)

For inactive CURP: BD (Baja por Defuncion), BDA (Baja por Duplicidad), BCC (Baja por Cambio en CURP), BCN (Baja no Afectando a CURP)

Sample Response
{
    "statusCurp": "RCN",
    "curp": "FOHJ920625HGTLRR06"
}

GET /sessions/{sessionId}/decision/combined-ine-curp-registry

Returns combined result of INE/IFE and CURP.

INE (Institutio Nacional Electoral - Mexican Electoral Registry) is the organization that issues the voter ID cards and maintains the voters registry.

The CURP (Unique Key of Population Registry) is the name of the population number/certificate in Mexico.

ifeIdentifeir and ineIdentifier both represent person's identification number. ife is a legacy name, it was changed to ine.

Request

Request properties explained

Request method: GET
Media type: application/json
Type: object
Headers
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = sessionId signed with the shared secret key
Content-Type: application/json (required)
Query parameters:
version: string (required) = the version number of the check

Sample request

Note: the examples below are for illustrative purposes only, and are using mock data for API URL and X-HMAC-SIGNATURE, and a placeholder for API-PUBLIC-KEY. You need to replace these with the actual values that you use.

curl
curl -X GET 'v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/decision/combined-ine-curp-registry?version=1.0.0' \
-H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
-H 'X-HMAC-SIGNATURE: 334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14' \
-H 'Content-Type: application/json' \
Node.js
var request = require('request');
var url = '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/decision/combined-ine-curp-registry?version=1.0.0';
var options = {
    method: 'GET',
    url: url,
    headers: {
        'X-AUTH-CLIENT': 'API-PUBLIC-KEY',
        'X-HMAC-SIGNATURE': '334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14',
        'Content-Type': 'application/json'
    }
};
request(options, function (error, response, body) {
    if (error) {
        console.error('Error:', error);
    } else {
        console.log('Response:', body);
    }
});
Python3.py
import requests
import json
import pprint
url = "/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/decision/combined-ine-curp-registry"
headers = {
    "X-AUTH-CLIENT": "API-PUBLIC-KEY",
    "X-HMAC-SIGNATURE": "334141f052e317fde6668de54dc6640b4a5c47582ad86a8bed63afe566f17b14",
    "Content-Type": "application/json"
}
params = {
    "version": "1.0.0"
}
response = requests.get(url, headers=headers, params=params)
if response.status_code == 200:
    data = json.loads(response.text)
    pprint.pprint(data)
else:
    print(f"Error: {response.status_code}")

Response

Headers

X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = payload signed with the shared secret key
Content-Type: application/json

Response properties explained
Full forms of the statusCurp acronyms

Active CURP: AN (Alta Normal), AH (Alta con Homonimia), CRA CU (CURP Reactivada), RCN (Registro de Cambio no Afectando a CURP), RCC (Registro de Cambio Afectando a CURP)

For inactive CURP: BD (Baja por Defuncion), BDA (Baja por Duplicidad), BCC (Baja por Cambio en CURP), BCN (Baja no Afectando a CURP)

Sample Response
{
  "eventType": "combined-ine-curp-registry",
  "sessionId": "f04bdb47-d3be-4b28-b028-a652feb060b5",
  "attemptId": "e30122d1-740b-4764-853f-470374a7abf4",
  "vendorData":  "1234567812345678",
  "endUserId": "fa820aba-019f-455a-ae81-cfca8075bc3f",
  "version": "1.0.0",
  "data": {
      "status": "found",
      "code": 200,
      "details": {
          "ine": {
              "active": true,
              "status": "La credencial esta vigente",
              "comments": [
                  "CIC 000000000\r\nClave de elector JRLGLS00000000H000\r\nNúmero de emisión 1\r\nDistrito Federal 3\r\nDistrito Local 4\r\nNúmero OCR 0000000000000\r\nAño de registro 2009\r\nAño de emisión 2020",
                  "Fecha de actualización de la información: 10 de agosto del 2023 19:48",
                  "Fecha de consulta: 11 de agosto del 2023",
                  "Tus datos se encuentran en el Padrón Electoral, y también en la Lista Nominal de Electores"
              ],
              "information": "CIC 000000000\r\nClave de elector JRLGLS00000000H000\r\nNúmero de emisión 1\r\nDistrito Federal 3\r\nDistrito Local 4\r\nNúmero OCR 0000000000000\r\nAño de registro 2009\r\nAño de emisión 2020\r\nFecha de actualización de la información: 10 de agosto del 2023 19:48\r\nFecha de consulta: 11 de agosto del 2023\r\nEsta vigente como medio de identificación y puedes votar.\r\nTus datos se encuentran en el Padrón Electoral, y también en la Lista Nominal de Electores.\r\nSerá válida hasta el 31 de diciembre de 2030",
              "ifeIdentifier": "",
              "ineIdentifier": "000000000"
          },
          "curp": {
              "curp": "ABCD000000HVZRGS00",
              "statusCurp": "RCN",
              "descriptionStatusCurp": "Registro de cambio no afectando a curp",
              "names": "LOREM IPSUM",
              "firstSurname": "JUAREZ",
              "secondSurname": "LAGUNES",
              "gender": "HOMBRE",
              "dateOfBirth": "06/04/1991",
              "nationality": "MEX",
              "birthRegion": "Veracruz",
              "regionCode": "VZ",
              "documentEvidence": 1,
              "docEvidenceData": {
                  "registrationYear": "1991",
                  "actNumber": "00123",
                  "regionRegistry": "30",
                  "registryRegionCode": "VZ"
                  "registryCity": "",
                  "registryCityCode": "125",
                  "volume": "",
                  "sheet": "",
                  "book": ""
              },
          }
      }
  }
}

Test the requests in Postman

It is possible to test the Veriff API v1.0 Collection in Postman. Click on the button below to get started.

API requests signing with X-HMAC-SIGNATURE

X-HMAC-SIGNATURES are a security measure, which we generate for the API requests and webhook listeners, to make sure that the exchanged data has not been tampered with.

If you are familiar with the signing concept, jump to the Generate X-HMAC-SIGNATURE section. Here you find:

If you want a conceptual overview of the feature, we recommend taking a look at this What is an X-HMAC-SIGNATURE? section.

Generate an X-HMAC-SIGNATURE

Prerequisites for live requests signing

If you want to generate the X-HMAC-SIGNATURE for an actual API request, have the following info at hand and use these in your preferred signature generation tool:

If you are unsure which method you want to use, the Options to generate a X-HMAC-SIGNATURE section lists some options. You can use the mock data here to test them in your local machine.

Mock data for local testing

If you want to test the signature generation options locally, you can use the following mock shared secret key and mock payload.

Mock shared secret key:

abcdef12-abcd-abcd-abcd-abcdef012345

POST /sessions request mock payload (as .json):

{"verification":{"callback":"https://veriff.com","person":{"firstName":"John","lastName":"Smith"},"document":{"type":"PASSPORT","country":"EE"},"vendorData":"unique id of the end-user","timestamp":"2016-05-19T08:30:25.597Z"}}

If your preferred method is correct, you should get the following mock X-HMAC-SIGNATURE:

0dcab73ddd20062616d104231c7439657546a5c24e4691977da93bb854c31e25

Note: to generate an actual signature for your live API requests, the Headers explanation in each API request’s section tells you what to use as payload for encryption.

Options to generate a X-HMAC-SIGNATURE

There are several ways to do that:

Scripts

Command-line tools

Built-in crypto libraries

Online tools

Validate X-HMAC-SIGNATURE locally

Below are few examples how to validate the generated X-HMAC-SIGNATURE.

What is an X-HMAC-SIGNATURE?

This section aims to explain the nature and use of X-HMAC-SIGNATURES and webhook listeners, and describe the reasons why it is important to implement them.

Sessions lifecycle diagram (API)

API sessions lifecycle diagram

Webhooks

To handle the response from Veriff services, you need to implement an endpoint that accepts payloads posted by our services.

Webhook delivery, receipt and resending

Delivery order: to follow the best practices, we do not guarantee that the webhooks are delivered in the order in which they are generated. Therefore, you should not expect to receive them in that order either, and should implement a logic to handle this accordingly.

Delivery approach: we guarantee the delivery of webhook at-least-once. The receiving API should be idempotent.

After sending the webhook, our systems expect a confirmation about receiving the webhook from your side. This confirmation from your server should come within 5,000 ms, and we expect it to be in the form of a successful HTTP response code (a 200 code).

If the confirmation does not arrive within that timeframe, for example there is a network connectivity issue or technical issue with delivering the notification (any non-200 response code), we will try to resend the failed webhook for up to a week.

Configuring the webhook endpoint

  1. Go to the Veriff environment
  2. Click on the Integrations on the top menu
  3. Find and open the relevant integration
  4. Navigate to the Settings tab on the integration's page
  5. Fill in the webhook URL input field with the URL where your endpoint is accepting payloads from Veriff

There are several types of webhooks. Veriff will post payloads to respective webhook URLs.

Note that the image below does not contain all the possible webhook URLs. The list available depends on your integration.

Recognizing your end-user

When your server receives a payload from Veriff, you need to be able to reference an end-user. You can do this by using the Veriff session ID or by using your own end-user ID.

Using the Veriff session ID

The easiest way is to track the session ID provided by Veriff during session creation. Some webhooks payloads refer to either session ID or attempt ID or both. Please see the specific webhook payload for exact info.

Using your own end-user ID

To use your own end-user ID you need to provide your internal end-user ID to Veriff, or some other key that uniquely identifies your end-user. You can store your identifier in the vendorData or endUserID property during the session creation.

Note: it is technically possible for one end-user to be associated with multiple verification sessions, and this could potentially create ambiguous situations in code if you are only recognizing end-users by your own identifier, and not Veriff's session ID.

Handling security

It is important to check that the webhook responses do indeed originate from Veriff. For that we use the X-HMAC-SIGNATURE header, which value is an HMAC-SHA256 hex encoded keyed hash using your API private key.

Different webhook types

There are several webhook types to help you to tailor your service specifically to your needs.

Decision webhook

This is the description of the payload sent to Webhook decisions URL.
The result of the verification is sent back to the customer once the verification has been processed.

In most cases we send a decision webhook instantly after a decision is made, with an exception to "resubmission_requested" status. In case resubmission is required, we allow the end-user to resubmit session data instantly without a need to exit the flow. If the end-user does not do it within 5 minutes, we will send out a webhook with the resubmission_requested decision.

Driver's license categories extraction: to extract the validFrom and validUntil dates from a driver's license, please communicate with your solutions engineer to activate the feature.

Request properties explained:

Sample request

  {
    "status": "success",
    "verification": {
        "id": "12df6045-3846-3e45-946a-14fa6136d78b",      
        "vendorData": "12345678",
        "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
        "status": "approved",
        "code": 9001,
        "reason": null,
        "reasonCode": null,
        "decisionTime": "2019-11-06T07:18:36.916Z",
        "acceptanceTime": "2019-11-06T07:15:27.000Z",
        "person": {
            "firstName": "SARAH",
            "lastName": "MORGAN",
            "dateOfBirth": "1967-03-30",
            "gender": null,
            "nationality": null,
            "idNumber": null,
            "yearOfBirth": "1967",
            "placeOfBirth": "MADRID",
            "citizenship": null,
            "addresses": [
              {
                "fullAddress": "1234 Snowy Ridge Road, Indiana, 56789 USA",
                "parsedAddress": {
                    "city": null,
                    "unit": null,
                    "state": "Indiana",
                    "street": "1234 Snowy Ridge Road",
                    "country": "USA",
                    "postcode": "56789",
                    "houseNumber": "null"
                }
              }
            ],
            "fullName": "SARAH MORGAN",
            "occupation": "Engineer",
            "employer": "Any Company LLC",
            "foreignerStatus": "EXTRANJERO",
            "extraNames": "NOM D'USAGE",
            "pepSanctionMatch": null
        },
        "document": {
            "number": "MORGA753116SM9IJ",
            "validFrom": null,
            "validUntil": "2022-04-20",
            "type": "DRIVERS_LICENSE",
            "country": "US",
            "remarks": "WORK PERMITTED",
            "state": "NY",
            "placeOfIssue": "NEW YORK",
            "firstIssue": "2015-03-21",
            "issueNumber": "01",
            "issuedBy": "ISSUER",
            "nfcValidated": true,
            "residencePermitType": "C",
            "portraitIsVisible": "true",
            "signatureIsVisible": "true"
            }
        },
        "additionalVerifiedData": {
            "driversLicenseNumber": "1234569",  
            "driversLicenseCategory": {
                "B": true
            },
            "driversLicenseCategoryFrom": {
                "B": "2019-10-06"
            },
            "driversLicenseCategoryUntil": {
                "B": "2025-10-05"
            },
            "estimatedAge": 32,
            "estimatedGender": 0.613,
            "processNumber": "12345678912 1234",        
            "cpfValidation": {
                "status": "CPF is validated",
                "cpfNumber": "123456789",
                "name": "SARAH MORGAN",
                "dateOfBirth": "1967-03-30",
                "yearOfDeath": null
            },
            "ineBiometricRegistryValidation": {
                "faceMatch": true,
                "faceMatchPercentage": 89,
                "responseStatus": "success"
            },
            "proofOfAddress": {
                "nameMatch": true,
                "nameMatchPercentage": 100.00
            },
        },
        "riskScore": {
            "score": 0.12
        },
        "riskLabels": [
        {
            "label": "document_integration_level_crosslinked_with_fraud",
            "category": "document",
            "sessionIds": ["5a2358e7-fd31-4fcb-a23f-4d76651ba68a"]
        },
        {
            "label": "document_integration_level_crosslinked_with_multiple_declines",
            "category": "document",
            "sessionIds": ["fd5c1563-1d23-4b1a-ae46-7ba429927ed8"]
        }],
        "biometricAuthentication": {
            "matchedSessionId": "d40edb60-6ae6-...",
            "matchedSessionEndUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
            "matchedSessionVendorData": "12345678",
            "details": {
                  ...
            }
        },
        "comments": []
    },
    "technicalData": {
        "ip": "186.153.67.122"
    }
  }

Event webhook

This is the description of the payload sent to Webhook events URL. It tracks the events happening in the identity verification process as the end-user is passing through it.

Possible events over the webhook

Webhook code Webhook action Description Available Configuration to receive events "Waiting for decision" page enabled
7001 started The end-user arrives to Veriff verification flow and starts the verification process via API and SDK Not needed Not needed
7002 submitted The end-user is done with the process and submits the attempt via API and SDK Not needed Not needed
7007 waiting_complete The end-user gets the decision on the "waiting for decision" page Web only Yes, required Yes, required
7008 waiting_continued The end-user clicks on the Continue button on the "waiting for decision" page before the decision is available. This triggers the action that you have configured for the case when the end-user finishes the flow. Web only Yes, required Yes, required
7009 flow_finished The end-user reached the final screen and clicked on the Continue button Web only Yes, required Not needed
7010 flow_cancelled The end-user abandons the verification flow by clicking on the X in the UI and confirming the cancelling Web only Yes, required Not needed

As shown in the table above, 7007-7010 events can be received only when you are using Veriff's web flow, and these require some additional configuration on Veriff side.
Contact your Solutions Engineer for info and configuration.

There are also events which we do not notify about. See this Knowledge Base article [↗] for more info (requires a login to the Veriff environment).

Event webhook payload

Request properties explained:

Sample request

{
  "id": "f04bdb47-d3be-4b28-b028-a652feb060b5",
  "attemptId": "e30122d1-740b-4764-853f-470374a7abf4",
  "feature": "selfid",
  "code": 7002,
  "action": "submitted",
  "vendorData": "QWE123",
  "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4"
}

Watchlist screening webhook

This is the description of the payload sent to Webhook watchlist screening URL.
Only available for customers using the Veriff PEP and Sanctions services.

Depending on the types of solutions that have been enabled for your integration, different types of webhooks are used to return the data.

PEP & Sanction screening with IDV checks

PEP & Sanction screening without IDV (including optional adverse media and ongoing monitoring checks)

Results of all the checks are returned via watchlist-screening webhook. Decision webhook is not used to pass the checks' info.


Request properties explained:

Sample request

{
  "checkType": "updated_result",
  "attemptId": "54233318-f81c-4ec4-8e4c-413168a3f5e6",
  "sessionId": "f04bdb47-d3be-4b28-b028-a652feb060b5",
  "vendorData": "12345678",
  "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
  "matchStatus": "possible_match",
  "searchTerm": {
    "name": "Mirko Kokki",
    "year": "1960"
  },
  "totalHits": 5,
  "createdAt": "2021-06-02T11:04:00.287Z",
  "hits": [
    {
      "matchedName": "Miro kokkino",
      "countries": [
        "Australia",
        "Brazil"
      ],
      "dateOfBirth": "1960",
      "dateOfDeath": null,
      "matchTypes": [
        "aka_exact"
      ],
      "aka": [
        "Kokki Mirko",
        "Mirko Kokki"
      ],
      "associates": [
        "Desmon Lamela",
        "Fred Austin"
      ],
      "listingsRelatedToMatch": {
        "warnings": [
          {
            "sourceName": "FBI Most Wanted",
            "sourceUrl": "http://www.fbi.gov/wanted",
            "date": null
          }
        ],
        "sanctions": [
          {
            "sourceName": "Argentina Ministerio de Relaciones Exteriores y Culto Sanciones de la ONU",
            "sourceUrl": "https://www.cancilleria.gob.ar/es/politica-exterior/seguridad-internacional/comite-de-sanciones",
            "date": null
          },
          {
            "sourceName": "Argentina Public Registry of People and Entities linked to acts of Terrorism and Terrorism Financing",
            "sourceUrl": "https://repet.jus.gob.ar/#entidades",
            "date": null
          }
        ],
        "fitnessProbity": [
          {
            "sourceName": "United Kingdom Insolvency Service Disqualified Directors",
            "sourceUrl": "https://www.insolvencydirect.bis.gov.uk/IESdatabase/viewdirectorsummary-new.asp"
          }
        ],
        "pep": [
          {
            "sourceName": "United States Navy Leadership and Senior Military Officials",
            "sourceUrl": "https://www.navy.mil/Leadership/Biographies/"
          }
        ],
        "adverseMedia": [
          {
            "date": "2020-09-23T00:00:00Z",
            "sourceName": "SNA's Old Salt Award Passed to Adm. Davidson",
            "sourceUrl": "https://www.marinelink.com/amp/news/snas-old-salt-award-passed-adm-davidson-443093"
          }
        ]
      }
    }
  ]
}

INE registry validation webhook

INE (Institutio Nacional Electoral - Mexican Electoral Registry) is the organization that issues the voter ID cards and maintains the voters registry.

Below is the description of the payload sent to Webhook INE registry URL.
The response of the check is sent back once the check is completed.

Request properties explained
Sample request
{
  "eventType": "ine_registry",
  "sessionId": "f04bdb47-d3be-4b28-b028-a652feb060b5",
  "attemptId": "e30122d1-740b-4764-853f-470374a7abf4",
  "vendorData": "1234567812345678",
  "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
  "version": "1.0.0",
  "time": "2021-06-02T11:04:00.287Z",
  "data": {
    "status": "La credencial es válida",
    "code": 200,
    "details": {
      "active": true,
      "documentState": "El documento es válido."
    }
  }
}

CURP registry validation webhook

The CURP (Unique Key of Population Registry) is the name of the population number/certificate in Mexico.

Below is the description of the payload sent to Webhook CURP registry URL.
The response of the check is sent back once the check is completed.

Request properties explained

Full forms of the statusCurp acronyms

Active CURP: AN (Alta Normal), AH (Alta con Homonimia), CRA CU (CURP Reactivada), RCN (Registro de Cambio no Afectando a CURP), RCC (Registro de Cambio Afectando a CURP)

For inactive CURP: BD (Baja por Defuncion), BDA (Baja por Duplicidad), BCC (Baja por Cambio en CURP), BCN (Baja no Afectando a CURP)

Sample request
{
  "type": "curp_registry",
  "id": "f04bdb47-d3be-4b28-b028-a652feb060b5",
  "vendorData":  "1234567812345678",
  "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
  "version": "1.0.0",
  "data": {
      "attemptId": "e30122d1-740b-4764-853f-470374a7abf4",
      "name": "curp_registry",
      "status": "found",
      "code": 200,
      "details": {
          "statusCurp": "RCN",
          "curp": "VISH760905HSRLNN06",
          "description": "Registro de cambio no afectando a curp"
      }
  }
}

Combined INE CURP validation webhook

INE (Institutio Nacional Electoral - Mexican Electoral Registry) is the organization that issues the voter ID cards and maintains the voters registry.

The CURP (Unique Key of Population Registry) is the name of the population number/certificate in Mexico.

ifeIdentifeir and ineIdentifier both represent person's identification number. ife is a legacy name, it was changed to ine.

Below is the description of the payload sent to Webhook combined INE CURP registry URL.
The response of the check is sent back once the check is completed.

Request properties explained

Full forms of the statusCurp acronyms

Active CURP: AN (Alta Normal), AH (Alta con Homonimia), CRA CU (CURP Reactivada), RCN (Registro de Cambio no Afectando a CURP), RCC (Registro de Cambio Afectando a CURP)

For inactive CURP: BD (Baja por Defuncion), BDA (Baja por Duplicidad), BCC (Baja por Cambio en CURP), BCN (Baja no Afectando a CURP)

Sample request
{
  "eventType": "combined-ine-curp-registry",
  "sessionId": "f04bdb47-d3be-4b28-b028-a652feb060b5",
  "attemptId": "e30122d1-740b-4764-853f-470374a7abf4",
  "vendorData":  "1234567812345678",
  "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
  "version": "1.0.0",
  "data": {
      "status": "found",
      "code": 200,
      "details": {
            "ine": {
                "active": true,
                "status": "La credencial esta vigente",
                "comments": [
                    "CIC 000000000\r\nClave de elector JRLGLS00000000H000\r\nNúmero de emisión 1\r\nDistrito Federal 3\r\nDistrito Local 4\r\nNúmero OCR 0000000000000\r\nAño de registro 2009\r\nAño de emisión 2020",
                    "Fecha de actualización de la información: 10 de agosto del 2023 19:48",
                    "Fecha de consulta: 11 de agosto del 2023",
                    "Tus datos se encuentran en el Padrón Electoral, y también en la Lista Nominal de Electores"
                ],
                "information": "CIC 000000000\r\nClave de elector JRLGLS00000000H000\r\nNúmero de emisión 1\r\nDistrito Federal 3\r\nDistrito Local 4\r\nNúmero OCR 0000000000000\r\nAño de registro 2009\r\nAño de emisión 2020\r\nFecha de actualización de la información: 10 de agosto del 2023 19:48\r\nFecha de consulta: 11 de agosto del 2023\r\nEsta vigente como medio de identificación y puedes votar.\r\nTus datos se encuentran en el Padrón Electoral, y también en la Lista Nominal de Electores.\r\nSerá válida hasta el 31 de diciembre de 2030",
                "ifeIdentifier": "",
                "ineIdentifier": "000000000"
            },
            "curp": {
                "curp": "ABCD000000HVZRGS00",
                "statusCurp": "RCN",
                "descriptionStatusCurp": "Registro de cambio no afectando a curp",
                "names": "LOREM IPSUM",
                "firstSurname": "JUAREZ",
                "secondSurname": "LAGUNES",
                "gender": "HOMBRE",
                "dateOfBirth": "06/04/1991",
                "nationality": "MEX",
                "birthRegion": "Veracruz",
                "regionCode": "VZ",
                "documentEvidence": 1,
                "docEvidenceData": {
                    "registrationYear": "1991",
                    "actNumber": "00001",
                    "regionRegistry": "30",
                    "registryRegionCode": "VZ"
                    "registryCity": "",
                    "registryCityCode": "125",
                    "volume": "",
                    "sheet": "",
                    "book": ""
                },
            }
      }
  }
}

User-defined session statuses webhook

This is the description of the payload sent to the Webhook URL for sessions statuses set in Station.
This webhook is sent after the user has added a status to an attempt in the Veriff environment.

Properties explained

{
    "data": {
        "verification": {
            "id": "a1c68aea-7f4d-478d-80ab-ca9356074f69",
            "userDefinedData": {
                "reason": "Looks like velocity abuse",
                "status": "Custom status for suspicious attempt",
                "createdAt": "2023-10-27T09:59:15.090805Z",
                "reasonCode": null,
                "statusCode": "custom_status_for_suspicious_attempt"
            }
        }
    },
    "time": "2023-10-27T10:00:02.998Z",
    "attemptId": "f2270684-8c51-4d03-88eb-dafd43e8b486",
    "eventType": "user-status.created",
    "sessionId": "0b10cb53-4f3b-48af-bd74-60b85354e51f",
    "vendorData": null,
    "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4"
}

Full Auto webhook

This section gives a more general overview of the contents of the Full Auto webhook, which is used to send decision info for Full Auto sessions that return insights, extractions and the decision score.

Log in to Veriff environment to see:

Full Auto webhook request properties explained

Note about the decision score

Parameter data.verification.decisionScore shows how confident the system is that the session is genuine. Lower number means that the confidence is low, higher number means that the session is more likely to be genuine.

The score is shown on two scales:

Full Auto webhook lightweight sample

{
  "status": "success",
  "eventType": "fullauto",
  "sessionId": "1234567d-1ab2-34c5-bba7-a23gh58908er",
  "attemptId": "12e3d456-9ea2-7821-12io-aabb4113bgtf",
  "vendorData": null,
  "version": "1.0.0",
  "acceptanceTime": "2023-10-05T17:34:06.882846Z",
  "time": "2023-10-05T17:33:22.449Z",
  "data": {
      "verification": {
          "decisionScore": 0.96,
          "decision": "approved",
          "person": {
              "firstName": {
                  "confidenceCategory": "medium",
                  "value": "ASHOK",
                  "sources": [
                      "MRZ",
                      "VIZ"
                  ]
              },
              ...
          },
          "document":{
              "type": {
                  "value": "id_card"
              },
              "country": {
                  "value": "IN"
              },
              "number": {
                  "confidenceCategory": "high",
                  "value": "123abc456",
                  "sources": [
                      "MRZ",
                      "VIZ"
                  ]
              },
              ...
          },
          "insights":[
              {
                  "label": "xwz",
                  "result": "yes",
                  "category": "abc"
              },
              {
                  ...
              },
          ]
      },
  },
}

Webhooks testing

For testing purposes we provide an example payload, so you do not depend on Veriff sending the response. You can use the Curl command below.

Note that the signature will not match your API Public Key and API Private Key. To validate this example signature and payload, use API Private Key 'abcdef12-abcd-abcd-abcd-abcdef012345'.

curl --request POST 'https://your.url' -k \
--header 'accept:application/json' \
--header 'x-auth-client:8e4f7cd8-7a19-4d7d-971f-a076407ee03c' \
--header 'x-hmac-signature:01fa3ded011bfce75672c99877a6cc1cf7aeaeda0ccb6b43fc21b60f595063c2' \
--header 'content-type:application/json' \
--data '{"status":"success","verification":{"id":"12df6045-3846-3e45-946a-14fa6136d78b","code":9001,"person":{"gender":null,"idNumber":null,"lastName":"MORGAN","addresses":[{"fullAddress":"1234 Snowy Ridge Road, Indiana, 56789 USA","parsedAddress":{"city":null,"unit":null,"state":"Indiana","street":"1234 Snowy Ridge Road","country":"USA","postcode":"56789","houseNumber":"null"}}],"firstName":"SARAH","citizenship":null,"dateOfBirth":"1967-03-30","nationality":null,"yearOfBirth":"1967","placeOfBirth":"MADRID","pepSanctionMatch":null},"reason":null,"status":"approved","comments":[],"document":{"type":"DRIVERS_LICENSE","number":"MORGA753116SM9IJ","country":"GB","validFrom":null,"validUntil":"2022-04-20","placeOfIssue":"MADRID","firstIssue":"2015-03-21","issueNumber":"01","issuedBy":"ISSUER"},"reasonCode":null,"vendorData":"12345678","decisionTime":"2019-11-06T07:18:36.916Z","acceptanceTime":"2019-11-06T07:15:27.000Z","additionalVerifiedData":{"driversLicenseCategory":{"B":true},"driversLicenseCategoryFrom":{"B":"2019-10-06"},"driversLicenseCategoryUntil":{"B":"2025-10-05"},"estimatedAge":32,"estimatedGender":0.613},"riskLabels":[{"label":"document_integration_level_crosslinked_with_fraud","category":"document","sessionIds":["5a2358e7-fd31-4fcb-a23f-4d76651ba68a"]},{"label":"document_integration_level_crosslinked_with_multiple_declines","category":"document","sessionIds":["fd5c1563-1d23-4b1a-ae46-7ba429927ed8"]}],"biometricAuthentication":{"matchedSessionId":"d40edb60-6ae6-4475-be72-84b81669cce6","matchedSessionVendorData":"User001"}},"technicalData":{"ip":"186.153.67.122"}}'

Full Auto

This is a fully automated identity verification service, which can be integrated via SDKs and the API.

There are two options for identity verification:

The system analyzes the images, verifies the end-user and returns the results via decision webhook. All the information can also be queried via GET sessions/{sessionId}/decision endpoint.

The results of the verification can also be viewed in the Veriff environment.

Full Auto prerequisites

Full Auto flow

  1. Create a new session using the keys and the baseURL of the Full Auto integration (see the API Reference about how to find these in the Veriff environment).

  2. Direct the end-user to the verification flow.

  3. The end-user passes through the end-user flow on their device. They are required to capture the front and back of their ID document, and, in case of face validation, take a selfie.

    a. When using the SDK/Web flow, the session status is automatically updated to submitted as soon as the end-user has submitted the images.

    b. When using the API requests, you need to do this manually. See the Sending the end-user data via API section below for more information.

  4. Receive the results from Veriff via decision webhook, query them using the GET sessions/{sessionId}/decision endpoint, or view them in the Veriff environment.

Full Auto over SDK

If you have integrated with Veriff using the SDKs and you have set up the decision webhook URL in the Veriff environment, you are all set.

Full Auto over API

Before you start, make sure that you have configured the decision webhook.

Sending the end-user data via API

  1. Start a session using the POST /sessions
    • If you want to use the Biometric Authentication, make sure to also pass the vendorData/endUserId
  2. Upload the highly recommended device/session data via POST sessions/{sessionid}/collected-data for improved fraud detection
  3. Upload end-user's ID document (and selfie images, if applicable) via POST sessions/{sessionId}/media
  4. Specify the image.context as appropriate for the image (see the context types for more info)
  5. Patch the session status to submitted using the PATCH sessions/{sessionId}

Getting Full Auto session decision

You can get the data from three sources:

Full Auto results in decision webhook

Results of the Full Auto session are returned in the decision webhook.

Note that below is an explanation and a sample of a decision webhook payload for a Full Auto session. The decision webhook is used for many purposes, to find more info about it, see the full decision webhook section.

Webhook payload properties explained

Sample request

{
    "status": "success",
    "verification": {
        "id": "12df6045-3846-3e45-946a-14fa6136d78b",
        "code": 9001,
        "person": {
            "gender": null,
            "idNumber": null,
            "lastName": "MORGAN",
            "addresses": [],
            "firstName": "SARAH",
            "citizenship": null,
            "dateOfBirth": "1990-01-09",
            "nationality": null,
            "yearOfBirth": null,
            "placeOfBirth": null,
            "pepSanctionMatch": null
        },
        "reason": null,
        "status": "approved",
        "comments": [],
        "document": {
            "type": "DRIVERS_LICENSE",
            "state": "NY",
            "number": "1234569",
            "country": "US",
            "validFrom": "2024-04-20",
            "validUntil": "2028-04-19"
        },
        "endUserId": null,
        "reasonCode": null,
        "vendorData": "12345678",
        "decisionTime": "2024-08-15T17:57:03.376067Z",
        "acceptanceTime": "2024-08-15T17:56:31.021837Z",
        "additionalVerifiedData": {}
    },
    "technicalData": {
        "ip": "186.153.67.122"
    }
}

Querying the Full Auto decision data via API

You can use the GET sessions/{sessionId}/decision endpoint to get the decision data.

Note that below is an explanation and a sample of a GET call payload for a Full Auto session. The GET sessions/{sessionId}/decision endpoint is used for many purposes, to find more info about it, see the GET sessions/{sessionId}/decision section.

API request

Request method: GET
Media type: application/json
Type: object
Headers
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = sessionId signed with the shared secret key
Content-Type: application/json

API response properties explained

Sample response

{
    "status": "success",
    "verification": {
        "id": "12df6045-3846-3e45-946a-14fa6136d78b",
        "code": 9001,
        "person": {
            "gender": null,
            "idNumber": null,
            "lastName": "MORGAN",
            "addresses": [],
            "firstName": "SARAH",
            "citizenship": null,
            "dateOfBirth": "1990-01-09",
            "nationality": null,
            "yearOfBirth": null,
            "placeOfBirth": null,
            "pepSanctionMatch": null
        },
        "reason": null,
        "status": "approved",
        "comments": [],
        "document": {
            "type": "DRIVERS_LICENSE",
            "state": "NY",
            "number": "1234569",
            "country": "US",
            "validFrom": "2024-04-20",
            "validUntil": "2028-04-19"
        },
        "endUserId": null,
        "reasonCode": null,
        "vendorData": "12345678",
        "decisionTime": "2024-08-15T17:57:03.376067Z",
        "acceptanceTime": "2024-08-15T17:56:31.021837Z",
        "additionalVerifiedData": {}
    },
    "technicalData": {
        "ip": "186.153.67.122"
    }
}

Biometric Authentication

Veriff’s Biometric Authentication solution uses facial biometric analysis and advanced AI to swiftly and securely verify that the person authenticating themselves is the person they claim they are. This fast and fully automated process can be integrated into any stage of the user journey. Veriff Biometric Authentication is available via API, web flow, and native SDKs.

Prerequisites

*If you have generated the unique end-user identifier in the UUID v4 format, we recommend sending it in the endUserID field.

**If you have the unique end-user identifier in a format that is not UUID v4, you can send it in the vendorData field.

How to set up a Biometric Authentication solution?

Set up the selfie enrollment integration

To use Veriff’s biometric authentication solution, you first need the selfie enrollment integration. Read on for more information, but contact your Solutions Engineer for configuration.

In general terms[↗], enrollment is a process of capturing biometrics samples, processing them to create a biometric template and storing the templates onto storage. In Veriff’s case, the enrollment integration is the one during which the raw biometrics data (e.g., end-user's face image) is processed and converted into a mathematical biometric template. The template is stored so it can be used in the future to verify the end-user during a biometric authentication session.

The image is taken from an approved IDV session, or a selfie-only session that is run in the enrollment integration. If the session is approved (the image quality meets certain criteria, the endUserId/vendorData is present, there is no suspicion of fraudulent activity, etc.) the selfie image from the session is stored and can be used as a reference image.

How to pass selfie images to Veriff?

The image that is used for enrollment (biometric data capturing, processing and conversion into a biometric template) can come from different sources.

Customers using the Veriff’s Doc & Selfie IDV solution Customers not using Veriff’s Doc & Selfie IDV solution
The selfie image taken from an approved IDV session becomes the reference image. It is converted into a biometric template and stored for future use. It is possible to migrate* images from previous IDV sessions for authentication. An IDV/selfie-only session is done inside the biometric enrollment integration. If the session is approved, the selfie enrollment image is converted into a biometric template and stored for future. If existing face images are available: previously collected selfie images become reference images and are enrolled. This may require migration*.

*In cases of migration, contact your Solutions Engineer for more info.

Set up the authentication integration

This is the integration that you will use to create biometric authentication sessions for the end-users. It must be connected to the enrollment integration, so the system has access to the following end-user-related data in the enrollment integration:

Contact your Solutions Engineer for configuration. Once ready, you can start creating authentication sessions for your end-users in the SDKs, or send us collected end-user data over the API.

When creating the verification sessions in the SDKs or sending us the end-users’ data over the API, use the API keys and tokens of the authentication integration (you can find these in the Veriff environment. See here for more info about how to find the keys and tokens.)

Make sure to always include the endUserId/vendorData as we need to see that it matches the end-user’s approved session’s endUserId/vendorData in the selfie enrollment integration.

How to use Biometric Authentication over the SDK?

Step-by-step guide

  1. Generate an authentication session using the authentication integration tokens (check the POST /sessions endpoint in the API reference)
    • Make sure that you include the same endUserId/vendorData that you used in the enrollment integration session
  2. Capture end-user’s face images with Veriff’s SDKs
    • Send the end-user through the verification flow to capture the new face image (using one of Veriff SDKs: iOS, Android, React Native, Flutter, InContext)
    • You need the session URL generated in step 1 to use the SDKs
    • Session will be submitted automatically once the end-user takes and submits necessary images of their face
  3. Receive the results from Veriff via decision webhook

From the end-user point of view

When the end-user needs to authenticate, they simply take a selfie using their device camera. A new template is created and compared against the stored template from enrollment. If they match within a set accuracy threshold, and the endUserId/vendorData in the enrollment integration session match that in the authentication integration session, the user is successfully identified.

How to use Biometric Authentication over the API?

This is applicable once the end-user has an approved session containing a populated endUserID/vendorData.

Step-by-step guide

  1. Generate an authentication session using the authentication integration tokens (check the POST /sessions endpoint in the API reference)
    • Make sure that you include the same endUserId/vendorData that you used in the enrollment integration session
  2. Use your face-capturing method, or prepare previously collected end-user face images
  3. Upload the end-user's face image via the POST /sessions/{sessionId/}media call. Specify context parameter as face.
  4. Patch session status to submitted status using PATCH /sessions/{sessionId} call
  5. Receive the results from Veriff via decision webhook

How to get the verification results?

All biometric authentication results are returned via the decision webhook, inside the verification.biometricAuthentication object.

If the session was declined, you can find additional information by checking the verification.status, verification.code, verification.reason and verification.reasonCode data objects.

Request properties

Sample request properties

{
    "status": "success",
    "verification": {
        ...
        "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
        "vendorData": "12345678",
        "status": "approved",
        "code": 9001,
        "reason": null,
        "reasonCode": null
        "biometricAuthentication": {
            "matchedSessionId": "d40edb60-6ae6-...",
            "matchedSessionEndUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",
            "matchedSessionVendorData": "12345678",
            "details": {
                  ...
            }
        },
        ...
    }
}

How to handle authentication integration statuses and decisions?

Biometric authentication session status and status code

These values are available in the decision webhook payload, in verification.status and verification.code data objects.

verification.status verification.code What does it mean?
approved 9001 Positive: end-user was verified. The verification process is complete. Accessing the sessionURL again will show the end-user that nothing is to be done here.
declined 9102 Negative: end-user has not been verified. The verification process is complete. Either it was a fraud case or some other severe reason that the end-user can not be verified. It could also have been that due to a bad image quality the end-user could not be matched. If you decide to give the end-user another try, you need to create a new session.
expired 9104 Negative: Verification has expired. The verification process is complete. After the session creation, if the end-user has not started the verification in 7 days, the session gets expired.
abandoned Negative: Verification has been abandoned. The verification process is complete. After the session creation, if the end-user has started but not completed the verification in 7 days, the session gets abandoned status.

Biometric authentication session decision reason and reason codes

These values are available in the decision webhook payload, in verification.status, verification.reasonCode and verification.reason data objects.

verification.status verification.reasonCode verification.reason What does it mean?
declined 105 Decline - Suspicious behavior The session contains some suspicious behaviour, for example the face image is shown from a device, screen or print-out. The end-user is declined.
declined 106 Decline - Known fraud The session contains fraudulent behaviour, for example the photos are streamed. The end-user is declined.
declined 120 Decline - Person on the portrait does not appear to match reference photo The end-user is declined
declined 121 Decline - user ID missing The vendorData does not match the vendorData used during enrollment, the end-user is declined. To avoid this issue, ensure the same vendorData is sent.
declined 122 Decline - No reference found No enrollment face image (reference image) found that would match the endUserId/vendorData, the end-user is declined.
declined 128 Decline - endUserId mismatch The endUserId does not match the endUserId used during enrollment, the end-user is declined. To avoid this issue, ensure the same endUserId is sent.
expired null null The end-user did not complete the verification flow. If you want to let them to try again, create a new session for them
abandoned

AML Screening

PEP & Sanction screening with IDV

PEP & Sanctions, adverse media screening together with identity verification

Prerequisites

An IDV integration with PEP & Sanctions checks configured together with optional adverse media checks and ongoing monitoring. Turn to your dedicated Solutions Engineer for configuration.

Process overview

  1. Once the integration is set up, generate a verification session using the regular /sessions endpoint.
  2. After the end-user has submitted the verification flow and the session has been verified, the AML result will be sent in a separate webhook. You can also query for the result using the watchlist-screening API endpoint
  3. In case ongoing monitoring is enabled, we will send a new webhook if the PEP & Sanctions status of a verified person has changed.
    a. The Webhook PEP & Sanctions URL can be configured from the “Integrations” menu

PEP & Sanction screening without IDV

PEP & Sanctions, adverse media screening without identity verification

Prerequisites

A non-IDV integration with PEP & Sanctions checks configured together with optional adverse media checks and ongoing monitoring. Turn to your dedicated Solutions Engineer for configuration.

Process overview

  1. Generate a new verification session using the /sessions endpoint and specify the following fields in the request:
    a. First name (required)
    b. Last name (required)
    c. Date of Birth (optional)
  2. Change the status of the session to “Submitted” using PATCH /sessions/{sessionId} endpoint
  3. The results will be sent in a separate webhook and are also available using the /watchlist-screening end-point.
    a. The Webhook PEP & Sanctions URL can be configured from the “Integrations” menu

UK DIATF

Veriff is a certified IDSP under the UK Digital Identity and Attributes Trust Framework (UK DIATF), UK Government site[↗]

Within the framework of UK DIATF, we offer the following solutions:

UKDIATF Certified Identity Verification (M1A)

This is a solution that is completed using Veriff’s end-user flow (cannot be customized). Sending the address on session creation is optional.

Below is a step-by-step overview of the flow.

Step 1: create a session using the POST /sessions endpoint

See the POST /sessions section for a detailed overview of how to create a session. Sending the verification.address.fullAddress parameter is optional.

Step 2: create a session using the POST /sessions endpoint

Open the response payload of the POST /sessions request you just made and use the URL in the verification.url parameter. A web flow will start, which will guide you through the process.

Step 3: wait for session decision and decision webhook response

As soon as the session is verified, the decision webhook will send the response with session status. It will be one of 9000-code statuses.

In case the session is declined, the webhook contains relevant info about the reason. This info is visible in verification.code, verification.reason, and verification.reasonCode parameters.

M1A webhook response

M1A Webhook response = decision webhook response (see documentation here)

UKDIATF Certified Identity Verification (M1B)

This is a solution that requires that the end-user's address is provided to return info from registries, and that the flow must be completed using Veriff's verification flow (cannot be customized). Below is a step-by-step overview of the flow.

Step 1: create a session using the POST /sessions endpoint

See the POST /sessions section for a detailed overview of how to create a session. Sending the verification.address.fullAddress parameter is mandatory.

Step 2: capture user pictures and videos via verification flow

Open the response payload of the POST /sessions request you just made and use the URL in the verification.url parameter. A web flow will start, which will guide you through the process.

Step 3: wait for session approval and decision webhook response

As soon as the session is approved, the decision webhook will send an approved response.

This response will include the session status, as well as all the data that was extracted from the UK DIATF checks. This info is visible in verification.additionalVerifiedData.UKTFCheckResult array.

In case the session is declined, the webhook contains relevant info about the reason. This info is visible in verification.code, verification.reason, verification.reasonCode and verification.additionalVerifiedData.UKTFCheckResult parameters.

M1B webhook response

Response properties explained

Example response of approved session

{
    "status": "success",
    "verification": {
        
        "additionalVerifiedData": {
            "UKTFCheckResult": {
                "CIFAS": "Registry validation was successful",
                "Electoral roll and Credit History UK": "Registry validation was successful"
                "PEP": "Registry validation was successful",
            }
        }
    },
    
}

Example responses of declined session due to failed CIFAS check

Scenario: there may be a possible match in the CIFAS database

{
    "status": "success",
    "verification": {
        
        "additionalVerifiedData": {
            "UKTFCheckResult": {
                "CIFAS": "CIFAS registry detected a potential match.",
                "Electoral roll and Credit History UK": "Registry check did not result in a match"
                "PEP": "Registry check was not executed",
            }
        }
    },
    
}

Example responses of declined session due to UK Electoral Roll and Credit History check

Scenario: the end-user data may be incorrect or missing in the database

{
    "status": "success",
    "verification": {
        
        "additionalVerifiedData": {
            "UKTFCheckResult": {
                "CIFAS": "Registry validation was successful",
                "Electoral roll and Credit History UK": "Registry check did not result in a match"
                "PEP": "Registry check was not executed",
            }
        }
    },
    
}

Example responses of declined session due to failed PEP check

Scenario: end-user detected as potential PEP

{
    "status": "success",
    "verification": {
        
        "additionalVerifiedData": {
            "UKTFCheckResult": {
                "CIFAS": "Registry validation was successful",
                "Electoral roll and Credit History UK": "Registry validation was successful"
                "PEP": "Person detected to be potentially a PEP",
            }
        }
    },
    
}

UKDIATF Certified Identity Verification (L1B)

The solution is a UK-certified version of Veriff’s standard identity verification. You must use Veriff’s end-user flow to capture the document & selfie, but you can customize the flow.

If you are not integrated with us yet, see the Getting started with Veriff for first steps. If you are, contact your Solutions Engineer for info and configuration.

Age Estimation

This solution estimates end-user's age from the selfie images that they capture. Customers receive the end-user's estimated age and estimated gender.

Age Estimation process overview

There are two different ways to utiliaze the Age Estimation service: via Veriff's verification flow or trough API.

Age Estimation via Veriff's verification flow

  1. Create a session using the Age Estimation integration's tokens (see POST /sessions for more details about how to create a session)
    • You can use vendorData or endUserId parameter to pass a unique identifier for the end-user in the flow. We require only non-semantic data to be submitted (e.g. UUID-s that can not be resolved or used outside the customer's environment).
  2. Direct the end-user into the verification flow
  3. The end-user passes through the verification flow on their device, where they are required to capture only a selfie (no ID document is needed)
  4. Session will be automatically set to submitted
  5. Receive the results from Veriff via decision webhook; you can also query them using GET sessions/{sessionId/decision}

Age Estimation over the API

  1. Create a session using the Age Estimation integration's tokens (see POST /sessions for more details about how to create a session)
    • You can use vendorData or endUserId parameter to pass a unique identifier for the end-user in the flow. We require only non-semantic data to be submitted (e.g. UUID-s that can not be resolved or used outside the customer's environment).
  2. Upload the end users selfie via POST sessions/{sessionId}/media endpoint with image.context as face
  3. Patch the session to submitted using the PATCH sessions/{sessionId}
  4. Receive the results from Veriff via decision webhook; you can also query them using GET sessions/{sessionId/decision}


In the webhook and the endpoint, the data is in:

*Values closer to 0.0 indicate that the end-user is likely to be male, values closer to 1.0 indicate that the end-user is likely to be female.

Age Estimation session decisions

The verification.status and verification.code can be:

End-user in the Age Estimation flow (diagram)

Proof of Address Capture

Proof of Address Capture (PoA Capture) feature captures the submitted document. No further analysis is performed.

The flow is completed using several IDV endpoints.

Brief overview of the flow

  1. Submit a session using the POST sessions endpoint
  2. Make a POST /sessions/{sessionId}/media request to send image file
  3. Update the session status to "submitted" using the PATCH /sessions/{sessionId}
  4. Now you can now use the following endpoints to query the document info:
    • GET /sessions/{sessionId}/media
    • GET /attempts/{attemptId}/media
    • GET /media/{mediaId}

Step-by-step overview of the flow

Click on the step to expand.

Proof of Address Extraction

Proof of Address Extraction (PoA Extraction) feature captures the submitted document and extracts the firstName, fullAddress and document.validFrom data from it.

The flow is completed using several IDV endpoints.

It is possible to get the additional name match check enabled for your integration. See the Optional Proof of Address name match check section below for more info.

Brief overview of the PoA Extraction flow

  1. Submit a session using the POST sessions endpoint
  2. Make a POST /sessions/{sessionId}/media request to send image file
  3. Update the session status to "submitted" using the PATCH /sessions/{sessionId}
  4. Wait for the session to be approved and decision webhook to send response
  5. Now you can now use the following endpoints to query the document info:
    • GET /sessions/{sessionId}/media
    • GET /attempts/{attemptId}/media
    • GET /media/{mediaId}

Step-by-step overview of the PoA Extraction flow

PoA Extraction step 1: submit a session using the POST /sessions endpoint

See the POST /sessions section for detailed overview of how to create a session.

PoA Extraction step 2: make a POST /sessions/{sessionId}/media request

You can use this endpoint to send any number of image files (also for purposes other than PoA Extraction), but you need to upload them one at a time. Also, if you post several image files, make sure that the value of image.context parameter of the image relevant to the PoA Extraction flow is "document-front", otherwise the PoA Extraction flow will not work.

Request

Request method: POST
Media type: application/json
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
X-HMAC-SIGNATURE: string (required) = Request body signed with the shared secret key
Content-Type: application/json


Request properties explained


Sample request body

curl -X POST \
  --url '/v1/sessions/aea9ba6d-1b47-47fc-a4fc-f72b6d3584a7/media' \
  -H 'Content-Type: application/json' \
  -H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
  -H 'X-HMAC-SIGNATURE: 034c6da2bb31fd9e6892516c6d7b90ebe10f79b47cfb3d155d77b4d9b66e1d53' \
  -d '{
    "image": {
        "context": "document-front",
        "content": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA+.../9fgAEAKcxisFjVfn0AAAAASUVORK5CYII="
    }
}'

PoA Extraction step 3: update the session status to "submitted"

Use the PATCH sessions/{sessionId} endpoint to update the session status to "submitted". See the endpoint's description for detailed overview of how to update the session status.

Once done, an event webhook with submitted status will be sent. See the "Verification webhooks" section in Event webhooks for more info.

PoA Extraction step 4: wait for session approval and decision webhook response

As soon as the session is approved, the decision webhook will send an approved response. This response will include the session status, as well as all the data that was extracted from the PoA document.


Webhook payload

Request properties explained

Sample request

{
    "status": "success",
    "verification": {
        "id": "ab1c2345-678d-4e3b-98a3-a75b00b715kj",
        "code": 9001,
        "person": {
            "gender": null,
            "idNumber": null,
            "firstName": "Jane Doe",
            "lastName": "null",
            "addresses": [
                {
                    "fullAddress": "Jaan Koorti 777, 99999 Tallinn, Estonia"
                }
            ],
            "citizenship": null,
            "dateOfBirth": null,
            "nationality": null,
            "yearOfBirth": null,
            "placeOfBirth": null,
            "pepSanctionMatch": null
        },
        "reason": null,
        "status": "approved",
        "comments": [],
        "document": {
            "type": null,
            "number": null,
            "country": null,
            "validFrom": "2022-11-25",
            "validUntil": null
        },
        "reasonCode": null,
        "vendorData": null,
        "endUserId": "fa820aba-019f-455a-ae81-cfca8075bc3f",
        "decisionTime": "2023-01-23T10:31:05.293000Z",
        "acceptanceTime": "2023-01-23T10:25:40.026Z",
        "additionalVerifiedData": {
            "proofOfAddress": {
                "nameMatch": true
                "nameMatcPercentage": "100.00"
            },
        },
    },
    "technicalData": {
        "ip": null
    }
}

PoA Extraction step 5: use endpoints to query PoA document info

When the steps above have been successfully completed, you can use the following endpoints to query the document info:

Optional Proof of Address name match check

In order to do the Proof of Address name match check, you can add the optional parameters person.firstName and person.lastName to the POST /sessions request payload.

If the check has been enabled, and you have sent us the first name and last name data, the check will be performed. The results are displayed in decision webhook response, in additionalVerifiedData.proofOfAddress object, more specifically in proofOfAddress.nameMatch and proofOfAddress.nameMatchpercentage strings. If the check has been enabled, but you do not send us the name data, the strings will be null.

Sample POST /sessions request payload to do the optional name match check

Request method: POST
Media type: application/json
Type: object
Headers:
X-AUTH-CLIENT: string (required) = API key
Content-Type: application/json

curl -X POST \
  --url '/v1/sessions/' \
  -H 'Content-Type: application/json' \
  -H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
  -d '{
    "verification": {
        "person": {
            "firstName": "John",
            "lastName": "Smith",
        },
    }
}'

Sample decision webhook payload

The explanation and sample below show only the part of the payload that is relevant to the name match check. To see the full decision webhook response related to Proof of Address check, see the PoA Extraction Webhook payload section above.

Request properties explained

Sample response

{
    "status": "success",
    "verification": {
        ...
        "additionalVerifiedData": {
            "proofOfAddress": {
                "nameMatch": true
                "nameMatcPercentage": "100.00"
            },
        },
    },
    ...
}

INE Biometric Database Verification

Veriff INE Biometric Database Verification aka INE Biometric Validation is a check required for establishing identity in the Mexican market.

INE Biometric Validation prerequisites

INE Biometric Validation flow

  1. Create a identity verification session for the end-user. Make sure to include the consent.
  2. Collect and pass the end-user's data and media:
    • If using the SDK solution, direct the end-user to the flow and wait for them to get approved
    • If you have collected end-user's data and images yourself, pass them using the API endpoints
  3. Veriff verifies the end-user
  4. Check the verification results from decision webhook and/or GET /decision API call response

When generating a session for INE Biometric Database Verification purposes, in the verification object include the consents array with type: ine and approved: true attributes (as shown below). true is mandatory to start the INE Biometric Validation. If false or missing, the session is not created.

Below is an excerpt from the request payload, to highlight the relevant attributes. For full view of the payload, see the POST /sessions documentation.

curl -X POST \
  --url '/v1/sessions/' \
  -H 'Content-Type: application/json' \
  -H 'X-AUTH-CLIENT: API-PUBLIC-KEY' \
  -d '{
    "verification": {
        "callback": "https://veriff.com",
        "consents": [
            {
                "type": "ine",
                "approved": true
            }
        ],
        ...
    }
}'

How to find results in the decision webhook?

You will find the INE Biometric Validation check results in the decision webhook request payload, as additionalVerifiedData.ineBiometricRegistryValidation object.

Below is an excerpt from the request payload, to highlight the relevant attributes. For full view of the payload, see the decision webhook documentation.

Request properties explained

Sample request

{
    "status": "success",
    "verification": {
        ...
        "additionalVerifiedData": {
            "ineBiometricRegistryValidation": {
                "faceMatch": true,
                "faceMatchPercentage": 89,
                "responseStatus": "success"
            },
          ...
        },
        ...
    }
}

How to find results in the GET /decisions response?

You will find the INE Biometric Validation check results in the GET /decision API call response, as additionalVerifiedData.ineBiometricRegistryValidation object.

Below is an excerpt from the response payload, to highlight the relevant objects. For full view of the payload, see the GET /decisions response documentation.

Response properties explained

Sample response

{
    "status": "success",
    "verification": {
        ...
        "additionalVerifiedData": {
            "ineBiometricRegistryValidation": {
                "faceMatch": true,
                "faceMatchPercentage": 89,
                "responseStatus": "success"
            },
          ...
        },
        ...
    }
}

Reference Info, Codes, Tables

Verification session status and decision codes

Session status

Session Status Code Sent by Description
Started 7001 Event webhook The end-user has started their session and landed in our verification flow.
No decision is available yet.
Submitted 7002 Event webhook The end-user has submitted the requested data in the verification flow.
No decision is available yet.
Approved 9001 Decision webhook The end-user was verified. The verification process is complete.
Accessing the sessionURL again will show the end-user that nothing is to be done here.
Declined 9102 Decision webhook The end-user has not been verified. The verification process is complete.
Either it was a fraud case or some other severe reason that the end-user could not be verified. You should investigate the session further and read the reason and decision codes. If you decide to give the end-user another try, you need to create a new session..
Resubmission
aka resubmission_requested
9103 Decision webhook Resubmission has been requested. The verification process has not been completed.
Something was missing from the end-user, and they need to go through the flow once more. The same sessionURL can and should be used for this purpose.
Expired/Abandoned 9104 Decision webhook Verification has been expired (a session will expire 7 days after having been created unless it gets a conclusive decision before that). The verification process is complete.
If the end-user started the verification process, the response shows abandoned. If the end-user has never accessed the verification, the status will be expired. If you decide to give the end-user another try, you need to create a new session.
Review 9121 Decision webhook Note that this status is sent only when you have implemented the fully automated verification flow.
Review status is issued whenever the automation engine could not issue a conclusive decision and the verification session needs to be reviewed by a human on your side.

Responses 9001, 9102, 9121 and 9104 are conclusive responses. The session is closed and the sessionURL is not available for the end-user.

Response 9103 is an inconclusive response. The session remains open until you receive one of the above conclusive responses. The session is re-opened for the end-user, accepting a new attempt.

Additional info can be found in our Knowledge base article [↗] (requires a login to the Veriff environment)

Verification decision: declined

This table contains values for verification.reasonCode in case the verfication.status returned declined. If you do not see the reason code you received here, see also granular reason codes

Code Description
102 Suspected document tampering
103 Person showing the document does not appear to match document photo
105 Suspicious behaviour
106 Known fraud
108 Velocity/abuse duplicated end-user
109 Velocity/abuse duplicated device
110 Velocity/abuse duplicated ID
112 Restricted IP location
113 Suspicious behaviour - Identity Farming

Verification decision: resubmission required

This table contains values for verification.reasonCode in case the verfication.status returned resubmission_requested. If you do not see the reason code you received here, see also granular reason codes

Note about the number of resubmissions: one user can resubmit their data up to 9 times. This means that the 10th attempt is automatically declined, and code 539 - Resubmission limit exceeded is sent. If you wish to allow the end-user to retry verification, you need to create a new session for them (see POST sessions for info).

Code Description
201 Video and/or photos missing
204 Poor image quality
205 Document damaged
206 Document type not supported
207 Document expired

Common HTTP status codes

Code Value Description
200 status: success, data Returned as a general "OK" code
201 status: created, data Returned when creating a session
400 status: fail
code: 1102
Mandatory parameters are missing from the request
See the troubleshooting codes table
401 status: fail Not authorized
404 status: fail Entry not found
409 status: conflict Returned when you try to upload media to a session that was already updated to submitted status
500 status: fail Something went wrong

Credentials and authorization codes

Code Description
1801 Mandatory X-AUTH-CLIENT header containing the API key is missing from the request
1802 API key is not a valid UUID
1803 Integration with the API key was not found
1804 Integration with the API key is not active
1812 Signature is not a valid SHA256 hash
1813 Signature does not match the SHA256 hash of query ID and integration API secret
1814 Signature does not match the SHA256 hash of request body and integration API secret
1818 Signature does not match the HMAC-SHA256 of query ID and integration API secret
1819 Signature does not match the HMAC-SHA256 of request body and integration API secret

Some troubleshooting codes

Code Description
1001 Query ID must be between 20 and 40 symbols.
1002 Query ID must be a valid UUID V4
1003 Query ID must be unique, it has already been used.
1102 Mandatory parameters are missing from the request.
1104 Request includes invalid parameters.
1201 Invalid timestamp. Timestamp must not be older than one hour.
1202 Timestamp format is incorrect. YYYY-MM-DDTHH:MM:S+Timezone Offset|Z or UTC.
1203 Invalid ISO 8601 date. Date needs to be in format YYYY-MM-DD.
1301 Requested features are not supported.
1302 Only HTTPS return URLs are allowed.
1303 Invalid status.
1304 Cannot transition to "$STATUS" status.
1308 ID number is missing.
1309 SSN validation requires person firstName + lastName OR fullName to be provided.
1310 "SSN validation requires person.dateOfBirth or address data to be provided.
1400 Image data not found.
1401 Image is not in valid base64.
1402 Image context is not supported.
1403 Image property is missing.
1500 vendorData field cannot be more than 1000 symbols. We require only non-semantic data to be submitted (UUID-s etc., that can not be resolved or used outside the customer's domain)
1501 vendorData must be a string. We require only non-semantic data to be submitted (UUID-s etc., that can not be resolved or used outside the customer's domain)
2003 Date of birth is not a valid date.
2101 Document number has to be between 6 and 9 characters.
2102 Document number may contain only characters and numbers A-Z, 0-9.
2103 Document type is not supported.
2104 Document from provided country is not supported.

Granular reason codes

The granular reason codes (hereinafter the GRC) mentioned here are subject to custom configuration on integration level, meaning that you may or may not receive all the reason codes listed here.

GRC verification decision: declined

This table contains values for verification.reasonCode in case the verfication.status returned declined.

Code Description
101 Physical document not used
102 Suspected document tampering
103 Person showing the document does not appear to match document photo
105 Suspicious behaviour
106 Known fraud
108 Velocity/abuse duplicated end-user
109 Velocity/abuse duplicated device
110 Velocity/abuse duplicated ID
112 Restricted IP location
113 Suspicious behaviour - Identity Farming
120 Person on the portrait does not appear to match reference photo
121 User ID missing
122 No reference found
123 Unable to pass registry checks
126 Potential PEP match
127 Face match with blocklist
502 Multiple parties present in session
503 Attempted deceit
504 Attempted deceit, device screen used
505 Attempted deceit, printout used
507 Presented document tampered, data cross reference
508 Presented document tampered, document similarity to specimen
509 Person showing the document does not match document photo
510 Presented document type not supported
511 Presented document expired
515 Attempted deceit, device screen used for face image
526 Attempted deceit, photos streamed
527 Unable to collect proof of address data
528 Proof of address issue date too old
530 Person is under 13 years old
531 Person is under 14 years old
532 Person is under 16 years old
533 Person is under 18 years old
534 Person is under 20 years old
535 Person is under 21 years old
536 Person is under 25 years old
537 Unable to perform document media portrait cropping
539 Resubmission limit exceeded
540 Low confidence score for the session
541 Name on document does not match with name in session initialisation data
542 Unable to validate CPF
543 Reference face image has poor quality
544 Regisry did not respond
545 Reference image missing
546 Face image quality insufficient
547 Face missing
548 Attempted deceit, with face reference missing
549 NFC validation failed

GRC verification decision: resubmit

This table contains values for verification.reasonCode in case the verfication.status returned resubmission_requested.

Code Description
203 Full document not visible
602 Presented document type not supported
603 Video missing
605 Face image missing
606 Face is not clearly visible
608 Document front missing
609 Document back missing
614 Document front not fully in frame
615 Document back not fully in frame
619 Document data not visible
620 Presented document expired
621 Document annulled or damaged
625 Unable to collect surname
626 Unable to collect first names
627 Unable to collect date of birth
628 Unable to collect issue date
629 Unable to collect expiry date
630 Unable to collect gender
631 Unable to collect document number
632 Unable to collect personal number
633 Unable to collect nationality
634 Unable to collect home address
635 Document and face image missing
636 Presented document not real, screen used
637 Presented document not real, printout used
640 Person did not give consent
641 Multiple Faces Detected
642 Multiple Documents Uploaded
643 Unable to crop face image from a document front
644 Unable to collect Identificador de Ciudadano (INE)
645 Resubmit - Unable to collect OCR (IFE)
646 Unable to estimate age
647 Document not recognised
648 Technical issues
649 Unable to collect foreigner information
650 Unable to collect process number
651 Unable to collect occupation information
652 Unable to collect employer information
653 Unable to collect residence permit type
654 Unable to collect driver's license number
655 Unable to collect additional name
657 Open passport image missing
662 Unable to collect document remarks

Image context types

The context parameter in the request and response payload basically describes what the image or video was taken of, for example if the image/video is about the selfie (the end-users face), the document front or back, etc.

Veriff captures multiple images. The image with the -pre suffix is the first one, and the one without is the second image.

Identity verification process

Context label name Description
face Returns the selfie picture
face-pre Returns the selfie picture
face-nfc Returns the selfie picture extracted from the document's NFC chip
document-front Returns the picture of the ID document's front
document-front-pre Returns the picture of the ID document's front
document-front-qrcode Returns the picture of the ID document's front, to display the QR-code
document-front-qrcode-pre Returns the picture of the ID document's front, to display the QR-code
document-front-face-cropped Returns a cropped portrait image from a document
document-back Returns the picture of the ID document's back
document-back-pre Returns the picture of the ID document's back
document-and-face Returns the selfie with the the ID document's front
document-and-face-pre Returns the selfie with the the ID document's front
document-back-barcode Returns the picture of the ID document's back, to display the barcode
document-back-barcode-pre Returns the picture of the ID document's back, to display the barcode
document-back-qrcode Returns the picture of the ID document's back, to display the QR-code
document-back-qrcode-pre Returns the picture of the ID document's back, to display the QR-code
registry-face Returns the selfie picture extracted from a third party registry
face-reference Returns the selfie picture that is used as reference image

Proof of Address verification process

Context label name Description
address-front Returns the image of the address that's displayed on the Proof of Address document's front

Video context types

Context label name Description Platform
selfid_video Returns one video of the whole session, comprising the selfie, document front and document back videos Web flow and Native SDKs
face-pre-video Returns the selfie video only Native SDKs
document-front-pre-video Returns the video of the document's front only Native SDKs
document-back-pre-video Returns the video of the document's back only Native SDKs
document-and-face-pre-video Returns the selfie video with the document's front only Native SDKs
document-back-barcode-pre-video Returns the selfie video with the document's back to display the document's barcode only Native SDKs
document-front-qrcode-pre-video Returns the selfie video with the document's front to display the document's QR-code only Native SDKs
document-back-qrcode-pre-video Returns the selfie video with the document's back to display the document's QR-code only Native SDKs

Supported document types for IDV

In the Identity Verification process, the request and response bodies can display the document object. This contains the type string. The type can be one of the following document types:

If it's not possible to classify the document as one of the above, the response can show "type": "OTHER".

See also:

Document data fields

Abbreviation Field name Explanation
VIZ Visual Inspection Zone The data group of this zone includes the photograph, the document designation, personal data and the date of issue and validity of the document
MRZ Machine Readable Zone The two to three lines where the information from the viewing zone is strung together with alphanumeric characters and the "<" symbol
Barcode The barcode or the QR code on the document
NFC Near Field Communication Document's NFC chip

Media file mimetypes

In API responses, the mimetype parameter indicates the format of the media file.

Possible values are:

Reasons for different types of decisions

Preconditions for approval decisions

We give a positive conclusive decision (status approved, code 9001) when the end-user has provided us with:

Accessing the KYC session URL again will tell the end-user that nothing more is to be done.

Reasons for negative conclusive decisions

We give a negative conclusive decision (status declined, code 9102) when:

A negative decision means that the person has not been verified. The verification process is complete. Either it was a fraud case or some other severe reason that the person can not be verified. You should investigate the session further and read the "reason". If you decide to give the client another try you need to create a new session.

Reasons for inconclusive decisions

We give an inconclusive decision (status resubmission_requested, code 9103), when

Final decisions

You have the right to make the final decision about verifying an end-user even after they have completed the verification process with Veriff.

In order for you to make the final decision, we recommend you create an appropriate functionality in your back-end. This will enable you to either approve or reject applications after the person has completed Veriff’s verification session.

When you perform additional checks outside of Veriff’s service, it is necessary to have another layer of decision-making. The decision has to be motivated based on further checks or extra information independent of Veriff’s decision.

The additional verification details can be determined in accordance with your business needs and the amount of data and background information available to you about the end-user.

Potential use cases:

Veriff provides a more standardized solution where unconventional end-user behavior is not deferred to for the benefit of overall decision quality.

Storing verification media

For businesses which are regulated by various KYC and AML laws and rules, storing proof of the end-user's verification is often a requirement. While Veriff stores and holds the end-user's media - photos and videos - it might also be mandatory and more convenient for the business to store this media internally.

Downloading the photo and video files

  1. You need to get the sessionId of a session you want to download the media for. This can be found from the decision webhook (verification.id parameter), which is automatically sent after a decision has been made for a verification session.
  2. With the sessionId, make a GET request to /sessions/{sessionId}/media endpoint.
  3. From there, you will find a mediaId for every media file we have stored.
  4. With the mediaId-s, you can make a request to GET /media/{mediaId} endpoint to get the media file in .jpeg or .mp4 format.

Glossary

Term Context Definition Additional info
API Key Public API A unique identifier of an integration and a required parameter for authentication. It is used to create the X-AUTH-CLIENT header value for API requests. You can find it in Station > Integration's page (requires a Station login).
Occasionally, referred to as the API public key or Publishable key.
API request Public API A message sent to a server asking for the API to provide service or information. Also referred to as the API call.
API URL Public API An address that allows you to access an API and its various features. It consists of a BaseURL and an Endpoint. Also referred to as the API URL path.
Attempt ID Public API, Webhooks An UUID v4 of a specific attempt.
You can find its value in your GET /sessions/{sessionId}/attempts response, as verification.id.
In the API requests' context, an "attempt" is one step (uploading required data and getting a decision) inside a verification session, and it can be made several times during a verification session. This means that calling the GET /sessions/{sessionId}/attempts can return several verification objects, each one with a unique id value.
BaseURL Public API A "base address" for the specific API that you’re using.
Used to create the API URL value for API requests.
Found in Station > Integration page (requires a Station login).
Body Public API, Webhooks Data inside the request and response payloads in an API request. A GET request's payload does not contain a body.
Callback URL Public API URL address of the page where the end-user is sent after they have completed the web verification flow You can find its value in the response payload of your POST /sessions, as verification.callback. If the callback URL is not specified for the session, the end-user will be redirected to integration's default callback URL, which is visible in the Veriff environment > Integration > Settings tab. Changing the value in the POST /sessions request body will overwrite the default callback URL, but it will not change the callback URL that is visible in the Veriff environment
This does not yet contain any verification or decision info.
See here [↗] for more info about how to set it up.
Also referred to as the redirect URL.
Customer General Veriff's customer who is using our verification services. Occasionally, referred to as the vendor
Content-type header Public API Indicates the media type of the resource, in Veriff's context, usually "application/json".
Decision code General Numeric value representing the decision given to a verification session. See the Verification session status and decision codes for more info.
End-user General User of Veriff's customer's solution, the person who goes through the verification flow (aka the end-user flow).
endUserId General, Biometric Authentication A unique uuid created by the customer for their end-user. It is recommended for Biometric Authentication solutions, especially if you are not sending the vendorData field, but can be used for other solutions as well. It is always retruned unmodified in webhooks and public API calls, or as null if not provided. It must be uuid, no text or .json values are allowed.
It is stored by the customer, but also by Veriff for biometric authentication purposes. It must be usable only inside customer's environment and in relation to only the specific end-user. It is a great alternative to vendorData, especially if you are already using the UUID format to create unique end-user identifiers.
Endpoint Public API A specific “point of entry” in an API. You attach these to the end of your BaseURL, thus completing the API URL. The results that you'll get from the API request will depend on the Endpoint you attach.
You can find a list of endpoints in the Endpoints section.
Granular Reason Code General It is a kind of code which is sent depending on the configuration of the client's integration. See the Granular reason codes table for more info.
Headers Public API Mandatory elements in the API requests, containing the metadata.
IDV General Abbreviation of Identity Verification.
Integration Station An environment created according to client's needs to carry out, manage and observe verifications. Client can find the list of their integrations in Station > Integrations page on the top of the page (requires a Station login.
Live Integration General Integration which is created as per your requirements. It is used for production and verification sessions created will count towards paid usage. For live integration sessions, the sessions' statuses are set automatically. You need to define the Webhook decisions URL in Station (see here for instructions).
Payload Public API, Webhooks, SDK The data that you send when you make an API request, or that you receive when you get a response. In the API requests context, the hashed hex encoded payload is signed with the shared secret key to generate the X-HMAC-SIGNATURE.
PoA General Abbreviation of Proof of Address. See the article [↗] in the Knowledge Base for more info.
Reason code General Numeric value representing the reason for rejecting a verification session or for asking it to be resubmitted. See the tables here for more info.
Session status General A label describing the status of a verification session. See the table here for more info.
Session ID Public API, Webhooks A unique identifier of a verification session.
It is automatically created as soon as you create a session.
You can find its value in the response payload of your POST /sessions, as verification.id.
In the API requests' context, one verification session comprises many steps (uploading data, uploading images, getting a decision, etc.). You can call several endpoints using the same session ID, to get all kinds of different data from that specific session.
sessionToken Public API Session-specific token for a verification session.
You can find its value in the response payload of the POST /sessions, as verification.sessionToken.
It is a JSON Web Token (JWT) that consists of the session ID and the session creation timestamp. It should always have the variable max length type and must be able to accept data up to 8KB.
Session URL Public API, SDKs A combination of the base URL and the sessionToken, created as soon as a session is started.
You can find its value in the response payload of your POST /sessions, as verification.url.
This where the end-user is directed to go through the verification flow, and it is unique for each verification session.
Shared secret key Public API Required parameter for authentication, used to sign the payload to create the X-HMAC-SIGNATURE for API requests. This is a secret credential. You can find it in Station > Integration's page (requires a Station login).
Occasionally, referred to as the API private key or the Private key.
Test Integration General Integration which is automatically created for every client who onboards with Veriff. It is used for development purposes, and verification sessions that are created will not count towards paid usage. Veriff will not provide statuses for sessions created in test integration, you need to set them manually in the Station (see here for instructions). The Webhook decision URL is automatically created.
UUID General Abbreviation of the Universal Unique Identifier. It is a 128-bit value used to uniquely identify an object or entity on the internet. Must meet the regular expression pattern [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}.
UUID v4 General It is an UUID (see above) which has been created using a random number generator. In Veriff context, whenever a UUID is needed, it is the v4.
vendorData General A unique identifier of the end-user, created by the customer. It can be max 1,000 characters long and contain only non-semantic data, for example UUID-s etc., that can not be resolved or used outside your systems or environments. Veriff returns it unmodified in webhooks and API response payloads, or as null if it has not been provided.
It has many use-cases, but it is a recommended field to improve fraud mitigation solutions.
It is an alternative to endUserId if you have been creating the unique end-user identifiers in some non-UUID format.
See this article[↗] for more info (requires a signin to the Veriff environment).
Veriff Environment General Veriff customer back-office, a dashboard where the customers can see their end-users' verification data. Also referred to as Veriff Customer Portal, Veriff Station or Veriff Hub. See an introductory video here[↗].
Depending on your setup, you may be required to access the environment via station.veriff.com or hub.veriff.com. Please check your sign-up email to make sure that you log in via correct address.
Verification flow General A process where the end-user submits the data required to get verified. Also referred to as the end-user flow.
Verification session General One verification session from start to end, i.e., from the moment a session is created until the moment a conclusive decision (“approved”, “declined”, “expired”/”abandoned”) is granted. Each verification session receives an unique ID, aka the session ID used in the API request endpoints.
Verification session lifecycle General Umbrella term for the whole process of completing a verification process, comprising the stages completed by the client, the end-user, and Veriff.
Webhook Public API An event-triggered API, meaning that rather than sending information or performing a function as a response to an application's request, it performs this when a certain trigger event happens. There are different types of webhooks, see the Webhooks section for more info.
X-AUTH-CLIENT header Public API A mandatory header field in API requests, required to identify the request sender. Its value is the API Key (see above).
X-HMAC-SIGNATURE header Public API A mandatory header field in API requests, required to authenticate the request sender.
Its value is a HMAC-SHA256 hex encoded hashed value of the request payload that has been signed using a shared secret key known to both the sending and receiving party.
See the relevant API request in the API Reference section for more details about which payload to encode, and the X-HMAC-SIGNATURE section for more info about the signature itself.
X-SIGNATURE
Legacy solution
Public API A solution used before the X-HMAC-SIGNATURE header was implemented (see above).