Documentation
Intégrer Verifyed
Tout ce qui est décrit ici correspond au service déployé. La référence des routes est lue sur le contrat OpenAPI de l'API au moment où vous ouvrez cette page.
1
Démarrer
Créez votre organisation sur la page d'inscription, puis générez une clé d'API dans votre espace, rubrique Développeurs. Une clé commence par sk_, n'est affichée qu'une fois, et appartient à un environnement : test ou live.
Chaque appel porte la clé dans l'en-tête Authorization. Les appels qui créent quelque chose portent aussi une clé d'idempotence d'au moins huit caractères : rejouer le même appel avec la même clé renvoie le même résultat au lieu de créer un doublon.
curl https://api.verifyed.online/v1/balance \
-H "Authorization: Bearer sk_votre_cle"
curl https://api.verifyed.online/v1/sessions \
-H "Authorization: Bearer sk_votre_cle" \
-H "Idempotency-Key: commande-104233" \
-H "Content-Type: application/json" \
-d '{ "product": "kyc.basic", "country": "CI", "reference": "CLT-104233" }'Jamais côté navigateur
La clésk_ ne quitte pas votre serveur. Le navigateur ne reçoit que le jeton de session (st_) d'un parcours, limité à ce parcours et périmé avec lui.2
Environnements de test et de production
Une clé test ouvre des sessions d'essai : rien n'est facturé, aucun examinateur n'intervient, et ces sessions sont invisibles des clés de production. Chaque réponse et chaque webhook indique livemode à false. Les webhooks d'essai ne partent qu'aux points de terminaison déclarés en environnement test.
Pour éprouver vos branches de code, fixez l'issue d'une session d'essai : elle suit alors le vrai chemin, mêmes transitions, mêmes événements, mêmes webhooks.
curl -X POST https://api.verifyed.online/v1/sessions/{session_id}/simulate \
-H "Authorization: Bearer sk_cle_de_test" \
-H "Content-Type: application/json" \
-d '{ "outcome": "review", "reason": "Scénario : pièce illisible" }'
# outcome : approved | rejected | review3
Ouvrir une vérification
Trois voies, selon ce que vous voulez développer. Elles aboutissent toutes au même dossier, à la même décision et aux mêmes webhooks.
Lien de vérification
Votre serveur demande un lien ; la personne l'ouvre sur son téléphone ou son ordinateur. Canal email : la plateforme envoie le courriel. Canal link : vous transmettez l'adresse vous-même. Durée de validité de 1 à 720 heures.
curl -X POST https://api.verifyed.online/v1/links \
-H "Authorization: Bearer sk_votre_cle" \
-H "Content-Type: application/json" \
-d '{
"type": "kyc", "kyc_level": "standard", "country": "CI",
"channel": "email", "ttl_hours": 72,
"recipient_name": "Awa Koné", "recipient_email": "awa@exemple.ci",
"external_ref": "CLT-104233"
}'
# → 201 { "link": { "id", "token", "url", "status", "expires_at", "delivery", … } }Widget dans votre site
Déclarez d'abord l'origine de votre page dans votre espace (Développeurs, origines du widget) : le parcours ne s'affichera que depuis ces origines. Puis votre serveur ouvre une session de widget et remet le jeton à la page, qui charge le SDK.
# Serveur
curl -X POST https://api.verifyed.online/v1/widget/sessions \
-H "Authorization: Bearer sk_votre_cle" \
-H "Content-Type: application/json" \
-d '{ "external_ref": "CLT-104233", "kyc_level": "standard", "country": "CI" }'
# → 201 { "session_token": "…", "link_id": "…", "expires_at": "…" } (30 minutes, usage unique)
<!-- Page -->
<script src="https://www.verifyed.online/sdk/v1.js" defer></script>
<script>
KycWidget.open({ // ou KycWidget.mount("#conteneur", { … })
sessionToken,
locale: "fr",
onSubmitted: ({ reference, status }) => { /* statut indicatif */ },
onExit: ({ reason }) => { /* user_closed | completed */ },
onError: ({ code, message }) => { /* invalid_token, token_expired, origin_not_allowed… */ },
});
</script>Les événements du navigateur servent à l'affichage. La décision qui fait foi arrive à votre serveur par webhook : c'est lui qui débloque un compte ou un service.
API complète
Votre application pilote chaque étape : ouverture avec gel du prix, consentement, dépôt des pièces, défi de vivacité, soumission. C'est la voie des parcours entièrement intégrés dans votre propre interface. Les routes sont détaillées dans la référence ci-dessous, rubrique Sessions et Pièces.
4
Suivre et relire un dossier
| Route | Usage |
|---|---|
GET /v1/sessions/{id} | État courant : étape, décision, motif, montant gelé ou débité. |
GET /v1/sessions/{id}/events | Chronologie numérotée (seq). Curseur de reprise après un incident. |
GET /v1/sessions/{id}/stream | Flux temps réel en Server-Sent Events, pour une interface qui suit la session. |
GET /v1/cases | Vos dossiers, avec filtres et pagination. |
GET /v1/balance | Solde disponible, réservé et total du compte prépayé. |
Les états d'une session : created, collecting, processing, puis approved, rejected, failed, cancelled ou expired. Un dossier envoyé en revue manuelle reste en processing jusqu'à la décision de l'examinateur.
5
Webhooks signés
Déclarez un point de terminaison HTTPS ; la réponse contient son secret de signature, affiché une seule fois. Vous pouvez filtrer les types d'événements, faire tourner le secret, envoyer un essai et rejouer une livraison.
curl -X POST https://api.verifyed.online/v1/webhook_endpoints \
-H "Authorization: Bearer sk_votre_cle" \
-H "Content-Type: application/json" \
-d '{ "url": "https://votre-serveur.example/hooks", "event_kinds": ["session.decided"] }'
# → 201 { "id", "url", "event_kinds", "status", "secret": "…" }Chaque livraison est un POST JSON avec trois en-têtes, au format Standard Webhooks :
webhook-id: <identifiant de livraison> dédupliquez sur cet identifiant
webhook-timestamp: <secondes Unix> rejetez au-delà de cinq minutes d'écart
webhook-signature: v1,<base64(HMAC-SHA256)> calculée sur "{webhook-id}.{webhook-timestamp}.{corps brut}"
{
"type": "session.decided",
"session_id": "…",
"seq": 7,
"created_at": "2026-10-08T09:41:07Z",
"livemode": true,
"data": { "from": "processing", "outcome": "approved", "reason": null }
}Types émis : session.created, session.state_changed, session.decided, balance.debited, balance.released, ainsi que verification.created, verification.review, verification.approved et verification.rejected. Répondez par un code 2xx en moins de dix secondes ; sinon la livraison est retentée huit fois, avec des délais croissants de dix secondes à six heures. Les échecs restent consultables et rejouables depuis votre espace.
Vérifier la signature
Recalculez le HMAC-SHA256 du message{webhook-id}.{webhook-timestamp}.{corps} avec votre secret, encodez-le en base64 et comparez-le, en temps constant, à la valeur qui suit v1,. Un en-tête x-signature au format t=…,v1=… est aussi fourni pour les bibliothèques qui l'attendent.6
Erreurs
Toute erreur est un document application/problem+json (RFC 9457) avec un champ code stable, destiné à votre code, et un detail destiné à un humain. Les codes HTTP suivent l'usage : 400 corps invalide, 401 clé absente ou inconnue, 402 solde insuffisant, 404 ressource inconnue pour cette clé, 409 conflit d'idempotence ou d'état, 422 réglage refusé, 429 trop d'appels.
{
"type": "about:blank",
"title": "Solde insuffisant",
"status": 402,
"code": "insufficient-funds",
"detail": "Le solde disponible ne couvre pas le prix du produit."
}7
Référence des routes
Contrat OpenAPI 0.1.0 lu sur l'API déployée. Le document complet, avec les schémas, est à https://api.verifyed.online/openapi.json.
Sessions
Cycle de vie d'une vérification
- GET
/v1/casesDossiers de l'organisation
Sessions envoyées, avec leur statut de dossier (pending, in_review, awaiting_documents, approved, rejected, expired), leur risque et leur revue. Les identités sont masquées pour qui n'a pas le droit de les lire.
- GET
/v1/cases/{session_id}Un dossier : contrôles, champs lus, entreprise, personnes, pièces
- GET
/v1/reviewsVérifications retenues pour examen humain
Pourquoi une session n'avance pas. Un dossier `blocking` interdit toute décision automatique : la session attend un examinateur, quelles que soient les pièces déposées ensuite. La décision est rendue par nos analystes — cette route ne l'expose pas, elle explique l'attente.
- GET
/v1/sessionsDernières vérifications du compte
Fenêtre récente, de la plus récente à la plus ancienne. Sert à retrouver une session dont l'identifiant n'a pas été conservé, ou à reprendre après un incident. L'export d'historique complet n'est pas cette route.
- POST
/v1/sessionsOuvrir une vérification
Gèle le prix du produit. Échoue en 402 si le solde ne le couvre pas, avant tout traitement coûteux.
- GET
/v1/sessions/{session_id}État courant d'une session
- POST
/v1/sessions/{session_id}/cancelAbandonner une vérification
Rend les fonds gelés. Impossible une fois l'analyse engagée (`processing`) : le travail est déjà consommé.
- POST
/v1/sessions/{session_id}/consentConsigner le consentement de la personne
À appeler avant toute collecte. Idempotent pour une même finalité et une même version du texte. Émet `consent.granted`. Conservé en ajout seul : un retrait se date, il ne s'efface pas.
- PUT
/v1/sessions/{session_id}/documentChoisir le pays et la pièce d'identité
Validé contre le catalogue : pays ouvert, palier de la session ouvert sur ce pays, pièce d'identité active et recevable à ce palier. Changer de pièce efface la lecture en temps réel précédente. Émet `document.chosen`.
- GET
/v1/sessions/{session_id}/eventsJournal des événements
- GET
/v1/sessions/{session_id}/extractionDernière lecture, corrections comprises
- POST
/v1/sessions/{session_id}/extractionLire la pièce en temps réel
Lit la pièce déposée (zone codée, face imprimée) et juge chaque champ par le gabarit du pays : obligatoire, format, confiance, recoupement avec la zone codée. À appeler après le dépôt du document, pour l'écran de relecture. Ne décide rien : l'analyse finale relit la pièce à l'envoi. Émet `extraction.completed` (clés en défaut, sans valeurs).
- PATCH
/v1/sessions/{session_id}/extractionCorriger des valeurs lues
La personne corrige ce qui a été mal lu. La valeur probante n'est jamais remplacée : l'examinateur voit les deux, et corriger une valeur protégée par un chiffre de contrôle bloque le dossier (`CorrectionConflictsWithMrz`). Refusé une fois la session envoyée. Émet `extraction.corrected` (clés seulement).
- POST
/v1/sessions/{session_id}/liveness/challengesTirer la séquence de vivacité
Trois mouvements tirés par le serveur, dont toujours une rotation de tête, dans un ordre imprévisible : une séquence connue d'avance se rejoue avec une vidéo. Émet `liveness.challenges_issued`.
- GET
/v1/sessions/{session_id}/streamFlux temps réel (Server-Sent Events)
Diffuse chaque étape au moment où elle se produit et se ferme seul sur une session terminée. En cas de coupure, renvoyer l'en-tête `Last-Event-ID` pour reprendre exactement où le flux s'était arrêté.
Solde
Consultation du solde prépayé
- GET
/v1/balanceSolde disponible, réservé et total
- PUT
/v1/balance/alertRégler le seuil d'alerte de solde
Sous ce seuil, un événement `balance.low` part vers les destinations webhook actives. Il n'est envoyé qu'une fois : la marque se lève au premier rechargement, faute de quoi chaque débit sous le seuil enverrait une alerte et le client cesserait de les lire.
Webhooks
Notifications sortantes signées
- GET
/v1/webhook_deliveriesJournal des livraisons
- POST
/v1/webhook_deliveries/{delivery_id}/retryRemettre une livraison abandonnée en file
Réservé aux livraisons épuisées après leurs huit tentatives. Le compteur repart à zéro et la livraison est reprise au tour suivant du distributeur.
- GET
/v1/webhook_endpointsLister les destinations
- POST
/v1/webhook_endpointsEnregistrer une destination
Le secret de signature n'est renvoyé qu'ici, une seule fois. L'URL doit être en HTTPS.
- DELETE
/v1/webhook_endpoints/{endpoint_id}Désactiver une destination
Désactivation, pas suppression : « cette destination a reçu des livraisons jusqu'au 12 mars » est une information d'audit, une ligne absente n'en est pas une. Les livraisons déjà en file ne sont plus tentées.
- POST
/v1/webhook_endpoints/{endpoint_id}/rotateNouveau secret de signature
- POST
/v1/webhook_endpoints/{endpoint_id}/testEnvoi d'essai signé
Pièces
Dépôt des images depuis l'appareil
- GET
/v1/artifacts/{artifact_id}/duplicatesAutres sessions ayant déposé la même image
Rapprochement par empreinte du contenu. Une même photo présentée dans plusieurs dossiers est un signal de fraude ; ce n'en est pas la preuve.
- GET
/v1/sessions/{session_id}/artifactsMétadonnées des pièces déposées
Ne renvoie jamais les octets. Une image d'identité n'a pas à retraverser le réseau, et l'exposer ouvrirait une voie de récupération des données biométriques.
- POST
/v1/sessions/{session_id}/artifactsDéposer une image
Le corps est le **binaire brut** de l'image, pas du multipart ni du base64 : deux mégaoctets encodés en base64 en font presque trois, pour rien. Les métadonnées voyagent en en-têtes. Le type déclaré ne fait pas foi : le format est reconnu à ses octets d'en-tête, et un `Content-Type` qui ne correspond pas est refusé. Un dépôt est immuable — redéposer le même type dans la même session est un conflit. Limites : 8 Mio par image, 24 pièces par session, `image/jpeg`, `image/png` ou `image/webp`.
Passerelle
Capture déportée de l'ordinateur vers le téléphone
- POST
/v1/handoffs/claimRejoindre une session depuis le téléphone
Consomme le jeton lu dans le QR code et remet au téléphone son propre jeton de session, de portée identique à celui de l'ordinateur. Sans autre authentification : c'est le jeton qui authentifie. Un jeton inconnu, périmé ou déjà lu répond de la même façon (404).
- GET
/v1/sessions/{session_id}/handoffÉtat de la passerelle la plus récente
- POST
/v1/sessions/{session_id}/handoffDéporter la capture vers un téléphone
Émet un jeton de passerelle à encoder dans un QR code, sous la forme d'une URL de continuation. Le jeton vit dix minutes, ne sert qu'une fois, et n'est **pas** le jeton de session : il peut traverser un écran que d'autres regardent. Réémettre périme la passerelle précédente et révoque le téléphone qui l'avait réclamée. L'écran qui l'a demandé n'a ensuite qu'à écouter le flux SSE : `handoff.claimed` quand le téléphone se connecte, `artifact.uploaded` à chaque image, `handoff.completed` quand il a terminé.
- POST
/v1/sessions/{session_id}/handoff/completeDéclarer la capture mobile terminée
Appelée par le téléphone après la dernière image. Son jeton de session est révoqué dans la même transaction : il ne peut plus rien déposer, et l'ordinateur reprend la main.
Catalogue
Pays couverts et pièces acceptées
- GET
/v1/countriesPays couverts et pièces acceptées
Sans authentification : c'est la liste que l'utilisateur final voit dans un sélecteur, avant d'avoir le moindre jeton. Ne renvoie que les pays et pièces ouverts. Pour chaque pièce : les faces à photographier, le format lisible par machine attendu, et les règles propres au document. Pour chaque pays : les pièces d'entreprise attendues et les seuils de décision. Une session ouverte pour un pays absent d'ici répond 422.
Personnes
Dirigeants et bénéficiaires effectifs d'une entreprise
- GET
/v1/sessions/{session_id}/personsPersonnes déclarées sur le dossier d'entreprise
- POST
/v1/sessions/{session_id}/personsDéclarer un dirigeant, un bénéficiaire effectif ou un signataire
Un bénéficiaire effectif se déclare avec sa part détenue. Au plus douze personnes par dossier ; au moins une avant l'envoi.
- DELETE
/v1/sessions/{session_id}/persons/{person_id}Retirer une personne déclarée
Refusé une fois sa vérification d'identité ouverte.
- POST
/v1/sessions/{session_id}/persons/{person_id}/kycOuvrir la vérification d'identité d'une personne
Crée une session `person` sur le compte — son prix est gelé — rattachée au dossier d'entreprise dans ses métadonnées, et rend un jeton de passerelle (`hd_…`, trois jours, usage unique) à placer dans le lien transmis à la personne : `/verifier?jeton=…`. C'est elle qui consent et capture, dans son propre parcours.
Réservations
Gel et débit du solde, hors vérification
- POST
/v1/reservationsGeler un montant sans ouvrir de vérification
Sert aux traitements dont le prix n'est pas celui d'un produit du catalogue. Le cycle est le même que celui d'une session : gel, puis débit (`capture`) ou restitution (`release`).
- GET
/v1/reservations/{session_id}État d'une réservation
- POST
/v1/reservations/{session_id}/captureDébiter la réservation
Idempotent : rejouer une capture déjà faite renvoie 200. Le client qui a perdu la réponse n'a donc rien de particulier à gérer. Capturer une réservation déjà libérée reste un conflit réel.
- POST
/v1/reservations/{session_id}/releaseRestituer la réservation au solde disponible
Idempotent, au même titre que la capture.
Bac à sable
- POST
/v1/sessions/{session_id}/simulateSimuler l'issue d'une session d'essai
Réservé aux sessions ouvertes avec une clé `test`. Fixe l'issue (`approved`, `rejected` ou `review`) en suivant le vrai chemin : mêmes transitions, mêmes événements, mêmes webhooks (envoyés aux seuls points de terminaison `test`, avec `livemode: false`). Rien n'est facturé, personne n'est certifié.
Clients vérifiés
- GET
/v1/subjectsClients vérifiés et revues périodiques
Risque, statut PPE, prochaine revue, fin de relation, conservation. `due=true` : revues arrivées à échéance (aussi notifiées par webhook `subject.review_due`).
- GET
/v1/subjects/{external_ref}Droit d'accès : tout ce qui est détenu sur la personne
- POST
/v1/subjects/{external_ref}/erasureTransmettre une demande d'effacement de la personne
Pendant la conservation légale, l'effacement est différé et l'accès restreint (`status: restricted`, avec la date d'échéance et la base légale) ; après, effacement immédiat (`status: erased`).
- POST
/v1/subjects/{external_ref}/relationship-endDéclarer la fin de la relation d'affaires
La conservation légale (10 ans) court à partir de cette date ; la surveillance continue s'arrête. Données effacées à l'échéance (webhook `subject.purged`).
Consentement
- GET
/v1/consent-noticeNotice d'information à afficher avant la collecte
Construite depuis vos réglages (responsable du traitement, délégué, hébergement, conservation, alternative en agence). Renvoyez `version` et `hash` avec le consentement : le texte exact est conservé comme preuve.
Entreprises
- GET
/v1/kyb/draftSaisie et état du dossier
- PUT
/v1/kyb/draftEnregistrer la saisie
- POST
/v1/kyb/draft/documentsFournir une pièce après soumission
Corps : le fichier (image ou PDF) ; `x-artifact-doc-type` : la pièce demandée par le pays.
- POST
/v1/kyb/draft/persons/{person_id}/kycVérifier l'identité d'une personne du dossier
Ouvre sa session d'identité au niveau du dossier et rend un jeton de passerelle (72 h).
- POST
/v1/kyb/draft/sessionOuvrir la session où déposer les pièces
Ouvre (ou rouvre, sans second prix gelé) la session facturée de la soumission et rend un jeton limité à elle, pour déposer les pièces par `POST /v1/sessions/{id}/artifacts` avec `x-artifact-doc-type`.
- POST
/v1/kyb/draft/submitSoumettre le dossier
Le service rejoue toutes les règles : pièces exigées par le pays à ce niveau (les différables mettent le dossier en attente), format du numéro d'immatriculation, exigence de bénéficiaires effectifs selon la forme juridique, le niveau et le seuil du pays, repli sur le dirigeant. Enregistre l'entreprise, le dirigeant et les bénéficiaires, consigne le motif d'une exemption, et remet le dossier à un examinateur.
- POST
/v1/kyb/draftsOuvrir un parcours KYB hébergé
Appelé par le serveur du client, avec la clé du compte. Rend un lien de reprise (`kd_…`, 30 jours) à remettre au représentant de l'entreprise : il porte la saisie au fil des jours, puis le suivi et les pièces différées. N'engage aucun prix : la session facturée n'est ouverte qu'à la soumission.
- POST
/v1/sessions/{session_id}/challengeEnvoyer un code de confirmation
Le code part vers l'adresse **déclarée dans le profil**, jamais vers une adresse fournie ici : laisser choisir la destination au moment de l'envoi reviendrait à laisser le sujet se confirmer sur une boîte jetable. Valable une heure, trois essais. Émettre un nouveau code invalide le précédent. Seul `email` est acheminé aujourd'hui.
- POST
/v1/sessions/{session_id}/challenge/verifyConfirmer le code reçu
- PUT
/v1/sessions/{session_id}/companyDéclarer l'entreprise vérifiée
Remplaçable tant que la session est ouverte : un formulaire de dix champs se corrige, et refuser la correction pousserait à rouvrir une session — donc à payer deux fois. Le téléphone s'écrit en E.164, indicatif compris.
- POST
/v1/sessions/{session_id}/submitClore la collecte et remettre le dossier
Clôt la collecte ; la session ne s'abandonne plus. Pour une **personne**, l'analyse démarre : lecture de la zone codée et de la face imprimée, appariement du visage au portrait du document, épreuve de rotation de tête, aiguillage par les règles puis par les seuils du pays. La décision (`session.decided`) ou la mise en revue arrivent par le flux et le webhook ; `analysis.completed` les précède avec les scores. Pour une **entreprise**, le dossier part à un examinateur : profil déclaré, contact confirmé et au moins une pièce sont exigés.
Filtrage LBC/FT
- GET
/v1/screening/alertsAlertes sanctions et PPE de vos dossiers
Correspondances entre vos clients (personnes, sociétés, dirigeants, bénéficiaires effectifs) et les listes de sanctions (ONU, OFAC, UE, Royaume-Uni, France, listes nationales) ou de personnes politiquement exposées. Levées à l'entrée en relation et à chaque mise à jour des listes (surveillance continue). Chaque alerte vous est aussi notifiée par webhook : `screening.alert`, puis `screening.confirmed` (correspondance confirmée : gel et déclaration à votre cellule de renseignement financier) ou `screening.cleared` (homonymie).
Liens
- GET
/v1/linksLiens de vérification émis
- POST
/v1/linksÉmettre un lien de vérification
Le dossier naîtra chez vous, au niveau et dans le pays imposés. Canal `email` : le lien part par courriel ; `sms` : aucun opérateur raccordé, `delivery: not_available` — transmettez le lien vous-même.
- GET
/v1/links/resolve/{token}Résoudre un lien (public)
- POST
/v1/links/{link_id}/resendRenvoyer un lien (remplacé s'il est périmé)
- POST
/v1/links/{link_id}/revokeRévoquer un lien
- GET
/v1/links/{token}/noticeNotice d'information de l'organisation qui a émis le lien (public)
- POST
/v1/links/{token}/openOuvrir le parcours d'un lien (public)
KYC : une session et son jeton client. KYB : un brouillon et son lien de reprise.
- POST
/v1/widget/sessionsJeton de widget (depuis votre serveur)
Appelé par le serveur de l'intégrateur avec sa clé d'API (droit links:write). Rend un jeton valable 30 minutes, à usage unique, que seules les origines déclarées dans l'espace client peuvent afficher dans une iframe. Refusé tant qu'aucune origine n'est déclarée.
Une question d'intégration ?
Écrivez-nous avec votre cas d'usage : nous répondons avec des exemples adaptés à votre pile technique.