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",
    "country_code": "FR",
    "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. 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.

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.

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.