Identification Process#
End-to-end flow for identifying a user via the web-sdk API: sign in, create a
session, submit photos for async identification, then poll for the result.Base path (local): http://localhost:6007/api/web-sdkAll responses are wrapped in GenericResponse:{ "code": 200, "message": "OK", "data": { ... } }
1. Sign in — POST /v1/auth/sign-in#
Exchange client_id / client_secret for a bearer access token. Public
endpoint, no auth required.{
"client_id": "web-sdk-client",
"client_secret": "s3cr3t-value"
}
{
"code": 200,
"message": "OK",
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read write",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}
Use data.access_token as Authorization: Bearer <access_token> on every
call below. When it expires, exchange data.refresh_token via
POST /v1/auth/refresh instead of signing in again.
2. Create a session — POST /v1/sessions#
Opens a verification session and returns its id. Body is polymorphic on
client_type (WEB or MOBILE); include user_info to make the session
WITH_INFO (citizen data gets validated during identification).Headers: Authorization: Bearer <access_token>{
"client_type": "WEB",
"retry_count": 3,
"external_id": "ORDER-123",
"threshold": 0.7,
"locale": "UZ",
"additional_params": { "order_id": "123" },
"user_info": { "pinfl": "12345678901234", "id_number": "AA1234567", "birth_date": "01.01.1990" },
"ip_address": "192.168.1.10"
}
ip_address is required when client_type is WEB.{
"code": 200,
"message": "OK",
"data": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
data is the session id — carry it into every subsequent call.
3. Submit photos for identification — POST /v1/sessions/async/identify#
Runs the submitted selfie photo(s) through anti-spoofing + face comparison
against the session. At least one photo is required; user_info is
mandatory when the session was created WITH_INFO.This is a long-poll endpoint (DeferredResult, 3s timeout): if the
pipeline hasn't finished within 3s, it returns immediately with a
WAITING_ASYNC_PROCESS response instead of blocking the connection — poll
step 4 to get the final result.Headers: Authorization: Bearer <access_token>{
"session_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"photos": [
{ "sort_order": 1, "photo_base64": "/9j/4AAQSkZJRgABAQ..." }
],
"user_info": { "pinfl": "12345678901234", "id_number": "AA1234567", "birth_date": "01.01.1990" }
}
Response 200 (finished within 3s){ "code": 200, "message": "OK", "data": "3fa85f64-5717-4562-b3fc-2c963f66afa6" }
Response (still processing){ "code": <WAITING_ASYNC_PROCESS_CODE>, "message": "waiting for async process" }
Response 400 (spoofed image / below-threshold match){ "code": 400, "message": "Bad request", "errors": [{ "error_message": "spoofed file detected" }] }
A failed match (spoofed or below threshold) consumes one retry from the
session's remaining_retry_count.
4. Poll for the result — GET /v1/sessions/poll/status/{id}#
{id} = the session id from step 2. Same long-poll pattern as step 3 (3s
DeferredResult timeout) — call it repeatedly until you get a terminal
result instead of WAITING_ASYNC_PROCESS.Headers: Authorization: Bearer <access_token>{ "code": 200, "message": "OK", "data": "3fa85f64-5717-4562-b3fc-2c963f66afa6" }
Response (still processing) — same WAITING_ASYNC_PROCESS shape as
step 3; keep polling.Optional follow-ups after a terminal result:GET /v1/sessions/{id} — session snapshot (status, type, remaining retry count).
GET /v1/sessions/jobs/{id} — per-attempt job list with comparison values.
Flow summary#
sign-in (client_id/secret)
-> access_token
create session (access_token)
-> session_id
async/identify (access_token, session_id, photos[, user_info])
-> 200 result | WAITING_ASYNC_PROCESS
poll/status/{session_id} [repeat while WAITING_ASYNC_PROCESS]
-> final result
Modified at 2026-08-24 10:35:31