Skip to content

Flow Widget

Description#

The Flow Widget is a way to integrate a biometrics service into a client-side web application using an off-the-shelf solution in the form of a JavaScript library.

Using this integration method involves receiving a session on the created flow and then redirecting the end user to our server.

Below is a more detailed description of all the steps of the connection. You can also download the full example .

Note

The current version of the documentation covers plugging a widget into a HTML page.

Important

When using the Flow Widget integration, the Document Recognition V2 technology will not function.


Stages:#

1. Creating a Flow#

The first thing you need to do is to create a Flow in your personal account. To do this, go to this link.

Once the flow has been created it is necessary to use its API KEY in the second step. You can find the API KEY on the list of created flows page .

Simplified example of the table of personal account flows:
Flow name API KEY Technologies
Flow for everyone TTpme201NiUMBA... LD, F2F
Flow for individuals Efy202XKbVAWRu... LD, ED, F2F
Flow for legal entities UuuH4V1XC-M9je... LD, DR, F2F

Note

The following examples will use the first flow from the table above: "Flow for everyone".

Also, a shortened API KEY length is used for clarity. Its actual length is 47 characters or more.

2. Session Creation#

To work with the service you need to create a session. To do this, you need to send a POST-request to create a session, using the API KEY of the created flow. Read more about sessions here.

Requests to our service use only data in JSON format. Response data from the service will be presented in the same format.

Request URL:

https://kyc.biometric.kz/api/v1/flows/session/create/

Request format Request method
JSON POST

API KEY must be passed in the request body:

Field name Type Obligatorily Description
api_key String Yes API KEY of the created flow in the personal cabinet

Request examples:

curl --location --request POST 'https://kyc.biometric.kz/api/v1/flows/session/create/' \
--header 'Content-Type: application/json' \
--data-raw '{
"api_key": "YOUR_FLOW_API_KEY"
}'
import requests
import json

url = "https://kyc.biometric.kz/api/v1/flows/session/create/"

payload = json.dumps({
  "api_key": "YOUR_FLOW_API_KEY",
})
headers = {
  'Content-Type': 'application/json',
}

response = requests.request(
  "POST",
  url=url,
  headers=headers,
  data=payload,
)

print(response.json())
const apiKey = 'YOUR_FLOW_API_KEY' // flow api key

fetch('https://kyc.biometric.kz/api/v1/flows/session/create/', {
    method: 'POST',
    body: JSON.stringify({
        api_key: apiKey
    })
})
.then(response => response.json())
.then(data => {
    const { session_id, technologies } = data
})
const apiKey: string = 'YOUR_FLOW_API_KEY' // flow api key

interface SessionResponseData {
    session_id: string,
    technologies: string[]
}

fetch('https://kyc.biometric.kz/api/v1/flows/session/create/', {
    method: 'POST',
    body: JSON.stringify({
        api_key: apiKey
    })
})
.then(response => response.json())
.then(data => {
    const { session_id, technologies }: SessionResponseData = data
})

The response will be JSON with the following fields:

  • session_id - one-time session identifier to pass the flow;
  • technologies - an ordered set of flow technologies.

Response example:

{
  "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "technologies": ["LDHP", "F2F"]
}

Session lifetime

The session is valid for 30 minutes from the moment of creation. If the user does not complete the verification in time, a new session must be created.

2.1. Digital Signature based session creation#

If the session which is being created has Digital Signature technologies in the flow, the response will have a digital_signature object containing the check_id value. This value is used in QR-code generation, which is attached to the last page on the copy of the signed documents. Scanning it, short information of people who signed the documents can be received.

This value can be used to generate QR-code on one's own.

The URL which is encoded into QR-code:

https://remote.b-key.kz/kyc/check/{check_id}

Response example:

{
  "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "technologies": ["LDHP", "F2F"],
  "digital_signature": {
    "check_id": "2dc43214-5717-4123-abcd-2c721defcdba"
  }
}

3. Session Metadata#

When creating a flow, certain metadata can be included to facilitate a more flexible and dynamic process, as well as to simplify the verification procedure.

