KyvShield SDK

Integrez la verification d'identite KYC complete dans votre application en quelques minutes.

Flow KYC Complet

Document
Capture recto/verso
Liveness
Detection anti-spoof
Face Match
Selfie vs document
Resultat
PASS / REVIEW / REJECT

Installation

Choisissez votre plateforme

kyvshield — Performances maximales. Ideal pour la production.
# pubspec.yaml
dependencies:
kyvshield: ^1.0.0
flutter pub get
kyvshield_lite — Integration ultra-simple, zero config. Ideal pour les MVPs.
# pubspec.yaml
dependencies:
kyvshield_lite: ^1.0.0
flutter pub get
<!-- CDN -->
<script src="https://kyvshield.innolink.sn/static/sdk/kyvshield.min.js"></script>
iOS Safari : L'audio des challenges nécessite une interaction utilisateur (AudioContext suspendu). Le SDK déverrouille l'AudioContext automatiquement lors du clic « Lancer KYC » en jouant un son réel dans le handler du geste. Testez sur un vrai iPhone — le simulateur iOS est plus restrictif.
HTTPS requis : La caméra (getUserMedia) ne fonctionne que sur https:// ou localhost. En production, servez toujours votre page en HTTPS.
// build.gradle.kts
dependencies {
implementation("sn.innolink.kyvshield:kyvshield:1.0.0")
}

Source: Maven Central

Swift Package Manager

// Xcode → File → Add Package Dependencies
URL: https://github.com/innolink-sn/kyvshield-ios.git

CocoaPods

pod 'KyvShield', '~> 1.0'
iOS : Ajoutez NSCameraUsageDescription dans votre Info.plist.
npm install @kyvshield/react-native
# iOS
cd ios && pod install
iOS : Ajoutez NSCameraUsageDescription dans votre Info.plist.

Quick Start

Exemple minimal par plateforme

import 'package:kyvshield/kyvshield.dart';

final granted = await Kyvshield.checkCameraPermission();
if (!granted) return;

final result = await Kyvshield.initKyc(
  context: context,
  config: KyvshieldConfig(baseUrl: 'https://api.kyvshield.sn', apiKey: 'YOUR_KEY'),
  flow: KyvshieldFlowConfig(steps: [CaptureStep.selfie, CaptureStep.recto], language: 'fr'),
);
if (result.success) print('KYC valide!');
const result = await KyvShield.initKyc(
  { baseUrl: 'https://api.kyvshield.sn', apiKey: 'YOUR_KEY' },
  { steps: ['selfie', 'recto'], target: 'SN-CIN', language: 'fr' },
);
if (result.success) console.log('KYC passed!');
val granted = KyvShield.checkCameraPermission(activity)
if (!granted) return

val result = KyvShield.startKyc(activity,
    config = KyvShieldConfig(
        apiKey = "YOUR_KEY", apiUrl = "https://api.kyvshield.sn",
        documentType = "SN-CIN", steps = listOf(KycStep.SELFIE, KycStep.RECTO), language = "fr",
    )
)
if (result.success) Log.d("KYC", "Score: ${result.selfieResult?.score}")
let granted = await KyvShield.checkCameraPermission()
guard granted else { return }

let result = try await KyvShield.startKyc(
    from: self,
    config: KyvShieldConfig(
        apiKey: "YOUR_KEY", apiUrl: "https://api.kyvshield.sn",
        documentType: "SN-CIN", steps: [.selfie, .recto], language: "fr"
    )
)
if result.success { print("Score: \(result.selfieResult?.score ?? 0)") }
import { KyvShield } from '@kyvshield/react-native';

const granted = await KyvShield.checkCameraPermission();
if (!granted) return;

const result = await KyvShield.startKyc({
  apiKey: 'YOUR_KEY', apiUrl: 'https://api.kyvshield.sn',
  documentType: 'SN-CIN', steps: ['selfie', 'recto'], language: 'fr',
});
if (result.success) console.log('Score:', result.selfieResult?.score);

Full Configuration

All available options

import 'package:kyvshield/kyvshield.dart';

// ── Permission ──
final granted = await Kyvshield.checkCameraPermission();
final denied = await Kyvshield.isCameraPermissionPermanentlyDenied();
await Kyvshield.openSettings();

// ── Config ──
final config = KyvshieldConfig(
  baseUrl: 'https://api.kyvshield.sn',        // API server URL
  apiKey: 'your-api-key',                    // API key
  enableLog: true,                           // Debug logs (default: false)
  theme: KyvshieldThemeConfig(primaryColor: Color(0xFFEF8352)),
);

