KyvShield SDK
Integrez la verification d'identite KYC complete dans votre application en quelques minutes.
Flow KYC Complet
Installation
Choisissez votre plateforme
getUserMedia) ne fonctionne que sur https:// ou localhost. En production, servez toujours votre page en HTTPS.
Source: Maven Central
Swift Package Manager
CocoaPods
NSCameraUsageDescription dans votre Info.plist.
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, MRZconst 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) | KycResult | Launch the full KYC flow. Returns result when user completes or cancels. |
| checkCameraPermission() | bool | Check and request camera permission. Returns true if granted. |
| isCameraPermissionPermanentlyDenied() | bool | Returns true if camera was permanently denied. User must go to Settings. |
| openSettings() | bool | Opens device settings so user can manually enable camera permission. |
config KyvshieldConfig
| Property | Type | Default | Description |
|---|---|---|---|
| baseUrl | String | required | API server URL |
| apiKey | String | required | API key from dashboard |
| apiVersion | String | 'v1' | API version |
| timeoutSeconds | int | 60 | HTTP request timeout (not session timeout) |
| enableLog | bool | false | Enable debug logs |
| theme | ThemeConfig? | null | Custom theme (see below) |
| acceptReviewStatus | bool | false | Accept REVIEW status as valid |
flow KyvshieldFlowConfig
| Property | Type | Default | Description |
|---|---|---|---|
| steps | CaptureStep[] | [selfie, recto, verso] | Steps to execute (order matters) |
| target | String? | null (auto-detect) | Document type: SN-CIN, SN-PASSPORT, SN-DRIVER-LICENCE |
| challengeMode | ChallengeMode | standard | minimal (1) | standard (3) | strict (5+) |
| language | String | 'fr' | fr | en | wo |
| showIntroPage | bool | true | Show intro screen before KYC |
| showInstructionPages | bool | true | Show instructions before each step |
| showResultPage | bool | true | Show result screen after KYC |
| showSuccessPerStep | bool | true | Show success animation after each step |
| requireFaceMatch | bool | true | Compare selfie vs document photo |
| selfieDisplayMode | DisplayMode | standard | standard | compact | immersive |
| documentDisplayMode | DisplayMode | standard | standard | compact | immersive |
| playChallengeAudio | bool | false | Play voice instructions for each challenge |
| maxChallengeAudioPlay | int | 1 | Repeat audio 1, 2 or 3 times |
| kycIdentifier | String? | null | Your reference ID (returned in webhooks) |
| strings | Strings? | null | Override 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 |
|---|---|---|
| primaryColor | Color / String | Brand color (buttons, accents, indicators) |
| successColor | Color? | Success feedback color (default: #10B981) |
| warningColor | Color? | Warning color (default: #F59E0B) |
| errorColor | Color? | Error color (default: #EF4444) |
| themeMode | String | light | dark | auto |
Presets
#EF8352#3B82F6#10B981#8B5CF6#00377D#FFD100Localization & Custom Strings
3 built-in languages. Override any text via strings parameter.
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 verificationrectoDocument 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 belowcompactCamera + overlaid instructionsimmersiveFull-screen camera, floating overlaysSupported 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 |
|---|---|---|
| success | bool | KYC completed without error |
| overallStatus | VerificationStatus | pass | review | reject | error |
| sessionId | String? | Server session ID (for webhook correlation) |
| selfieResult | SelfieResult? | Liveness verification result |
| rectoResult | DocumentResult? | Front side OCR + fraud analysis |
| versoResult | DocumentResult? | Back side (NIN, MRZ) |
| fraudIndicators | String[] | Detected fraud signals |
| totalProcessingTimeMs | int | Total processing time |
| errorMessage | String? | Error description if failed |
| Convenience getters: | ||
| selfieImage | bytes? | Captured selfie image |
| rectoImage | bytes? | Aligned recto document image |
| versoImage | bytes? | Aligned verso document image |
| faceMatches | bool? | Selfie matches document photo |
| faceSimilarityScore | double? | Face match score (0-100%) |
| getExtractedValue(key) | String? | Get any OCR field by key |
| mainPhoto | ExtractedPhoto? | Face photo from document |
result SelfieResult
| Property | Type | Description |
|---|---|---|
| success | bool | Step completed successfully |
| isLive | bool | Real person detected (not photo/screen/mask) |
| confidence | double | Confidence score (0.0 - 1.0) |
| status | VerificationStatus | pass or reject |
| capturedImage | bytes? | Captured selfie image (JPEG) |
| challengesPassed | int | Number of challenges passed |
| challengesTotal | int | Total challenges assigned |
| userMessages | String[] | Localized messages for user |
| spoofingIndicators | String[] | Detected spoofing signals |
| processingTimeMs | int | Processing time in ms |
result DocumentResult
Used for both recto and verso
| Property | Type | Description |
|---|---|---|
| success | bool | Step completed successfully |
| isLive | bool | Real physical document (not screen/printout) |
| score | double | Authenticity score (0.0 - 1.0) |
| confidenceLevel | String | HIGH | MEDIUM | LOW |
| status | VerificationStatus | pass | review | reject |
| alignedDocument | bytes? | Perspective-corrected document image |
| extraction | DocumentData? | OCR extracted fields (see below) |
| extractedPhotos | ExtractedPhoto[] | Face photos extracted from document |
| faceVerification | FaceResult? | Selfie vs document face match |
| userMessages | String[] | Localized messages for user |
| fraudIndicators | String[] | Detected fraud signals |
| processingTimeMs | int | Processing time in ms |
data ExtractedField & DocumentData
DocumentData contains a sorted list of ExtractedField. Use getValue(key) or iterate sortedFields.
| Property | Type | Description |
|---|---|---|
| key | String | Generic key (document_id, first_name, birth_date...) |
| documentKey | String | Document-specific key (numero_carte, prenoms...) |
| label | String | Localized display label |
| value | any | Extracted value (String, array, or map) |
| displayPriority | int | Sort order (lower = show first) |
| icon | String? | Icon name (user, calendar, credit_card...) |
DocumentData methods
data ExtractedPhoto
| Property | Type | Description |
|---|---|---|
| imageBytes | bytes | Face photo (JPEG) |
| confidence | double | Detection confidence (0-1) |
| width | int | Image width px |
| height | int | Image height px |
| bbox | double[] | Bounding box [x1, y1, x2, y2] |
result FaceResult
Selfie vs document face match (inside DocumentResult.faceVerification)
| Property | Type | Description |
|---|---|---|
| isMatch | bool | Faces match (selfie = document photo) |
| similarityScore | double | Similarity percentage (0-100%) |
| threshold | double | Match threshold used |
| confidenceLevel | String | VERY_HIGH | HIGH | MEDIUM | LOW |
| detectionModel | String | Model used (e.g., scrfd_10g) |
| recognitionModel | String | Model used (e.g., buffalo_l) |
| processingTimeMs | int | Face comparison time in ms |
Reponses API
Structure commune a tous les SDKs
class KYCResult
Resultat final du flow KYC complet.
| Champ | Type | Description |
|---|---|---|
| success | bool | true si KYC complete sans erreur |
| overallStatus | VerificationStatus | pass, review, reject, error |
| selfieResult | SelfieResult? | Resultat liveness selfie |
| rectoResult | DocumentResult? | Resultat analyse recto |
| versoResult | DocumentResult? | Resultat analyse verso |
| fraudIndicators | List<String> | Indicateurs de fraude detectes |
| totalProcessingTimeMs | int | Temps 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 |
|---|---|---|
| success | bool | Analyse reussie |
| isLive | bool | Document reel (pas photo d'ecran) |
| score | double | Score d'authenticite (0-1) |
| status | VerificationStatus | pass, review, reject |
| extraction | DocumentData? | Donnees OCR extraites |
| extractedPhotos | List<ExtractedPhoto> | Photos visage extraites |
| fraudIndicators | List<String> | Indicateurs de fraude |
class SelfieResult
Resultat liveness selfie.
| Champ | Type | Description |
|---|---|---|
| isLive | bool | Personne reelle detectee |
| confidence | double | Score de confiance (0-1) |
| status | VerificationStatus | pass ou reject |
| challengesPassed | int | Challenges reussis |
| challengesTotal | int | Total challenges |
| spoofingIndicators | List<String> | Indicateurs de spoofing |
class ExtractedField
Champ OCR extrait dynamiquement.
| Champ | Type | Description |
|---|---|---|
| key | String | Cle generique (document_id, first_name...) |
| documentKey | String | Cle specifique (numero_carte, prenoms...) |
| label | String | Libelle affichable |
| value | String | Valeur extraite |
| displayPriority | int | Ordre d'affichage |
| icon | String? | Nom icone (user, calendar...) |
class FraudAnalysis
Resume analyse de fraude.
| Champ | Type | Description |
|---|---|---|
| score | double | Score authenticite (0-1) |
| status | String | PASS, REVIEW, REJECT |
| indicators | List<String> | Indicateurs de fraude |
| isLive | bool | Document/selfie reel |
Documents Supportes
Champs extractibles par type de document
Carte d'Identite CEDEAO
SN-CIN
| Cle | Label | Format | Requis |
|---|---|---|---|
| numero_carte | N° Carte d'identite | X XXXX AAAA XXXXX | Oui |
| prenoms | Prenoms | Texte | Oui |
| nom | Nom | Texte | Oui |
| date_naissance | Date de naissance | JJ/MM/AAAA | Oui |
| sexe | Sexe | M / F | Oui |
| taille | Taille | X,XX m | Non |
| lieu_naissance | Lieu de naissance | Texte | Non |
| date_delivrance | Date de delivrance | JJ/MM/AAAA | Non |
| date_expiration | Date d'expiration | JJ/MM/AAAA | Oui |
| centre_enregistrement | Centre d'enregistrement | Texte | Non |
| adresse_domicile | Adresse du domicile | Texte | Non |
| birth_region | Region de naissance (derive) | Deduit | Auto |
| Cle | Label | Format | Requis |
|---|---|---|---|
| code_pays | Code Pays | SEN (fixe) | Oui |
| Informations electorales — presents si l'electeur est inscrit, sinon null | |||
| inscrit_liste_electorale | Inscrit sur la liste electorale | true / false | Non |
| numero_electeur | Numero d'electeur | chiffres | Non |
| region | Region | Texte | Non |
| departement | Departement | Texte | Non |
| arrondissement | Arrondissement | Texte | Non |
| commune | Commune | Texte | Non |
| lieu_de_vote | Lieu de vote | Texte | Non |
| bureau_de_vote | Bureau de vote | Numero | Non |
| nin | NIN (Numero d'Identification Nationale) | 13 chiffres sans espaces | Oui |
| mrz | MRZ (Machine Readable Zone) | 3 lignes x 30 chars | Oui |
Structure MRZ (ICAO 9303)
Passeport Biometrique
SN-PASSPORT
| Cle | Label | Format | Requis |
|---|---|---|---|
| numero_passeport | N° Passeport | AXXXXXXXX | Oui |
| nom | Nom | UPPERCASE | Oui |
| prenoms | Prenoms | UPPERCASE | Oui |
| nationalite | Nationalite | SENEGALAISE | Oui |
| date_naissance | Date de naissance | DD MMM YYYY | Oui |
| nin | N° personnel (NIN) | 13 chiffres | Oui |
| sexe | Sexe | M / F | Oui |
| lieu_naissance | Lieu de naissance | Texte | Oui |
| autorite | Autorite | Texte | Oui |
| date_delivrance | Date de delivrance | DD MMM YYYY | Oui |
| date_expiration | Date d'expiration | DD MMM YYYY | Oui |
| mrz | MRZ (Machine Readable Zone) | 2 lignes x 44 chars | Oui |
Structure MRZ Passeport (ICAO 9303 TD3)
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
| Cle | Label | Format | Requis |
|---|---|---|---|
| numero_permis | N° Permis | XXXXXXXX | Oui |
| nom | Nom | Texte | Oui |
| prenoms | Prenoms | Texte | Oui |
| date_naissance | Date et lieu de naissance | DD/MM/YYYY + Ville | Oui |
| date_emission | Date d'emission | DD/MM/YYYY | Oui |
| date_expiration | Date d'expiration | DD/MM/YYYY | Oui |
| delivre_par | Delivre par | MITTD | Oui |
| categories | Categories | A1 B etc | Oui |
| groupe_sanguin | Groupe sanguin | O+ A- B+ | Non |
| Cle | Label | Format | Requis |
|---|---|---|---|
| adresse | Adresse | Texte | Oui |
| commune | Commune | Texte | Oui |
| departement | Departement | Texte | Oui |
| region | Region | Texte | Oui |
| sexe | Sexe | M / F | Oui |
| categories_actives | Categories actives (derive) | ["A1", "B"] | Auto |
| mrz | MRZ | D1SN... | Oui |
Tableau des Categories (colonnes 9-12)
Structure MRZ Permis (1 ligne)
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
Face Verification Playground
Testez l'API de verification faciale.
Visage de reference
Selfie ou photo
Verification en cours...
Uploadez deux images et cliquez sur Verifier
Face Detection Playground
Detectez les visages dans une image et obtenez les bounding boxes.
Glissez ou cliquez pour uploader
Detection en cours...
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.
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.
Chargement des documents...
Cliquez sur Charger (API Key requise ci-dessus)
Usage API
Consultez les statistiques d'utilisation de votre application avec suivi mensuel.
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)
Chargement des statistiques...
Cliquez sur Charger (API Key requise ci-dessus)
Compteurs disponibles
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.
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...
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))
}
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