Outils pour utilisateurs

Documentation API PVID Cloud

L'API PVID Cloud vous permet de,

  • générer les liens PVID à transmettre à vos utilisateurs pour qu'ils puissent effectuer le parcours de vérification d'identité,
  • récupérer les informations des PVID effectués par vos utilisateurs,
  • configurer le parcours de vérification d'identité pour qu'il s'intègre au mieux dans votre parcours métier
  • tester l'appareil mobile de votre utilisateur avant qu'il ne démarre son parcours

Cette documentation a pour but de vous guider dans l'intégration et la consommation de l'API PVID Cloud.

Ressources

Getting Started

Pour utiliser l'API PVID Cloud vous devez posséder des identifiants. Vous pouvez demander vos identifiants directement au support PVID Cloud.



1. Authentification

Pour l'ensemble des routes de l'API PVID Cloud il faut être en capacité de,

  • soumettre une authentification valide
  • déchiffrer le retour de l'API PVID Cloud

L'API PVID Cloud utilise OAuth 2.0 avec des tokens JWT. Toutes les requêtes API authentifiées nécessitent un token JWT valide 5 minutes.


1.1 Se connecter à l'API (POST /api/login)

Voir dans le Swagger

Route permettant d'obtenir un token JWT pour pouvoir requêter les autres endpoints.

Paramètres

Paramètre Type Description Requis
username string Identifiant de votre application
password string Mot de passe associé


Réponse | Succès

Code Status
——– —–
200 OK

Exemple de réponse

snippet.json
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_in": 300,
  "refresh_expires_in": 1800,
  "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "not-before-policy": 0,
  "session_state": "123e4567-e89b-12d3-a456-426614174000",
  "scope": "email profile"
}


Réponse | Erreurs

Code Status Valeur
400 Bad Request Missing credentials
401 Unauthorized Invalid credentials or Keycloak error


1.2 Headers d'authentification

Pour vous authentifier, il faut ajouter ce header à toutes vos requêtes.

Header Valeur
Authorization Bearer ACCESS_TOKEN


1.3 Rafraîchir le token (POST /api/refresh_token)

Voir dans le Swagger

Route pour obtenir un nouveau token d'accès sans vous reconnecter.

Paramètres

Paramètre Type Description Requis
refresh_token string Token de rafraîchissement obtenu lors du login


Réponse | Succès

Code Status
200 OK

Exemple de réponse

snippet.json
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_in": 300,
  "refresh_expires_in": 1800,
  "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "not-before-policy": 0,
  "session_state": "123e4567-e89b-12d3-a456-426614174000",
  "scope": "email profile"
}


Réponse | Erreurs

Code Status Message
400 Bad Request Missing refresh token
400 Bad Request Invalid refresh token
401 Unauthorized Invalid credentials or Keycloak error


1.4 Infos complémentaires

  • Le token d'accès est valide 300 secondes (5 minutes).
  • Le refresh token est valide 1800 secondes (30 minutes).
  • Utilisez le token via le header : Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
  • Si vous utilisez un token expiré, vous recevrez une erreur 401 Unauthorized


2. Signature et déchiffrement des requêtes

Pour des raisons de sécurité, vos requêtes vers PVID Cloud doivent être signées et les réponses de notre API devront être déchiffrées.

2.1 Mécanisme de chiffrement

Pour toutes les routes sécurisées (sauf /api/login et /api/refresh_token), un header signature est obligatoire. Ce header permet de valider l'authenticité de la requête.

Header requis

Header Type Description Requis
signature string Signature générée à partir du paramètre date


Algorithme de génération de la signature

Élément Valeur
Algorithme AES-256-CBC avec padding PKCS7
Clé 32 premiers caractères de SHA256(tokenSecret) en hexadécimal
IV 16 premiers caractères de SHA256(SHA256(tokenSecret)) en hexadécimal
Valeur à chiffrer Le paramètre date (format YYYY-MM-DD HH:mm:ss)
Sortie Base64


Réponse | Erreurs

Code Status Slug Message
400 Bad Request invalid_date Wrong date format (must be YYYY-MM-DD HH:mm:ss, eg: 2021-10-19 20:10:06)
400 Bad Request empty_date No date parameter found in your request
400 Bad Request expired_date Given datetime is older than current datetime
400 Bad Request date_in_future Given datetime must be set between call submission and +10 minutes
400 Bad Request validation_error Signature verification failed
400 Bad Request failed_signature Signature verification failed
401 Unauthorized N/A JWT Token not found
401 Unauthorized N/A Expired JWT Token
401 Unauthorized user_not_exist Unknown user
500 Bad Request internal_server_error Internal server error


2.1.1 Génération de la signature en PHP

snippet.php
<?php
 
function generateSignature(string $date, string $tokenSecret): string
{
    $key = substr(hash('sha256', $tokenSecret), 0, 32);
    $iv = substr(hash('sha256', hash('sha256', $tokenSecret)), 0, 16);
    return openssl_encrypt($date, 'aes-256-cbc', $key, 0, $iv);
}
 
$date = "2026-05-20 14:30:00";
$tokenSecret = "votre-token-secret";
$signature = generateSignature($date, $tokenSecret);
echo $signature;


2.1.2 Génération de la signature en Python

snippet.python
import hashlib
from Crypto.Cipher import AES
import base64
 
