Cette documentation existe aussi en texte brut pour les agents :
llms.txt pour l’index, llms-full.txt pour tout le contenu.Prompt
Intègre la vérification d'identité VerifNer dans cette application.
Documentation : https://docs.verifner.com (index pour agents : https://docs.verifner.com/llms.txt)
API : https://api.verifner.com — schéma OpenAPI : https://api.verifner.com/openapi.json
Contexte
- VerifNer vérifie un passeport ou une carte d'identité du Niger, du Mali ou du Burkina Faso,
compare le portrait à un selfie et rend un verdict : "verified" (score >= 0.90),
"review" (0.60 à 0.89, un humain tranche dans la console) ou "rejected" (< 0.60).
- Authentification : en-tête "Authorization: Bearer <clé>". Clé secrète vn_test_… ou vn_live_…,
lue depuis la variable d'environnement VERIFNER_API_KEY. Ne jamais l'exposer au navigateur ni la commiter.
À faire
1. Côté serveur, une route qui ouvre une session :
POST https://api.verifner.com/v1/sessions
corps JSON : {"reference": "<id interne de l'utilisateur ou du dossier>", "document_type": "cni" | "passport" (facultatif)}
réponse 201 : {"id": "ses_…", "client_token": "vn_ct_…", "status": "pending", "expires_at": …}
Renvoie seulement id et client_token au navigateur. Enregistre id avec le dossier.
2. Côté navigateur, sur une page HTTPS, monte le SDK web :
<script src="https://cdn.jsdelivr.net/npm/@verifner/web@0.1/dist/verifner.iife.js"></script>
VerifNer.create({ sessionId, clientToken, apiUrl: "https://api.verifner.com", lang: "fr",
onComplete: (r) => { /* afficher un écran d'attente ; ne rien décider ici */ },
onError: (e) => { /* e.code : unreadable, session_expired, session_completed, network */ }
}).mount(element)
(ou npm install @verifner/web puis import { create } from "@verifner/web"). Appelle destroy() en quittant la page.
3. Côté serveur, un endpoint webhook (POST, corps brut, réponse 2xx en moins de 10 s) :
- En-tête VerifNer-Signature: t=<secondes unix>,v1=<hex>.
- Recalcule HMAC-SHA256(secret, "<t>.<corps brut>") en hex avec VERIFNER_WEBHOOK_SECRET,
compare en temps constant, refuse si |maintenant - t| > 300 s. Calcule sur le corps BRUT, avant JSON.parse.
- Événement : {"id": "evt_…", "type": "verification.completed", "data": {"id": "vrf_…", "mode", "verdict",
"final_verdict", "score", "document_type", "document": {"fields": …}, "checks": [...]}}
- Idempotent sur event.id (les livraisons sont réessayées jusqu'à 8 fois).
- Décision : v = data.final_verdict ?? data.verdict. "verified" → valider le dossier,
"review" → mettre en attente (un second événement avec final_verdict arrivera), "rejected" → refuser.
- Retrouve le dossier via GET /v1/sessions/{id} (champ verification_id) ou en stockant data.id.
4. En secours du webhook, GET https://api.verifner.com/v1/sessions/{id} renvoie status ("pending",
"completed", "expired") et result.verdict / result.final_verdict.
5. Si l'application envoie déjà des photos depuis le serveur, utilise plutôt
POST /v1/verify en multipart (champs front, back pour une carte, selfie) avec un en-tête
Idempotency-Key unique par tentative, et un délai client de 60 s. Le verdict est dans la réponse 201.
Erreurs : corps {"error": {"code", "message"}}. 401 unauthorized, 409 session_completed / session_expired
(ouvrir une nouvelle session), 422 unreadable (redemander une photo), 429 rate_limited (réessayer plus tard).
Ajoute VERIFNER_API_KEY et VERIFNER_WEBHOOK_SECRET à la configuration (fichier .env d'exemple, sans valeur réelle),
écris des tests pour la vérification de signature du webhook et la logique de décision,
puis explique-moi comment enregistrer l'URL du webhook dans https://console.verifner.com (page Webhooks).
Après l’intégration
- Testez avec une clé
vn_test_: le traitement est complet, rien n’est conservé ni facturé. - Déclarez l’URL du webhook dans la console, page Webhooks, et copiez son secret dans
VERIFNER_WEBHOOK_SECRET. - Vérifiez à la main un parcours complet sur un téléphone : la caméra ne s’ouvre qu’en HTTPS.