Référence technique
Le détail contractuel des endpoints que votre application appelle directement : codes de réponse, cas d'erreur, limites de débit. Pour le schéma exact, interrogeable et à jour en continu, la documentation Swagger est disponible sur todis.eu/docs, sans jeton requis.
Authentification et limites de débit
Toutes les routes de vérification exigent l'en-tête
Authorization: Bearer <jeton>. Un jeton
manquant, invalide, révoqué ou expiré renvoie 401.
Au-delà de la limite de votre plan (30 requêtes/seconde en
Starter, 60 en Standard), une requête renvoie 429.
Quand votre jeton arrive à moins de 7 jours de son expiration,
chaque réponse authentifiée porte en plus l'en-tête
X-License-Warning (ex. license expires in 3
day(s), renew soon) : un simple signal, la requête en
cours aboutit normalement.
Qui décide quelles informations sont divulguées
Chaque attribut d'une présentation SD-JWT VC (l'âge, un diplôme, un statut) est protégé par son propre digest salé dans le JWT signé. Le portefeuille ne joint à sa présentation que la valeur et le sel des attributs que l'utilisateur a accepté de révéler : les autres restent des empreintes non réversibles. Todis n'a techniquement accès qu'à ce qui est effectivement divulgué dans la présentation qu'il reçoit, jamais plus.
Avec POST /verify/sessions, le champ
claims de votre requête devient une requête DCQL
intégrée à la demande d'autorisation envoyée au portefeuille :
l'utilisateur voit et approuve exactement cette liste avant que
son portefeuille ne construise la présentation, et le résultat de
la session ne vous rend que ces attributs, même si le
portefeuille en divulgue davantage. Avec
POST /verify/sd-jwt-vc, cette étape a déjà eu lieu
avant que vous n'obteniez la présentation : Todis la vérifie et
vous renvoie son contenu tel quel.
POST /verify/sd-jwt-vc
Vérifie une présentation SD-JWT VC. Avec
country_code, l'émetteur se résout par la liste de
confiance de ce pays, via le registre officiel de l'UE, parmi ses
fournisseurs qualifiés d'attestations, et pour les seuls
vct que le registre SD-JWT VC classe
qeaa, jamais un PID ; sans lui,
par le registre SD-JWT VC de ce déploiement
(GET /trust/registries), dont l'ancre doit couvrir le
vct du credential. La réponse dit d'où vient l'ancre
(trust). Les ancres sont portées par Todis : aucune
clé ne se fournit dans la requête, et une requête qui porte encore
issuer_public_key_pem est refusée.
Un PID ne se vérifie plus en donnant un pays.
Jusqu'à la version 4.5.0, un PID SD-JWT VC pouvait se vérifier
avec country_code. Depuis la version 5.0.0, un PID
envoyé avec country_code échoue toujours, quel que
soit le pays : la liste de confiance d'un pays ne vérifie que des
attestations qualifiées (vct classé
qeaa). Vérifiez un PID sans
country_code, contre les registres de ce déploiement
(GET /trust/registries).
Sur verify.todis.eu, aucun type n'est classé
qeaa aujourd'hui : la voie country_code
n'y vérifie donc aucun credential. Le classement d'un type
qualifié est une donnée du registre, pas une version du service.
200: présentation vérifiée,claimsettrustrenseignés.400: la requête porteissuer_public_key_pem, quelle qu'en soit la valeur ; l'erreur nomme le champ.401: jeton de licence manquant, invalide, révoqué ou expiré.422: présentation malformée, signature non vérifiée, ou émetteur qu'aucune ancre n'accepte (verified: false, détail danserror). Un émetteur refusé est nommé : le détail porte le sujet, l'empreinte SHA-256, l'autorité émettrice et l'identifiant de clé de cette autorité du certificat présenté, de quoi le faire déclarer sans un aller-retour. Et si ce certificat chaîne vers une ancre que le registre porte déjà, mais qui n'est pas déclarée pour le type présenté, le détail le dit et nomme cette ancre et ses types : le remède est alors de déclarer un type, pas d'obtenir un certificat. Ces informations sont celles d'un certificat, publiques ; aucune revendication du porteur n'y figure. Aussi, aveccountry_code, un credential dont levctn'est pas classéqeaa, que l'erreur nomme avec sa catégorie, ou toute présentation quand ce déploiement ne classe aucun typeqeaa, que l'erreur dit : dans les deux cas, sans qu'aucune liste soit lue. Aussi un credential dont letypn'est nidc+sd-jwtnivc+sd-jwt, et un credential qui porteaud, quelle qu'en soit la valeur : sans session, Todis n'est le destinataire d'aucun credential. Dans une session,audest accepté quand il désigne la même audience que le KB-JWT de la requête (leclient_iden redirection).429: quota de requêtes du plan dépassé.502: résolution du registre de confiance de l'émetteur impossible (modecountry_codeuniquement, pour un type classéqeaa, ex. registre européen temporairement indisponible, ou liste nationale close ou passée sa prochaine mise à jour, ou liste qui n'a pas pu être relue avec succès depuis 24 h, que l'erreur nomme).503: le registre SD-JWT VC n'a aucune base chargée, avec ou sanscountry_code, qui ne juge que les types que ce registre classe.
POST /verify/mdoc
Vérifie une présentation mdoc (ISO/IEC 18013-5, notamment permis
de conduire mobile), contre le registre mdoc de ce déploiement
(GET /trust/registries), qui porte les
IACA des émetteurs acceptés : la chaîne du
signataire, embarquée dans la présentation, est validée jusqu'à
l'une d'elles, signature et fenêtre de validité comprises, sur un
seul niveau comme le prévoit ISO/IEC 18013-5, et l'ancre retenue
doit couvrir le doctype signé. La réponse dit quelle ancre a
validé l'émetteur (trust). Les ancres sont portées
par Todis : aucun certificat ne se fournit dans la requête, et une
requête qui porte encore issuer_trust_anchor_pem est
refusée. Un émetteur mdoc qui manque au registre se signale à
integration@todis.eu.
200: présentation vérifiée,doc_type,namespacesettrustrenseignés.400: la requête porteissuer_trust_anchor_pem, quelle qu'en soit la valeur ; l'erreur nomme le champ.401: jeton de licence manquant, invalide, révoqué ou expiré.422: présentation malformée, signature non vérifiée, ou émetteur qu'aucune ancre du registre n'accepte, nommé comme surPOST /verify/sd-jwt-vc.429: quota de requêtes du plan dépassé.503: le registre mdoc n'a aucune base chargée.
POST /hosted/sessions
Le parcours de vérification hébergé : ce service sert lui-même
la page présentée à l'utilisateur (QR code, lien vers le
portefeuille, textes en français, anglais ou espagnol). C'est
l'intégration recommandée quand vous ne voulez pas construire
d'écran de vérification, et elle est détaillée sur la page
Intégrations. Vous redirigez
l'utilisateur vers l'URL renvoyée, il revient sur votre
success_url, et vous confirmez toujours le résultat
côté serveur avec GET /verify/sessions/{id}.
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.
C'est le seul endpoint qui accepte un webhook_url
(POST JSON signé en HMAC-SHA256 à l'issue du parcours, même si
l'utilisateur ferme la page) et les raccourcis
check ("age_over_18",
"identity"), disponibles sur tous les plans. Il
exige un déploiement avec identité de signature des requêtes,
ce qui est le cas du service hébergé.
Deux requêtes sur la page. Le bouton « Ouvrir
mon portefeuille » porte la requête du même appareil : après sa
réponse, le portefeuille renvoie le navigateur à la page avec un
code frais (le Response Code, OpenID4VP 1.0 §14.2), et
la page libère alors le résultat. Elle ne le libère que dans le
navigateur qui l'a ouverte le premier, qu'elle reconnaît par un
cookie todis_parcours ; un retour arrivé dans un
autre navigateur fait échouer la session. Le QR code porte une
requête cross-device à part, pour un portefeuille sur un autre
appareil, sans retour, et servie trois fois au plus. Dans
une iframe, le bouton ouvre la page dans un nouvel onglet. Deux
conséquences pour vous : n'ouvrez pas hosted_url
dans un navigateur avant d'y rediriger l'utilisateur, sinon le
parcours serait lié à votre navigateur et non au sien ; et le
webhook session.verified d'un retour sur le même
appareil part quand la page libère le résultat, et non quand le
portefeuille transmet sa réponse.
Champs purpose et
cross_device. purpose
(optionnel, texte non vide de 300 caractères au plus) est la
finalité de la vérification, dans vos mots et dans la langue de
la page : la page l'affiche avant que le visiteur ouvre son
portefeuille, précédée de « Finalité indiquée par le site : »
(OpenID4VP 1.0 §6.2). Sans lui, la page affiche la finalité du
raccourci check (âge ou identité), sinon la liste
des informations demandées. cross_device (booléen,
true par défaut) à false sert une page
du seul même appareil, sans QR code : HAIP 1.0 §5.1 le recommande
quand vous comptez sur la liaison au navigateur de l'utilisateur
contre l'hameçonnage.
Option dc_api. Avec
"dc_api": true, la page hébergée propose au visiteur
d'ouvrir son portefeuille par la Digital Credentials API du W3C,
quand son navigateur la prend en charge ; le QR code reste
affiché. La page passe au navigateur, en un seul appel, une
requête par protocole que la vérification permet, et le
portefeuille répond par celle qu'il sait servir. La première est
OpenID4VP 1.0 (openid4vp-v1-signed), signée par le
même certificat et porteuse de la même requête que le QR code :
le PID au format SD-JWT VC comme les attestations mdoc
(ISO/IEC 18013-5) passent par elle.
Avec check, le PID SD-JWT VC n'est demandé que si le
registre SD-JWT VC de ce déploiement le couvre ; celui de
verify.todis.eu ne le couvre pas, et le parcours
demande donc les seules routes mdoc. La seconde, pour les
attestations mdoc seulement, est l'Annexe C d'ISO/IEC 18013-7
(org-iso-mdoc). Avec
check: "age_over_18", la requête OpenID4VP offre
les mêmes sources d'âge que le QR code, l'attestation de preuve
d'âge (eu.europa.ec.av.1) en premier ; la requête de
l'Annexe C demande un seul document, sans repli : l'attribut
age_over_18 de cette attestation, que le registre
mdoc de verify.todis.eu couvre, comme le montre
GET /trust/registries. Un portefeuille qui ne répond
que par l'Annexe C et ne détient pas cette attestation ne peut pas
répondre par le bouton ; le QR code reste sur la page. La réponse du
portefeuille est chiffrée
pour Todis et liée à l'origine https://verify.todis.eu :
vous n'avez aucune origine à déclarer. Le résultat de
GET /verify/sessions/{id} et le webhook gagnent
dc_api_protocol, le protocole par lequel le
portefeuille a répondu. Hors navigateur, par exemple dans une application
native, utilisez le QR code ou le lien profond.
Un déploiement en mode HAIP verrouillé (option
HAIP_VERROUILLE, fermée par défaut) verrouille ce que
Todis émet : requête signée sous x509_hash et réponse
chiffrée. Il ne restreint pas le protocole que le portefeuille
retient : la page offre toujours l'Annexe C à côté d'OpenID4VP,
pour qu'un portefeuille qui ne sait répondre que par elle puisse
répondre. Pour n'offrir qu'OpenID4VP, sur la plateforme
d'intégration seulement, créez la session avec l'en-tête
todis-essai-openid4vp: seul.
Option revocation. Comme sur
POST /verify/sessions, report par
défaut ou require : la conduite du parcours face à
un statut qui n'a pas pu être établi. Le résultat de la session
et le webhook session.verified portent
revocation, la conduite appliquée et ce que le
contrôle a établi.
Option profil_av. Avec
"profil_av": true, la page hébergée propose aussi,
dans un onglet à part, l'application de vérification d'âge du
profil européen : un QR code et un lien av:// qui
lui passent la requête par valeur, non signée, à l'attestation de
preuve d'âge (eu.europa.ec.av.1) seule, sans repli
sur le PID. C'est la forme que ces applications exigent, et la
seule qu'elles acceptent : elles refusent toute requête signée.
Le premier onglet reste la page d'avant. Ce que vous perdez avec
cette option : l'application ne peut pas authentifier Todis,
faute de signature ; la réponse reste liée à cette requête et se
vérifie comme les autres. Le résultat,
GET /verify/sessions/{id} et le webhook sont
inchangés.
L'option exige qu'une route du parcours offre cette attestation :
avec check: "age_over_18", c'est le cas quand le
registre mdoc du déploiement la couvre, ce que fait celui de
verify.todis.eu (voir
GET /trust/registries). Sur un déploiement dont le
registre ne la couvre pas, la création répond 400.
201: parcours créé, avechosted_url,expires_atet le secret de webhook.400: URL de retour invalide,checkinconnu, champs de vérification incohérents,purposevide ou de plus de 300 caractères, ou ancre de confiance,transaction_dataou requête DCQL mal formée fournis (mêmes règles quePOST /verify/sessions).401: jeton de licence manquant, invalide, révoqué ou expiré.403: le plan du jeton n'inclut pas la grammaire DCQL complète (dcql_queryfourni par vous).429: quota de requêtes du plan dépassé.501: déploiement sans identité de signature, flux hébergé indisponible.
POST /verify/sessions
Crée une session de vérification OpenID4VP. Le corps de la
requête liste le type de credential demandé (vct)
et les attributs demandés (claims, chemins
simples, ex. "age_over_18"). La confiance dans
l'émetteur vient de country_code (SD-JWT VC dont le
vct est classé qeaa, liste officielle de
l'UE ; un autre type échoue à la vérification, par un message qui
le nomme) ou des registres d'ancres de ce déploiement,
listés par GET /trust/registries. La réponse contient une
requête d'autorisation OpenID4VP à présenter au portefeuille de
l'utilisateur (QR code ou lien profond) ; la construction exacte
de la chaîne du code QR ou du lien est détaillée dans notre
fichier d'intégration. La session expire 15
minutes après sa création, qu'elle ait reçu une réponse ou non.
Pour les besoins avancés (plusieurs credentials par session,
alternatives entre credentials ou entre attributs, valeurs
contraintes), le champ dcql_query accepte une
requête DCQL complète à la place de
vct/claims, et peut mélanger SD-JWT VC
et mdoc. Le champ credential_trust donne alors à un
credential SD-JWT VC son propre country_code, pour
vérifier dans une même session des credentials d'émetteurs de
pays différents (chaque entrée ne vaut que pour son credential,
jamais pour un autre). Voir le détail dans la
spécification OpenAPI.
Un PID ne se vérifie plus en donnant un pays.
Jusqu'à la version 4.5.0, un PID SD-JWT VC pouvait se vérifier
avec country_code. Depuis la version 5.0.0, un PID
envoyé avec country_code échoue toujours, quel que
soit le pays : la liste de confiance d'un pays ne vérifie que des
attestations qualifiées (vct classé
qeaa). Vérifiez un PID sans
country_code, contre les registres de ce déploiement
(GET /trust/registries).
Sur verify.todis.eu, aucun type n'est classé
qeaa aujourd'hui : la voie country_code
n'y vérifie donc aucun credential. Le classement d'un type
qualifié est une donnée du registre, pas une version du service.
encrypted_response vaut false par
défaut sur cet endpoint, contrairement au flux hébergé : c'est
donc ici que vous devez agir. Certains portefeuilles nationaux
n'acceptent rien d'autre qu'une réponse chiffrée
(response_mode=direct_post.jwt) et, sans elle, ne
renvoient aucune erreur : ils lisent la requête puis
abandonnent, et la session reste indéfiniment
pending. Si vous visez un portefeuille de
production, activez-le.
revocation (optionnel, report par
défaut) fixe la conduite de la session face à une révocation qui
n'a pas pu être contrôlée : avec report, la session
est vérifiée et son résultat dit que le statut n'a pas été
établi, et pourquoi ; avec require, elle échoue.
Todis contrôle le statut de chaque credential qui en déclare un
(liste de statut d'un SD-JWT VC, liste de statut ou
d'identifiants d'un mdoc), avant de conclure la session et sur
tous les transports. Un credential révoqué, suspendu ou dont
l'index sort de sa liste fait échouer la session quelle que soit
la conduite ; un credential qui ne prévoit aucun statut passe
sous les deux. Le claim status d'un SD-JWT VC ne
vous est jamais rendu. Ouvert dans tous les plans.
profil_av (optionnel, false par
défaut) demande en plus le transport OpenID4VP du profil européen
de vérification d'âge : la réponse porte alors
profil_av, avec wallet_uri, un lien
av:// qui ouvre l'application de vérification d'âge
en lui passant la requête par valeur, et
authorization_request, cette requête, non signée,
sous redirect_uri:, en direct_post en
clair, à l'attestation de preuve d'âge
(eu.europa.ec.av.1) seule. C'est la seule forme que
ces applications acceptent ; en échange, l'application ne peut
pas authentifier Todis. La requête par redirection ne change pas.
La session doit demander cette attestation en mdoc
(400 sinon), et n'en demander que des éléments
age_over_NN de son espace de noms : tout autre
chemin est refusé à la création, par un 400 qui le
nomme. Ce transport ne porte que cette attestation : une réponse
postée sur son response_uri qui porte un autre
credential est rejetée, alors que la requête par redirection et
la DC API continuent d'accepter les autres sources d'âge de la
session.
redirect_uri : même appareil ou QR
code. Avec redirect_uri (optionnel, un URI
absolu, 400 sinon), la session est un flux du même
appareil : après sa réponse, le portefeuille renvoie le
navigateur à redirect_uri, augmenté du paramètre
response_code, un secret frais. Le résultat vérifié
reste alors retenu : GET /verify/sessions/{id} rend
{"status": "pending", "response_code_required": true}
tant que vous n'avez pas présenté ce code à
POST /verify/sessions/{id}/response-code (voir
ci-dessous). Sans redirect_uri, la session est
cross-device (QR code) : pas de redirection, et le résultat se
lit directement. Ne passez donc pas redirect_uri
pour un QR code, le résultat resterait retenu.
encrypted_response: true n'exige pas
redirect_uri. Cette adresse doit être joignable
depuis l'appareil qui exécute le portefeuille, et non depuis
votre serveur : une adresse de bouclage
(http://localhost:...) y désigne le téléphone
lui-même.
Requête DCQL. dcql_query est
contrôlé à la création (400) : tableaux présents non
vides (credentials, credential_sets,
claims, claim_sets,
options, values), identifiants de
credential et de revendication faits de lettres, chiffres,
_ et -, aucune revendication demandée
deux fois (règle qui vaut aussi pour claims et
mdoc_claims), values limité aux
chaînes, entiers et booléens, chemin mdoc fait exactement de
l'espace de noms puis de l'élément, claim_sets
seulement avec claims. Un chemin de revendication
suit le Claims Path Pointer d'OpenID4VP 1.0 §7 : un nom désigne
une clé, null tous les éléments d'un tableau, un
entier l'élément de ce rang ; une contrainte values
est satisfaite dès qu'une valeur sélectionnée y figure. Avec
"multiple": true sur un credential, chaque
présentation reçue sous son identifiant est vérifiée, et
credentials.<id> comme
trust.<id> deviennent des tableaux, une entrée
par présentation retenue ; sans lui, une seconde présentation
sous l'identifiant, ou un tableau vide, fait échouer la session.
Autorités nommées au portefeuille. Pour chaque
credential qu'un registre de ce déploiement jugera, Todis ajoute
lui-même à la requête un trusted_authorities de type
aki : l'identifiant de clé de chaque autorité (IACA)
que le registre accepte pour son type. Un portefeuille qui
applique ce filtre ne propose alors que les credentials qui en
relèvent. Rien n'est ajouté pour un credential jugé par la liste
européenne (country_code), ni quand une ancre
candidate ne peut se désigner ainsi (ancre de rôle signataire).
Un trusted_authorities que vous fournissez dans
dcql_query est transmis tel quel ; une valeur
aki qui n'est pas du base64url est refusée
(400). C'est une aide au portefeuille : la
vérification juge la confiance comme avant. Enfin,
transaction_data est refusé (400) :
Todis n'envoie pas de données de transaction au portefeuille et
n'en vérifie pas les empreintes.
Intention de conservation. Sur une revendication
d'un credential mso_mdoc de dcql_query,
"intent_to_retain": true déclare que vous entendez
conserver cet élément au-delà de la transaction (OpenID4VP 1.0
§B.2.4). Todis le transmet au portefeuille sur chaque transport :
tel quel dans la requête OpenID4VP, et en
IntentToRetain dans la requête de l'Annexe C
d'ISO/IEC 18013-7 ; le portefeuille peut l'afficher à
l'utilisateur. Absent, il vaut faux : Todis annonce alors au
portefeuille que l'élément ne sera pas conservé, ce qui vous
engage à ne pas le stocker plus longtemps que nécessaire pour
mener la transaction (ISO/IEC 18013-5 §8.3.2.1.2.1). C'est ce
qu'annoncent toujours les champs simplifiés et les raccourcis
check. Le champ n'est jamais ignoré : dans
mdoc_claims, sur une revendication SD-JWT VC ou avec
une valeur qui n'est pas un booléen, il est refusé par une erreur
qui le nomme.
curl -X POST https://verify.todis.eu/verify/sessions \
-H "Authorization: Bearer VOTRE_JETON" \
-H "Content-Type: application/json" \
-d '{
"vct": "https://example.eu/credentials/pid",
"claims": ["age_over_18"]
}'
201: session créée, avecsession_idetauthorization_request.400:claimsvide, aucune ancre valide ne couvre le type demandé,redirect_uriqui n'est pas un URI absolu, requête DCQL mal formée,transaction_datafourni,intent_to_retainhors d'une revendication mdoc dedcql_query, ou la requête porteissuer_public_key_pem, ou une entrée decredential_trustqui en porte un ; l'erreur nomme le champ, quel que soit le transport demandé.401: jeton de licence manquant, invalide, révoqué ou expiré.403: le plan du jeton n'inclut pas la grammaire DCQL complète (dcql_query, plan Premium).429: quota de requêtes du plan dépassé.502: résolution du registre de confiance impossible (modecountry_code).503: le registre d'ancres dont dépend la session n'a aucune base chargée.
GET /verify/sessions/{id}
Consulte le résultat d'une session créée par
POST /verify/sessions, à interroger après que
l'utilisateur a répondu avec son portefeuille (ou
périodiquement en attendant).
curl https://verify.todis.eu/verify/sessions/<session_id> \
-H "Authorization: Bearer VOTRE_JETON"
200: trois statuts possibles,{"status": "pending"},{"status": "verified", "claims": {...}}ou{"status": "failed", "error": "..."}. Pour une session mdoc (doctype/mdoc_claims),claimsimbrique les éléments sous leur espace de noms. Une session vérifiée porte aussitrust, d'où vient l'ancre qui l'a validée. Une session conclue par la Digital Credentials API portedc_api_protocol,openid4vp-v1-signedouorg-iso-mdoc, le protocole par lequel le portefeuille a répondu. Une session du même appareil (créée avecredirect_uri) dont le résultat attend son code rend{"status": "pending", "response_code_required": true}. Une présentation liée à une autre requête (KB-JWT d'un autrenonceou d'une autre audience, mdoc dont la signature de l'appareil ne vérifie pas sur la requête) rejette la réponse entière, même à côté d'un credential valide : l'erreur commence alors parthe response is rejected(OpenID4VP 1.0 §14.1.2). Une session vérifiée porte aussirevocation: la conduite appliquée (policy) et ce que le contrôle a établi,statusparminot_provided(aucun statut prévu),valid(avecmechanism,list_issued_atet, quand la liste a été admise sous une déclaration de transition du registre,signer_exception) etnot_checked(avecreason) ;validetnot_providedportent aussicertificates, la révocation des certificats de la chaîne de l'émetteur par la CRL de leur émetteur,not_providedouchecked; Une session conclue porte aussichecks, la liste des contrôles effectués sur le credential présenté, dans l'ordre où ils ont abouti, chacun avec son issue (passed,not_checkedoufailed) :issuer_signature,issuer_trust_anchor,credential_integrity,credential_validity,holder_binding,credential_type,requested_claims,credential_status,certificate_revocation. Un contrôle qui n'a pas eu lieu n'y figure pas, et celui dont le détail est ailleurs nomme le chemin où le lire sousreported_in:trust,revocationourevocation.certificates. Une session échouée le porte aussi : les contrôles qui ont abouti avant celui qui a échoué, puis ce dernier avecfailed; un échec qui n'a fait juger aucune présentation, un refus du porteur par exemple, ne porte paschecks. Une session échouée porte aussicode, la cause dans un vocabulaire fermé à côté deerror:wallet_declined,wallet_error,credential_missing,presentation_invalid,requirement_not_met,trust_resolution_unavailable,credential_revoked,revocation_not_checkedouunspecified.401: jeton de licence manquant, invalide, révoqué ou expiré.404: session inconnue (identifiant invalide, session expirée après 15 minutes, ou session créée sous la licence d'un autre client).429: quota de requêtes du plan dépassé.
POST /verify/sessions/{id}/response-code
Libère le résultat d'une session du même appareil, créée avec
redirect_uri. Votre page de retour reçoit
response_code en paramètre : présentez-le depuis
votre serveur, pour la session que votre
utilisateur a lancée, dont vous avez gardé l'identifiant de votre
côté (dans sa session serveur, par exemple), jamais pour une
session déduite de l'adresse de retour. C'est ce qui empêche
qu'une requête relayée à une autre personne vous livre son
identité (OpenID4VP 1.0 §14.2, HAIP 1.0 §5.1). Un portefeuille
qui ne suit pas la redirection ne libère jamais le résultat : il
reste retenu jusqu'à l'expiration de la session.
curl -X POST https://verify.todis.eu/verify/sessions/<session_id>/response-code \
-H "Authorization: Bearer VOTRE_JETON" \
-H "Content-Type: application/json" \
-d '{"response_code": "<valeur reçue sur redirect_uri>"}'
200: même corps queGET /verify/sessions/{id}, avec le résultat libéré, queGET /verify/sessions/{id}rend ensuite sans code.400: session sans retour du même appareil (créée sansredirect_uri), ou session d'une page hébergée, où c'est la page qui présente le code.401: jeton de licence manquant, invalide, révoqué ou expiré.403: ce code n'est pas celui de la session ; rien n'est libéré.404: session inconnue, expirée, ou créée sous la licence d'un autre client.429: quota de requêtes du plan dépassé.
GET /trust/registries
Liste, sans jeton, les ancres de confiance que ce déploiement
accepte : pour chaque registre (mdoc,
sd_jwt_vc), ses sources et ses ancres, avec les
types de credential que chacune couvre et les dates de validité
de son certificat, les sources officielles que ce déploiement doit
interroger, avec la date et le résultat de leur dernière lecture
(official_sources), et les pays qu'un
country_code peut atteindre.
trust_list_cache montre les listes de confiance que
ce déploiement garde, vérifiées, pour country_code :
la LOTL et chaque pays déjà résolu, avec leur numéro de séquence,
l'empreinte du fichier lu, leur dernière lecture réussie, la
date jusqu'à laquelle la copie est servie, et si elle l'est
maintenant, sinon pourquoi. Une liste qui n'a pas pu être relue
avec succès depuis 24 h n'est plus servie, jusqu'à la relecture
suivante qui réussit. Une source que la
Commission n'a pas encore publiée y dit ce qui manque pour la
lire, et un compte nul y est une lecture, datée, pas une absence
de lecture. Chaque ancre est un rôle d'un certificat, tel
qu'une source le déclare : un même certificat figure une fois par
source qui lui donne un rôle. Son usage vaut
issuance quand elle valide des credentials,
status quand elle signe leurs listes de statut, ce
qui ne valide jamais un credential. type_categories
donne la catégorie de chaque type que classe ce déploiement,
couvert par une ancre ou non (pid,
qeaa, pub_eaa, eaa), que
la réponse d'une vérification reprend dans
trust.category ; seuls les types qeaa du
registre SD-JWT VC se vérifient par country_code. Une source lue d'un VICAL, la liste signée des
autorités d'émetteurs mdoc, dit de quel VICAL elle vient. Une
source lue d'une liste d'entités de confiance (LoTE, ETSI TS 119
602) porte list, avec la prochaine mise à jour de la
liste : passée cette date, ses ancres ne sont plus acceptées.
discarded liste les entrées de ces listes qui ne sont
pas devenues des ancres, avec leur raison : c'est là que se
comprend l'absence d'une ancre attendue. Pour signaler une ancre
manquante :
report_missing_anchor. La page
Ancres de confiance présente ces
ancres par pays, lues en direct sur la même route.
curl https://verify.todis.eu/trust/registries
200: ancres des registres et pays de la liste officielle de l'UE, réponse cachable (Cache-Control,ETag).304: inchangé depuis l'ETagprésenté dansIf-None-Match.
GET /usage
Consultez votre volume de requêtes directement avec votre jeton de licence, sans attendre un tableau de bord ni solliciter le support : utile pour vérifier votre consommation avant qu'un bloc Starter ne s'épuise, ou simplement suivre votre activité au fil du temps. Si vous avez racheté plusieurs blocs Starter, le total additionne automatiquement tous les jetons associés à votre adresse email, pas besoin de les cumuler vous-même.
curl https://verify.todis.eu/usage \
-H "Authorization: Bearer VOTRE_JETON"
200:{"client_ids": [...], "total_authenticated_requests": 42}, outotal_authenticated_requests: nullavec un champerrorsi les métriques sont temporairement indisponibles (le reste de la réponse reste fiable).401: jeton de licence manquant, invalide, révoqué ou expiré.429: quota de requêtes du plan dépassé.
GET /usage/history
L'historique quotidien de votre consommation, à partir du plan
Standard : totaux par jour sur 30 jours. Le plan Premium y
ajoute la ventilation par endpoint, les latences, une
profondeur de 400 jours et l'export CSV
(?days=30&format=csv). Aucune donnée brute de
vérification n'est conservée, seulement des agrégats.
200: historique JSON, ou CSV siformat=csv.401: jeton de licence manquant, invalide, révoqué ou expiré.403: le plan du jeton n'inclut pas l'historique (Standard et au-delà).429: quota de requêtes du plan dépassé.501: déploiement sans base de données (auto-hébergement sansDATABASE_URL).
Format de réponse (vérification directe)
Pour /verify/sd-jwt-vc et /verify/mdoc :
un champ verified (booléen) et, selon le résultat,
soit les informations divulguées (claims pour
SD-JWT VC, doc_type/namespaces pour
mdoc), soit un champ error texte. Jamais
l'intégralité du document d'identité, seulement les attributs
effectivement divulgués (voir ci-dessus).
Aller plus loin
Pour la vue d'ensemble (authentification, deux façons
d'intégrer, exemple curl), voir
Comment fonctionne l'API. Pour le
schéma exact des requêtes/réponses,
todis.eu/docs
(Swagger). Une question qui n'est pas couverte ici ?
contact@todis.eu.