Vérification d’identité (KYC)
Objectif : cette documentation décrit comment intégrer le système de vérification d’identité de Roommatik. Vous pouvez utiliser le widget web dans l’un de ses six modes de fonctionnement, consommer l’API REST directement, ou combiner les deux approches.
Le widget couvre la capture de documents comme la vérification biométrique complète (document + selfie + comparaison faciale). L’API REST expose les mêmes services pour les intégrations serveur à serveur.
Référence technique complète · Télécharger la collection Postman
1. Démarrage rapide
Copiez le code ci-dessous, remplacez YOUR_API_KEY par votre clé et ouvrez-le dans un navigateur. Cet exemple exécute le flux de vérification complet : capture du document, capture du selfie et comparaison faciale.
<!DOCTYPE html>
<html>
<head>
<script src="https://sdk.roommatik.com/kyc/v1/roommatik-kyc.js"></script>
<link rel="stylesheet" href="https://sdk.roommatik.com/kyc/v1/roommatik-kyc.css">
</head>
<body>
<roommatik-kyc
mode="verify"
api-url="https://kyc.roommatik.com"
api-key="YOUR_API_KEY"
lang="fr">
</roommatik-kyc>
<script>
document.querySelector('roommatik-kyc')
.addEventListener('kyc-complete', (e) => {
if (e.detail.success) {
alert('Identité vérifiée : ' + e.detail.document.DocumentNumber);
}
});
</script>
</body>
</html>
2. Prérequis
- Clé API : clé d’authentification fournie par Roommatik.
- URL de base :
https://kyc.roommatik.com. - HTTPS : le widget nécessite un environnement HTTPS (ou
localhost) pour accéder à la caméra.
Contactez votre gestionnaire de compte Roommatik pour obtenir vos identifiants.
3. Modes du widget
Sélectionnez le mode correspondant à votre cas d’usage via l’attribut mode :
| Mode | Description | Clé API requise |
|---|---|---|
capture-only | Capture des images (document ou visage) et les renvoie à votre code. Aucun appel à l’API. | Non |
document | Capture du document avec OCR et extraction des champs. | Oui |
verify | Vérification complète : document + selfie + comparaison faciale. | Oui |
face-compare | Capture ou téléversement de deux images faciales et renvoi d’un score de similarité. | Oui |
face-embed | Capture d’un visage et extraction d’un vecteur facial à 512 dimensions. | Oui |
4. Attributs du widget
| Attribut | Type | Valeur par défaut | Description |
|---|---|---|---|
mode | chaîne | capture-only | Mode de fonctionnement (voir tableau précédent). |
api-url | chaîne | — | URL de base de l’API. Obligatoire sauf en capture-only. |
api-key | chaîne | — | Clé API. Obligatoire sauf en capture-only. |
lang | chaîne | en | Langue : en, es, fr, de, it, pt. |
primary-color | chaîne (hex) | #3b82f6 | Couleur principale de l’interface. |
two-sided | booléen | true | Document à deux faces (carte d’identité, titre de séjour). Utilisez two-sided="false" pour les passeports et documents à une seule face. Applicable uniquement aux modes document et verify. |
capture-target | chaîne | document | En mode capture-only : document ou face. |
input-mode | chaîne | camera | Méthode de saisie : camera, upload ou both. L’option upload accepte les fichiers JPG, PNG et PDF multipage. |
scan-mode | chaîne | ocr | Pour les modes document/verify : ocr (capture par caméra avec OCR) ou digitalIdQr (lecture du QR de la DNIe espagnole / miDNI). |
combine-images | booléen | false | Combine le recto et le verso en une seule image et les envoie en une seule requête API. |
return-type | chaîne | Data | Valeurs séparées par des virgules : Data, Face, Signature. Par exemple "Data,Face". |
is-mapping-applied | booléen | true | Renvoie des noms de champs normalisés (FullName, DocumentNumber, etc.). |
max-image-width | nombre | 1600 | Largeur maximale de l’image capturée, en pixels. |
jpeg-quality | nombre (0–1) | 0.92 | Qualité de compression JPEG. |
auto-start | booléen | true | Démarrer automatiquement la caméra au montage du widget. |
labels | chaîne JSON | — | Remplace les traductions intégrées pour certaines étiquettes. |
5. Événements
| Événement | Modes | e.detail |
|---|---|---|
kyc-captured | capture-only | { frontImage, backImage, combinedImage, frontBlob, backBlob, combinedBlob, qrData? } |
kyc-complete | tous les autres | Objet discriminé par mode (voir section 6). |
kyc-error | tous | Objet Error. |
kyc-cancel | tous | — |
6. Résultat par mode
L’objet e.detail de l’événement kyc-complete peut être discriminé par mode :
Dans les modes du widget qui renvoient les données du document (document et verify), les champs du document sont fournis dans un objet data (ou document en mode verify), avec les noms en PascalCase lorsque is-mapping-applied="true".
6.1. Mode document
{
"mode": "document",
"success": true,
"data": {
"Name": "JEAN",
"Surname": "DUPONT",
"FullName": "JEAN DUPONT",
"DocumentNumber": "AB123456",
"DocumentType": "Identity Card",
"DateOfBirth": "15/03/1990",
"DateOfExpiry": "20/01/2030",
"Sex": "M",
"Nationality": "FRA"
}
}
6.2. Mode verify
{
"mode": "verify",
"success": true,
"document": {
"FullName": "JEAN DUPONT",
"DocumentNumber": "AB123456",
"DateOfBirth": "15/03/1990",
"DateOfExpiry": "20/01/2030"
},
"verification": {
"verified": true,
"similarity": 87.3,
"distance": 0.127
}
}
6.3. Mode face-compare
{
"mode": "face-compare",
"success": true,
"verified": true,
"similarity": 87.3,
"distance": 0.127
}
6.5. Mode face-embed
{
"mode": "face-embed",
"success": true,
"results": [{
"embedding": [0.0123, -0.0456, "...512 valeurs"],
"boundingBox": { "x": 50, "y": 30, "width": 120, "height": 150 },
"confidence": 0.99
}]
}
7. Mode capture-only — téléverser les images depuis le navigateur
Si vous souhaitez que les images ne transitent pas par votre propre serveur, le widget peut les téléverser directement vers une URL S3 présignée et ne vous remettre que la clé de l’objet :
const kyc = document.querySelector('roommatik-kyc');
kyc.uploadCapturedImage = {
getPresignedUrl: async () => {
const res = await fetch('/mon-backend/presign', { method: 'POST' });
return await res.json(); // { uploadUrl, key }
},
onUploaded: (key) => {
console.log('Image téléversée :', key);
}
};
Combiné avec two-sided="true", l’option combine-images="true" est appliquée afin d’effectuer un seul téléversement par capture.
8. Intégration React
import { KycWidget } from '@roommatik/id-document-capture';
import '@roommatik/id-document-capture/style.css';
<KycWidget
mode="verify"
apiUrl="https://kyc.roommatik.com"
apiKey="YOUR_API_KEY"
lang="fr"
onComplete={(result) => {
if (result.mode === 'verify' && result.success) {
console.log('Vérifié :', result.verification.verified);
console.log('Document :', result.document);
}
}}
onError={(err) => console.error(err)}
/>
9. SDK (sans interface graphique)
Si vous disposez déjà de votre propre interface de capture, utilisez le SDK KycClient pour communiquer avec l’API :
import { KycClient } from '@roommatik/id-document-capture';
const client = new KycClient({
apiUrl: 'https://kyc.roommatik.com',
apiKey: 'YOUR_API_KEY',
returnType: ['Data', 'Face'],
isMappingApplied: true
});
// OCR de document (une ou deux faces)
const result = await client.verify(frontImage, backImage);
// Comparaison faciale
const compare = await client.compareFaces(imageA, imageB);
// Vecteur facial à 512 dimensions
const embed = await client.embedFace(image);
// Décodage du QR miDNI
const qr = await client.verifyQr(qrBase64);
De plus, KycClient expose des utilitaires statiques pour coder et décoder les vecteurs faciaux dans un format compact adapté aux codes QR :
const qrPayload = KycClient.encodeEmbeddingForQr(embedding); // ~700 caractères
const vector = KycClient.decodeEmbeddingFromQr(qrPayload);
10. API REST (v2)
Tous les endpoints du gateway s’authentifient via l’en-tête X-Api-Key. Le Content-Type est application/json sauf mention contraire. Vous pouvez éventuellement inclure l’en-tête X-Account-Name avec le nom de votre compte pour accélérer l’authentification.
| Méthode | Endpoint | Description |
|---|---|---|
| POST | /api/v2/kyc | OCR de document — une face (image) ou deux faces (image1 + image2). |
| POST | /api/v2/mrz | Lecture exclusive de la zone MRZ (passeports et cartes d’identité). |
| POST | /api/v2/face/compare | Comparaison faciale. |
| POST | /api/v2/face/embed | Extraction de vecteur facial à 512 dimensions. |
| POST | /api/v2/qr/midni | Décodage du QR de la DNIe espagnole (miDNI). |
| GET | /health | Contrôle public de disponibilité. |
10.1. POST /api/v2/kyc
Corps de la requête (une face) :
{
"image": "BASE64_IMAGE_SANS_PREFIXE",
"returnType": ["Data", "Face"],
"IsMappingApplied": true
}
Corps de la requête (deux faces) :
{
"image1": "BASE64_RECTO",
"image2": "BASE64_VERSO",
"returnType": ["Data", "Face"],
"IsMappingApplied": true
}
| Champ | Type | Description |
|---|---|---|
image / image1 / image2 | chaîne | Image en Base64 sans le préfixe data:image/...;base64,. |
imageUrl | chaîne | Alternative à image : URL S3 présignée depuis laquelle le service téléchargera l’image. |
returnType | chaîne[] | Ce qu’il faut renvoyer : Data, Face, Signature. |
IsMappingApplied | booléen | Renvoie les champs avec des noms normalisés. |
face_vector | booléen | Calcule un vecteur facial à 512 dimensions. Nécessite Face dans returnType. |
faceImage | chaîne | Selfie en Base64 à comparer avec le visage du document. La réponse inclura FaceMatchAccuracy. |
Réponse (200 OK) :
{
"Data": {
"Name": "JEAN",
"Surname": "DUPONT",
"FullName": "JEAN DUPONT",
"DocumentNumber": "AB123456",
"DocumentType": "Identity Card",
"DateOfBirth": "15/03/1990",
"DateOfExpiry": "20/01/2030",
"Sex": "M",
"Nationality": "FRA"
},
"GeoData": {
"Region": "Île-de-France",
"Province": "Paris",
"PostalCode": "75001"
},
"ResponseTime": 1250,
"Description": "France - Identity Card",
"Face": "BASE64_VISAGE_RECADRE"
}
Les champs Face, Signature, FaceVector, FaceMatchAccuracy et GeoData sont omis lorsqu’ils ne s’appliquent pas. Si l’image ne permet pas d’extraire de données, l’API répond par 204 No Content.
10.2. POST /api/v2/face/compare
Prend en charge quatre modes d’entrée :
// 1) Deux photos
{ "image1": "BASE64_A", "image2": "BASE64_B" }
// 2) Document + selfie (le visage est automatiquement recadré depuis le document)
{ "document": "BASE64_DOC", "selfie": "BASE64_SELFIE" }
// 3) Vecteur précalculé + photo
{ "vector": [0.0123, ...], "image": "BASE64" }
// 4) Deux vecteurs (le plus rapide)
{ "vector1": [0.0123, ...], "vector2": [0.0456, ...] }
Réponse :
{
"verified": true,
"similarity": 87.3,
"distance": 0.127,
"face1": { "detected": true, "confidence": 0.99, "boundingBox": {...} },
"face2": { "detected": true, "confidence": 0.98, "boundingBox": {...} },
"processingTimeMs": 320
}
10.3. POST /api/v2/face/embed
// Image unique
{ "image": "BASE64" }
// Lot
{ "images": ["BASE64_1", "BASE64_2"] }
Réponse :
{
"results": [{
"faceDetected": true,
"confidence": 0.99,
"boundingBox": {...},
"embedding": [0.0123, -0.0456, "...512 valeurs"]
}],
"processingTimeMs": 280
}
10.4. POST /api/v2/qr/midni
Décode le QR de la DNIe espagnole (miDNI). L’endpoint attend les données binaires brutes extraites du QR, et non une image de celui-ci :
{ "Base64Data": "PAYLOAD_BASE64" }
// ou
{ "HexData": "PAYLOAD_HEX" }
Réponse :
{
"Data": {
"DocumentNumber": "12345678Z",
"FirstName": "JEAN",
"Surname": "DUPONT",
"DateOfBirth": "15-03-1990",
"Gender": "M",
"ExpiryDate": "20-01-2030",
"Nationality": "ES",
"SignatureValid": "true"
},
"GeoData": { "Region": "...", "Province": "...", "PostalCode": "..." },
"ResponseTime": 45,
"Description": "miDNI QR (Complete) - Verification: Valid"
}
10.6. Exemple complet (cURL)
curl -X POST https://kyc.roommatik.com/api/v2/kyc \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"image": "BASE64_IMAGE",
"returnType": ["Data", "Face"],
"IsMappingApplied": true
}'
11. Codes de réponse HTTP
| Code | Signification |
|---|---|
200 | Opération réussie. |
204 | Aucune donnée extraite — qualité d’image insuffisante ou document non reconnu. |
400 | Requête incorrecte : JSON mal formé, champs obligatoires manquants ou paramètres invalides. |
401 | Non autorisé — clé API manquante ou invalide. |
402 | Crédits insuffisants pour cette opération. |
403 | Compte bloqué, licence expirée ou IP non autorisée. |
422 | Endpoints faciaux : aucun visage détecté sur l’image fournie. |
429 | Limite de requêtes dépassée (par minute ou par jour). |
500 | Erreur interne du service. |
503 | Service temporairement indisponible. |
12. Limites et restrictions
| Élément | Détails |
|---|---|
| Limitation de débit | Configurable par compte (par minute et par jour). |
| Délai d’expiration | 30 secondes par défaut. |
| Format d’image | JPEG ou PNG (Base64, URL présignée ou envoi multipart). PDF multipage depuis le widget. |
| HTTPS | Le widget nécessite HTTPS pour accéder à la caméra. |
| Navigateurs pris en charge | Chrome, Firefox, Safari et Edge (versions récentes). |
| Taille maximale de l’image | Recommandée à moins de 2 Mo par image. |