// ── Flow ──
final flow = KyvshieldFlowConfig(
  steps: [CaptureStep.selfie, CaptureStep.recto, CaptureStep.verso],
  target: 'SN-CIN',                           // 'SN-CIN' | 'SN-PASSPORT' | 'SN-DRIVER-LICENCE'
  challengeMode: 'standard',                  // 'minimal' | 'standard' | 'strict'
  language: 'fr',                              // 'fr' | 'en' | 'wo'
  showIntroPage: true,                       // Intro screen (default: true)
  showInstructionPages: true,                // Step instructions (default: true)
  showResultPage: true,                      // Result screen (default: true)
  requireFaceMatch: true,                    // Selfie vs document (default: true)
  displayMode: 'standard',                    // 'standard' | 'compact' | 'immersive'
  playChallengeAudio: true,                  // Voice instructions (default: false)
  strings: KyvshieldStrings.french.copyWith(introTitle: 'Welcome'),
);

// ── Launch ──
final result = await Kyvshield.initKyc(context: context, config: config, flow: flow);

// ── Result ──
result.success;                  // bool
result.overallStatus;            // pass | review | reject | error
result.selfieResult?.isLive;     // bool
result.selfieResult?.score;      // double 0-1
result.rectoResult?.extraction;  // List<ExtractedField> (OCR)
result.rectoResult?.extractedPhotos;  // face photos from doc
result.rectoResult?.alignedDocument;  // aligned image
result.rectoResult?.fraudIndicators;  // fraud signals
result.versoResult?.extraction;  // NIN, MRZ
const result = await KyvShield.initKyc(
  { // Config
    baseUrl: 'https://api.kyvshield.sn', apiKey: 'your-key',
    enableLog: true,
    theme: { primaryColor: '#EF8352', themeMode: 'light' },
  },
  { // Flow
    steps: ['selfie', 'recto', 'verso'],
    target: 'SN-CIN',              // 'SN-CIN' | 'SN-PASSPORT' | 'SN-DRIVER-LICENCE'
    challengeMode: 'standard',     // 'minimal' | 'standard' | 'strict'
    language: 'fr',                 // 'fr' | 'en' | 'wo'
    showIntroPage: true,          showInstructionPages: true,
    showResultPage: true,         requireFaceMatch: true,
    displayMode: 'standard',       // 'standard' | 'compact' | 'immersive'
    playChallengeAudio: true,
    strings: { introTitle: 'Welcome' },  // Override UI texts
  }
);

// Result (same as Flutter)
result.success;                  // bool
result.overallStatus;            // 'pass' | 'review' | 'reject' | 'error'
result.selfieResult?.isLive;     // bool
result.selfieResult?.score;      // number 0-1
result.rectoResult?.extraction;  // ExtractedField[]
val result = KyvShield.startKyc(activity,
    config = KyvShieldConfig(
        apiKey = "key", apiUrl = "https://api.kyvshield.sn",
        documentType = "SN-CIN",    // 'SN-CIN' | 'SN-PASSPORT' | 'SN-DRIVER-LICENCE'
        steps = listOf(KycStep.SELFIE, KycStep.RECTO, KycStep.VERSO),
        challengeMode = "standard", // 'minimal' | 'standard' | 'strict'
        language = "fr",             // 'fr' | 'en' | 'wo'
        showIntroPage = true, showResultPage = true,
        requireFaceMatch = true, displayMode = "standard",
        playChallengeAudio = true, primaryColor = "#EF8352",
    )
)
result.success // Boolean
result.selfieResult?.score // Double
result.rectoResult?.extraction // List<ExtractedField>
let result = try await KyvShield.startKyc(
    from: self,
    config: KyvShieldConfig(
        apiKey: "key", apiUrl: "https://api.kyvshield.sn",
        documentType: "SN-CIN",    // 'SN-CIN' | 'SN-PASSPORT' | 'SN-DRIVER-LICENCE'
        steps: [.selfie, .recto, .verso],
        challengeMode: "standard", // 'minimal' | 'standard' | 'strict'
        language: "fr",             // 'fr' | 'en' | 'wo'
        showIntroPage: true, showResultPage: true,
        requireFaceMatch: true, displayMode: "standard",
        playChallengeAudio: true, primaryColor: "#EF8352"
    )
)
result.success // Bool
result.selfieResult?.score // Double
result.rectoResult?.extraction // [ExtractedField]
const result = await KyvShield.startKyc({
  apiKey: 'key', apiUrl: 'https://api.kyvshield.sn',
  documentType: 'SN-CIN',        // 'SN-CIN' | 'SN-PASSPORT' | 'SN-DRIVER-LICENCE'
  steps: ['selfie', 'recto', 'verso'],
  challengeMode: 'standard',     // 'minimal' | 'standard' | 'strict'
  language: 'fr',                 // 'fr' | 'en' | 'wo'
  showIntroPage: true, showResultPage: true,
  requireFaceMatch: true, displayMode: 'standard',
  playChallengeAudio: true,
  theme: { primaryColor: '#EF8352' },
});
result.success; // boolean
result.selfieResult?.score; // number
result.rectoResult?.extraction; // ExtractedField[]

API Reference

Common to all platforms

Methods

