IDify Sessions (API)

The go-to solution for using Datakeen's screens in your application

Verification of Identity documents is essential for onboarding processes and KYC compliance. It allows you to confirm the identity of an individual, ensuring that they are who they claim to be. This is vital for preventing identity fraud and building trust with your customers.

As a developer looking to integrate Datakeen's screens in your application you can generate a IDify link that you can send to your end customers in order for them to capture their identity card and take a selfie. Results are available by API.

📘

Please note that contrary to Off the Shelf APIs the host URL for IDify sessions is https://app.datakeen.co


I. Create sessions by API

1. Retrieve a new token (POST)

In order to retrieve a token you must make a POST call on the /auth endpoint. The token is valid 24h.

POST Request

curl --location 'https://app.datakeen.co/backend/auth' \
--header 'Content-Type: application/json' \
--data '{
    "username": string,
    "password": string
}'
const axios = require('axios');
let data = JSON.stringify({
  "username": string,
  "password": string
});

let config = {
  method: 'post',
  maxBodyLength: Infinity,
  url: 'https://app.datakeen.co/backend/auth',
  headers: { 
    'Content-Type': 'application/json'
  },
  data : data
};

axios.request(config)
.then((response) => {
  console.log(JSON.stringify(response.data));
})
.catch((error) => {
  console.log(error);
});


import http.client
import json

conn = http.client.HTTPSConnection("app.datakeen.co")
payload = json.dumps({
  "username": string,
  "password": string
})
headers = {
  'Content-Type': 'application/json'
}
conn.request("POST", "/backend/auth", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))

POST Answer

The POST answer is the following :

{
    "status": 200,
    "data": {
        "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2M2RhNzU4NGVmNWViYTAwMTIzNDRjOTciLCJmdWxsTmFtZSI6IkFkbWluIE9ueSIsImVtYWlsIjoiYWRtaW5AZGF0YWtlZW4uY29tIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNzI2NzM1MzUzLCJleHAiOjE3MjY4MjE3NTN9.PcdqdPstUO9ByVhkTuYRidmB-m-44M25SKykKs-FmKQ"
    }
}

2. Retrieve session templates (GET)

If you have more than one session template for your customers. For example :

  • Template 1 : verify identity document and selfie
  • Template 2 : verify identity document and proof of address

You can retrieve template ids with the following call :

📘

You must add a header with Authorization: Basic {token} to be authorized

GET Request

curl --location 'https://app.datakeen.co/backend/admin/templates'
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {token}'
const axios = require('axios');

let config = {
  method: 'get',
  maxBodyLength: Infinity,
  url: 'https://app.datakeen.co/backend/api/v1/session/{sessionId}',
  headers: { }
};

axios.request(config)
.then((response) => {
  console.log(JSON.stringify(response.data));
})
.catch((error) => {
  console.log(error);
});

import http.client

conn = http.client.HTTPSConnection("app.datakeen.co")
payload = ''
headers = {}
conn.request("GET", "/backend/api/v1/session/{sessionId}", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))

GET Answer

[
    {
        "templateKey": "67516435254355c29507d255",     
        "name": "Vérification Identité avec selfie",
        "default": true,
        "status": "active",
        "_id": "6747253f954e810012b37zer",
        "createdAt": "2024-11-27T13:57:19.752Z"
    },
    {
        "templateKey": "67516435254355c29507d266",
        "name": "Vérification Identité et Justificatif de domicile",
        "default": false,
        "status": "active",
        "_id": "6745fcdf34177200112cc345",
        "createdAt": "2024-11-26T16:52:47.731Z"
    }
]

The following fields are returned

  • templateKey : this field is a fix id of to the library template
  • _id : this field is the unique id of the template
  • default : is this template the default template true / false
  • status : "active" or "inactive"
  • createdAt : time of creation

3. Create a new session (POST)

A session corresponds to the verification of one client. Each session is single-use and comes with an expiration time of 1 hour. Once the expiration time has passed, you cannot perform ID verification using that session, and a new session must be created.

In order to retrieve a new session link (unique URL) you must make a POST call on the /session endpoint.

In option you can provide the following information : "templateId", "firstName", "lastName", "birthDate", "callbackURL", "webhookURL" and are detailed below :

POST Request

  • templateId [OPTIONAL] : STRING - the unique identifier of the template
  • firstName [OPTIONAL] : STRING - the first name of the person to verify
  • lastName [OPTIONAL] : STRING - the last name of the person to verify
  • birthDate [OPTIONAL] : STRING - the birth date of the person to verify ('dd/mm/yyyy' format)
  • callbackURL [OPTIONAL] : STRING - a URL to redirect the user when the session is over
  • webhookURL [OPTIONAL] : STRING -a URL to call when the session is over. The call made is a POST request with the following payload : {sessionId : ""}.
  • QR : BOOLEAN [OPTIONAL] - True/False. option to generate a QR Code. This QR Code redirects the user to the unique session URL.

Authentication

📘

You must add a header with Authorization: Basic {token} to be authorized

