Bazik ID Documentation Request access Partner console

Integration guide: API

Your backend opens a case, hands its token to your app, then reads the decision. Every address in this guide is relative to https://bazik.id.

API keys

Cases opened with a test key stay apart: the console shows them when you pick Test at the top of the screen. The checks are the same as in production; use your own test documents, never real customers'.

1. Open a case

POST /v1/cases
X-Api-Key: bz_live_…
Content-Type: application/json

{ "reference": "CLI-48210" }

The body is optional. reference is your own reference for the case (customer or application number): you find it in the console and in the response. Letters, digits and . _ : - only, 64 characters at most: never a name, a phone number or personal data.

{
  "case_id": "cas_7e3d90c2a41f5b08",
  "access_token": "…",
  "expires_at": "2026-11-10T14:42:03Z",
  "reference": "CLI-48210"
}

The token (access_token) is valid for this case only, for 30 minutes. A case without a decision after 30 minutes expires: open a new one to start over.

curl -X POST https://bazik.id/v1/cases \
  -H "X-Api-Key: $BAZIK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reference": "CLI-48210"}'

2. Hand the token to the app

Your backend returns access_token to your app, which runs the flow with the SDK. The app gets nothing else: neither the key nor the decision that counts.

Without the SDK (your own app, a test), the app calls the three routes below itself, with the Authorization: Bearer <access_token> header.

Send the document photos

POST /v1/kyc/documents
Authorization: Bearer <access_token>
Content-Type: multipart/form-data

document_type = cin | passport
side          = recto | verso         (CIN)   ·   data_page   (passport)
image         = the photo, JPEG, 15 MB at most

One side at a time. The response is { "accepted": true }, or { "accepted": false, "reason": "blurry" | "glare" | "unreadable" }: take the photo again. On the 3rd try for the same side, the server keeps it as is and lets the decision handle it. As soon as the front of a CIN is read, the national registry is looked up in the background.

With Accept: text/event-stream, the response comes live: a check event for each finished check (document_visible, no_glare, text_readable, with ok), then result with the same content as the JSON response.

Open the selfie session

POST /v1/liveness/sessions
Authorization: Bearer <access_token>
{
  "session_id": "ses_…",
  "nonce": "…",
  "challenges": ["blink", "turn_left", "smile"],
  "pauses_ms": [900, 1300],
  "issued_at": "2026-11-10T14:14:00Z",
  "expires_at": "2026-11-10T14:15:30Z",
  "server_sig": "…"
}

Three challenges among blink, turn_left, turn_right, smile and open_mouth, and two pauses to respect between them. The session lasts 90 seconds and can be used once.

Send the selfie

POST /v1/liveness/sessions/{session_id}/submit
Authorization: Bearer <access_token>
Content-Type: multipart/form-data

payload  = JSON (below)
frame_0, frame_1, …  = the key frames, JPEG, 3 at least, 12 at most
{
  "nonce": "the session's nonce",
  "frames": [{ "t_ms": 0, "part": "frame_0" }, { "t_ms": 2140, "part": "frame_1" }],
  "events": [{ "challenge": "blink", "shown_ms": 1200, "done_ms": 2100 }],
  "attestation": "",
  "device_sig": ""
}

The response is { "outcome": "verified" | "manual_review" }. It is only indicative, for the final screen: the decision that counts is the one your backend reads.

3. Read the decision

GET /v1/cases/cas_7e3d90c2a41f5b08
X-Api-Key: bz_live_…

The response is 404 until the person has submitted their selfie. Then:

FieldContents
outcomeverified or manual_review: this is what you act on
decisionaccepter, revue or rejet: the strictest signal. A rejet always gives manual_review
raisonsthe checks that did not accept (registre, comparaison_document…)
signauxeach check: nom, issue and its detail
documentthe data read on the document (donnees) and the MRZ
registreDELIDOC's answer: NINU status, date of birth, error if any
reference, document_type, recu_leyour reference, cin or passport, the time of the decision
revuepresent once the manual review has been decided in the console, see below
{
  "case_id": "cas_7e3d90c2a41f5b08",
  "reference": "CLI-48210",
  "outcome": "manual_review",
  "decision": "revue",
  "raisons": ["registre", "comparaison_document"],
  "signaux": [
    { "nom": "document", "issue": "accepter" },
    { "nom": "registre", "issue": "revue", "detail": { "statut": "non_consulte" } },
    { "nom": "comparaison_document", "issue": "revue", "detail": { "similarite": 0.31 } }
  ]
}

The checks, from the most to the least frequent in review: registre (DELIDOC did not answer, or the NINU is not active), comparaison_document (likeness between the selfie and the document photo), document (document to check, photo unreadable after 3 tries), comparaison_registre (likeness with the official photo), chronologie, integrite_session, visages_session.

Manual review

A manual_review case waits in the console's Revue manuelle (manual review) page. An Analyst or the Owner compares the faces, then accepts or refuses the identity with a reason. Your backend reads it in the revue field:

"revue": { "issue": "accepter", "motif": "registre_indisponible", "tranchee_le": "2026-11-10T14:15:09Z" }

Bazik never tells the person about a refusal: you contact them.

Following the progress

GET /v1/cases/{case_id}/progress, with the API key, gives the state of each step (document, registry, selfie, decision) during the flow, with no data from the document. It answers 404 once the case is closed. The response of GET /v1/cases/{case_id} holds "decision" as soon as it exists: that is the field to test when you poll.

Errors

CodeCauseWhat to do
401missing, unknown or revoked keycheck the X-Api-Key header
403partner space suspendedcontact Bazik
404unknown case, another partner's case, or not decided yetwait for the end of the flow, or check the id
422reference refusedletters, digits and . _ : - only
429too many cases opened this minuteretry after the Retry-After delay
503key check temporarily unavailableretry in a moment

Another partner's case answers exactly like a case that does not exist.

In short