Method Returns Description
initKyc(config, flow)KycResultLaunch the full KYC flow. Returns result when user completes or cancels.
checkCameraPermission()boolCheck and request camera permission. Returns true if granted.
isCameraPermissionPermanentlyDenied()boolReturns true if camera was permanently denied. User must go to Settings.
openSettings()boolOpens device settings so user can manually enable camera permission.

config KyvshieldConfig

Property Type Default Description
baseUrlStringrequiredAPI server URL
apiKeyStringrequiredAPI key from dashboard
apiVersionString'v1'API version
timeoutSecondsint60HTTP request timeout (not session timeout)
enableLogboolfalseEnable debug logs
themeThemeConfig?nullCustom theme (see below)
acceptReviewStatusboolfalseAccept REVIEW status as valid

flow KyvshieldFlowConfig

Property Type Default Description
stepsCaptureStep[][selfie, recto, verso]Steps to execute (order matters)
targetString?null (auto-detect)Document type: SN-CIN, SN-PASSPORT, SN-DRIVER-LICENCE
challengeModeChallengeModestandardminimal (1) | standard (3) | strict (5+)
languageString'fr'fr | en | wo
showIntroPagebooltrueShow intro screen before KYC
showInstructionPagesbooltrueShow instructions before each step
showResultPagebooltrueShow result screen after KYC
showSuccessPerStepbooltrueShow success animation after each step
requireFaceMatchbooltrueCompare selfie vs document photo
selfieDisplayModeDisplayModestandardstandard | compact | immersive
documentDisplayModeDisplayModestandardstandard | compact | immersive
playChallengeAudioboolfalsePlay voice instructions for each challenge
maxChallengeAudioPlayint1Repeat audio 1, 2 or 3 times
kycIdentifierString?nullYour reference ID (returned in webhooks)
stringsStrings?nullOverride any UI text
Flow Presets (Flutter)
KyvshieldFlowConfig.selfieOnly()

Selfie only, no document

KyvshieldFlowConfig.standard()

Selfie + recto (recommended)

KyvshieldFlowConfig.full()

Selfie + recto + verso

KyvshieldFlowConfig.quick()

No UI pages, minimal challenges

KyvshieldFlowConfig.strict()

Maximum security (5+ challenges)

KyvshieldFlowConfig.documentOnly()

Recto + verso, no selfie

ThemeConfig

