Guide d'intégration : API
Votre backend ouvre un dossier, passe son jeton à votre application, puis lit la décision. Toutes les adresses de ce guide sont relatives à https://bazik.id.
Clés API
- Elles se créent dans la console partenaire, page Intégration, par un Propriétaire ou un Développeur. La clé complète ne s'affiche qu'une fois, à sa création : Bazik n'en garde que l'empreinte.
bz_test_…: environnement de test.bz_live_…: production, disponible une fois votre espace ouvert en production par Bazik (après le contrat).- Chaque appel de votre backend porte la clé dans l'en-tête
X-Api-Key. - Une clé révoquée cesse de marcher en moins d'une minute.
Les dossiers ouverts avec une clé de test restent à part : la console les montre quand vous choisissez Test en haut de l'écran. Les contrôles sont les mêmes qu'en production ; utilisez vos propres pièces de test, jamais celles de vrais clients.
1. Ouvrir un dossier
POST /v1/cases
X-Api-Key: bz_live_…
Content-Type: application/json
{ "reference": "CLI-48210" }
Le corps est facultatif. reference est votre référence du dossier (numéro de client, de demande) : vous la retrouvez dans la console et dans la réponse. Lettres, chiffres et . _ : - seulement, 64 caractères au plus : jamais un nom, un téléphone ou une donnée personnelle.
{
"case_id": "cas_7e3d90c2a41f5b08",
"access_token": "…",
"expires_at": "2026-11-10T14:42:03Z",
"reference": "CLI-48210"
}
Le jeton (access_token) ne vaut que pour ce dossier, pendant 30 minutes. Un dossier sans décision au bout de 30 minutes expire : ouvrez-en un nouveau pour recommencer.
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. Passer le jeton à l'application
Votre backend renvoie access_token à votre application, qui lance le parcours avec le SDK. L'application ne reçoit rien d'autre : ni la clé, ni la décision qui fait foi.
Sans le SDK (une application maison, un test), l'application appelle elle-même les trois routes ci-dessous, avec l'en-tête Authorization: Bearer <access_token>.
Envoyer les photos de la pièce
POST /v1/kyc/documents
Authorization: Bearer <access_token>
Content-Type: multipart/form-data
document_type = cin | passport
side = recto | verso (CIN) · data_page (passeport)
image = la photo, JPEG, 15 Mo au plus
Une face à la fois. La réponse est { "accepted": true }, ou { "accepted": false, "reason": "blurry" | "glare" | "unreadable" } : reprenez la photo. Au 3ᵉ essai de la même face, le serveur la garde telle quelle et laisse la décision trancher. Dès que le recto d'une CIN est lu, le registre national est consulté en arrière-plan.
Avec Accept: text/event-stream, la réponse arrive en direct : un événement check par contrôle terminé (document_visible, no_glare, text_readable, avec ok), puis result avec le même contenu que la réponse JSON.
Ouvrir la session selfie
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": "…"
}
Trois défis parmi blink (cligner), turn_left, turn_right, smile (sourire) et open_mouth (ouvrir la bouche), et deux pauses à respecter entre eux. La session dure 90 secondes et ne sert qu'une fois.
Envoyer le selfie
POST /v1/liveness/sessions/{session_id}/submit
Authorization: Bearer <access_token>
Content-Type: multipart/form-data
payload = JSON (ci-dessous)
frame_0, frame_1, … = les images clés, JPEG, 3 au moins, 12 au plus
{
"nonce": "le nonce de la session",
"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": ""
}
- Les temps sont en millisecondes depuis le début de la session.
shown_ms: quand le défi a été montré ;done_ms: quand le geste a été reconnu. eventssuit l'ordre des défis de la session. Un temps de réaction sous 120 ms, un défi hors d'ordre ou une session expirée mettent le dossier en revue.- Une image de face au début, puis une image clé par geste, au moment où il est fait : c'est sur ces images que le serveur revérifie les défis et compare les visages.
attestationetdevice_sig: l'attestation de l'appareil (Play Integrity). Sans elle, hors mode dev, le dossier part toujours en revue manuelle.
La réponse est { "outcome": "verified" | "manual_review" }. Elle n'est qu'indicative, pour l'écran de fin : la décision qui fait foi est celle que lit votre backend.
3. Lire la décision
GET /v1/cases/cas_7e3d90c2a41f5b08
X-Api-Key: bz_live_…
La réponse est 404 tant que la personne n'a pas envoyé son selfie. Ensuite :
| Champ | Contenu |
|---|---|
outcome | verified ou manual_review : c'est sur lui que vous agissez |
decision | accepter, revue ou rejet : le signal le plus strict. Un rejet donne toujours manual_review |
raisons | les contrôles qui n'ont pas accepté (registre, comparaison_document…) |
signaux | chaque contrôle : nom, issue et son détail |
document | les données lues sur la pièce (donnees) et la MRZ |
registre | la réponse de DELIDOC : statut du NINU, date de naissance, erreur éventuelle |
reference, document_type, recu_le | votre référence, cin ou passport, l'heure de la décision |
revue | présent une fois la revue manuelle tranchée dans la console, voir plus bas |
{
"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 } }
]
}
Les contrôles, du plus fréquent au plus rare en revue : registre (DELIDOC n'a pas répondu ou le NINU n'est pas actif), comparaison_document (ressemblance entre le selfie et la photo de la pièce), document (pièce à revoir, photo illisible après 3 essais), comparaison_registre (ressemblance avec la photo officielle), chronologie, integrite_session, visages_session.
Revue manuelle
Un dossier manual_review attend dans la page Revue manuelle de la console. Un Analyste ou le Propriétaire compare les visages, puis accepte ou refuse l'identité, avec un motif. Votre backend le lit dans le champ revue :
"revue": { "issue": "accepter", "motif": "registre_indisponible", "tranchee_le": "2026-11-10T14:15:09Z" }
issue:accepterourefuser.motif:visage_concordant,registre_indisponible,piece_verifiee_autrement(accepté) ;visage_different,piece_douteuse,selfie_inexploitable,autre(refusé).- Le champ n'apparaît qu'une fois la revue tranchée, et une revue ne se tranche qu'une fois.
Bazik n'informe jamais la personne d'un refus : c'est à vous de la recontacter.
Suivre l'avancement
GET /v1/cases/{case_id}/progress, avec la clé API, donne l'état de chaque étape (pièce, registre, selfie, décision) pendant le parcours, sans aucune donnée de la pièce. Il répond 404 une fois le dossier fermé. La réponse de GET /v1/cases/{case_id} contient "decision" dès qu'elle existe : c'est ce champ qu'il faut tester quand on interroge en boucle.
Erreurs
| Code | Cause | Que faire |
|---|---|---|
401 | clé absente, inconnue ou révoquée | vérifiez l'en-tête X-Api-Key |
403 | espace partenaire suspendu | contactez Bazik |
404 | dossier inconnu, d'un autre partenaire, ou pas encore décidé | attendez la fin du parcours, ou vérifiez l'identifiant |
422 | reference refusée | lettres, chiffres et . _ : - seulement |
429 | trop de dossiers ouverts cette minute | réessayez après la durée de Retry-After |
503 | vérification de la clé momentanément indisponible | réessayez dans un instant |
Un dossier d'un autre partenaire répond exactement comme un dossier qui n'existe pas.
En résumé
- La clé reste sur votre serveur ; l'application ne reçoit que le jeton du dossier.
- La décision qui fait foi est celle que lit votre backend, jamais celle qu'affiche l'application.
manual_reviewveut dire « en attente » : ni accepté, ni refusé, tant que la revue n'est pas tranchée.- La référence client n'est jamais une donnée personnelle.