Aller au contenu

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 | review

3

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

RouteUsage
GET /v1/sessions/{id}État courant : étape, décision, motif, montant gelé ou débité.
GET /v1/sessions/{id}/eventsChronologie numérotée (seq). Curseur de reprise après un incident.
GET /v1/sessions/{id}/streamFlux temps réel en Server-Sent Events, pour une interface qui suit la session.
GET /v1/casesVos dossiers, avec filtres et pagination.
GET /v1/balanceSolde 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/cases

    Dossiers 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/reviews

    Vé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/sessions

    Derniè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/sessions

    Ouvrir 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}/cancel

    Abandonner 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}/consent

    Consigner 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}/document

    Choisir 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}/events

    Journal des événements

  • GET/v1/sessions/{session_id}/extraction

    Dernière lecture, corrections comprises

  • POST/v1/sessions/{session_id}/extraction

    Lire 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}/extraction

    Corriger 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/challenges

    Tirer 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}/stream

    Flux 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/balance

    Solde disponible, réservé et total

  • PUT/v1/balance/alert

    Ré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_deliveries

    Journal des livraisons

  • POST/v1/webhook_deliveries/{delivery_id}/retry

    Remettre 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_endpoints

    Lister les destinations

  • POST/v1/webhook_endpoints

    Enregistrer 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}/rotate

    Nouveau secret de signature

  • POST/v1/webhook_endpoints/{endpoint_id}/test

    Envoi d'essai signé

Pièces

Dépôt des images depuis l'appareil

  • GET/v1/artifacts/{artifact_id}/duplicates

    Autres 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}/artifacts

    Mé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}/artifacts

    Dé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/claim

    Rejoindre 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}/handoff

    Dé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/complete

    Dé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/countries

    Pays 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}/persons

    Personnes déclarées sur le dossier d'entreprise

  • POST/v1/sessions/{session_id}/persons

    Dé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}/kyc

    Ouvrir 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/reservations

    Geler 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}/capture

    Dé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}/release

    Restituer la réservation au solde disponible

    Idempotent, au même titre que la capture.

Bac à sable

  • POST/v1/sessions/{session_id}/simulate

    Simuler 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/subjects

    Clients 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}/erasure

    Transmettre 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-end

    Dé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-notice

    Notice 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/draft

    Saisie et état du dossier

  • PUT/v1/kyb/draft

    Enregistrer la saisie

  • POST/v1/kyb/draft/documents

    Fournir 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}/kyc

    Vé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/session

    Ouvrir 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/submit

    Soumettre 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/drafts

    Ouvrir 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}/challenge

    Envoyer 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/verify

    Confirmer le code reçu

  • PUT/v1/sessions/{session_id}/company

    Dé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}/submit

    Clore 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/alerts

    Alertes 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/links

    Liens 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}/resend

    Renvoyer un lien (remplacé s'il est périmé)

  • POST/v1/links/{link_id}/revoke

    Révoquer un lien

  • GET/v1/links/{token}/notice

    Notice d'information de l'organisation qui a émis le lien (public)

  • POST/v1/links/{token}/open

    Ouvrir le parcours d'un lien (public)

    KYC : une session et son jeton client. KYB : un brouillon et son lien de reprise.

  • POST/v1/widget/sessions

    Jeton 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.