curl --location 'https://app.datakeen.co/backend/api/v1/session' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {token}' \
--data '{
    "QR": boolean,
    "firstName": "JEAN",
    "lastName": "DUPONT",
    "birthDate": "01/01/1970",
    "webhookURL": "https://google.com",
    "callbackURL": "https://google.com"
}'
const axios = require('axios');
let data = JSON.stringify({
  "QR": boolean,
  "firstName": `${firstname}`,
  "lastName": `${lastName}`
});

let config = {
  method: 'post',
  maxBodyLength: Infinity,
  url: 'https://app.datakeen.co/backend/api/v1/session',
  headers: { 
    'Content-Type': 'application/json', 
    'Authorization': 'Basic {token}'
  },
  data : data
};

axios.request(config)
.then((response) => {
  console.log(JSON.stringify(response.data));
})
.catch((error) => {
  console.log(error);
});


import http.client
import json

conn = http.client.HTTPSConnection("app.datakeen.co")
payload = json.dumps({
  "QR": True,
  "firstName": "alex",
  "lastName": "bdt"
})
headers = {
  'Content-Type': 'application/json',
  'Authorization': 'Basic {token}'
}
conn.request("POST", "/backend/api/v1/session", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))

POST Answer

{
    "status": 200,
    "message": "Magic Link",
    "data": {
        "link": "https://app.datakeen.co/client/test?sessionId=662f5f9c9c18e30012c2f021",
        "sessionId": "662f5f9c9c18e30012c2f021",
        "QRCode": "data:image/png;base64,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"
    }
}

You will receive a link to access the session, along with a sessionId and a QR code encoded in base64 if set to true.


4. Get the result of an IDify session by sessionId (GET)

You can retrieved the result of a past session with it's id.

📘

You must add a header with Authorization: Basic {token} to be authorized

GET Request

curl --location 'https://app.datakeen.co/backend/api/v1/session/{sessionId}'
--header 'Content-Type: application/json' \
--header 'Authorization: Basic {token}'
const axios = require('axios');

let config = {
  method: 'get',
  maxBodyLength: Infinity,
  url: 'https://app.datakeen.co/backend/api/v1/session/{sessionId}',
  headers: { }
};

axios.request(config)
.then((response) => {
  console.log(JSON.stringify(response.data));
})
.catch((error) => {
  console.log(error);
});

import http.client

conn = http.client.HTTPSConnection("app.datakeen.co")
payload = ''
headers = {}
conn.request("GET", "/backend/api/v1/session/{sessionId}", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))

GET Answer

The list of codes are the following :

Code Code Name Description
1.0 ai_approved The document has been fully verified by the AI, it is valid and conform
2.2 readability The document could not be processed: Could not read textual information
2.4 missingMRZ The document could not be processed: The MRZ could not be found
2.5 missingPart The document could not be processed: One side of the document is missing
2.6 noIdFound The document could not be processed: Could not find any ID
3.0 expired The document has expired
4.0 toVerify We could not process all the controls on the given document, please review its authenticity
5.0 fraudulent At least one element on the document is suspected to be fraudulent
7.0 owner The owner of the document does not match the user input
8.0 specimen The document has been found in our specimen database

You will find below an example of an API answer :

