Référence de l'API Live ID

Points de terminaison de Live ID Validation — émettre une clé d'identification, créer une session de capture, ouvrir la page de capture hébergée, soumettre un selfie, interroger le résultat, et charge utile du webhook de validation.

Trois surfaces : la gestion des clés (authentifiée par session du tableau de bord, administrateur), le cycle de vie de la session (authentifié par clé et jeton de session, public) et le webhook. L'URL de base ci-dessous est l'hôte de votre locataire.

Les points de terminaison de session se trouvent sous /api/kyc/public/live-id et ne sont pas authentifiés par clé d'API : ils sont protégés par la clé d'identification (création) ou par le jeton de session à usage unique (validation / interrogation), et limités en débit par adresse IP.

Émettre une clé d'identification

POST /api/kyc/live-id/:orgSlug/keys    Authentification : session du tableau de bord (administrateur / propriétaire)

Émet une clé propre à un profil. Le jeton en clair n'est renvoyé qu'une seule fois : conservez-le de façon sécurisée sur votre backend ; seul son haché est conservé.

Corps de la requête

{ "applicantId": "app_…", "label": "mobile-app", "expiresInDays": 365 }
ChampTypeObligatoireRemarques
enrollmentIdchaînel'un des deuxL'identifiant d'inscription Live ID.
applicantIdchaînel'un des deuxL'identifiant du demandeur KYC (résolu vers son inscription).
labelchaînenonLibellé libre à votre usage.
expiresInDaysentiernonDe 1 à 3650. Omettez ce champ pour une clé sans expiration.

Réponse 201

{
  "id": "lik_…",
  "token": "livid_…",          // shown ONCE
  "keyVersion": 1,
  "label": "mobile-app",
  "expiresAt": null,
  "createdAt": "2026-06-18T12:00:00.000Z"
}

Points de terminaison associés : GET /api/kyc/live-id/:orgSlug/keys (liste, métadonnées uniquement), DELETE /api/kyc/live-id/:orgSlug/keys/:id (révocation), GET /api/kyc/live-id/:orgSlug/enrollments (liste des profils inscrits).

Créer une session

POST /api/kyc/public/live-id/sessions    Authentification : clé d'identification (dans le corps)

À appeler côté serveur. Vérifie la clé, applique le contrôle de facturation, et crée un jeton de session à usage unique.

Corps de la requête

{ "key": "livid_…", "deviceFingerprint": "optional", "captureMethod": "live_camera" }

Réponse 201

{
  "sessionId": "lis_…",
  "sessionToken": "…",
  "expiresAt": "2026-06-18T12:02:00.000Z",
  "captureUrl": "https://app.certivant.com/live-id/…",
  "nonce": "…"
}

Transmettez captureUrl à l'appareil. Le sessionToken est aussi renvoyé afin que vous puissiez interroger le statut côté serveur. nonce est la valeur à usage unique de la session : elle n'est nécessaire que si vous créez votre propre interface de capture (voir Soumettre un selfie).

La création est refusée avec 429 enrollment_locked tant que le profil est verrouillé après des validations échouées à répétition (5 échecs en 15 minutes le verrouillent pendant 30 minutes et déclenchent live_id.enrollment.locked).

Ouvrir la page de capture

GET /live-id/:sessionToken    Authentification : jeton de session (dans le chemin)

La page de capture hébergée, conçue d'abord pour le mobile : ouvrez-la au premier niveau, dans une fenêtre contextuelle, par redirection, ou dans une WebView native. Elle est servie avec frame-ancestors 'none' : elle ne peut pas être intégrée dans un iframe. Elle affiche l'interface de caméra et de selfie lorsque la session est active, et un avis clair lorsque la session est expirée, non valide ou déjà terminée.

Au chargement, la page hébergée appelle POST /api/kyc/public/live-id/sessions/:sessionToken/open. Cet appel enregistre l'adresse IP de l'appareil et renvoie la valeur à usage unique de la session, que la page renvoie avec le selfie. À partir de ce moment, un selfie soumis sans la bonne valeur est refusé.

Ouvrir une capture (interface de capture propre uniquement)

POST /api/kyc/public/live-id/sessions/:sessionToken/open    Authentification : jeton de session (dans le chemin)

Appelez ce point de terminaison depuis l'appareil lorsque votre propre écran de capture s'ouvre. Réponse 200 :

{ "nonce": "…", "expiresAt": "2026-06-18T12:02:00.000Z" }

Soumettre un selfie

POST /api/kyc/public/live-id/validate    Authentification : jeton de session (dans le corps)

La page hébergée appelle ce point de terminaison à votre place. Ne le documentez que si vous créez votre propre interface de capture native au lieu d'utiliser la page hébergée.

Corps de la requête

