General introduction of SDK
Welcome to Verifai's technical documentation. Verifai provides software that verifies all types of ID documents from all countries. Our aim is to create a solution for every use case. What sets Verifai apart is our "privacy first" approach, which means that you are compliant straight out of the box. We won't dictate the process, but instead find ways to suit your needs. We do, however, also aim to offer the very best default settings. That way, you won't need to configure a lot to get started.
General overview of our approach
We think that a modular approach is the best way to do this. For instance, you might not need NFC. In that case, there is no reason to request dependencies and permissions from your users. For every feature that is not strictly related to the other, we have a "component". These components can be used independently and are supported by the "Core", an essential core component that contains the basics that are needed to communicate with our backend services, and is able to validate your licenses.
For example, you are running an electric scooter rental business (like Bird), and someone wants to sign up for your service. You want to check their driver's license, and verify the authenticity of that document using NFC.
- You direct the user to the Verifai Core component, and configure it to only accept driver's licenses.
- When the result is returned from the core, you see that the driver's license has an NFC chip, so you direct the user to that component (yes, you can really do that!).
- You check the NFC results, and see that
originality()
,authenticity()
,confidentiality()
all have a positive outcome. - Your new customer's driver's license has now been verified!
The components used in this example are linked together in the following way:
Components
Core
The Core is the main component of Verifai. Everything that is needed to scan documents and communicate with our backend services is available. It does everything that the other components can't and provides the foundation for all the other components to build upon.
The user flow is changed by setting certain requirements.
Let's say you need a copy of someone's ID and would like to use the MRZ contents to fast fill their name in a form. By default, this is all taken care of by the SDKs. However, if you do not require a copy of the ID, you can change the configuration so the user will take a different route through the SDKs and will not be confronted with unnecessary tasks and screens.
Example (high level) user flow:
Obviously, there is a lot more to it. To find out more, see the section about customization.
Copy ID
Using the camera, it can take a picture of the ID, and store that data. The data can be accessed after the scanning process has been completed. We always store the largest resolution available (on any platform). If the document has been classified, either manually or automatically, masking will also be applied.
In the example below (taken with an iPhone), you can see that the pictures have been blocked by the masking template.
Read the MRZ (Machine Readable Zone)
There are several standardized types of MRZs. Travel documents are standardized by ICAO. Verifai supports all documents that implement this standard.
Standards that we support are:
- TD1 (3x30): Typically an ID card (ICAO)
- TD2 (2x36): Intermediate format ID card (ICAO)
- TD3 (2x44): The Passport format (ICAO)
- MRV-A (2x44): VISA - Almost like TD3 format (ICAO)
- MRV-B (2x36): VISA - Almost like TD1 format (ICAO)
- Dutch Driver's License (1x30): Format of Dutch driver's licenses
- French ID Card (2x36) Alternative implementation of TD2
We also use the MRZ to see if we can find meta data about the document and to check whether the classification is correct.
In the Result processing section, you will find extensive documentation about the MRZ, the standards, and how to access the processed data.
NFC
Since the introduction of biometric passports many countries have integrated an NFC chip in their document. That chip can be read by the NFC component.
The chip is secured with a password (access key). That password can be found in the MRZ of the document.
Therefore, you can't access the NFC chip without reading the MRZ first. That is
why you need a VerifaiResult
to start the NFC component.
See the high level diagram below:
The chips also contain digital signatures over the data. All countries sign their documents using "Signing Certificates". We have an extensive database of certificates that allow us to verify the signatures. If the signatures are proven to be correct, you can safely assume the chip is authentic. The process is called Public Key Infrastructure (PKI) and is used all over the world to check data integrity.
We regularly update the certificates with publicly provided MasterLists.
In the Result processing section, you will find extensive documentation about NFC and how to check the results.
Liveness check
The liveness checks allow you to check whether the person whose document you're scanning actually is the one using the app at the moment. By using the Liveness check component, you can set up a few simple tasks that the user can perform to confirm that they are alive. We also built in 4 default checks that allow you to simply start the liveness check.
Available checks:
- Close eyes check: User is asked to close their eyes for two seconds
- Head tilt check (left, right or both): User needs to tilt head 15 deg
- Read text out loud: User is asked to pronounce the names of 3 types of fruits
- Selfie check: User is asked to take a selfie
In the Result processing section, you will find extensive information about the way the results of this check are processed.
Manual Data Crosscheck
The Manual Data Crosscheck is compatible with Verifai 3.1 and newer. This check guides the user to manually check the data that has been read from the machine readable zone (MRZ) with the data Visual Inspection Zones (VIZ). It can also let the user compare the picture from inside the NFC chip with the picture on the document.
Manual Security Features Check
Verifai's Manual Data Security Features Check lets the user check visible and invisible security features of a scanned document. It helps the user to distinguish counterfeit documents from real documents. Improving the security and reliability of manual document checks. Combined with the NFC validity check from the NFC module and the visual check from the Manual Data Crosscheck it will give perfect results.
The Manual Security Features Check will present checks of the following types:
- "Hold against the light"
- "Tilt the document"
- "Feel this area"
- "Check this"
- "Enlarge this area"
Hold against the light
The "Hold against the light"-check asks the user to hold the document against a light. Some documents allow you to see through them (through tiny holes). Certain security features or color changes then become visible.
Tilt the document
Some security features change color, reflections or an image when the document is tilted. This type of security feature check asks the user to tilt the document and shows what should change.
Feel this area
Lets the user feel a particular, in the screen highlighted, area to feel e.g. a pattern or "bold" text. Counterfeit documents mostly do not contain these tactile parts since these are difficult to fake.
Check this
Lets the user check a certain part of the document. The question will be stated on the screen.
Enlarge this area
Enlarges a part of the document to let the user check if a small security features, like a micro size printed text, are on the document and valid.
Threshold
The Verifai document database contains many security features. Each security features consists of a score between 0 and 1 (e.g. 0.35). It is possible to set a threshold, where the default is 1.0 when no threshold has been set, to prevent the user from checking for a long time. The checks are finished when the threshold has been met.
All checks are always presented in a random order, to keep the focus of the person that checks the document. Checks might differ every time, when there are more checks available than the threshold allows.
In the result processing section, you will find extensive information about the way the results of this security features check are processed.
Customization
We believe that every company is unique and therefore requires tailor-made changes to accommodate the use case in the SDKs. You can change quite a lot, ranging from the colors to the internal workings, by making your own validators and enabling or disabling certain features.
Validators
Every use case is different and our product has to fit around your process. That is why we have a validation system in place with which you can limit the amount of acceptable documents, and check the user input instantly. This sets Verifai apart from other solutions, which only let you check once the whole process has been completed.
We believe that this is the most user-friendly way, as it is very interactive.
The validators run immediately after taking a picture of the document, and just before the cropping screen.
When the document is scanned, an idModel
metadata object (as included in the result)
is fetched from our backend so it can determine whether certain data, like the type and country,
is allowed. When an MRZ has been read, an mrzData
object is create
(also like the result), so it can verify the checksums and/or the NFC key.
Here's what the process looks like:
Name | Arguments | Looks at | Description | Default enabled |
---|---|---|---|---|
CountryWhitelist | takes list of countries | idModel |
Checks if the document is on the whitelist | No |
CountryBlacklist | takes list of countries | idModel |
Checks if the document is on the blacklist | No |
HasMrz | - | idModel |
Checks if the IdModel has MRZ | No |
Types | takes list of types | idModel |
Checks for type based on IdModel | No |
MrzAvailable | - | mrzData |
Sees if there is a MRZ result | No |
NfcKeyWhenAvailable | - | Both | Checks for an MRZ result if there is an NFC chip in the document | No |
Build a custom validator
If you would like to build your own validator, you can! A validator has a generic interface that you can implement.
What we provide:
idModel
: The metadata of the model, like country or typemrzData
: The data read from the document, parsed and split out, like in the results
By using these two objects you can build your own validator. It doesn't matter what it all does, as long as these two are implemented:
validate()
function has to return a bool, True for valid,False
for invalid (breaking the validation chain)invalidMessage
string that has the error message, it gets displayed whenvalidate()
returnsFalse
Enabling and disabling features
By default, we route the user through all features we think are necessary to
reach the goal of getting a idModel
and mrzData
for you in the end.
However, there are some routes the user can take through the system that prevent this from happening. For example, the user could reach the "Take photo manually" screen and draw over it by hand. That way, you will receive the images but no metadata for the document or the MRZ (if applicable).
For this reason, you get access to configuration options that let you limit the freedom of the user, and force them through a route.
The settings you can change are:
Setting | Description | Adds validator | Default |
---|---|---|---|
enable_automatic |
Controls the automatic document recognition (Blue line) | - | True |
enable_post_cropping |
Controls the cropping interaction (Yellow line) | - | True |
enable_manual |
Controls if you can manually draw masking (Red line) | - | True |
require_document_copy |
If False , you won't go to automatic mode and correction screens |
- | True |
require_mrz_contents |
If True , it adds a validator and disables all docs without MRZ |
HasMrz | False |
require_nfc_when_available |
Adds an NFC key validator if the document has an NFC chip | NfcKeyWhenAvailable | False |
read_mrz_contents |
Lets you disable the MRZ OCR, which is useful if you only require a copy | - | True |
enable_auto_update |
If we check for Neural Network updates every time | - | True |
Recommended settings
We have several recommended settings to achieve a certain goal. The
enable_auto_update
setting is left out because it does not influence
functionality or the path the user takes.
Full functionality
If you don't adjust anything, this will be the standard configuration (default settings).
Setting | Value |
---|---|
enable_automatic |
True |
enable_post_cropping |
True |
enable_manual |
True |
require_document_copy |
True |
require_mrz_contents |
False |
require_nfc_when_available |
False |
read_mrz_contents |
True |
Quickly read the MRZ
Setting | Value |
---|---|
enable_automatic |
False |
enable_post_cropping |
False |
enable_manual |
False |
require_document_copy |
False |
require_mrz_contents |
True |
* please note that defaults are not displayed in the table, only the settings you need to change or set
Quickly read the NFC chip
Setting | Value |
---|---|
enable_automatic |
False |
enable_post_cropping |
False |
enable_manual |
False |
require_document_copy |
False |
require_mrz_contents |
True |
require_nfc_when_available |
True |
* please note that defaults are not displayed in the table, only the settings you need to change or set
Afterwards, you should add the HasNfc
validator to make sure a document
with NFC is scanned.
You can then use that data to run the NFC component.
Only photograph the ID
Setting | Value |
---|---|
read_mrz_contents |
False |
Disabling manual masking
Setting | Value |
---|---|
enable_manual |
False |
Styling and theming
Because every company has it's own style, you can set specific colors for almost every element in the SDK.
All colors used
Full overview, with names, colors and default values. By default, the "non-Main" colors inherit from another (Main) color.
Where | Name of color | Main color | Default | Inherits from | Filter |
---|---|---|---|---|---|
Main | PrimaryColor | Yes | #FF576D | ||
Main | SecondaryColor | Yes | #FFFFFF | ||
Main | PositiveColor | Yes | #5FB501 | ||
Main | NegativeColor | Yes | #FF576D | ||
Main | NavBarBackgroundColor | No | PrimaryColor | ||
Main | NavBarTextColor | Yes | #FFFFFF | ||
Viewfinder | CameraOverlayColor | Yes | #FFFFFF | ||
Viewfinder | DocumentScanHighlightColor | Yes | #FF576D | ||
Viewfinder | DocumentCropHighlightColor | Yes | #F5E216 | ||
Viewfinder | ScanHighlightTextColor | Yes | #FFFFFF | ||
Viewfinder | HintBoxBackgroundColor | Yes | #409ECA | ||
Viewfinder | HintBoxTextColor | No | NavBarTextColor | ||
Viewfinder | CameraHintBoxTextColor | No | CameraOverlayColor | ||
Viewfinder | CameraHintBoxBackgroundColor | Yes | #000000 | opacity 0.5 | |
Viewfinder | BlockedFieldColor | Yes | #000000 | opacity 0.5 | |
Viewfinder | MrzBoxHintBorder | No | DocumentScanHighlightColor | ||
Viewfinder | MrzBoxHintBackgroundColor | No | MrzBoxHintBorder | opacity 0.5 | |
Viewfinder | MrzBoxDetectedBorder | No | PositiveColor | ||
Viewfinder | MrzBoxDetectedBackgroundColor | No | MrzBoxDetectedBorder | opacity 0.5 | |
Viewfinder | CroppingOverlayColor | No | CameraHintBoxBackgroundColor | ||
Bottom | BottomBoxBackgroundColor | Yes | #212121 | ||
Bottom | BottomBoxTitleTextColor | Yes | #FFFFFF | ||
Bottom | BottomBoxImageTintColor | No | BottomBoxTitleTextColor | ||
Bottom | BottomBoxTextAreaBackgroundColor | No | BottomBoxTitleTextColor | opacity 0.15 | |
Bottom | BottomBoxTextAreaTextColor | No | BottomBoxTitleTextColor | ||
Bottom | BottomBoxImageLowlightTintColor | No | BottomBoxImageTintColor | opacity 0.5 | |
Bottom | BottomBoxImageHighlightTintColor | No | PrimaryColor | ||
Bottom | PaginationCircleColor | No | BottomBoxTitleTextColor | ||
Top | TopBoxBackgroundColor | Yes | #E6E6E6 | ||
Top | TopBoxImageTintColor | No | BottomBoxBackgroundColor | opacity 0.5 | |
Top | TopBoxTextColor | No | TopBoxImageTintColor | ||
Buttons | AffirmativeButtonBackgroundColor | No | PositiveColor | ||
Buttons | AffirmativeButtonTextColor | No | SecondaryColor | ||
Buttons | PrimaryButtonBackgroundColor | No | PrimaryColor | ||
Buttons | PrimaryButtonTextColor | No | SecondaryColor | ||
Buttons | PrimaryButtonImageTintColor | No | PrimaryButtonTextColor | ||
Buttons | InvertedButtonBackgroundColor | No | SecondaryColor | opacity 0.15 | |
Buttons | InvertedButtonTextColor | No | SecondaryColor | ||
Buttons | InvertedButtonBorderColor | No | SecondaryColor | ||
Buttons | InvertedButtonImageTintColor | No | InvertedButtonTextColor | ||
Buttons | AlternativeInvertedButtonBackgroundColor | No | PrimaryColor | opacity 0 | |
Buttons | AlternativeButtonBorderColor | No | PrimaryColor | ||
Buttons | AlternativeInvertedButtonTextColor | No | PrimaryColor | ||
Buttons | CameraButtonColor | No | SecondaryColor | ||
ListView | SearchBoxBackgroundColor | No | BackgroundColor | darken 0.15 | |
ListView | BackgroundColor | Yes | #FFFFFF | ||
ListView | TextColor | Yes | #000000 |
Implementation docs
iOS SDK
All documentation needed to integrate the Verifai iOS SDK can be found here:
Upgrade guides providing details on how to upgrade from previous iOS SDK versions can be found here:
Android SDK
All documentation needed to integrate the Verifai Android SDK can be found here:
Upgrade guides providing details on how to upgrade from previous Android SDK versions can be found here:
Windows Desktop SDK
Result processing
Quickstart
Introduction
When Verifai has completed its process, it will provide access to a
VerifaiResult
object. The object is a boiled-down version of all information
we have extracted from the document.
In general, there are a few major components to the result:
frontImage
: Picture of the front (bitmap or UIImage)backImage
: Picture of the back (bitmap or UIImage)mrzData
: The MRZ Data object, instance ofVerifaiMrzDataResult
(orVerifaiMRZModel
on iOS)idModel
: The ID Model for further processing, instance ofVerifaiDocumentResult
There are some functions in the VerifaiResult
as well, so you can access
crops of certain parts of the document, including the holder's picture.
If there is no need for a picture of the document, both of these
VerifaiResult:
frontImage: UIImage?
backImage: UIImage?
mrzModel: VerifaiMRZModel?
idModel: VerifaiDocumentResult?
Code example
VerifaiResult:
frontImage: Bitmap
backImage: Bitmap
mrzData: VerifaiMrzDataResult
idModel: VerifaiDocumentResult
Processing the pictures
The pictures are stored in the platform's main image format type. You can access them
with frontImage
or backImage
. Please note that the privacy sensitive data
is already removed from that image.
If there is no need for a picture of the document, both of these fields might be 'null'.
The picture is taken in the maximum size that the device supports. If you need a scaled version, you will need to take care of that yourself. The image is uncompressed, so you can work with the highest quality possible.
MRZ Data (VerifaiMrzDataResult
)
While a lot of data is stored in the MRZ, it does not include everything. We try to get as much out of the MRZ as we can, and provide you with the easiest way to interface with that data.
Below, you will find an example of a MRZ from a passport. It is 44 chars long and has two rows. As you can see, not all data on the card had a place in the MRZ.
Doc (2) | Country (3) | Surname << Given names (39) | |||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
P | < | U | T | O | E | R | I | K | S | S | O | N | < | < | A | N | N | A | < | M | A | R | I | A | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < |
Document Number (9) | Check (1) | Nationality (3) | Birthday (6) | Check (1) | Sex (1) | Expiry Date (6) | Check (1) | Optional Data (14) | Check (1) | Check (1) | |||||||||||||||||||||||||||||||||
L | 8 | 9 | 8 | 9 | 0 | 2 | C | 3 | 6 | U | T | O | 7 | 4 | 0 | 8 | 1 | 2 | 2 | F | 1 | 2 | 0 | 4 | 1 | 5 | 9 | Z | E | 1 | 8 | 4 | 2 | 2 | 6 | B | < | < | < | < | < | 1 | 0 |
The supported formats are:
Format | Size | Description |
---|---|---|
TD1 | 3x30 | Typically an ID card |
TD2 | 2x36 | Intermediate format ID card |
TD3 | 2x44 | The Passport format. The example above is TD3 |
MRV-A | 2x44 | VISA - Almost like TD3 format |
MRV-B | 2x36 | VISA - Almost like TD1 format |
EDL-NLD | 1x30 | Format of dutch driver's licenses |
ID-FRA | 2x36 | Alternative implementation of TD2 |
Not all fields are available for all types of MRZs. The format codes above are
referenced in the overview of fields in the mrzData
object.
Getting the MRZ data
See and example of how we access the MRZ data after a successful scan on the right. Note that you will only receive MRZ data if your configuration is setup to return it.
Accessing the MRZ data after a successful scan
do {
try Verifai.start(over: self) { result in
switch result {
case .failure(let err):
print("Error: \(err)")
case .success(let successResult):
// Continue with the result
let mrzData = successResult.mrzData
// Print the given names
print("Given names: \(mrzData?.givenNames)")
}
}
} catch {
print("🚫 Licence error: \(error)")
}
Data fields for all ICAO compatible documents
Property | Type | Description | Formats |
---|---|---|---|
mrzString |
str | Entire MRZ as read by OCR engine | All |
format |
str | Format of the MRZ read | All |
documentType |
str | Type of document, first char of MRZ | All |
documentSubType |
str | Second char of document type part | All |
countryCode |
str | 3 digit country code | All |
surname |
str | Surname of holder | TD1, TD2, TD3, MRV-A, MRV-B, ID-FRA |
givenNames |
str | Given names of holder | TD1, TD2, TD3, MRV-A, MRV-B, ID-FRA |
documentNumber |
str | Unique doc number | All |
documentNumberCheckDigit |
str | Check digit documentNumber |
TD1, TD2, TD3, MRV-A, MRV-B, ID-FRA |
nationality |
str | Nationality of holder | TD1, TD2, TD3, MRV-A, MRV-B |
dateOfBirth |
str | Date of birth of holder | TD1, TD2, TD3, MRV-A, MRV-B, ID-FRA |
dateOfBirthCheckDigit |
str | Check digit dateOfBirth |
TD1, TD2, TD3, MRV-A, MRV-B, ID-FRA |
sex |
str | Sex of holder | TD1, TD2, TD3, MRV-A, MRV-B, ID-FRA |
dateOfExpiry |
str | Expiration date of doc | TD1, TD2, TD3, MRV-A, MRV-B |
dateOfExpiryCheckDigit |
str | Check digit dateOfExpiry |
TD1, TD2, TD3, MRV-A, MRV-B |
optionalData |
str | Optional data (first one if there are two) | TD1, TD2, TD3, MRV-A, MRV-B |
optionalDataCheckDigit |
str | Check digit optionalData |
TD3 |
optionalDataTwo |
str | Additional Optional data | TD1 |
compositeCheckDigit |
str | Check digit of all fields | TD1, TD2, TD3, ID-FRA, EDL-NLD |
documentSpecificData |
obj | Key value list of extra available fields | ID-FRA, EDL-NLD |
firstName |
str | Alias of givenNames |
- |
lastName |
str | Alias of surname |
- |
Composed data
Not actual fields but convenient to access.
Property | Type | Description | Formats |
---|---|---|---|
nfcKey |
str | Key to access the NFC chip (might also be available on documents without a chip) | TD1, TD2, TD3, MRV-A, MRV-B |
Validation and read errors
Property | Type | Description | Formats |
---|---|---|---|
validityScore |
float | All checks passed will return a float 1.0 |
All |
isNfcKeyValid |
bool? | nfcKey fields read correctly |
TD1, TD2, TD3, MRV-A, MRV-B, EDL-NLD |
isDocumentCodeValid |
bool? | Document code (P, I, D) is valid for the MRZ | All |
isDocumentNumberValid |
bool? | documentNumber correct |
TD1, TD2, TD3, MRV-A, MRV-B, ID-FRA |
isDateOfBirthValid |
bool? | dateOfBirth correct |
TD1, TD2, TD3, MRV-A, MRV-B, ID-FRA |
isDateOfExpiryValid |
bool? | dateOfExpiry correct |
TD1, TD2, TD3, MRV-A, MRV-B |
isCompositeValid |
bool? | All fields correct | TD1, TD2, TD3, ID-FRA, EDL-NLD |
isOptionalDataValid |
bool? | optionalData correct (only TD3!) |
TD3 |
isDateOfIssueValid |
bool? | If the date of issue fields are correct | ID-FRA |
isLine1LengthValid |
bool? | First line length correct | All |
isLine2LengthValid |
bool? | Second line length correct | TD1, TD2, TD3, MRV-A, MRV-B, ID-FRA |
isLine3LengthValid |
bool? | Third line length correct | TD1 |
"bool?" means a nullable boolean
French ID specific (documentSpecificData
)
Property | Type | Description | Formats |
---|---|---|---|
departmentOfIssuance |
str | Issuing department doc | ID-FRA |
officeOfIssuance |
str | Issuing office doc | ID-FRA |
dateOfIssue |
str | Year and month of issue | ID-FRA |
Dutch driver's license specific (documentSpecificData
)
Property | Type | Description | Formats |
---|---|---|---|
driversLicenceVersion |
str | Version of driver's license | EDL-NLD |
driversLicenceRandomItem |
str | Random data | EDL-NLD |
driversLicenceChip |
str | Driver's license chip version (char 6) | EDL-NLD |
Document model (VerifaiDocumentResult
)
VerifaiDocumentResult object in JSON format
{
"uuid": "7dd168c5-4125-499c-b6a3-bba103ebab5f",
"type": "P",
"model": "NLD-AO-04002p",
"country": "NL",
"width_mm": 125.0,
"height_mm": 88.0,
"sample_front": "https://[...].jpg",
"has_mrz": true,
"mrz_type": "td3",
"mrz_start": "P<NLD",
"nfc_type": "emrtd",
"zones": [
{
"side": "FRONT",
"x": 0.32,
"y": 0.12,
"width": 0.04,
"height": 0.03,
"block": false,
"title": "DOCUMENT_TYPE"
},
{
"side": "FRONT",
"x": 0.36,
"y": 0.12,
"width": 0.06,
"height": 0.04,
"block": false,
"title": "COUNTRY_CODE"
}
]
}
We keep a record of (most) of the Passports, ID cards and Driver's Licenses in our database. For a current overview, please look at our website. Even if we are not familiar with the actual model, we are still able to return MRZ and NFC data objects.
The model contains some data that is not very relevant for most use cases. However, we have chosen to expose as much data as we can, as you might just be the one who does need it.
We have split the information up into three parts:
- General information: Generic data available for all documents
- Machine processing: All things needed to determine how to process the
document, like the
nfcType
andhasMrz
. - Zones:
zones
contains a list of coordinates and a description of what is on those coordinates
Field | Type | Example | Description |
---|---|---|---|
uuid |
str | 72bf03...265cdb6 |
Unique identifier in our database |
type |
str | "P" |
Internal ID Model type see list below |
model |
str | "NLD-AO-04002p" |
Name of document according to the naming schema |
country |
str | "NL" |
ISO 3166-1 alpha-2 country code |
widthMm |
float | 125.0 |
document width in millimetres |
heightMm |
float | 88.0 |
document height in millimetres |
sampleFront |
str | "https://....jpg" |
URL to preview image |
mrzType |
str | "td3" |
Type of MRZ on the document, see list below for types |
mrzStart |
str | "P<NLD" |
Document MRZ should start with this |
nfcType |
str | "emrtd" |
Protocol type in chip, see list below for types |
zones |
list | See example code | List of zones, see Zones section |
hasMrz |
bool | true |
Convenience function to check for a MRZ type zone |
Document Model VerifaiDocumentResult.type
list options
Value | Description |
---|---|
P |
Passport |
I |
ID Card |
D |
Driver's License |
R |
Refugee travel doc |
IT |
Residence Permit |
The VerifaiDocumentResult.model
naming schema
Every document in our database has a name that is partly generated.
If we take a document name (model
in the Document model), for
example NLD-AO-04002p
(Dutch Passport), we can split it up in its
individual parts.
Example | Position | Length | Description |
---|---|---|---|
NLD |
0-2 | 3 | Country code |
- |
3 | 1 | Divider |
A |
4 | 1 | Category (see possible options below) |
O |
5 | 1 | Kind (see possible options below) |
- |
6 | 1 | Divider |
04 |
7-8 | 2 | Series |
002 |
9-11 | 3 | Version |
p |
12 | 1 | Internal |
Possible options for "Category":
Value | Description |
---|---|
A |
Passport |
B |
Identity card |
C |
Visa |
D |
Stamp |
E |
Entry paper |
F |
Driver's license |
G |
Vehicle license/log book |
H |
Residence-related document |
I |
Seafarers\' identity document |
J |
Travel document issued to non-nationals |
K |
Train driver's license |
L |
Crew member certificate / pilot\'s license |
M |
Certificate for operators of pleasure crafts / captain\'s license |
P |
Civil status/other official document |
S |
Special authorisation card |
T |
Travel document |
V |
Authorisation to represent a company |
W |
Work permit |
X |
Other document |
Possible options for "Kind":
Value | Description |
---|---|
B |
Birth |
D |
Diplomatic |
E |
Entry stamp |
F |
Military |
I |
Social security card/tax card |
M |
Marriage |
N |
Nationality/citizenship |
O |
Ordinary document |
P |
Temporary/Provisional/Emergency |
R |
Divorce |
S |
Service/official |
T |
Death certificate |
X |
Exit stamp |
Y |
Related/associated document |
Document Model VerifaiDocumentResult.mrzType
options
Value | Description |
---|---|
td1 |
TD1 (ICAO), 3x30 chars |
td2 |
TD2 (ICAO), 2x36 chars |
td3 |
TD3 (ICAO), 2x44 chars |
id_fr |
French ID, 2x36 chars |
edl_nl |
Dutch Electronic Driver's license (NL), 1x30 chars |
Document Model VerifaiDocumentResult.nfcType
types
Value | Description |
---|---|
emrtd |
ICAO compliant NFC chip |
edl_nl |
Dutch Electronic Driver's license |
unsupported |
Has chip, but we don't support the protocol |
Document Model VerifaiDocumentResult.zones
items
All documents have zones
. Those zones contain a few fields so you know the
contents, and the location. Please note that is is a list of objects.
Field | Type | Description |
---|---|---|
title |
str | Value from the list of zones below |
side |
str | Side of document, either FRONT or BACK |
x |
float | Start position of zone on x-axis (left) |
y |
float | Start position of zone on y-axis (top) |
width |
float | Width in ratio with the entire width of document |
height |
float | Height in ratio with the entire height of document |
block |
bool | If we blocked the zone in processing |
List of zone types (title
in the zone object):
Value | Group | Description |
---|---|---|
BLOOD_TYPE |
Biometric | Blood type |
COLOR_EYES |
Biometric | Color of eyes |
COLOR_HAIR |
Biometric | Color of hair |
FINGERPRINT |
Biometric | Fingerprint |
SEX |
Biometric | Sex |
HEIGHT |
Biometric | Height |
PHOTO |
Biometric | Photo |
FACIAL_FEATURES |
Biometric | Facial features |
VIS_DIST_MARKS |
Biometric | Visible distinguishing marks |
GLASSES |
Biometric | Glasses |
WEIGHT |
Biometric | Weight |
DOCUMENT_NUMBER |
Document Details | Document number |
PREV_DOCUMENT_NUMBER |
Document Details | Previous document number |
CATEGORY |
Document Details | Category |
COUNTRY_CODE |
Document Details | Country code (Alpha-3) |
ISSUING_AUTH |
Document Details | Issuing authority |
ISSUING_COUNTRY |
Document Details | Issuing country |
MODIFICATIONS |
Document Details | Modifications |
NUMBER_ENTRIES |
Document Details | Number of entries |
NUMBER_REGISTRATION |
Document Details | No. of registration |
OBSERVATIONS_PAGE |
Document Details | Observations page |
PLACE_ISSUE |
Document Details | Place of issue |
REMARKS |
Document Details | Remarks / Notes |
STATUS |
Document Details | Status |
DOCUMENT_TYPE |
Document Details | Type of document |
DRIVERS_LICENSE_TYPE |
Document Details | Type of driver's license |
PERMIT_TYPE |
Document Details | Type of permit |
VISA_TYPE |
Document Details | Visa Type |
COSTS |
Document Details | Fee / Costs |
COPY |
Document Details | Copy |
RENEWAL_COUNT |
Document Details | No. of renewals |
REPLACEMENT_COUNT |
Document Details | No. of replacement |
TRAN_CODE |
Document Details | Tran. code |
ISSUE_NO |
Document Details | Issue No. |
CHILDREN |
Family | Children |
FATHER_NAME |
Family | Father's name |
MAIDEN_NAME |
Family | Maiden name |
MARITAL_STATUS |
Family | Marital status |
MOTHER_NAME |
Family | Mother's name |
SPOUSE_NAME |
Family | Name of spouse (Husband/Wife') |
BARCODE |
Machine Readable | Barcode |
CHIP |
Machine Readable | Microchip |
QR-CODE |
Machine Readable | QR-Code |
MRZ |
Machine Readable | MRZ |
CC |
Payment | Credit Card number |
CVC |
Payment | CVC |
CONTINUE_SURNAME |
Name | Continue surname |
FULL_NAME |
Name | Full Name |
GIVEN_NAME |
Name | Given name |
NAME_IN_NAT_LANGUAGE |
Name | Name in National Language |
SURNAME |
Name | Surname |
ALIAS |
Name | Alias (also known as) |
DATE_OF_BIRTH |
Personal | Date of birth |
DOMESTIC_DATE |
Personal | Date of domestication |
PERSONAL_IDENTITY_NO |
Personal | Personal/Identity number |
NATIONALITY |
Personal | Nationality |
RACE |
Personal | Race |
QUALITY/FUNCTION |
Personal | Quality/Function |
PLACE_OF_BIRTH |
Personal | Place of birth |
STATE_BIRTH |
Personal | State of birth |
BEARER_SIGNATURE |
Personal | Bearer's signature |
TITLE |
Personal | Title |
PHONE |
Personal | Telephone number |
INSURANCE_NUMBER |
Personal | Insurance number |
DONOR |
Personal | Donor State |
HOST_ORG |
Personal | Host Organization |
ALLERGIES |
Personal | Allergies |
ICE_CONTACT |
Personal | ICE / Emergency Contact |
PERM_MEDS |
Personal | Permanent medication |
STREET |
Residential | Living address |
MUNICIPALITY |
Residential | Municipality |
PLACE_LANDING |
Residential | Place of landing |
RESIDENCE |
Residential | Residence |
RESIDENT_SINCE |
Residential | Resident since |
STATE |
Residential | State |
DESTINATION |
Travel | Destination |
ENDORSEMENT |
Travel | Endorsement |
TRANSPORTATION |
Travel | Mode of transportation |
DATE_OF_DEPARTURE |
Travel | Date of departure |
ENTRY_PURPOSE |
Travel | Purpose of Entry |
DATE_OF_EXPIRY |
Validity | Date of expiry |
DATE_OF_ISSUE |
Validity | Issuing date |
DATE_OF_RENEWAL |
Validity | Renewal date |
DATE_OF_TEST |
Validity | Date of test |
DURATION_STAY |
Validity | Duration of stay |
DURATION_LICENSE |
Validity | Duration of license |
UNSPECIFIED |
Residential | Unspecified |
NFC Result
Once the process of NFC scanning is complete, you will receive the VerifaiNfcResult
.
It contains all the details from the chip in the document. Which data is available depends on
the configuration that you set up for the component. For example,
downloading the picture from the chip takes a long time. If you skip this step,
you can check the authenticity in a split second.
Validation and checks
When you use the NFC chip to check the authenticity of the document, you only
have to call three functions If they are all True
, you can assume the chip is valid,
and signed by the issuer.
Checking the validity of a document after an NFC scan
// Use result obtained earlier with `Verifai.start`
var result: VerifaiResult
do {
try VerifaiNFC.start(over: self, documentData: result, retrieveImage: true) { nfcResult in
switch nfcResult {
case .failure(_):
print("Error")
case .success(let nfcResult):
// Check the document validity
if nfcResult.originality && nfcResult.authenticity && nfcResult.confidentiality {
print("Document is valid")
} else {
print("Document is not valid or validity uncertain")
}
}
}
} catch {
print("🚫 Licence error: \(error)")
}
if nfc_result.originality() && nfc_result.authenticity() && nfc_result.confidentiality():
print('VALID')
else:
print('INVALID')
Originality, Authenticity and Confidentiality
In this more detailed section we provide you with more information about the chip and the process of validation.
To make sure the document and data is valid, you can use this triangle.
The first concerns the secure communication layer (confidentiality()
),
the second concerns gaining access to the chip data according to protocols
(originality()
) and the last concerns the integrity of the data itself
(authenticity()
). If you miss one of these checks, you cannot be sure the
data that has been read is not falsified.
Field | Type | Description |
---|---|---|
originality() |
bool | Did Chip Authentication and/or Active Authentication pass their checks |
authenticity() |
bool | Did the document signing, certificate, root certificate and passive authentication hashes checks all pass |
confidentiality() |
bool | Were the BAC and optionally the Chip Authentication successful |
Advanced Validation and checks
Field | Type | Description |
---|---|---|
mrzMatch |
bool | Does the MRZ from the OCR match the MRZ from the card |
comSodMatch |
bool | Does the EF.COM from the OCR match the datagroups in EF.SOd |
bacSuccess |
bool | Chip was accessed successfully, see bacStatus |
activeAuthenticationSuccess |
bool | Active authentication was performed successfully, see activeAuthenticationStatus |
chipAuthenticationSuccess |
bool | Chip authentication was performed successfully, see chipAuthenticationStatus |
documentSignatureCorrect |
bool | Is the document data signed by the certificate from the EF.SOd |
documentCertificateValid |
bool | Is the certificate valid (so not expired or revoked for example) |
signingCertificateMatchesWithParent |
enum | MATCH The signing certificate match with the parent or root in Verifai's database |
NO_MATCH Signing does not match with parent or root |
||
REVOKED Matches, but certificate has been revoked by the issuer |
||
NOT_FOUND There was no matching parent or root certificate found in Verifai's database |
||
NOT_CHECKED Check did not take place yet, or has been skipped |
||
scanCompleted |
bool | If the process of scanning completed. |
More details about the status of Basic Authentication, Active Authentication and Chip Authentication
Field | Type | Description |
---|---|---|
bacStatus |
enum | SUCCESS Chip was accessed successfully |
FAILED Failed to gain access to chip |
||
NOT_CHECKED Process has not been performed yet |
||
RANDOM_FAILED The chip did not return a challenge |
||
activeAuthenticationStatus |
enum | SUCCESS Active authentication was performed successfully |
SIGNATURE_FAILED Unable to verify the public key on the chip |
||
FAILED Active authentication failed |
||
NOT_PRESENT Active authentication not present on the chip |
||
NOT_CHECKED Active authentication process hasn't been performed |
||
chipAuthenticationStatus |
enum | SUCCESS Chip authentication was performed successfully |
FAILED Chip authentication failed |
||
NOT_PRESENT Chip authentication not present on the chip |
||
NOT_CHECKED Chip authentication process hasn't been performed |
Data in the chip
The ICAO has standardized the protocol, the data structure, and security mechanisms of eMRTD's in the Doc 9303 part 9, 10, 11 and 12. You can view those documents here: ICAO Doc 9303
Data fields in the chip
Not all data in the chip is readable for everyone. Examples include fingerprints. General available data includes the chip always contains a digital copy of the holder's passport photo and a digital version of the MRZ.
Field | Type | Description |
---|---|---|
photo |
Bitmap (or UIImage on iOS) | Photo of the document holder |
mrzData |
VerifaiMrzDataResult |
Parsed MRZ data from the MRZ copy in the chip |
Advanced data fields in the chip
If your use case requires even more data from the chip, we can expose all of it using the fields below.
Field | Type | Description |
---|---|---|
dataGroups |
list | list of LDS data objects |
documentCertificate |
str | DER formatted X.509 certificate from the document |
edlNlData |
object | See Dutch Driver's License section |
type |
enum | MRTD Standard ICAO compliant document |
EDL_NLD Dutch driver's license |
Detailed raw information:
Field | Type | Description |
---|---|---|
sodHashes |
list | list of bytes of hashes |
sodData |
bytes | raw SOD data |
featurePoints |
int | Number of feature points in the photo (DG5) |
mimeBytes |
bytes | MIME type of image (DG5) |
aaDigestAlgorithm |
str | Active Authentication digest algorithm type |
chipAuthenticationOid |
str | raw OID (like 2.16.840.1.101.3.4.2.1 ), see https://oidref.com for reference |
chipAuthenticationAgreementAlgorithm |
enum | <!-- TODO --> |
chipAuthenticationPublicKeyAlgorithm |
enum | <!-- TODO --> |
Additional data from Verifai backend (so not actually in the chip):
Field | Type | Description |
---|---|---|
signingCertificate |
str | DER formatted X.509 certificate from the Verifai backend |
LDS (Logical Data Groups)
Data in passports is stored in Logical Data Groups. For example, the photo is stored in DG2, and the MRZ in DG1. See ICAO Doc 9303p10 page 4 for more information.
Field | Type | Description |
---|---|---|
data |
bytes | The data read from the datagroup |
hash |
bytes | Digest of the data in the datagroup |
readStatus |
enum | SUCCESS The file has been read successfully |
FAILED Reading the file failed |
||
NO_ACCESS The file is protected, Verifai did not gain access |
||
FILE_NOT_FOUND The file has not been found on the MRTD |
Dutch driver's license specific (EdlNlData
)
The Dutch driver's license also contains a chip. However, in addition to the eMRTD standard fields, it contains more available fields. Below is a list of fields that are available:
Field | Type | Description |
---|---|---|
issuingMemberState |
str | The state issuing the driver's license |
surname |
str | The last name(s) of the document holder |
givenNames |
str | The first name(s) of the document holder |
dateOfBirth |
str | The date of birth of the document holder |
placeOfBirth |
str | The place of birth of the document holder |
dateOfIssue |
str | Date when the document was issued |
dateOfExpiry |
str | Date when the document expires |
issuingAuthority |
str | The authority that issued the document |
documentNumber |
str | The document's document number |
bsn |
str | The document holder personal number |
nationality |
str | The nationality of the document holder |
sex |
str | The document holder's gender |
surnameIcao |
str | The surname of the document holder in ICAO notation |
firstnameIcao |
str | The first name of the document holder in ICAO notation |
surnameGba |
str | The surname of the document holder in GBA notation |
firstnameGba |
str | The first name of the document holder in GBA notation |
placeOfBirthGba |
str | The place of birth of the document holder in GBA notation |
countryOfBirthGba |
str | The country of birth of the document holder in GBA notation |
firstNames |
str | Alias of givenNames |
lastName |
str | Alias of surname |
Liveness Check
Once the checks are completed, Verifai will return a VerifaiLivenessCheckResults
object, which contains a list of all the VerifaiLivenessCheckResult
(no s
)
objects. However, the checks now include 3 extra variables with the results:
Liveness check result object (VerifaiLivenessCheckResult
)
Field | Type | Description |
---|---|---|
automaticChecksPassed |
bool | If all checks have SUCCESS or UNDETERMINED status |
successRatio |
float | number of checks divided by number of SUCCESS status results |
resultList |
list | list of VerifaiLivenessCheckResult objects for further processing |
Liveness check result list items (VerifaiLivenessCheckResult
)
Every check produces such a result. It is composed of the original check with additional result fields.
Field | Type | Description |
---|---|---|
check |
VerifaiLivenessCheck |
Reference to the actual check provided at the start |
videoFile |
File | (Android only) The location of the video H.264 file including the audio |
recordingUrl |
URL? | (iOS only) The location of the result recording or image |
status |
enum | SUCCESS Check is successfully passed |
UNDETERMINED Check couldn't be validated automatically |
||
SKIPPED Check was skipped by the user |
Manual Data Crosscheck
The Manual Data Crosscheck will return all the field names that have been checked, and a boolean value that will indicated if check was passed or not.
Field | Type | Description |
---|---|---|
checks |
MutableMap<String,Boolean> (Android), [String: Bool] (iOS) |
A map with the name of every check and a boolean if the check has passed (or not) |
passedAll |
boolean | True when all checks are passed. False if one or more check(s) failed |
Manual Security Features Check
The result object of the Manual Security Features check is quite simple. The class where the object is an instance of is called VerifaiManualSecurityFeaturesCheckResult
. It contains three floats.
Field | Type | Description |
---|---|---|
maxScore |
float | The summed score of all available security feature checks |
score |
float | The score of the performed security feature checks |
threshold |
float | The threshold that has been set |
passed |
bool | (iOS only) Shorthand for score >= threshold |
Older versions of Verifai
- Mobile SDKs
- Windows desktop SDK