def generate_signature(date: str, token_secret: str) -> str:
    key = hashlib.sha256(token_secret.encode()).hexdigest()[:32]
    iv = hashlib.sha256(hashlib.sha256(token_secret.encode()).hexdigest().encode()).hexdigest()[:16]
 
    cipher = AES.new(key.encode(), AES.MODE_CBC, iv.encode())
    pad_len = 16 - (len(date) % 16)
    padded_date = date + chr(pad_len) * pad_len
    encrypted = cipher.encrypt(padded_date.encode())
 
    return base64.b64encode(encrypted).decode()
 
date = "2026-05-20 14:30:00"
token_secret = "votre-token-secret"
signature = generate_signature(date, token_secret)
print(signature)


2.1.3 Génération de la signature en JavaScript

snippet.javascript
const crypto = require('crypto');
 
function generateSignature(date, tokenSecret) {
    const key = crypto.createHash('sha256').update(tokenSecret).digest('hex').slice(0, 32);
    const fullHash = crypto.createHash('sha256').update(tokenSecret).digest('hex');
    const iv = crypto.createHash('sha256').update(fullHash).digest('hex').slice(0, 16);
 
    const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
    let encrypted = cipher.update(date, 'utf8', 'base64');
    encrypted += cipher.final('base64');
 
    return encrypted;
}
 
const date = "2026-05-20 14:30:00";
const tokenSecret = "votre-token-secret";
const signature = generateSignature(date, tokenSecret);
console.log(signature);


2.1.4 Génération de la signature en Java

snippet.java
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;
 
public class SignatureGenerator {
    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) sb.append(String.format("%02x", b));
        return sb.toString();
    }
 
    public static String generateSignature(String date, String tokenSecret) throws Exception {
        MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
        String fullHash = bytesToHex(sha256.digest(tokenSecret.getBytes(StandardCharsets.UTF_8)));
        String key = fullHash.substring(0, 32);
        sha256.reset();
        String iv = bytesToHex(sha256.digest(fullHash.getBytes(StandardCharsets.UTF_8))).substring(0, 16);
 
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE,
                new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES"),
                new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8)));
        byte[] encrypted = cipher.doFinal(date.getBytes(StandardCharsets.UTF_8));
 
        return Base64.getEncoder().encodeToString(encrypted);
    }
}


2.2 Déchiffrement des réponses

En dehors des routes d'authentification (/api/login et /api/refresh_token), toutes les réponses de l'API sont chiffrées. Il faut donc les déchiffrer pour pouvoir lire la réponse.

Le paramètre date est obligatoire.

Algorithme de chiffrement des réponses

Élément Valeur
Algorithme AES-256-CBC
Clé SHA256(date + tokenSecret)
IV 16 premiers octets du SHA256 de la clé
Encodage Base64


2.2.1 Déchiffrement des réponses en PHP

snippet.php
<?php
 