{ "sessionToken": "…", "selfieImage": "data:image/jpeg;base64,/9j/4AAQ…", "nonce": "…" }

selfieImage accepte une chaîne base64 ou une URL data:. Minimum d'environ 1 Ko, maximum 8 Mo.

nonce est la valeur à usage unique de la session (issue de la réponse de création ou de /open) :

  • Une valeur incorrecte est toujours refusée (reason: "nonce_mismatch", matched: false).
  • Une valeur absente n'est refusée que lorsque la capture a été ouverte avec /open (la page hébergée le fait toujours). Les intégrations serveur à serveur qui n'appellent jamais /open continuent de fonctionner sans elle, mais il est recommandé de l'envoyer.

Un même selfie ne peut jamais être utilisé deux fois : une copie exacte de la photo de référence inscrite, ou du selfie d'une session précédente, est refusée (reason: "replayed_image"). Les copies presque identiques sont signalées dans les riskSignals du webhook.

Réponse 200

{
  "matched": true,
  "faceMatchScore": 0.94,
  "livenessScore": 0.98,
  "livePassed": true,
  "reason": "matched",
  "sessionId": "lis_…"
}

reason est l'une des valeurs suivantes : matched, face_below_threshold, liveness_failed, face_and_liveness_failed, no_reference_image, nonce_mismatch, replayed_image, near_duplicate_image.

Interroger une session

GET /api/kyc/public/live-id/sessions/:sessionToken    Authentification : jeton de session (dans le chemin)

Réponse 200

{
  "sessionId": "lis_…",
  "status": "completed",
  "matched": true,
  "faceMatchScore": 0.94,
  "livenessScore": 0.98,
  "reason": "matched",
  "expiresAt": "2026-06-18T12:02:00.000Z"
}

status : pending → processing → completed (ou expired). Lorsque le statut vaut completed, matched donne le verdict. Interrogez toutes les 2 secondes environ ; arrêtez-vous à completed ou expired.

Webhook : live_id.validation.completed

Déclenché une fois par validation terminée, vers l'URL de webhook de votre locataire, signé exactement comme tous les autres webhooks Certivant (X-Certivant-Signature-V2: t=…,v1=… ; l'ancien en-tête X-KYC-Signature: sha256=… est toujours envoyé).

{
  "event": "live_id.validation.completed",
  "organizationId": "org_…",
  "validationId": "liv_…",
  "sessionId": "lis_…",
  "enrollmentId": "lie_…",
  "applicantId": "app_…",
  "matched": true,
  "faceMatchScore": 0.94,
  "livenessScore": 0.98,
  "decisionReason": "matched",
  "riskSignals": {
    "nearDuplicateImage": false,
    "nearestImageDistance": 0.21,
    "nearestImageSource": "previous_session",
    "nonceVerified": true,
    "deviceIpChanged": false
  },
  "timestamp": "2026-06-18T12:02:00.000Z"
}

Les riskSignals servent à votre propre décision de risque : ils ne modifient jamais matched à eux seuls. nonceVerified vaut vrai lorsque le selfie portait la valeur à usage unique de la session ; deviceIpChanged vaut vrai lorsque l'adresse IP de l'appareil a changé entre /open et le selfie (null lorsque la comparaison est impossible).

Webhook : live_id.enrollment.locked

Déclenché lorsqu'un profil est verrouillé après des validations échouées à répétition.

{
  "event": "live_id.enrollment.locked",
  "organizationId": "org_…",
  "enrollmentId": "lie_…",
  "applicantId": "app_…",
  "failures": 5,
  "lockedUntil": "2026-06-18T12:32:00.000Z",
  "timestamp": "2026-06-18T12:02:00.000Z"
}

Voir Webhooks → Vérification de la signature.

Erreurs

StatutCodeSignification
401invalid_key / unknown_key / key_mismatchLa clé d'identification a été altérée, n'est pas reconnue, ou ses revendications ne correspondent pas.
403key_revoked / key_expiredLa clé a été révoquée ou a expiré.
403live_id_disabledLive ID n'est pas activé pour le locataire.
402verification_unavailableQuota dépassé et le portefeuille ne peut pas couvrir la facturation à l'utilisation (continuer sans crédit désactivé). Le corps contient aussi error.organization (name, logoUrl) ; le message ne mentionne jamais la facturation, il peut donc être affiché à votre utilisateur.
409enrollment_inactiveLe profil n'est pas (ou n'est plus) inscrit.
429enrollment_lockedTrop de validations échouées : réessayez après la fin du verrouillage.
404unknown_sessionAucune session pour ce jeton.
409session_consumedLa session a déjà été utilisée ou est en cours.
410session_expiredLe jeton de session a expiré avant l'arrivée du selfie.
503biometric_unconfiguredLe fournisseur biométrique du locataire n'est pas configuré.