Integrations

Python

Server-side steps in Python.

Prerequisites

  • A current Python with the cryptography and requests packages.
  • The secret key of the scenario and a permanent API token, read from environment variables. Never put them in browser code or in a repository.
  • The API address provided with your access.

The call sequence

  1. Your server encrypts the raw client key with the secret key of the scenario.
  2. Your page opens the widget with the scenario identifier and the encrypted client key.
  3. The user completes the steps in the widget.
  4. Your server learns of the result from the SESSION_COMPLETE webhook, or reads session status.
  5. Your server decides on the customer from the server-side status.

Encrypt the client key

The secret key of the scenario never leaves your server. See working with clientKey for the algorithm.

import base64
import hashlib
import os

from cryptography.hazmat.primitives import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes


def encrypt_client_key(client_key_raw: str, secret: str) -> str:
    # First 32 characters of the SHA-256 hash of the secret, written as hex.
    key = hashlib.sha256(secret.encode()).hexdigest()[:32].encode()
    iv = os.urandom(16)

    padder = padding.PKCS7(128).padder()
    data = padder.update(client_key_raw.encode()) + padder.finalize()

    encryptor = Cipher(algorithms.AES(key), modes.CBC(iv)).encryptor()
    ciphertext = encryptor.update(data) + encryptor.finalize()

    return base64.b64encode(iv + ciphertext).decode()   # the clientKey for the widget

Store the raw value with your user or order, so that you can match the result later.

Create a session and read it back

import os
import requests

API = os.environ["API_BASE_URL"]


def create_session() -> dict:
    reply = requests.post(f"{API}/kyc/session/create", json={
        "token": os.environ["API_TOKEN"],            # permanent API token
        "schemaId": os.environ["SCENARIO_ID"],       # scenario identifier
    })
    body = reply.json()
    if "sessionId" not in body:
        # A failure arrives as a body with status "error" or "failed".
        raise RuntimeError(f"session was not created: {body.get('status')}")
    return body                                      # body["status"] is the session status, "idle"


def session_status(session_id: str) -> dict:
    reply = requests.post(f"{API}/kyc/session/status", json={
        "token": os.environ["API_TOKEN"],
        "sessionId": session_id,
    })
    return reply.json()                              # branch on body["status"]

Branch on status, never on message text. See response format and errors and session statuses.

Ready-made scripts

The Python examples show authorization with a dashboard token and with a JWT, and downloading the images of a session.

Troubleshooting

SymptomWhat to check
The widget does not openThe domain is in the allowed domains, the page is on HTTPS, and the widget is not inside a cross-origin iframe. See installation.
The widget reports that decryption failedThe client key was not encrypted, or a different secret key was used, or the string was cut. See working with clientKey.
A call returns success but the body has an errorBranch on the status field of the body. See response format and errors.
The result never reaches your serverCheck the callback URL in the scenario. See webhooks.

Next: receive the result

Set up a webhook endpoint on your backend.

Receiving webhooks