API KEY and metadata must be sent in the request body. The value for metadata is an object that includes an object with the technology name (face2face, edocument) consisting of metadata for the technology.

Field Name Type Required Description
api_key String Yes The API KEY of the created flow in the personal cabinet
metadata No Session metadata

Metadata for Face2Face technology:

Field Name Type Required Description
face2face No Metadata for Face2Face technology
photo1 String No Photo used for matching in base64 format

Metadata for E-Document technology:

Field Name Type Required Description
edocument No Metadata for E-Document technology
iin No IIN field
phone No Subject's phone number field, format: 77*********
value String No Field values
changeable Boolean No Ability for the user to change the data
skip_input Boolean No Skip user data input (Move to OTP code input step)

Interchangeable technologies

The list of interchangeable technologies (interchangeable_techs) is configured at the Flow configuration level in the personal cabinet, not in the session metadata.

Note

If metadata is absent, the flow will proceed by default.

3.1. Metadata for Face2Face#

If a user's face photo is available, it can be included in the session metadata. This helps simplify and shorten the verification process and prevent errors that might occur during user verification. The metadata field must be sent in the request body.

Important to Note

Face2Face technology metadata will only work for the following flows:

  • Liveness + Face2Face
  • E-Document + Face2Face
  • Document Recognition + Face2Face
Field Name Type Required Description
face2face No Metadata for Face2Face technology
photo1 String No Photo used for matching in base64 format

Request URL:

https://kyc.biometric.kz/api/v1/flows/session/create/

Request Format Request Method
JSON POST

Request Examples:

curl --location --request POST 'https://kyc.biometric.kz/api/v1/flows/session/create/' \
--header 'Content-Type: application/json' \
--data-raw '{
    "api_key": "YOUR_FLOW_API_KEY",
    "metadata": {
        "face2face": {
            "photo1": "base64"
        }
    }
}'
import requests
import json
import base64

url = "https://kyc.biometric.kz/api/v1/flows/session/create/"

with open('path/to/your/image.jpg', 'rb') as image_file:
    encoded_image = base64.b64encode(image_file.read()).decode('utf-8')

payload = json.dumps({
    "api_key": "YOUR_FLOW_API_KEY",
    "metadata": {
        "face2face": {
            "photo1": encoded_image,
        },
    },
})

headers = {
    'Content-Type': 'application/json',
}

response = requests.post(url=url, headers=headers, data=payload)

print(response.json())
const apiKey = 'YOUR_FLOW_API_KEY';
const imageFilePath = 'path/to/your/image.jpg'; // Path to your image

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

const imageBase64 = fs.readFileSync(path.resolve(imageFilePath), { encoding: 'base64' });

const payload = {
    api_key: apiKey,
    metadata: {
        face2face: {
            photo1: imageBase64
        }
    }
};

fetch('https://kyc.biometric.kz/api/v1/flows/session/create/', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify(payload)
})
.then(response => response.json())
.then(data => {
    const { session_id, technologies } = data;
})

The response will be a JSON with the following fields:

  • session_id - a one-time session identifier for passing the flow;
  • technologies - an ordered set of flow technologies.

Example response:

{
  "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "technologies": ["LDHP", "F2F"]
}

3.2. Metadata for E-Document#

If user data such as IIN, phone number, or presence in the Mobile Citizen Database is available, it can be sent to the input form when passing the EDocument technology. This helps simplify and shorten the verification process and prevent errors that might occur during user data entry. The metadata field must be sent in the request body.

Note

The skip_input field defaults to false (the data entry step is not skipped). The changeable field defaults to true (the user can change the data entry field values).

Field Name Type Required Description
edocument No Metadata for E-Document technology
iin No IIN field
phone No Subject's phone number field, format: 77*********
value String No Field values
changeable Boolean No Ability for the user to change the data
skip_input Boolean No Skip user data input

Request URL:

https://kyc.biometric.kz/api/v1/flows/session/create/

Request Format Request Method
JSON POST

Case №1:

Note

Skipping the user data entry step is only possible if:
1) value for iin and phone is provided
2) changeable for iin and phone is provided with a value of false
3) skip_input is provided with a value of true

