Créer, rediriger, confirmer

Créer le parcours (ici, un contrôle de majorité) :

curl -X POST https://verify.todis.eu/hosted/sessions \
  -H "Authorization: Bearer VOTRE_JETON" \
  -H "Content-Type: application/json" \
  -d '{
    "check": "age_over_18",
    "locale": "fr",
    "success_url": "https://votre-boutique.example/retour-verification",
    "reference": "commande-1042"
  }'

Réponse : l'URL vers laquelle rediriger, et l'identifiant à conserver.

{
  "session_id": "…",
  "hosted_url": "https://verify.todis.eu/v/…",
  "expires_at": "2026-08-19T12:34:56Z"
}

Redirigez le navigateur de votre utilisateur vers hosted_url : Todis affiche le QR code (portefeuille sur un autre appareil), le bouton d'ouverture (portefeuille sur le même appareil), et gère l'attente dans la langue demandée. Le bouton porte une requête du même appareil, dont le résultat n'est libéré que dans le navigateur qui a ouvert la page le premier : n'ouvrez donc pas hosted_url dans un navigateur avant d'y rediriger l'utilisateur. purpose (optionnel) affiche sur la page la finalité de la vérification, dans vos mots, et cross_device: false retire le QR code (voir la référence technique). success_url signifie vérification réussie, jamais que l'utilisateur est majeur : une preuve d'âge qui vaut false y renvoie aussi, comme tout résultat vérifié. Lisez le résultat côté serveur (claims.age_over_18 avec le raccourci age_over_18) et appliquez-y votre propre règle. Au retour sur votre success_url, votre backend confirme (jamais sur la seule foi des paramètres d'URL, falsifiables par l'utilisateur) :

curl https://verify.todis.eu/verify/sessions/SESSION_ID \
  -H "Authorization: Bearer VOTRE_JETON"

{ "status": "verified", "claims": { "age_over_18": true } }

Le raccourci "check": "identity" demande à la place nom, prénom, date de naissance et nationalité (le socle d'une entrée en relation KYC), et tous les champs avancés de l'API de session restent disponibles. cancel_url (optionnelle) reçoit l'utilisateur en cas d'échec. La page est aux couleurs de Todis ; un affichage en marque blanche est à l'étude pour le plan Premium.

Le webhook, votre ceinture de sécurité

Si l'utilisateur ferme la page avant la redirection, vous restez prévenu : ajoutez webhook_url à la création et votre backend reçoit un POST JSON {"event": "session.verified", "session_id": "…", "reference": "…"} à l'issue du parcours (relances automatiques tant que vous ne répondez pas 2xx). Chaque envoi est signé HMAC-SHA256 dans l'en-tête X-Todis-Signature avec le webhook_secret remis à la création :

// Node.js : vérifier la signature t=<horodatage>,v1=<hex>
const crypto = require("node:crypto");
function signatureValide(corps, entete, secret) {
  const [t, v1] = entete.split(",").map((p) => p.split("=")[1]);
  const attendu = crypto.createHmac("sha256", secret)
    .update(t + "." + corps).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(attendu));
}

Le webhook ne contient jamais les données vérifiées : il vous dit seulement que c'est terminé, et vous lisez le résultat par l'appel authentifié ci-dessus. Pour un portefeuille sur le même appareil, session.verified part quand la page hébergée libère le résultat, au retour du portefeuille, et non dès que le portefeuille transmet sa réponse. L'événement dit de la session ce qu'en dit l'appel authentifié, hors données vérifiées : trust, revocation, checks et transport sur un session.verified, code et, quand une présentation a été jugée, checks sur un session.failed.

Le QR dans votre page : le composant web

Si vous préférez garder l'utilisateur sur votre page plutôt que de le rediriger, un composant web encapsule la page hébergée et vous remonte les changements d'état :

<script src="https://todis.eu/js/todis-verify.js"></script>

<todis-verify hosted-url="HOSTED_URL_GENEREE_PAR_VOTRE_BACKEND"></todis-verify>

<script>
  document.querySelector("todis-verify")
    .addEventListener("todis:verified", () => {
      // Débloquer l'étape suivante de VOTRE interface,
      // puis confirmer côté serveur comme toujours.
    });
</script>

Événements émis : todis:status à chaque changement, puis todis:verified, todis:failed ou todis:expired. La hosted_url est toujours générée par votre backend : votre jeton de licence ne quitte jamais votre serveur. Dans le composant, le bouton d'ouverture du portefeuille ouvre la page hébergée dans un nouvel onglet ; le QR code reste dans votre page.

Les trois règles qui ne changent jamais. Le jeton de licence reste côté serveur. Le résultat se confirme par GET /verify/sessions/{id} authentifié, jamais sur la foi d'un paramètre d'URL ou d'un événement navigateur. Et il n'y a rien à stocker : pas de copie de pièce d'identité, pas de photo, seulement la réponse vérifiée que vous avez demandée, comme expliqué dans la FAQ.