@41devs/naya-id-js
v0.3.2
Published
SDK JavaScript officiel de Naya ID — vérification d'identité (eKYC) clé en main pour l'Afrique de l'Ouest : consentement, capture guidée, défi de vivacité imposé par le serveur, confirmation des données, résultat expliqué. Une balise <script>, un Web Comp
Readme
@41devs/naya-id-js
SDK JavaScript officiel de Naya ID — vérification d'identité (eKYC) clé en
main pour l'Afrique de l'Ouest. Une balise <script>, un Web Component ou un
import npm ; aucune dépendance à l'exécution ; ~40 Ko compressés.
Pièces acceptées : CNI CEDEAO, CIP béninois, passeport, permis de conduire.
Le parcours : consentement → capture guidée du document (recto ; verso pour la seule CNI CEDEAO, qui porte sa MRZ au dos) → selfie avec défi de vivacité imposé par le serveur → confirmation des données lues → décision expliquée. Sur ordinateur, relais vers le téléphone par QR code. Trois langues : français, anglais, portugais.
Démarrage rapide
1. Votre backend ouvre la session (recommandé)
curl -X POST https://api.naya.41devs.com/v1/verifications/start \
-H "X-API-Key: naya_live_xxx" -H "Content-Type: application/json" \
-d '{"documentType":"cni","country":"BJ","callbackUrl":"https://votre-backend.com/naya/hook"}'
# → { "data": { "verificationId": "…", "sessionToken": "…", "challenge": ["blink","turn-left","smile"] } }La clé ne quitte jamais votre serveur. Rendez verificationId + sessionToken
au navigateur (voir docs/backend-session.md pour Node, PHP, Python).
2. Votre page lance le parcours
<script
src="https://sdk.naya.41devs.com/sdk/0.3.0/naya-id.min.js"
integrity="sha384-…"
crossorigin="anonymous"
></script>
<script>
const result = await NayaId.startVerification({ verificationId, sessionToken });
// result.status : 'approved' | 'review' | 'rejected' | 'cancelled' | 'error'
</script>Ou avec npm :
npm install @41devs/naya-id-jsimport { startVerification } from '@41devs/naya-id-js';
const result = await startVerification({ verificationId, sessionToken, config: { locale: 'fr' } });Ne décidez jamais sur le résultat rendu par le navigateur : seul le webhook (ou
GET /verifications/:id avec votre clé) fait foi.
Prérequis
| Élément | Détail |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Compte Naya vérifié (KYB) | Sinon l'API répond 403 (kyb_pending). |
| HTTPS | La caméra exige un contexte sécurisé (http://localhost en développement). |
| Navigateur | Chrome, Safari, Firefox, Edge récents. Les navigateurs intégrés (WhatsApp, Facebook, Instagram) sont détectés : le SDK propose d'ouvrir le lien dans le navigateur. |
| Origine (mode clé) | Une clé live transmise au navigateur doit déclarer ses origines dans le dashboard. Sans objet avec le jeton de session. |
API
startVerification(params) → Promise<NayaResult>
| Champ | Type | Rôle |
| --------------------------------- | ------------ | --------------------------------------------------------------------- |
| verificationId + sessionToken | string | Session ouverte par votre backend. Production. |
| apiKey | string | Clé d'application transmise au navigateur. Démos et fronts maîtrisés. |
| config | NayaConfig | Voir ci-dessous. |
Ne rejette jamais : erreurs et annulation reviennent en NayaResult.
create(params) → NayaVerification
Instance avec open(), close(), on(event, cb), destroy(), isOpen —
pour les enveloppes de framework et l'analytique (docs/frameworks.md).
isSupported() → NayaSupport
À appeler avant d'afficher votre bouton : ok, code, inAppBrowserName,
deviceClass…
<naya-id-verification>
Web Component enregistré automatiquement par le bundle <script> ;
defineElement() en ESM/CJS.
Configuration (config)
| Champ | Défaut | Rôle |
| --------------------------------------- | --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| country, countries, documentTypes | tous | Pré-sélection ; l'écran de choix est sauté si un seul document et un pays. |
| locale | langue du navigateur | fr, en, pt. |
| consent | true | Écran de consentement ; { policyUrl, version } ou false si recueilli en amont. |
| confirmOcr | false | Écran des données lues : 'display' (lecture seule, l'utilisateur dit si c'est exact) ou 'edit' (corrections saisies). ocrData n'est jamais altéré : le déclaré part à part (declaredData), un écart plafonne à la revue. |
| capture | { autoCapture: true, maxDimension: 1600, fileUpload: 'auto' } | Capture automatique, taille d'image, import de fichier (ordinateur). |
| liveness | { timeoutMs: 45000, allowPassive: true, preload: true } | Délai avant conseils, parcours sans geste, préchargement. |
| handoff | true | Relais QR vers mobile sur ordinateur ; { baseUrl } pour une page hébergée par vous. |
| container | null | Monte dans un élément au lieu d'un overlay plein écran. |
| theme | encre / flamme | primaryColor, accentColor, fontFamily, radius, mode (light, dark, auto). Le texte des boutons reste lisible quelle que soit la couleur. |
| clientLogoUrl | — | Logo affiché à côté de « Propulsé par Naya ID ». |
| strings | — | Surcharge de libellés par clé. |
| livenessAssets | jsDelivr / Google | Auto-hébergement de MediaPipe, repli, intégrité (docs/csp-and-self-hosting.md). |
| callbackUrl | — | Mode clé uniquement ; en session serveur, l'URL est posée à l'ouverture. |
| maxAttempts | 2 | Nouveaux essais après rejet (mode clé). |
| eagerSession | false | Ouvre la session dès le choix du document (latence) — attention à la facturation. |
| telemetry | true | Télémétrie anonyme (docs/telemetry.md). |
| debug | false | Journal [NayaId] dans la console. |
| haptics | true | Retour haptique sur mobile. |
| onEvent | — | Hook d'événements (ready, step, session, document_captured, liveness_step, submitted, result, error…). |
Résultat (NayaResult)
| Champ | Présent | Rôle |
| ------------------------------------------------------ | ------------------------- | ---------------------------------------------------------------------------------------------------- |
| status | toujours | approved, review, rejected, cancelled, error. |
| verificationId | dès qu'une session existe | À conserver pour rapprocher webhooks et dashboard. |
| reasonCodes | décision | Motifs stables : DOC_EXPIRED, FACE_MISMATCH, LIVENESS_LOW, AML_SANCTION… (docs/errors.md). |
| livenessMode | décision | active ou passive. |
| errorCode, errorMessage, statusCode, requestId | status: 'error' | Catalogue dans docs/errors.md ; requestId pour le support. |
| scores, ocrData, note | décision | Indicatifs ; la vérité est côté serveur. ocrData est l'extraction brute, jamais modifiée. |
| declaredData, dataMismatches, dataDisputed | décision | Ce que l'utilisateur a déclaré ou contesté, conservé à part ; à vous de l'afficher ou non. |
Sécurité, en deux lignes
Le jeton de session n'ouvre qu'une vérification, expire en 4 h et meurt à la soumission. Le défi de vivacité est tiré par le serveur et vérifié par lui ; le score calculé sur l'appareil ne décide jamais. Les ressources MediaPipe viennent de jsDelivr et Google, téléchargées sans Referer, empreintes vérifiées ; auto-hébergement possible.
Documentation
docs/backend-session.md— ouvrir la session côté serveur (Node, PHP, Python)docs/webhooks.md— notifications signéesdocs/errors.md— catalogue deserrorCodedocs/csp-and-self-hosting.md— CSP, pare-feu, auto-hébergement, SRIdocs/frameworks.md— Web Component, React, Vue, Angular, conteneurdocs/liveness-challenge-spec.md— spécification du défi (commune aux SDK)docs/telemetry.md,docs/accessibility.md,docs/migration-0.2-to-0.3.mdhosting/README.md— CDNsdk.naya.41devs.com
Développement
npm ci
npm run typecheck && npm run lint && npm test # unitaires (vitest, jsdom)
npm run build && npm run size # dist/ + budget de taille
npm run assets:fetch # MediaPipe local pour le parcours complet e2e
npx playwright install chromium && npm run test:e2e # parcours réel, caméra factice, API simulée
E2E_PUBLIC_CDN=1 npm run test:e2e # + chargement réel depuis jsDelivr/Google (réseau)
npm run serve # example/index.htmlPublication : tag vX.Y.Z → CI → npm publish --provenance.
Dépannage
| Symptôme | Cause probable |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| errorCode: 'origin_not_allowed' | Clé live utilisée depuis une origine non déclarée : dashboard → clé → Origines autorisées, ou passez au jeton de session. |
| errorCode: 'network' | Hors-ligne, pare-feu ou proxy qui bloque api.naya.41devs.com ; CSP trop stricte (docs/csp-and-self-hosting.md). |
| errorCode: 'in_app_browser' | Lien ouvert dans WhatsApp/Facebook : le SDK propose de copier le lien. |
| errorCode: 'liveness_assets' | MediaPipe injoignable ou altéré : CSP (connect-src jsDelivr/Google, script-src blob:) ou auto-héberger. |
| Décision review avec LIVENESS_PASSIVE | L'utilisateur a choisi le parcours sans geste : revue humaine attendue. |
Licence : voir LICENSE.