The user data entry step will be skipped. The user will be redirected to the OTP code input step from 1414.

curl --location --request POST 'https://kyc.biometric.kz/api/v1/flows/session/create/' \
--header 'Content-Type: application/json' \
--data-raw '{
    "api_key": "YOUR_FLOW_API_KEY",
    "metadata": {
        "edocument": {
            "iin": {
                "value": "<subjects_iin>",
                "changeable": false,
            },
            "phone": {
                "value": "<subjects_phone>",
                "changeable": false,
            },
            "skip_input": true
        }
    }
}'
import requests
import json

url = "https://kyc.biometric.kz/api/v1/flows/session/create/"

payload = json.dumps({
    "api_key": "YOUR_FLOW_API_KEY",
    "metadata": {
        "edocument": {
            "iin": {
                "value": "<subjects_iin>",
                "changeable": False,
            },
            "phone": {
                "value": "<subjects_phone>",
                "changeable": False,
            },
            "skip_input": True
        },
})

headers = {
    'Content-Type': 'application/json',
}

response = requests.post(url=url, headers=headers, data=payload)

print(response.json())
const apiKey = 'YOUR_FLOW_API_KEY'; // Your flow API key
const subjectsIIN = '123456789012'; // Example user's IIN
const subjectsPhone = '77*********'; // Example user's phone number

fetch('https://kyc.biometric.kz/api/v1/flows/session/create/', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({
        api_key: apiKey,
        metadata: {
            edocument: {
                iin: {
                    value: subjectsIIN,
                    changeable: false,
                },
                phone: {
                    value: subjectsPhone,
                    changeable: false,
                },
                skip_input: true
            }
        }
    })
})
    .then(response => response.json())
    .then(data => {
        const { session_id, technologies } = data;
    })

Case №2:

At the data entry step, the user will see the values passed in the metadata fields, without the ability to change the IIN.

Note

The default value for changeable is true.
The default value for skip_input is false.

curl --location --request POST 'https://kyc.biometric.kz/api/v1/flows/session/create/' \
--header 'Content-Type: application/json' \
--data-raw '{
    "api_key": "YOUR_FLOW_API_KEY",
    "metadata": {
        "edocument": {
            "iin": {
                "value": "<subjects_iin>",
                "changeable": false,
            },
            "phone": {
                "value": "<subjects_phone>",
            }
        }
    }
}'
import requests
import json

url = "https://kyc.biometric.kz/api/v1/flows/session/create/"

payload = json.dumps({
    "api_key": "YOUR_FLOW_API_KEY",
    "metadata": {
        "edocument": {
            "iin": {
                "value": "<subjects_iin>",
                "changeable": False,
            },
            "phone": {
                "value": "<subjects_phone>",
            },
        },
})

headers = {
    'Content-Type': 'application/json',
}

response = requests.post(url=url, headers=headers, data=payload)

print(response.json())
const apiKey = 'YOUR_FLOW_API_KEY'; // Your flow API key
const subjectsIIN = '123456789012'; // Example user's IIN
const subjectsPhone = '77*********'; // Example user's phone number

fetch('https://kyc.biometric.kz/api/v1/flows/session/create/', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({
        api_key: apiKey,
        metadata: {
            edocument: {
                iin: {
                    value: subjectsIIN,
                    changeable: false,
                },
                phone: {
                    value: subjectsPhone,
                }
            }
        }
    })
})
    .then(response => response.json())
    .then(data => {
        const { session_id, technologies } = data;
    })

Case №3:

At the data entry step, the user will see the values passed in the metadata fields, with the ability to change the IIN and phone number.

curl --location --request POST 'https://kyc.biometric.kz/api/v1/flows/session/create/' \
--header 'Content-Type: application/json' \
--data-raw '{
    "api_key": "YOUR_FLOW_API_KEY",
    "metadata": {
        "edocument": {
            "iin": {
                "value": "<subjects_iin>",
            },
            "phone": {
                "value": "<subjects_phone>",
            }
        }
    }
}'
import requests
import json

url = "https://kyc.biometric.kz/api/v1/flows/session/create/"

