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 :

ModeDescriptionClé API requise
capture-onlyCapture des images (document ou visage) et les renvoie à votre code. Aucun appel à l’API.Non
documentCapture du document avec OCR et extraction des champs.Oui
verifyVérification complète : document + selfie + comparaison faciale.Oui
face-compareCapture ou téléversement de deux images faciales et renvoi d’un score de similarité.Oui
face-embedCapture d’un visage et extraction d’un vecteur facial à 512 dimensions.Oui

4. Attributs du widget

AttributTypeValeur par défautDescription
modechaînecapture-onlyMode de fonctionnement (voir tableau précédent).
api-urlchaîneURL de base de l’API. Obligatoire sauf en capture-only.
api-keychaîneClé API. Obligatoire sauf en capture-only.
langchaîneenLangue : en, es, fr, de, it, pt.
primary-colorchaîne (hex)#3b82f6Couleur principale de l’interface.
two-sidedbooléentrueDocument à 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-targetchaînedocumentEn mode capture-only : document ou face.
input-modechaînecameraMéthode de saisie : camera, upload ou both. L’option upload accepte les fichiers JPG, PNG et PDF multipage.
scan-modechaîneocrPour les modes document/verify : ocr (capture par caméra avec OCR) ou digitalIdQr (lecture du QR de la DNIe espagnole / miDNI).
combine-imagesbooléenfalseCombine le recto et le verso en une seule image et les envoie en une seule requête API.
return-typechaîneDataValeurs séparées par des virgules : Data, Face, Signature. Par exemple "Data,Face".
is-mapping-appliedbooléentrueRenvoie des noms de champs normalisés (FullName, DocumentNumber, etc.).
max-image-widthnombre1600Largeur maximale de l’image capturée, en pixels.
jpeg-qualitynombre (0–1)0.92Qualité de compression JPEG.
auto-startbooléentrueDémarrer automatiquement la caméra au montage du widget.
labelschaîne JSONRemplace les traductions intégrées pour certaines étiquettes.

5. Événements

ÉvénementModese.detail
kyc-capturedcapture-only{ frontImage, backImage, combinedImage, frontBlob, backBlob, combinedBlob, qrData? }
kyc-completetous les autresObjet discriminé par mode (voir section 6).
kyc-errortousObjet Error.
kyc-canceltous

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éthodeEndpointDescription
POST/api/v2/kycOCR de document — une face (image) ou deux faces (image1 + image2).
POST/api/v2/mrzLecture exclusive de la zone MRZ (passeports et cartes d’identité).
POST/api/v2/face/compareComparaison faciale.
POST/api/v2/face/embedExtraction de vecteur facial à 512 dimensions.
POST/api/v2/qr/midniDécodage du QR de la DNIe espagnole (miDNI).
GET/healthContrô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
}
ChampTypeDescription
image / image1 / image2chaîneImage en Base64 sans le préfixe data:image/...;base64,.
imageUrlchaîneAlternative à image : URL S3 présignée depuis laquelle le service téléchargera l’image.
returnTypechaîne[]Ce qu’il faut renvoyer : Data, Face, Signature.
IsMappingAppliedbooléenRenvoie les champs avec des noms normalisés.
face_vectorbooléenCalcule un vecteur facial à 512 dimensions. Nécessite Face dans returnType.
faceImagechaîneSelfie 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

CodeSignification
200Opération réussie.
204Aucune donnée extraite — qualité d’image insuffisante ou document non reconnu.
400Requête incorrecte : JSON mal formé, champs obligatoires manquants ou paramètres invalides.
401Non autorisé — clé API manquante ou invalide.
402Crédits insuffisants pour cette opération.
403Compte bloqué, licence expirée ou IP non autorisée.
422Endpoints faciaux : aucun visage détecté sur l’image fournie.
429Limite de requêtes dépassée (par minute ou par jour).
500Erreur interne du service.
503Service temporairement indisponible.

12. Limites et restrictions

ÉlémentDétails
Limitation de débitConfigurable par compte (par minute et par jour).
Délai d’expiration30 secondes par défaut.
Format d’imageJPEG ou PNG (Base64, URL présignée ou envoi multipart). PDF multipage depuis le widget.
HTTPSLe widget nécessite HTTPS pour accéder à la caméra.
Navigateurs pris en chargeChrome, Firefox, Safari et Edge (versions récentes).
Taille maximale de l’imageRecommandée à moins de 2 Mo par image.