function decryptResponse(string $encryptedData, string $date, string $tokenSecret): array
{
    // Décodage Base64
    $encrypted = base64_decode($encryptedData);
 
    // Génération de la clé (SHA256 de date + tokenSecret)
    $key = hash('sha256', $date . $tokenSecret, true);
 
    // Génération de l'IV (16 premiers octets du SHA256 de la clé)
    $iv = substr(hash('sha256', $key, true), 0, 16);
 
    // Déchiffrement AES-256-CBC
    $decrypted = openssl_decrypt($encrypted, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
 
    // Conversion JSON en tableau
    return json_decode($decrypted, true);
}
 
$encryptedResponse = "U2FsdGVkX1+abc123...";
$date = "2026-05-20 14:30:00";
$tokenSecret = "votre-token-secret";
 
$data = decryptResponse($encryptedResponse, $date, $tokenSecret);
print_r($data);


2.2.2 Déchiffrement en Python

snippet.python
import base64
import hashlib
import json
from Crypto.Cipher import AES
 
def decrypt_response(encrypted_data: str, date: str, token_secret: str) -> dict:
    # Décodage Base64
    encrypted = base64.b64decode(encrypted_data)
 
    # Génération de la clé
    key = hashlib.sha256((date + token_secret).encode()).digest()
 
    # Génération de l'IV
    iv = hashlib.sha256(key).digest()[:16]
 
    # Déchiffrement AES-256-CBC
    cipher = AES.new(key, AES.MODE_CBC, iv)
    decrypted = cipher.decrypt(encrypted)
 
    # Suppression du padding PKCS7
    padding_len = decrypted[-1]
    decrypted = decrypted[:-padding_len]
 
    return json.loads(decrypted.decode('utf-8'))
 
# Exemple d'utilisation
# pip install pycryptodome
encrypted_response = "U2FsdGVkX1+abc123..."  # Réponse chiffrée de l'API
date = "2026-05-20 14:30:00"                  # Date envoyée dans la requête
token_secret = "votre-token-secret"           # Votre clé secrète API
 
data = decrypt_response(encrypted_response, date, token_secret)
print(data)


2.2.3 Déchiffrement en JavaScript

snippet.javascript
const crypto = require('crypto');
 
function decryptResponse(encryptedData, date, tokenSecret) {
    // Décodage Base64
    const encrypted = Buffer.from(encryptedData, 'base64');
 
    // Génération de la clé
    const key = crypto.createHash('sha256').update(date + tokenSecret).digest();
 
    // Génération de l'IV
    const iv = crypto.createHash('sha256').update(key).digest().slice(0, 16);
 
    // Déchiffrement AES-256-CBC
    const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
    let decrypted = decipher.update(encrypted);
    decrypted = Buffer.concat([decrypted, decipher.final()]);
 
    return JSON.parse(decrypted.toString('utf-8'));
}
 
// Exemple d'utilisation
const encryptedResponse = "U2FsdGVkX1+abc123..."; // Réponse chiffrée de l'API
const date = "2026-05-20 14:30:00";                // Date envoyée dans la requête
const tokenSecret = "votre-token-secret";          // Votre clé secrète API
 
const data = decryptResponse(encryptedResponse, date, tokenSecret);
console.log(data);


2.2.4 Déchiffrement en Java

snippet.java
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Base64;
 
public class ApiDecrypter {
 
    public static String decryptResponse(String encryptedData, String date, String tokenSecret) throws Exception {
        // Décodage Base64
        byte[] encrypted = Base64.getDecoder().decode(encryptedData);
 
        // Génération de la clé (SHA256 de date + tokenSecret)
        MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
        byte[] key = sha256.digest((date + tokenSecret).getBytes(StandardCharsets.UTF_8));
 
        // Génération de l'IV (16 premiers octets du SHA256 de la clé)
        byte[] iv = Arrays.copyOf(sha256.digest(key), 16);
 
        // Déchiffrement AES-256-CBC
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
        byte[] decrypted = cipher.doFinal(encrypted);
 
        return new String(decrypted, StandardCharsets.UTF_8);
    }
}
 
    // Exemple d'utilisation
    public static void main(String[] args) throws Exception {
        String encryptedResponse = "U2FsdGVkX1+abc123..."; // Réponse chiffrée de l'API
        String date = "2026-05-20 14:30:00";                // Date envoyée dans la requête
        String tokenSecret = "votre-token-secret";          // Votre clé secrète API
 
        String json = decryptResponse(encryptedResponse, date, tokenSecret);
        System.out.println(json);
    }


3. Endpoints API

3.1 Vérification d'identité PVID

Cette section concerne les 2 méthodes permettant de générer un lien PVID et de récupérer les résultats d'une vérification d'identité après verdict.

POST /api/pvid | Générer un lien PVID

Voir dans le Swagger

Générer un lien PVID à transmettre à un utilisateur pour qu'il puisse effectuer le parcours de vérification d'identité à distance.


Paramètres

Paramètre Type Description Requis
date string Date pour chiffrement
customerEmail string Email de l'utilisateur à vérifier
urlAfterSuccess string URL de redirection après succès
urlAfterFailOrAbort string URL de redirection en cas d'échec/abandon
isPriority integer Traitement Express (0 ou 1). Surcoût applicable
linkValiditySharing integer Durée de validité en minutes (max 60)
disableLinkSharing integer Désactive le partage du lien via SMS/Qr-code (0 ou 1)
addUserAlertScreen integer Afficher un écran d'alerte à l'utilisateur (0 ou 1)
addUserAlertText string Ajouter un texte personnalisé sur l'écran d'alerte (5-120 caractères)
acceptedDocuments array Documents acceptés (ex: ["FR-passport"])
webhook string URL de webhook pour cette vérification (surcharge du webhook global, HTTPS obligatoire)


Notes

  • Le paramètre webhook est optionnel : si non fourni, le webhook global de configuration sera utilisé
  • Conservez l'id de la vérification pour les requêtes ultérieures (récupération des résultats)
  • L'URL de la vérification expire après le délai spécifié (par défaut 60 minutes, max 60 minutes) ; passé ce délai il faut demander un nouveau lien PVID Cloud


Réponse | Succès

Code Status
201 Created

Exemple de réponse

snippet.json
{
    "id": 987654,
    "isPriority": 0,
    "customerEmail": "jean.dupont@example.com",
    "date": "2026-05-20 14:25:00",
    "dateExpireLink": "2026-05-20 14:55:00",
    "url": "https://pvid-front.../verify/abc123xyz789",
    "urlAfterSuccess": "https://votre-site.com/verification/succes",
    "urlAfterFailOrAbort": "https://votre-site.com/verification/echec",
    "fullHashSha256": "a1b2c3d4e5f6..."
}


Réponse | Erreurs

Code Status Slug Message
400 Bad Request N/A Request payload contains invalid "form" data.
400 Bad Request no_email No email parameter found in your request
400 Bad Request email_not_valid This value is not a valid email address.
400 Bad Request empty_url_after_success No urlAfterSuccess found in your request
400 Bad Request empty_url_after_fail_or_abort No urlAfterFailOrAbort found in your request
400 Bad Request alert_text_too_short This value is too short. It should have 5 characters or more.
400 Bad Request alert_text_too_long This value is too long. It should have 120 characters or less.
422 Unprocessable Entity webhook The webhook URL must use HTTPS
422 Unprocessable Entity linkValiditySharing This value should be of type int.
422 Unprocessable Entity linkValiditySharing This value should be positive.
422 Unprocessable Entity disableLinkSharing This value should be of type int.
422 Unprocessable Entity disableLinkSharing Values accepted : 0, 1.
422 Unprocessable Entity addUserAlertScreen This value should be of type int.
422 Unprocessable Entity addUserAlertScreen Values accepted : 0, 1.
422 Unprocessable Entity acceptedDocuments This value is not valid.
422 Unprocessable Entity isPriority This value should be of type int.
422 Unprocessable Entity isPriority Values accepted : 0, 1.
400 Bad Request invalid_date Wrong date format (must be YYYY-MM-DD HH:mm:ss, eg: 2021-10-19 20:10:06)
400 Bad Request empty_date No date parameter found in your request
400 Bad Request expired_date Given datetime is older than current datetime
400 Bad Request date_in_future Given datetime must be set between call submission and +10 minutes
400 Bad Request validation_error Signature verification failed
400 Bad Request failed_signature Signature verification failed
401 Unauthorized N/A JWT Token not found
401 Unauthorized N/A Expired JWT Token
401 Unauthorized user_not_exist Unknown user
500 Bad Request internal_server_error Internal server error


GET /api/pvid/{id} | Récupérer les résultats d'une vérification PVID

Voir dans le Swagger

Récupérer les informations d'un ID PVID donné.

Réponse | Vérification validée

Code Status
200 OK

Exemple de réponse

snippet.json
{
    "id": 987654,
    "dateAdded": "2026-05-20 14:25:00",
    "verdictDate": "2026-05-20 15:30:00",
    "status": "done",
    "verdict": "validated",
    "document": {
        "type": "ID_CARD",
        "emitCountry": "FR",
        "documentNumber": "AB1234567",
        "documentNumberLast4": "4567",
        "emitDate": "2020-01-15",
        "expirationDate": "2030-01-15",
        "holderFirstname": "Jean",
        "holderLastname": "DUPONT",
        "birthdate": "1985-06-20",
        "holderNationality": "FR",
        "holderGender": "M",
        "holderBirthplace": "Paris",
        "mrz": "IDFRADUPONT<<JEAN..."
    },
    "files": {
        "availableUntil": "2026-06-20 15:30:00",
        "front": "https://storage.../front.jpg",
        "back": "https://storage.../back.jpg",
        "biometry": "https://storage.../bio.jpg"
    }
}


Réponse | Vérification refusée

Code Status
200 OK

Exemple de réponse

snippet.json
{
    "id": 987654,
    "dateAdded": "2026-05-20 14:25:00",
    "verdictDate": "2026-05-20 15:30:00",
    "status": "done",
    "verdict": "refused",
    "abortedReason": null,
    "refusalReasons": [
        {
            "slug": "doc_is_expired",
            "text": "Les documents que vous nous avez présentés sont expirés. Il faut impérativement présenter une pièce d'identité en cours de validité"
        }
    ]
}

Voir la liste complète des motifs d'abandon


Réponse | Vérification expirée

Code Status
200 OK

Exemple de réponse

snippet.json
{
    "id": 987654,
    "dateAdded": "2026-05-20 14:25:00",
    "verdictDate": "2026-05-20 15:25:00",
    "status": "expired",
    "verdict": null,
    "abortedReason": "expired_link",
    "refusalReasons": null
}


Réponse | Vérification abandonnée

Code Status
200 OK

Exemple de réponse

snippet.json
{
    "id": 987654,
    "dateAdded": "2026-05-20 14:25:00",
    "verdictDate": "2026-05-20 14:35:00",
    "status": "aborted",
    "verdict": null,
    "abortedReason": "canceled",
    "refusalReasons": null
}

Voir la liste complète des motifs d'abandon


Réponse | Vérification en cours

Code Status
200 OK

Exemple de réponse

snippet.json
{
    "id": 987654,
    "dateAdded": "2026-05-20 14:25:00",
    "verdictDate": null,
    "status": "currently_created",
    "verdict": null,
    "abortedReason": null,
    "refusalReasons": null
}


Réponse | Erreurs

Code Status Slug Message
400 Bad Request invalid_date Wrong date format (must be YYYY-MM-DD HH:mm:ss, eg: 2021-10-19 20:10:06)
400 Bad Request empty_date No date parameter found in your request
400 Bad Request expired_date Given datetime is older than current datetime
400 Bad Request date_in_future Given datetime must be set between call submission and +10 minutes
400 Bad Request validation_error Signature verification failed
400 Bad Request failed_signature Signature verification failed
401 Unauthorized N/A JWT Token not found
401 Unauthorized N/A Expired JWT Token
401 Unauthorized user_not_exist Unknown user
500 Bad Request internal_server_error Internal server error


3.2 Configuration du parcours PVID

Cette section concerne les méthodes et les endpoints permettant de personnaliser votre parcours PVID.

La personnalisation du parcours concerne les éléments suivants,

  • graphique : logo, couleurs des textes/titres/boutons, favicon
  • technique : url de webhook
  • règlementaire : liste des titres acceptés
  • anti-fraude renforcé : écran d'alerte utilisateur, empêcher le partage du lien PVID

GET /api/configs | Obtenir la configuration PVID

Voir dans le Swagger

Récupérer les paramètres de la personnalisation actuelle.

Paramètres

Paramètre Type Description Requis
date string Date pour le chiffrement (YYYY-MM-DD HH:mm:ss)


Réponse | Succès

Code Status
200 OK

Exemple de réponse

snippet.json
{
    "webhook": "https://api.votre-domaine.com/pvid/webhook",
    "linkValiditySharing": 60,
    "disableLinkSharing": 0,
    "addUserAlertScreen": 1,
    "addUserAlertText": "<b>Attention</b>",
    "titleColor": "#003366",
    "textColor": "#333333",
    "linkColorText": "#0066CC",
    "buttonColorText": "#FFFFFF",
    "buttonColorBackground": "#003366",
    "ghostButtonColor": "#003366",
    "acceptedDocuments": [...],
    "logo": "data:image/png;base64,...",
    "favicon": "data:image/x-icon;base64,..."
}


Réponse | Erreurs

Code Status Slug Message
400 Bad Request invalid_date Wrong date format (must be YYYY-MM-DD HH:mm:ss, eg: 2021-10-19 20:10:06)
400 Bad Request empty_date No date parameter found in your request
400 Bad Request expired_date Given datetime is older than current datetime
400 Bad Request date_in_future Given datetime must be set between call submission and +10 minutes
400 Bad Request validation_error Signature verification failed
400 Bad Request failed_signature Signature verification failed
401 Unauthorized N/A JWT Token not found
401 Unauthorized N/A Expired JWT Token
401 Unauthorized user_not_exist Unknown user
500 Bad Request internal_server_error Internal server error


PUT /api/configs | Remplacer la configuration PVID

Voir dans le Swagger

Méthode permettant de remplacer entièrement la configuration actuelle de votre PVID.

Attention : cette méthode remplacera l'ensemble des données de configuration en place. Pour effectuer une modification partielle de la configuration utiliser la méthode “PATCH” de mise à jour de la configuration.

Paramètres

Paramètre Type Description Requis
webhook string URL webhook (HTTPS obligatoire)
titleColor string Couleur titres (#XXXXXX)
textColor string Couleur textes (#XXXXXX)
linkColorText string Couleur liens (#XXXXXX)
buttonColorText string Couleur texte boutons (#XXXXXX)
buttonColorBackground string Couleur fond boutons (#XXXXXX)
ghostButtonColor string Couleur boutons fantômes (#XXXXXX)
linkValiditySharing integer Validité du lien en minutes (max: 60)
disableLinkSharing integer Désactiver partage (0 ou 1)
addUserAlertScreen integer Écran d'alerte fraude (0 ou 1)
addUserAlertText string Texte alerte (5-120 car.)
acceptedDocuments array Documents acceptés
date string Date chiffrement


Réponse | Succès

Code Status
201 OK

Même format que GET /api/configs


Réponse | Erreurs

Code Status Slug Message
400 Bad Request alert_text_too_short The alert's text you submitted is too short (less than 5 characters)
400 Bad Request alert_text_too_long The alert's text you submitted is too long (more than 120 characters)
422 Unprocessable Entity champ en erreur parmi titleColor, textColor, linkColorText, buttonColorText, buttonColorBackground, ghostButtonColor This value is not a valid CSS color
422 Unprocessable Entity webhook The webhook URL must use HTTPS
422 Unprocessable Entity linkValiditySharing This value should be of type int
422 Unprocessable Entity linkValiditySharing This value should be positive
422 Unprocessable Entity disableLinkSharing This value should be of type int
422 Unprocessable Entity disableLinkSharing Values accepted : 0, 1
422 Unprocessable Entity addUserAlertScreen This value should be of type int
422 Unprocessable Entity addUserAlertScreen Values accepted : 0, 1
400 Bad Request invalid_date Wrong date format (must be YYYY-MM-DD HH:mm:ss, eg: 2021-10-19 20:10:06)
400 Bad Request empty_date No date parameter found in your request
400 Bad Request expired_date Given datetime is older than current datetime
400 Bad Request date_in_future Given datetime must be set between call submission and +10 minutes
400 Bad Request validation_error Signature verification failed
400 Bad Request failed_signature Signature verification failed
401 Unauthorized N/A JWT Token not found
401 Unauthorized N/A Expired JWT Token
401 Unauthorized user_not_exist Unknown user
500 Bad Request internal_server_error Internal server error


PATCH /api/configs | Mettre à jour la configuration PVID

Voir dans le Swagger

Méthode permettant de mettre à jour partiellement votre configuration PVID (seuls les champs fournis sont modifiés).

Paramètres

Champ Type Description Requis
webhook string URL webhook (HTTPS obligatoire)
titleColor string Couleur titres (#XXXXXX)
textColor string Couleur textes (#XXXXXX)
linkColorText string Couleur liens (#XXXXXX)
buttonColorText string Couleur texte boutons (#XXXXXX)
buttonColorBackground string Couleur fond boutons (#XXXXXX)
ghostButtonColor string Couleur boutons fantômes (#XXXXXX)
linkValiditySharing integer Validité du lien en minutes (max: 60)
disableLinkSharing integer Désactiver partage (0 ou 1)
addUserAlertScreen integer Écran d'alerte fraude (0 ou 1)
addUserAlertText string Texte alerte (5-120 car.)
acceptedDocuments array Documents acceptés
date string Date chiffrement


Réponse | Succès

Code Status
201 OK

Même format que GET /api/configs


Réponse | Erreurs

Code Status Slug Message
400 Bad Request alert_text_too_short The alert's text you submitted is too short (less than 5 characters)
400 Bad Request alert_text_too_long The alert's text you submitted is too long (more than 120 characters)
422 Unprocessable Entity champ en erreur parmi titleColor, textColor, linkColorText, buttonColorText, buttonColorBackground, ghostButtonColor This value is not a valid CSS color
422 Unprocessable Entity webhook The webhook URL must use HTTPS
422 Unprocessable Entity linkValiditySharing This value should be of type int
422 Unprocessable Entity linkValiditySharing This value should be positive
422 Unprocessable Entity disableLinkSharing This value should be of type int
422 Unprocessable Entity disableLinkSharing Values accepted : 0, 1
422 Unprocessable Entity addUserAlertScreen This value should be of type int
422 Unprocessable Entity addUserAlertScreen Values accepted : 0, 1
400 Bad Request invalid_date Wrong date format (must be YYYY-MM-DD HH:mm:ss, eg: 2021-10-19 20:10:06)
400 Bad Request empty_date No date parameter found in your request
400 Bad Request expired_date Given datetime is older than current datetime
400 Bad Request date_in_future Given datetime must be set between call submission and +10 minutes
400 Bad Request validation_error Signature verification failed
400 Bad Request failed_signature Signature verification failed
401 Unauthorized N/A JWT Token not found
401 Unauthorized N/A Expired JWT Token
401 Unauthorized user_not_exist Unknown user
500 Bad Request internal_server_error Internal server error


DELETE /api/configs | Réinitialiser la configuration

Voir dans le Swagger

Méthode permettant de réinitialiser la configuration de votre PVID pour revenir au paramètres par défaut.

Attention : cette requête supprime tous vos paramètres personnalisés

Paramètres

Paramètre Type Description Requis
date string Date pour le chiffrement


Réponse | Succès

Code Status
204 No Content


Réponse | Erreurs

Code Status Slug Message
400 Bad Request invalid_date Wrong date format (must be YYYY-MM-DD HH:mm:ss, eg: 2021-10-19 20:10:06)
400 Bad Request empty_date No date parameter found in your request
400 Bad Request expired_date Given datetime is older than current datetime
400 Bad Request date_in_future Given datetime must be set between call submission and +10 minutes
400 Bad Request validation_error Signature verification failed
400 Bad Request failed_signature Signature verification failed
401 Unauthorized N/A JWT Token not found
401 Unauthorized N/A Expired JWT Token
401 Unauthorized user_not_exist Unknown user
500 Bad Request internal_server_error Internal server error


GET /api/configs/documents | Liste des documents d'identité acceptés

Voir dans le Swagger

Endpoint permettant de récupérer la liste des documents d'identité acceptés par PVID.

Paramètres

Paramètre Type Description Requis
date string Date pour le chiffrement


Réponse | Succès

Code Status
200 OK

Exemple de réponse

snippet.json
{
    "allowedDocuments": [
        { "code": "FR", "name": "France", "documents": ["passport", "id_card", "residence_permit"] },
        { "code": "BE", "name": "Belgium", "documents": ["passport", "id_card"] }
    ]
}


Réponse | Erreurs

Code Status Slug Message
400 Bad Request invalid_date Wrong date format (must be YYYY-MM-DD HH:mm:ss, eg: 2021-10-19 20:10:06)
400 Bad Request empty_date No date parameter found in your request
400 Bad Request expired_date Given datetime is older than current datetime
400 Bad Request date_in_future Given datetime must be set between call submission and +10 minutes
400 Bad Request validation_error Signature verification failed
400 Bad Request failed_signature Signature verification failed
401 Unauthorized N/A JWT Token not found
401 Unauthorized N/A Expired JWT Token
401 Unauthorized user_not_exist Unknown user
500 Bad Request internal_server_error Internal server error


POST /api/configs/files | Mettre à jour les fichiers

Voir dans le Swagger

Méthode permettant de mettre à jour le logo et le favicon du parcours PVID.

Cette requête utilise le multipart/form-data pour l'upload des fichiers.

Paramètres

Champ Type Description Requis
logo file Image PNG/JPEG (hauteur max: 64px)
favicon file Image PNG/JPEG/ICO (hauteur max: 64px)
date string Date pour chiffrement (YYYY-MM-DD HH:mm:ss)


Réponse | Succès

Code Status
201 OK

Même format que GET /api/configs


Réponse | Erreurs

Code Status Slug Message
422 Unprocessable Entity logo.path This value should be of type string
422 Unprocessable Entity favicon.path This value should be of type string
400 Bad Request invalid_date Wrong date format (must be YYYY-MM-DD HH:mm:ss, eg: 2021-10-19 20:10:06)
400 Bad Request empty_date No date parameter found in your request
400 Bad Request expired_date Given datetime is older than current datetime
400 Bad Request date_in_future Given datetime must be set between call submission and +10 minutes
400 Bad Request validation_error Signature verification failed
400 Bad Request failed_signature Signature verification failed
401 Unauthorized N/A JWT Token not found
401 Unauthorized N/A Expired JWT Token
401 Unauthorized user_not_exist Unknown user
500 Bad Request internal_server_error Internal server error


DELETE /api/configs/files | Supprimer les fichiers

Voir dans le Swagger

Méthode permettant de supprimer vos logo/favicon du parcours PVID pour remettre les logo/favicon par défaut.

Attention : cette requête supprime votre logo et votre favicon.

Paramètres

Paramètre Type Description Requis
date string Date pour le chiffrement (YYYY-MM-DD HH:mm:ss)


Réponse | Succès

Code Status
204 No Content


Réponse | Erreurs

Code Status Slug Message
——– —– —– ——–
400 Bad Request invalid_date Wrong date format (must be YYYY-MM-DD HH:mm:ss, eg: 2021-10-19 20:10:06)
400 Bad Request empty_date No date parameter found in your request
400 Bad Request expired_date Given datetime is older than current datetime
400 Bad Request date_in_future Given datetime must be set between call submission and +10 minutes
400 Bad Request validation_error Signature verification failed
400 Bad Request failed_signature Signature verification failed
401 Unauthorized N/A JWT Token not found
401 Unauthorized N/A Expired JWT Token
401 Unauthorized user_not_exist Unknown user
500 Bad Request internal_server_error Internal server error


3.3 Tests de compatibilité de l'appareil de l'utilisateur

Cette section concerne les endpoints permettant de tester, en amont du parcours PVID, certains paramètres de compatibilité de l'appareil de l'utilisateur.

GET /api/browser/list | Navigateurs compatibles

Voir dans le Swagger

Méthode permettant de récupérer la liste des navigateurs, et leurs versions, pris en charge par le PVID.

Paramètres

Paramètre Type Description Requis
date string Date pour le chiffrement (YYYY-MM-DD HH:mm:ss)


Réponse | Succès

Code Status
201 OK

Exemple de réponse

snippet.json
{
    "safari": "14",
    "chrome": "110",
    "firefox": "66",
    "samsung": "6",
    "opera": "73",
    "edge": "79",
    "miui": "13.21"
}


GET /api/browser/check | Vérifier un navigateur

Voir dans le Swagger

Méthode permettant de tester la compatibilité du navigateur de l'utilisateur.

Paramètres

Paramètre Type Description Requis
name string Nom du navigateur
version string Version du navigateur


Réponse | Succès

Code Status
201 OK

Exemple de réponse

snippet.json
{ "result": "The user's browser can be used for a PVID" }


Réponse | Erreurs

Code Slug Message
400 missing_browser_name The browser's name is missing
400 missing_browser_version The browser's version is missing
400 unknown_browser_name The browser's name is unknown
400 invalid_browser_version The browser's version is invalid
400 empty_date No date parameter found in your request
400 invalid_date Wrong date format (must be YYYY-MM-DD HH:mm:ss, eg: 2021-10-19 20:10:06)
400 expired_date Given datetime is older than current datetime
400 date_in_future Given datetime must be set between call submission and +10 minutes
401 error JWT Token not found


GET /api/camera/resolution | Résolution de la caméra

Voir dans le Swagger

Méthode permettant de récupérer la résolution minimale requise pour la caméra de l'appareil de l'utilisateur.

Paramètres

Paramètre Type Description Requis
date string Date pour le chiffrement (YYYY-MM-DD HH:mm:ss)


Réponse | Succès

Code Status
——– —–
200 OK

Exemple de réponse

snippet.json
{ "height": 720, "width": 1280 }


Réponse | Erreurs

Code Status Slug Message
400 Bad Request invalid_date Wrong date format (must be YYYY-MM-DD HH:mm:ss, eg: 2021-10-19 20:10:06)
400 Bad Request empty_date No date parameter found in your request
400 Bad Request expired_date Given datetime is older than current datetime
400 Bad Request date_in_future Given datetime must be set between call submission and +10 minutes
400 Bad Request validation_error Signature verification failed
400 Bad Request failed_signature Signature verification failed
401 Unauthorized N/A JWT Token not found
401 Unauthorized N/A Expired JWT Token
401 Unauthorized user_not_exist Unknown user
500 Bad Request internal_server_error Internal server error


4. Webhooks

Les événements webhook permettent au métier d'être informé en temps réel de chaque changement d'état d'un PVID.

4.1 Configuration

Pour recevoir des événements webhook il faut renseigner une URL en HTTPS dans le paramètre webhook des endpoints POST /api/pvid, PUT /api/configs ou PATCH /api/configs.


4.2 Réponse

Lors de la réception de l'événement vous devez nous retourner un code HTTP 200.

Si le code HTTP de réponse de votre part est différent, nous allons effectuer jusqu'à 48 tentatives. Nous augmenterons les timeout au fur et à mesure de ces tentatives selon le fonctionnement suivant,

  • 1ère à 9ème tentative : 2.5s timeout
  • 10ème à 19ème tentative : 4.5s timeout
  • 20ème à 29ème tentative : 6.5s timeout
  • 30ème à 39ème tentative : 8.5s timeout
  • 40ème à 48ème tentative : 11s timeout


4.3 Evénements

Les événements transmis par PVID sont les suivants,

Événement Description Déclencheur
validated PVID validé L'identité a été vérifiée avec succès
refused PVID refusé L'identité n'a pas pu être vérifiée
aborted PVID abandonné L'utilisateur a abandonné le parcours
expired PVID expiré Le lien de vérification a expiré


4.4 Payload

Les informations des événements webhook sont transmises au format Json.

Exemple de payload

snippet.json
{
    "pvid_id": "987654",
    "event": "validated",
    "event_date": "2026-05-20T15:30:00+00:00"
}
Champ Type Description
pvid_id string Identifiant unique de la vérification PVID
event string Type d'événement (validated, refused, aborted, expired)
event_date string Date et heure de l'événement (format ISO 8601)


5. Annexes

5.1 Diagramme de séquence

Voici un diagramme de séquence simplifié de l'utilisation de PVID Cloud.

sequenceDiagram participant Client as Serveur Client participant API as API PVID Cloud participant Browser as Navigateur Utilisateur rect rgb(200, 220, 255) Note over Client,Browser: Phase 1 : Initialisation & Authentification Client->>API: 1. POST /api/login Note right of Client: Identifiants API-->>Client: 2. access_token + refresh_token end rect rgb(200, 250, 200) Note over Client,Browser: Phase 2 : Configuration (optionnel) Client->>API: 3. GET /api/configs Note right of Client: Bearer + date API-->>Client: 4. Configuration (chiffrée AES-256-CBC) end rect rgb(255, 240, 200) Note over Client,Browser: Phase 3 : Création Vérification Client->>API: 5. POST /api/pvid Note right of Client: idUser, email, URLs, docs, webhook, date API-->>Client: 6. ID vérification + URL PVID Client->>Browser: 7. Redirection vers URL PVID Note right of Client: Valide 30-60 minutes end rect rgb(255, 220, 220) Note over Browser: Phase 4 : Parcours Utilisateur Browser->>Browser: 8. Capture document + selfie Note over Browser: Hors API Browser-->>Client: 9. Callback (succès ou échec) end rect rgb(220, 240, 220) Note over Client,API: Phase 5 : Notifications & Résultats API->>Client: 10. Webhook : status, verdict, event_date Note right of API: Notification en temps réel Client-->>API: 11. HTTP 2xx (accusé de réception) Client->>API: 12. GET /api/pvid/{id} Note right of Client: Bearer + date API-->>Client: 13. Résultats (verdict, document, fichiers chiffrés) end


5.2 Documents d'identité

Format

La nomenclature des différents documents d'identité accepté par le PVID Docaposte est la suivante : {CODE_PAYS}-{TYPE_DOCUMENT}.

Ce format est à utiliser dans les endpoints permettant de personnaliser les titres acceptés par le PVID.

Il sera également utilisé dans l'ensemble des retours de l'API PVID Cloud.

Exemples

  • FR-passport — Passeport français
  • FR-id_card — Carte d'identité française
  • BE-residence_permit — Titre de séjour belge

La liste complète des documents acceptés par pays est disponible via l'endpoint GET /api/configs/documents.

5.3 Motifs d'abandon

Ajout d'un paramètre dans l'URL d'abandon

Lorsque l'utilisateur est redirigé vers l'URL url_after_fail_or_abort transmis dans la requête de génération d'un lien PVID PVID Cloud rajoute un paramètre dans l'URL contenant le motif d'abandon du parcours.

Les motifs retournés sont les suivants,

Slug Description
canceled L'utilisateur a quitté le parcours inopinément (fermeture du navigateur, rafraichissement de la page, …)
expired_link Le lien du PVID est expiré et ne permet plus d'effectuer le parcours
no_camera L'utilisateur n'a pas donné accès à sa caméra
camera_resolution La résolution de la caméra n'est pas suffisante
browser_not_supported Le navigateur utilisé n'est pas accepté pour le PVID
browser_version La version du navigateur utilisé n'est pas acceptée pour le PVID
network La connexion internet de l'utilisateur est insuffisante
document_not_accepted L'utilisateur ne possède aucun titre d'identité accepté pour le PVID
recording_error Nous avons rencontré une difficulté lors de la capture vidéo
Exemple

L'accès à la caméra n'est pas autorisé : url_after_fail_or_abort?error=no_camera

Transmission via API

En plus d'être transmis dans l'URL url_after_fail_or_abort les motifs d'abandon sont également retournés via le paramètre abortedReason de la route GET /api/pvid/{id}.

5.4 Motifs de refus

Voici la liste des motifs de refus pour lesquels une vérification PVID peut être refusée.

Slug Description
document_capture_bad_quality Votre document d'identité n'a pas pu être analysé. Assurez-vous que votre pièce d'identité soit entièrement visible, bien cadrée et que la qualité vidéo permette de lire clairement les informations
biometry_capture_bad_quality La vérification n'a pas pu aboutir en raison de problèmes liés à la qualité de l'enregistrement ou à la reconnaissance du visage
document_not_accepted Le document présenté n'est pas accepté par notre service de vérification d'identité à distance
document_expired Le document présenté est expiré
document_not_allowed Votre document d'identité ne peut être accepté par nos services. Assurez-vous de présenter l'original (passeport, titre de séjour ou carte d'identité), en bon état sans étui ni obstruction visuelle.
document_not_complete Votre document n'a pas pu être entièrement analysé car une face est manquante ou mal cadrée
action_not_complete Les actions effectuées lors de la capture vidéo du document ou du visage n'ont pas été correctement réalisées et n'ont pas pu permettre la vérification de l'identité. Assurez-vous de bien respecter les consignes affichées lors du parcours (inclinaison et positionnement dans le cadre).
biometry_not_conform Les conditions dans lesquelles vous avez effectué votre vérification d'identité ne permettent pas de la traiter. Assurez-vous que votre visage soit entièrement visible, sans lunettes de soleil, verres teintés ou masque.
fraud_is_suspected Les conditions dans lesquelles vous avez effectué votre vérification d'identité ne permettent pas à notre service de la traiter
period_expired Un problème technique a empêché le traitement de votre vérification d'identité dans les delais impartis
technical_error Un problème technique a empêché le traitement de votre vérification d'identité

This website uses cookies. By using the website, you agree with storing cookies on your computer. Also, you acknowledge that you have read and understand our Privacy Policy. If you do not agree, please leave the website.

Plus d’informations