payload = json.dumps({
    "api_key": "YOUR_FLOW_API_KEY",
    "metadata": {
        "edocument": {
            "iin": {
                "value": "<subjects_iin>",
            },
            "phone": {
                "value": "<subjects_phone>",
            },
        },
})

headers = {
    'Content-Type': 'application/json',
}

response = requests.post(url=url, headers=headers, data=payload)

print(response.json())
const apiKey = 'YOUR_FLOW_API_KEY'; // Your flow API key
const subjectsIIN = '123456789012'; // Example user's IIN
const subjectsPhone = '77*********'; // Example user's phone number

fetch('https://kyc.biometric.kz/api/v1/flows/session/create/', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({
        api_key: apiKey,
        metadata: {
            edocument: {
                iin: {
                    value: subjectsIIN,
                },
                phone: {
                    value: subjectsPhone,
                }
            }
        }
    })
})
    .then(response => response.json())
    .then(data => {
        const { session_id, technologies } = data;
    })

The response will be a JSON with the following fields:

  • session_id - a one-time session identifier for passing the flow;
  • technologies - an ordered set of flow technologies.

Example response:

{
  "session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "technologies": ["LDHP", "ED", "F2F"]
}

3.3. Metadata for Digital Signature#

For flows with Digital Signature technology, the signer's data can be pre-filled via the ds_identifier metadata object:

Field Name Type Required Description
ds_identifier No Metadata for Digital Signature technology
iin No Signer's IIN field
phone No Signer's phone number field, format: 77*********
value String No Field value
changeable Boolean No Ability for the user to change the data
skip_input Boolean No Skip user data input

Request body example:

{
  "api_key": "YOUR_FLOW_API_KEY",
  "metadata": {
    "ds_identifier": {
      "iin": { "value": "<subjects_iin>", "changeable": true },
      "phone": { "value": "<subjects_phone>", "changeable": true },
      "skip_input": false
    }
  }
}

4. Widget integration into a web application#

After successfully creating flow and generating session_id, you need to integrate the finished widget into the client side web application. Widget integration consists of the following steps:

4.1 Creating a container for a widget in a web application#

It is necessary to create a container inside which the generated HTML widget structure will be embedded. The container must have an id attribute with a unique value.

Styles that are based on the height and width of the container will be used inside the application. To display it correctly, create an additional container in which the application itself will be placed.

Example:

For the parent container, you must specify the width and height (not max-width/max-height, namely height and width). For the container of the application itself, it is worth setting height and width styles of 100% (see the example below). We strongly recommend running the widget in fullscreen mode, as shown in the example below. However, it is possible to run it in a window with fixed height and width in pixels for the desktop version, but it is not recommended to run it in a window for mobile versions of your application/web application.

For all cases, you should add styles overflow: scroll; and position: relative;

.flow-widget-container {
  width: 100vw;
  height: 100vh;
}
#flow-widget {
  width: 100%;
  height: 100%;
  position: relative;
  overflow: scroll;
}
<div class="flow-widget-container">
  <div id="flow-widget"></div>
</div>

4.2 Widget loading in a web application#

To load a JavaScript file into a web application, you must add a HTML script tag.

The script tag must contain a type attribute with a module value and a src attribute, which will contain the URL from which the JavaScript file will be loaded.

Currently, the file should be uploaded via the following URL https://remote.biometric.kz/widget/flow-widget.js

Example:

<script type="module" src="https://remote.biometric.kz/widget/flow-widget.umd.js"></script>

4.3 Starting the verification process in a web application#

If you need to start the verification process, you must call the startSession method from the FlowWidget library.

Since the current example considers plugging into a HTML page, another HTML tag script will need to be added to start the verification process, specifying the type attribute with a value of module.

The startSession method accepts a configuration object with the following fields:

Field name Type Description
session_id string Unique session identifier received from the server
selector string Identifier of HTML container in which the widget will be generated
locale string Optional. Language in which the widget should run, supported values: 'kz' | 'en' | 'ru' | 'my' | 'de' | 'es' | 'fa' | 'fr' | 'it' | 'ja' | 'kg' | 'ko' | 'pt'
localeList array Optional. Languages to show in the language switcher. The array must contain at least one supported language. If an unsupported language is included, when the end user selects it, the interface is shown in English.
isMobile boolean Optional. Force the device type (mobile/desktop) instead of auto-detection.
shadow boolean Optional. Defaults to false. When set to true, the widget is mounted into an isolated Shadow DOM, preventing CSS styles from leaking between the widget and the host page in either direction.