Property Type Description
primaryColorColor / StringBrand color (buttons, accents, indicators)
successColorColor?Success feedback color (default: #10B981)
warningColorColor?Warning color (default: #F59E0B)
errorColorColor?Error color (default: #EF4444)
themeModeStringlight | dark | auto
Presets
Innolink#EF8352
Blue#3B82F6
Green#10B981
Purple#8B5CF6
Kratos#00377D
Luna#FFD100

Localization & Custom Strings

3 built-in languages. Override any text via strings parameter.

frFrancais
enEnglish
woWolof
Customizable string keys
Intro Screen
  • introTitle
  • introSubtitle
  • introStartButton
  • introDocTypeLabel
  • introDocTypePrefix
Selfie Capture
  • selfieStepTitle
  • selfiePlaceFace
  • selfieHoldStill
  • selfieFaceDetected
  • selfieNoFace
  • selfieTooFar
  • selfieTooClose
  • selfieNotCentered
Document Capture
  • stepRectoTitle
  • stepVersoTitle
  • capturePlaceCardInFrame
  • captureDocumentDetected
  • captureLookingForDocument
Challenges
  • challengeCenterFace
  • challengeCloseEyes
  • challengeTurnLeft
  • challengeTurnRight
  • challengeSmile
  • challengeLookUp
  • challengeLookDown
Results
  • resultLivenessSuccess
  • resultLivenessFailed
  • resultScoreLabel
  • resultRetryPrompt
  • buttonContinue
  • buttonRetry
  • buttonCancel
Analysis
  • statusAnalyzing
  • analyzingPleaseWait
  • analysisStepImageCaptured
  • analysisStepQualityVerified
  • analysisStepSecurityCheck
  • analysisStepAIVerification

enum Types & Enums

CaptureStep
selfieFace liveness verification
rectoDocument front side (OCR + fraud check)
versoDocument back side (NIN + MRZ)
ChallengeMode
minimal1-2 challenges (fastest)
standard3-4 challenges (balanced, default)
strict5+ challenges (max security)
DisplayMode
standardCamera + instructions section below
compactCamera + overlaid instructions
immersiveFull-screen camera, floating overlays
Supported Documents
SN-CINSenegal ID Card (recto + verso)
SN-PASSPORTSenegal Passport (recto only)
SN-DRIVER-LICENCESenegal Driver License (recto + verso)

result KYCResult

Returned by initKyc() / startKyc()

Property Type Description
successboolKYC completed without error
overallStatusVerificationStatuspass | review | reject | error
sessionIdString?Server session ID (for webhook correlation)
selfieResultSelfieResult?Liveness verification result
rectoResultDocumentResult?Front side OCR + fraud analysis
versoResultDocumentResult?Back side (NIN, MRZ)
fraudIndicatorsString[]Detected fraud signals
totalProcessingTimeMsintTotal processing time
errorMessageString?Error description if failed
Convenience getters:
selfieImagebytes?Captured selfie image
rectoImagebytes?Aligned recto document image
versoImagebytes?Aligned verso document image
faceMatchesbool?Selfie matches document photo
faceSimilarityScoredouble?Face match score (0-100%)
getExtractedValue(key)String?Get any OCR field by key
mainPhotoExtractedPhoto?Face photo from document

result SelfieResult

PropertyTypeDescription
successboolStep completed successfully
isLiveboolReal person detected (not photo/screen/mask)
confidencedoubleConfidence score (0.0 - 1.0)
statusVerificationStatuspass or reject
capturedImagebytes?Captured selfie image (JPEG)
challengesPassedintNumber of challenges passed
challengesTotalintTotal challenges assigned
userMessagesString[]Localized messages for user
spoofingIndicatorsString[]Detected spoofing signals
processingTimeMsintProcessing time in ms

result DocumentResult

Used for both recto and verso

PropertyTypeDescription
successboolStep completed successfully
isLiveboolReal physical document (not screen/printout)
scoredoubleAuthenticity score (0.0 - 1.0)
confidenceLevelStringHIGH | MEDIUM | LOW
statusVerificationStatuspass | review | reject
alignedDocumentbytes?Perspective-corrected document image
extractionDocumentData?OCR extracted fields (see below)
extractedPhotosExtractedPhoto[]Face photos extracted from document
faceVerificationFaceResult?Selfie vs document face match
userMessagesString[]Localized messages for user
fraudIndicatorsString[]Detected fraud signals
processingTimeMsintProcessing time in ms

data ExtractedField & DocumentData

DocumentData contains a sorted list of ExtractedField. Use getValue(key) or iterate sortedFields.

PropertyTypeDescription
keyStringGeneric key (document_id, first_name, birth_date...)
documentKeyStringDocument-specific key (numero_carte, prenoms...)
labelStringLocalized display label
valueanyExtracted value (String, array, or map)
displayPriorityintSort order (lower = show first)
iconString?Icon name (user, calendar, credit_card...)

DocumentData methods

sortedFields → fields sorted by displayPriority
getField(key) → ExtractedField? (by generic or document key)
getValue(key) → String? (value as string)

data ExtractedPhoto

PropertyTypeDescription
imageBytesbytesFace photo (JPEG)
confidencedoubleDetection confidence (0-1)
widthintImage width px
heightintImage height px
bboxdouble[]Bounding box [x1, y1, x2, y2]

result FaceResult

Selfie vs document face match (inside DocumentResult.faceVerification)

PropertyTypeDescription
isMatchboolFaces match (selfie = document photo)
similarityScoredoubleSimilarity percentage (0-100%)
thresholddoubleMatch threshold used
confidenceLevelStringVERY_HIGH | HIGH | MEDIUM | LOW
detectionModelStringModel used (e.g., scrfd_10g)
recognitionModelStringModel used (e.g., buffalo_l)
processingTimeMsintFace comparison time in ms

Reponses API

Structure commune a tous les SDKs

class KYCResult

Resultat final du flow KYC complet.

Champ Type Description
successbooltrue si KYC complete sans erreur
overallStatusVerificationStatuspass, review, reject, error
selfieResultSelfieResult?Resultat liveness selfie
rectoResultDocumentResult?Resultat analyse recto
versoResultDocumentResult?Resultat analyse verso
fraudIndicatorsList<String>Indicateurs de fraude detectes
totalProcessingTimeMsintTemps total en ms

enum VerificationStatus

pass

Verification reussie

review

Revision manuelle

reject

Verification echouee

error

Erreur technique

class DocumentResult

Resultat analyse document (recto ou verso).

Champ Type Description
successboolAnalyse reussie
isLiveboolDocument reel (pas photo d'ecran)
scoredoubleScore d'authenticite (0-1)
statusVerificationStatuspass, review, reject
extractionDocumentData?Donnees OCR extraites
extractedPhotosList<ExtractedPhoto>Photos visage extraites
fraudIndicatorsList<String>Indicateurs de fraude

class SelfieResult

Resultat liveness selfie.

Champ Type Description
isLiveboolPersonne reelle detectee
confidencedoubleScore de confiance (0-1)
statusVerificationStatuspass ou reject
challengesPassedintChallenges reussis
challengesTotalintTotal challenges
spoofingIndicatorsList<String>Indicateurs de spoofing

class ExtractedField

Champ OCR extrait dynamiquement.

Champ Type Description
keyStringCle generique (document_id, first_name...)
documentKeyStringCle specifique (numero_carte, prenoms...)
labelStringLibelle affichable
valueStringValeur extraite
displayPriorityintOrdre d'affichage
iconString?Nom icone (user, calendar...)

class FraudAnalysis

Resume analyse de fraude.

Champ Type Description
scoredoubleScore authenticite (0-1)
statusStringPASS, REVIEW, REJECT
indicatorsList<String>Indicateurs de fraude
isLiveboolDocument/selfie reel

Documents Supportes

Champs extractibles par type de document

Carte d'Identite CEDEAO

SN-CIN

Cle Label Format Requis
numero_carteN° Carte d'identiteX XXXX AAAA XXXXXOui
prenomsPrenomsTexteOui
nomNomTexteOui
date_naissanceDate de naissanceJJ/MM/AAAAOui
sexeSexeM / FOui
tailleTailleX,XX mNon
lieu_naissanceLieu de naissanceTexteNon
date_delivranceDate de delivranceJJ/MM/AAAANon
date_expirationDate d'expirationJJ/MM/AAAAOui
centre_enregistrementCentre d'enregistrementTexteNon
adresse_domicileAdresse du domicileTexteNon
birth_regionRegion de naissance (derive)DeduitAuto
Cle Label Format Requis
code_paysCode PaysSEN (fixe)Oui
Informations electorales — presents si l'electeur est inscrit, sinon null
inscrit_liste_electoraleInscrit sur la liste electoraletrue / falseNon
numero_electeurNumero d'electeurchiffresNon
regionRegionTexteNon
departementDepartementTexteNon
arrondissementArrondissementTexteNon
communeCommuneTexteNon
lieu_de_voteLieu de voteTexteNon
bureau_de_voteBureau de voteNumeroNon
ninNIN (Numero d'Identification Nationale)13 chiffres sans espacesOui
mrzMRZ (Machine Readable Zone)3 lignes x 30 charsOui
Structure MRZ (ICAO 9303)
L1: I<SENNUMERO_CARTE<<<<<<
L2: AAMMJJCMAAMMJJCSEN<<<<<<<<<<<C
L3: NOM<<PRENOMS<<<<<<<<<<<<

Passeport Biometrique

SN-PASSPORT

Recto uniquement
Cle Label Format Requis
numero_passeportN° PasseportAXXXXXXXXOui
nomNomUPPERCASEOui
prenomsPrenomsUPPERCASEOui
nationaliteNationaliteSENEGALAISEOui
date_naissanceDate de naissanceDD MMM YYYYOui
ninN° personnel (NIN)13 chiffresOui
sexeSexeM / FOui
lieu_naissanceLieu de naissanceTexteOui
autoriteAutoriteTexteOui
date_delivranceDate de delivranceDD MMM YYYYOui
date_expirationDate d'expirationDD MMM YYYYOui
mrzMRZ (Machine Readable Zone)2 lignes x 44 charsOui
Structure MRZ Passeport (ICAO 9303 TD3)
L1: P<SENNOM<<PRENOMS<<<<<<<<<<<<<<<<<<<<<<
L2: NUMERO_PASSSENAAMMJJCMAAMMJJCNIN<<<<CC
NUMERO_PASS = Numero passeport (9 chars)
AAMMJJ = Date (naissance / expiration)
M = Sexe (M/F)
NIN = N° personnel (13 digits)
C = Check digit
Caracteristiques
  • Format: ID-3 (125mm x 88mm)
  • Pages: 48
  • Materiau: Polycarbonate
  • Photo: Couleur, fond bleu
Cross-validation CIN
  • NIN doit correspondre au verso CIN
  • Nom/Prenoms identiques
  • Date de naissance identique
  • Sexe identique

Permis de Conduire

SN-DRIVER-LICENCE

Recto + Verso
Cle Label Format Requis
numero_permisN° PermisXXXXXXXXOui
nomNomTexteOui
prenomsPrenomsTexteOui
date_naissanceDate et lieu de naissanceDD/MM/YYYY + VilleOui
date_emissionDate d'emissionDD/MM/YYYYOui
date_expirationDate d'expirationDD/MM/YYYYOui
delivre_parDelivre parMITTDOui
categoriesCategoriesA1 B etcOui
groupe_sanguinGroupe sanguinO+ A- B+Non
Cle Label Format Requis
adresseAdresseTexteOui
communeCommuneTexteOui
departementDepartementTexteOui
regionRegionTexteOui
sexeSexeM / FOui
categories_activesCategories actives (derive)["A1", "B"]Auto
mrzMRZD1SN...Oui
Tableau des Categories (colonnes 9-12)
9. Categorie
10. Date obtention
11. Date expiration
12. Restrictions
A1 🏍️10/11/2109/11/31-
B 🚗10/11/2109/11/31-
C 🚛---
Structure MRZ Permis (1 ligne)
MRZ: D1SN10804940NDOUR<<<<<<<<<<<6
D1 = Document type (driving license)
SN = Country code (Senegal)
License number
Last name
Check digit

Modeles IA - InsightFace

Tous les modeles utilisent ONNX Runtime pour des performances optimales.

Modeles de Detection (SCRFD)

Modele FLOPs Vitesse Precision Usage
scrfd_10g 10G 4.9ms 95.16% Production
scrfd_2.5g 2.5G 4.2ms 93.78% Balance
scrfd_500m 500M ~2ms ~90% Mobile

Modeles de Reconnaissance (ArcFace / GLint)

Glossaire

Backbones (Architectures)

  • ResNet50 - Reseau de neurones a 50 couches. Bon equilibre precision/vitesse.
  • ResNet100 - Reseau a 100 couches. Plus precis mais plus lent.
  • MobileFaceNet - Architecture legere optimisee pour mobile. Tres rapide.

Datasets (Donnees d'entrainement)

  • WebFace600K - 600 000 identites, ~10M images de visages.
  • GLint360K - 360 000 identites, 17M images. Dataset plus large.
  • MS1MV2 - MS-Celeb-1M nettoye. ~5.8M images, 85K identites.

Convention de nommage des modeles

  • w600k_r50 = WebFace600K + ResNet50 (ArcFace standard)
  • w600k_mbf = WebFace600K + MobileFaceNet (version mobile)
  • glintr100 = GLint360K + ResNet100 (haute precision)
Pack Modele Backbone Dataset LFW Usage
buffalo_l w600k_r50 ResNet50 MS1MV2 (600K ids) 99.8% Production
buffalo_s w600k_mbf MobileFaceNet MS1MV2 (600K ids) 99.5% Mobile / Fast
antelopev2 glintr100 ResNet100 GLint360K (17M imgs) 99.8% Alternative

Recommandations par region

Afrique / Senegal
Detection: scrfd_10g
Recognition: w600k_r50
Mobile / Edge
Detection: scrfd_500m
Recognition: w600k_mbf
Haute precision
Pack: buffalo_l
Recognition: w600k_r50

Face Verification Playground

Testez l'API de verification faciale.

POST /api/v1/verify/face

Visage de reference

Selfie ou photo

Uploadez deux images et cliquez sur Verifier

Face Detection Playground

Detectez les visages dans une image et obtenez les bounding boxes.

POST /api/v1/detect/face

Glissez ou cliquez pour uploader

Uploadez une image et cliquez sur Detecter

Cles API Temporaires

Generez des cles API temporaires pour vos SDK mobiles. Les cles temporaires heritent des permissions de la cle parente et expirent automatiquement. Seules les cles principales peuvent generer/revoquer des cles temporaires.

POST /api/v1/gen_key
POST /api/v1/revoke_key

Securite

  • • Les cles temporaires ne peuvent PAS generer d'autres cles
  • • Les cles temporaires ne peuvent PAS revoquer d'autres cles
  • • Seules les cles principales (master) ont ces privileges
  • • Les cles expirent automatiquement (max 24h)

Documents API

Listez les documents d'identite supportes avec leurs champs, elements visuels et de securite.

GET /api/v1/documents

Cliquez sur Charger (API Key requise ci-dessus)

Usage API

Consultez les statistiques d'utilisation de votre application avec suivi mensuel.

GET /api/v1/usage

Retourne les statistiques d'utilisation a deux niveaux:

  • application_usage: Usage global de l'application (toutes les cles confondues)
  • api_keys_usage: Usage par cle API master (pas les cles temporaires)

Cliquez sur Charger (API Key requise ci-dessus)

Compteurs disponibles

liveness_sessions: Sessions WebSocket
selfie_analyses: Analyses selfie
recto_analyses: Analyses recto
verso_analyses: Analyses verso
face_verifications: Verifications visage
full_kyc: KYC complets (selfie+recto+verso)

Webhooks

Recevez des notifications en temps reel apres chaque etape et a la fin de chaque session KYC.

Configuration

Configurez votre webhook dans les settings de votre application:

{
  "settings": {
    "webhook_url": "https://your-api.com/kyvshield/webhook"
  }
}

Note: La signature HMAC utilise l'API key qui a initie la session comme secret.

Headers HTTP

POST     https://your-api.com/kyvshield/webhook
Host     your-api.com

x-kyvshield-timestamp: 2026-03-15T04:11:36Z
x-kyvshield-session: 468d970da539365c7f704ebd8f246cb4
x-kyvshield-event: selfie.completed
x-kyvshield-signature: sha256=<HMAC-SHA256 du body avec API key>
content-type: application/json
user-agent: KyvShield-Webhook/1.0

Evenements

selfie.completed

Selfie verifie avec succes

recto.completed

Recto analyse avec succes

verso.completed

Verso analyse avec succes

session.completed

Session KYC terminee avec succes

selfie.failed

Selfie rejete (non vivant/fraude)

recto.failed

Recto rejete (fraude detectee)

verso.failed

Verso rejete (fraude detectee)

session.failed

Session echouee ou timeout

selfie.completed Liveness

Envoye apres la verification liveness du selfie.

{
  "event": "selfie.completed",
  "timestamp": "2026-03-15T04:11:36Z",
  "session_id": "468d970da539365c7f704ebd8f246cb4",
  "app_id": "demo_app",
  "key_id": "demo_key_1",
  "step_data": {
    "captured_image": "/9j/4AAQSkZJRgABAQAAAQABAAD/...<base64>...",
    "liveness": {
      "confidence": "HIGH",
      "is_live": true,
      "score": 0.95
    },
    "processing_time_ms": 8907,
    "step_index": 0,
    "step_type": "selfie",
    "success": true,
    "verification": {
      "checks_passed": ["center_face", "close_eyes"],
      "confidence": 0.95,
      "fraud_indicators": [],
      "is_authentic": true
    }
  }
}

recto.completed OCR + Fraud

Envoye apres l'analyse du recto du document d'identite. Inclut OCR, detection de visage, et verification anti-fraude.

{
  "event": "recto.completed",
  "timestamp": "2026-03-15T04:57:25Z",
  "session_id": "5b5f09cd882170f81889dc9448bf43c6",
  "app_id": "demo_app",
  "key_id": "demo_key_1",
  "step_data": {
    "aligned_document": "/9j/4AAQSkZJRgABAQAAAQABAAD/...<base64 JPEG>...",
    "detected_faces": [
      {
        "image": "/9j/4AAQSkZJRgABAQAAAQABAAD/...<base64>...",
        "confidence": 0.828,
        "bbox": [96, 222, 210, 373],
        "area": 17214,
        "width": 114,
        "height": 151
      }
    ],
    "extracted_photos": [
      {
        "image": "/9j/4AAQSkZJRgABAQAAAQABAAD/...<base64 JPEG>...",
        "confidence": 0.95,
        "bbox": [96, 222, 210, 373],
        "area": 17214,
        "width": 114,
        "height": 151
      }
    ],
    "extraction": [
      {"key": "document_id", "document_key": "numero_carte", "label": "N° de la carte", "value": "1 06 19930515 00026 8"},
      {"key": "first_name", "document_key": "prenoms", "label": "Prenoms", "value": "MOUSSA"},
      {"key": "last_name", "document_key": "nom", "label": "Nom", "value": "NDOUR"},
      {"key": "birth_date", "document_key": "date_naissance", "label": "Date de naissance", "value": "15/05/1993"},
      {"key": "sex", "document_key": "sexe", "label": "Sexe", "value": "M"},
      {"key": "height", "document_key": "taille", "label": "Taille", "value": "175 cm"},
      {"key": "birth_place", "document_key": "lieu_naissance", "label": "Lieu de naissance", "value": "KAOLACK"},
      {"key": "issue_date", "document_key": "date_delivrance", "label": "Date de delivrance", "value": "29/07/2019"},
      {"key": "expiry_date", "document_key": "date_expiration", "label": "Date d'expiration", "value": "28/07/2029"},
      {"key": "issuing_authority", "document_key": "centre_enregistrement", "label": "Centre", "value": "COMM. DE DIEUPPEUL"}
    ],
    "liveness": {
      "confidence": "HIGH",
      "is_live": true,
      "score": 0.92
    },
    "processing_time_ms": 11631,
    "step_type": "recto",
    "success": true,
    "verification": {
      "checks_passed": ["center_document", "tilt_left", "tilt_right"],
      "confidence": 0.92,
      "fraud_indicators": [],
      "is_authentic": true
    }
  }
}

Note: aligned_document = image redresse, detected_faces = visages detectes par ML, extracted_photos = photos extraites du document (pour face match), extraction = donnees OCR.

verso.completed NIN + MRZ

Envoye apres l'analyse du verso. Contient le NIN et le MRZ.

{
  "event": "verso.completed",
  "timestamp": "2026-03-15T05:00:21Z",
  "session_id": "d59dc22f9e792aba85637150aef25cee",
  "app_id": "demo_app",
  "key_id": "demo_key_1",
  "step_data": {
    "aligned_document": "/9j/4AAQSkZJRgABAQAAAQABAAD/...<base64>...",
    "extraction": [
      {"key": "code_pays", "label": "Code Pays", "value": "SEN"},
      {"key": "inscrit_liste_electorale", "label": "Inscrit liste electorale", "value": true},
      {"key": "numero_electeur", "label": "Numero d'electeur", "value": "100656150"},
      {"key": "region", "label": "Region", "value": "DAKAR"},
      {"key": "departement", "label": "Departement", "value": "GUEDIAWAYE"},
      {"key": "arrondissement", "label": "Arrondissement", "value": "GUEDIAWAYE"},
      {"key": "commune", "label": "Commune", "value": "GOLF SUD"},
      {"key": "lieu_de_vote", "label": "Lieu de vote", "value": "LYCEE PARCELLES ASSAINIES GUEDIAWAY"},
      {"key": "bureau_de_vote", "label": "Bureau de vote", "value": "01"},
      {"key": "national_id", "document_key": "nin", "label": "NIN", "value": "1765198311101"},
      {"key": "mrz", "label": "MRZ", "value": "I<SEN101198304<...<3 lignes MRZ>..."}
    ],
    "liveness": {
      "confidence": "HIGH",
      "is_live": true,
      "score": 0.92
    },
    "processing_time_ms": 12308,
    "step_type": "verso",
    "success": true,
    "verification": {
      "checks_passed": ["center_document"],
      "confidence": 0.92,
      "fraud_indicators": [],
      "is_authentic": true
    }
  }
}

session.completed Final

Envoye quand toute la session KYC est terminee avec succes.

{
  "event": "session.completed",
  "timestamp": "2026-03-15T04:11:36Z",
  "session_id": "468d970da539365c7f704ebd8f246cb4",
  "app_id": "demo_app",
  "key_id": "demo_key_1",
  "final_result": {
    "success": true,
    "status": "PASS",
    "steps": {
      "face_match_passed": true,
      "face_match_score": 0.87,
      "overall_confidence": 0.95,
      "processing_time_ms": 8907,
      "rejection_reason": "",
      "steps_completed": 3,
      "steps_failed": 0,
      "steps_passed": 3
    }
  }
}

session.failed Erreur

Envoye quand la session expire ou echoue.

{
  "event": "session.failed",
  "timestamp": "2026-03-15T04:09:45Z",
  "session_id": "...",
  "app_id": "demo_app",
  "key_id": "demo_key_1",
  "final_result": {
    "success": false,
    "status": "TIMEOUT",
    "steps": {
      "reason": "session_expired"
    }
  }
}

Verification de signature HMAC

Le header X-KyvShield-Signature contient la signature HMAC-SHA256 du body JSON. Le secret est l'API key qui a cree la session.

Python
import hmac
import hashlib

def verify_signature(payload_bytes: bytes, api_key: str, signature_header: str) -> bool:
    """
    Verifie la signature HMAC du webhook.

    Args:
        payload_bytes: Le body JSON brut du webhook
        api_key: L'API key qui a cree la session
        signature_header: La valeur du header X-KyvShield-Signature

    Returns:
        True si la signature est valide
    """
    # Le header est au format "sha256=<hex>"
    if not signature_header.startswith("sha256="):
        return False

    expected_sig = signature_header[7:]  # Remove "sha256=" prefix

    # Calcul du HMAC-SHA256
    computed = hmac.new(
        api_key.encode('utf-8'),
        payload_bytes,
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(computed, expected_sig)

# Usage Flask/FastAPI:
# @app.post("/webhook")
# def handle_webhook(request: Request):
#     signature = request.headers.get("X-KyvShield-Signature", "")
#     if not verify_signature(request.body(), "your_api_key", signature):
#         raise HTTPException(401, "Invalid signature")
#     data = request.json()
#     # Process webhook...
Go
package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "strings"
)

// VerifySignature verifie la signature HMAC du webhook
func VerifySignature(payloadBytes []byte, apiKey, signatureHeader string) bool {
    // Le header est au format "sha256=<hex>"
    if !strings.HasPrefix(signatureHeader, "sha256=") {
        return false
    }
    expectedSig := signatureHeader[7:] // Remove "sha256=" prefix

    // Calcul du HMAC-SHA256
    mac := hmac.New(sha256.New, []byte(apiKey))
    mac.Write(payloadBytes)
    computed := hex.EncodeToString(mac.Sum(nil))

    return hmac.Equal([]byte(computed), []byte(expectedSig))
}
Node.js
const crypto = require('crypto');

function verifySignature(payloadBuffer, apiKey, signatureHeader) {
    // Le header est au format "sha256=<hex>"
    if (!signatureHeader.startsWith('sha256=')) {
        return false;
    }
    const expectedSig = signatureHeader.slice(7);

    // Calcul du HMAC-SHA256
    const computed = crypto
        .createHmac('sha256', apiKey)
        .update(payloadBuffer)
        .digest('hex');

    return crypto.timingSafeEqual(
        Buffer.from(computed),
        Buffer.from(expectedSig)
    );
}

// Usage Express:
// app.post('/webhook', express.raw({type: '*/*'}), (req, res) => {
//     const sig = req.headers['x-kyvshield-signature'];
//     if (!verifySignature(req.body, 'your_api_key', sig)) {
//         return res.status(401).send('Invalid signature');
//     }
//     const data = JSON.parse(req.body);
//     // Process webhook...
// });

Politique de retry

  • • Max 3 tentatives avec backoff exponentiel (1s, 5s, 30s)
  • • Timeout de 10 secondes par requete
  • • Les echecs sont logues et conserves 24h
  • • Votre endpoint doit retourner un code 2xx pour confirmer la reception