{
    "id": "67eeb0948e593a00113f0963",
    "code": "1",
    "status": "ai_approved",
    "entities": [
        {
            "id": "67eeb0a68e593a00113f0980",
            "code": "1",
            "status": "ai_approved",
            "firstName": "JEAN",
            "lastName": "DUPONT",
            "birthDate": ""
        }
    ],
    "documents": [
        {
            "id": "67eeb0f48e593a00113f09a7",
            "code": "1.0",
            "type": "national_id_card_fr_2003",
            "status": "ai_approved",
            "extractedInformations": {
                "address": {
                    "confidence": 0.43034044685720474,
                    "value": "1 BOULEVARD DES CAPUCINES 750002 PARIS"
                },
                "birthCountry": {
                    "confidence": 0.9,
                    "value": "FR"
                },
                "birthDate": {
                    "confidence": 0.9017348030120296,
                    "value": "25.09.1990"
                },
                "birthDepartment": {
                    "confidence": 0.9,
                    "value": "75"
                },
                "birthPlace": {
                    "confidence": 0.8898096682009218,
                    "value": "PARIS 20E ARRONDISSEMENT"
                },
                "countryCode": {
                    "confidence": 0.9,
                    "value": "FR"
                },
                "deliveryDate": {
                    "confidence": 0.8680884299127136,
                    "value": "01.04.2021"
                },
                "deliveryDateMRZ": {
                    "confidence": 1,
                    "value": "04.2021"
                },
                "deliveryDepartmentMRZ": {
                    "confidence": 1,
                    "value": "94"
                },
                "expiryDate": {
                    "confidence": 0.8898178831756276,
                    "value": "31.03.2036"
                },
                "firstName": {
                    "confidence": 0.8196075294754301,
                    "value": "JEAN"
                },
                "firstName1": {
                    "confidence": 0.8196075294754301,
                    "value": "JEAN"
                },
                "firstName2": {
                    "confidence": null,
                    "value": ""
                },
                "firstName3": {
                    "confidence": null,
                    "value": ""
                },
                "firstNameMRZ": {
                    "confidence": 1,
                    "value": "DUPONT"
                },
                "fullName": {
                    "confidence": 0.7701102725721481,
                    "value": "JEAN DUPONT"
                },
                "gender": {
                    "confidence": 0.892943529614854,
                    "value": "M"
                },
                "genderMRZ": {
                    "confidence": 1,
                    "value": "M"
                },
                "idNumber": {
                    "confidence": 0.9587318960040534,
                    "value": "210494150111"
                },
                "idNumberMRZ": {
                    "confidence": 1,
                    "value": "210494150111"
                },
                "lastName": {
                    "confidence": 0.9396085868867488,
                    "value": "DUPONT"
                },
                "lastNameMRZ": {
                    "confidence": 1,
                    "value": "DUPONT"
                },
                "mrz": {
                    "confidence": 1,
                    "value":""
                },
                "nationality": {
                    "confidence": 0.9,
                    "value": "FR"
                },
                "nationalityMRZ": {
                    "confidence": 1,
                    "value": "FRA"
                },
                "spouseName": {
                    "confidence": null,
                    "value": ""
                }
            },
            "controlCategories": {
                "dataCoherency": {
                    "controls": {
                        "countryCodeConformity": {
                            "confidence": 1,
                            "value": true
                        },
                        "durationValidity": {
                            "confidence": 0.8789531565441706,
                            "value": true
                        },
                        "matchDeliveryDateMRZ": {
                            "confidence": 0.9,
                            "value": true
                        },
                        "matchFirstNameMRZ": {
                            "confidence": 0.95,
                            "value": true
                        },
                        "matchLastNameMRZ": {
                            "confidence": 0.95,
                            "value": true
                        },
                        "matchNationalityMRZ": {
                            "confidence": 1,
                            "value": true
                        },
                        "mrzConformity": {
                            "confidence": 1,
                            "value": true
                        },
                        "notExpired": {
                            "confidence": 0.8898178831756276,
                            "value": true
                        },
                        "notSpecimen": {
                            "confidence": 1,
                            "value": true
                        }
                    },
                    "status": true
                },
                "input": {
                    "controls": {
                        "matchFirstName": {
                            "confidence": 0.8,
                            "value": true
                        },
                        "matchFullName": {
                            "confidence": 0.8,
                            "value": true
                        },
                        "matchLastName": {
                            "confidence": 0.8,
                            "value": true
                        }
                    },
                    "status": true
                },
                "metadata": {
                    "controls": {
                        "notMultipleVersions": {
                            "confidence": null,
                            "value": null
                        },
                        "notSuspectedSoftware": {
                            "confidence": null,
                            "value": null
                        }
                    },
                    "status": null
                },
                "visual": {
                    "controls": {
                        "initialsIsPresent": {
                            "confidence": 0.7879152297973633,
                            "value": true
                        },
                        "mrzVisualConformity": {
                            "confidence": 0.8,
                            "value": true
                        },
                        "photoIsPresent": {
                            "confidence": 0.9749646186828613,
                            "value": true
                        },
                        "rfSymbolIsPresent": {
                            "confidence": 0.2181098908185959,
                            "value": true
                        },
                        "stampIsPresent": {
                            "confidence": 0.928052544593811,
                            "value": true
                        },
                        "waveIsPresent": {
                            "confidence": 0.8638243675231934,
                            "value": true
                        }
                    },
                    "status": true
                }
            },
            "metadata": [
                {
                    "author": null,
                    "created_date": null,
                    "creator": null,
                    "file": "idcard_0.png",
                    "keywords": null,
                    "modified_date": null,
                    "producer": null,
                    "subject": null,
                    "title": null
                },
                {
                    "author": null,
                    "created_date": null,
                    "creator": null,
                    "file": "idcard_1.png",
                    "keywords": null,
                    "modified_date": null,
                    "producer": null,
                    "subject": null,
                    "title": null
                }
            ]
        },
        {
            "id": "67eeb1108e593a00113f09bf",
            "code": "1.0",
            "type": "photo",
            "status": "ai_approved",
            "extractedInformations": {},
            "controlCategories": {},
            "metadata": {}
        }
    ]
}

II. Common integrations into mobile applications

React Native

Here is an example of an integration of the session in React Native

For each client generate a session thanks to the create a new session API call.

Redirect the client to the given session in a web view, like so :

import WebView from "react-native-webview";

export function DatakeenScreen() {
  return (
    <WebView
      allowsInlineMediaPlayback
      source={{
        uri: "https://staging.datakeen.co/client/test?sessionId=6634a788316f3d00116c4378",
      }}
    />
  );
}

At the end of the session a webhook is called.

Flutter

Here is an example of an integration of the session in Flutter

import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

Widget buildWebView() {
  return WebView(
    initialUrl: 'https://staging.datakeen.co/client/test?sessionId=6634abb6316f3d00116c4578',
    javascriptMode: JavascriptMode.unrestricted,
  );
}