Style isolation via Shadow DOM

If the host application's global styles (e.g. a CSS framework) distort the widget's appearance — or, conversely, the widget's styles affect the page — enable the shadow: true option. The widget is mounted into an isolated Shadow DOM, and the styles stop clashing.

Unlike embedding via an iframe, Shadow DOM runs in the same origin, so access to the camera, gyroscope and other sensors is preserved with no extra host-side configuration.

Example:

<script type="module">
    FlowWidget.startSession({
      id: '<session_id>',
      selector: '#flow-widget',
      locale: 'ru',
      localeList: ['kz', 'en', 'ru'],
      shadow: true
    })
</script>

4.4 Catching widget termination#

At the end of its work the widget triggers an event called finish on the window object. The data collected by the frontend part of the widget is passed in the detail field of the event:

Field Type Description
aborted Boolean true if the flow was aborted because of a client-side failure
result Object Results collected by the widget during the flow. May be absent if the flow was completed via the QR mode — request the result via the API in that case

To catch this event you should add the following code:

<script type="module">
    window.addEventListener('finish', (data) => {
        console.dir(data.detail)
    })
</script>
As an example, we output the received data to the console, in your case you can work out the data on the received session by sending a request for the result.

QR mode

If the flow is configured with the QR option (show_qr) and no camera is found on the device — or the flow is marked as mobile-only (always_mobile) — the widget automatically displays a QR page instead of the camera view. The user scans the code and passes the verification on their phone while the widget polls the session status. The finish event is triggered as soon as the verification is completed on the mobile device — no additional integration code is required.

4.5 Getting the result#

To get the overall result of the sessions you can send a GET request to a special URL, passing the session identifier in the parameters:

Request URL::

https://kyc.biometric.kz/api/v1/flows/session/result/

Request format Request method
JSON GET

session_id must be passed in the request parameters:

Parameter Type Obligatorily Description
session_id String Yes flow session identifier
flow_api_key String Yes API KEY of the created flow in the personal cabinet that was used when creating the session

Request examples:

curl --location --request GET 'https://kyc.biometric.kz/api/v1/flows/session/result/?session_id=<session_id>&flow_api_key=<flow_api_key>'
import requests

url = "https://kyc.biometric.kz/api/v1/flows/session/result/"

params = {
  'session_id': '<session_id>',
  'flow_api_key': '<flow_api_key>,
}

response = requests.request(
  "GET",
  url=url,
  params=params,
)

print(response.json())

The response will be JSON with the following fields:

  • id - session identifier;
  • technologies - an ordered set of technologies according to the created flow;
  • liveness_result - Liveness passing result;
  • document_recognition_result - Document Recognition passing result;
  • face2face_result - Face2face passing result.
  • edocument_result - Edocument passing result

Important information

The fields liveness_result, document_recognition_result, face2face_result, edocument_result are displayed only if the client passed these technologies during Flow.

Response example:

{
  "id": "session_id",
  "technologies": [
    {
      "name": "Document Recognition",
      "description": "Parse document data from image"
    }
  ],
  "document_recognition_result": {
    "first_name": "First",
    "last_name": "Last",
    "patronymic": "Patronymic",
    "personal_number": "pers_number",
    "date_of_birth": "01.01.2000",
    "document_number": "doc_number",
    "authority": "authority"
    ...

Final connection example#

<div id="flow-widget"></div>
<script type="module" src="https://remote.biometric.kz/widget/flow-widget.umd.js"></script>
<script type="module">
    FlowWidget.startSession({
        id: '2569aadc-9ff2-4da3-a1c8-44057520e1d6',
        selector: '#flow-widget',
        locale: 'ru'
    })
    window.addEventListener('finish', (data) => {
        console.dir(data.detail)
    })
</script>