Méthode GET/passport /{identifier} /vc
Récupérer le justificatif signé d'un passeport, au format SD-JWT-VC, filtré au niveau d'accès demandé. Point d'entrée public aux niveaux public et end_user.
Sur cette page
- Autorisation
- Le contrôle d'origine
- Plafond d'appels
- Paramètres de chemin et de requête
- Les trois formes d'identifiant acceptées
- Les six valeurs de access_tier
- Corps de la requête
- Requête d'exemple
- Réponse d'exemple
- En-têtes de réponse à connaître
- Lire le champ sd_jwt_vc
- Vérifier la signature vous-même
- Erreurs
- Voir aussi
Vous récupérez le passeport d'un produit sous la forme d'un justificatif numérique signé par la marque. En quittant cette page, vous saurez demander ce justificatif au niveau d'accès qui vous concerne, lire les six champs de la réponse, et savoir où trouver la clef publique qui permet d'en vérifier la signature sans nous faire confiance.
Adresse complète :
GET https://api.sealtrust.io/v1/passport/{identifier}/vcLe même point d'entrée répond aussi sans le préfixe /v1, à
https://api.sealtrust.io/passport/{identifier}/vc. Les deux adresses appellent
le même code. Utilisez la forme /v1 pour une nouvelle intégration.
La réponse est un objet JSON de six champs. Le passeport lui-même y tient dans
un seul champ, sous la forme d'une chaîne de caractères signée au format
SD-JWT-VC. Pour lire les données du passeport sous forme de JSON directement
exploitable, appelez GET /v1/passport/{identifier}.
#Autorisation
Aucune pour les niveaux public et end_user. Ce point d'entrée est public à
ces deux niveaux.
Une clef d'API partenaire n'ouvre rien ici. Les niveaux qui demandent une identité s'ouvrent avec un jeton de session de compte utilisateur, jamais avec une clef d'API.
Quatre valeurs du paramètre access_tier exigent une session de compte, que vous
présentez par l'en-tête Authorization: Bearer <jeton de session> ou par le
cookie de session posé à la connexion.
| Niveau demandé | Ce qu'il faut |
|---|---|
public | rien |
end_user | rien |
repairer | une session, et une accréditation active de réparateur sur la marque du produit, ou un accès à cette marque, ou le rôle d'autorité |
recycler | une session, et une accréditation active de recycleur sur la marque du produit, ou un accès à cette marque, ou le rôle d'autorité |
upstream | une session ayant accès à la marque du produit, ou le rôle d'autorité. Aucune accréditation n'ouvre ce niveau. |
authority | une session portant le rôle d'autorité de surveillance du marché |
Une session ayant accès à la marque du produit ouvre les trois niveaux de métier sur les produits de cette marque.
Les règles de niveau d'accès sont les mêmes que celles du point d'entrée
GET /v1/passport/{identifier}. Ce chemin ne donne donc jamais accès à plus de
champs que la lecture en JSON.
Une différence sépare les deux chemins. Ce point d'entrée ne sert que les passeports dont la visibilité est publique. Un passeport réservé au propriétaire ou réservé à la marque n'y est jamais rendu, même à son propriétaire.
#Le contrôle d'origine
Vos appels de serveur à serveur passent tels quels. Deux situations donnent un 403.
Un appel émis par une page web ouverte sur un domaine qui n'est pas le nôtre
porte un en-tête Origin ou Referer que nous refusons. N'appelez donc pas ce
point d'entrée depuis le navigateur d'un visiteur, appelez-le depuis votre
serveur.
Un appel qui porte le cookie de session sans en-tête Origin ni Referer est
refusé lui aussi. Le cookie de session ne vaut que depuis une page servie par
un de nos domaines. Depuis un serveur ou depuis la ligne de commande, présentez
le jeton dans Authorization: Bearer.
#Plafond d'appels
60 appels par tranche de 60 secondes, comptés par adresse réseau appelante. La fenêtre est fixe.
Ce compteur est commun à tous les chemins qui commencent par /passport. Les
appels que vous adressez à l'un d'eux entament le budget des autres. Le préfixe
/v1 ne crée pas un second budget : /v1/passport/EXEMP1E00001/vc et
/passport/EXEMP1E00001/vc remplissent le même compteur.
Chaque réponse acceptée porte trois en-têtes.
| En-tête | Contenu |
|---|---|
X-RateLimit-Limit | le plafond appliqué sur la fenêtre, ici 60 |
X-RateLimit-Remaining | ce qu'il vous reste dans la fenêtre en cours |
X-RateLimit-Reset | l'horodatage de fin de la fenêtre, en secondes depuis le 1er janvier 1970 |
Un dépassement renvoie 429, avec ces trois en-têtes et Retry-After. Sur ce
point d'entrée, Retry-After vaut la durée de la fenêtre, soit 60 secondes.
#Paramètres de chemin et de requête
| Nom | Type | Obligatoire | Description |
|---|---|---|---|
identifier | string | oui | Le produit dont vous voulez le justificatif. Trois formes sont acceptées, voir ci-dessous. |
access_tier | string | non | Le niveau d'accès demandé. Vaut public par défaut. Six valeurs acceptées, listées plus bas. |
Aucun en-tête n'est obligatoire dans la requête.
#Les trois formes d'identifiant acceptées
| Forme | À quoi elle ressemble | Où vous la trouvez |
|---|---|---|
| Numéro de série | 12 caractères, chiffres et lettres majuscules. Les lettres I, L, O et U n'y figurent jamais. | Imprimé sur le produit, c'est ce que porte son QR |
| Identifiant de jeton | Une suite de chiffres, souvent très longue | Rendu par nos réponses dans le champ token_id |
| Empreinte d'identifiant | 0x suivi de 64 caractères hexadécimaux | Rendue par nos réponses dans le champ uid_hash |
L'empreinte d'identifiant existe pour un produit en QR seul comme pour un produit à puce NFC. Le serveur la tire au hasard pour un produit en QR, il la dérive de l'identifiant de la puce pour un produit NFC.
Le serveur reconnaît la forme à l'écriture. Il cherche une valeur qui commence
par 0x et fait exactement 66 caractères comme une empreinte d'identifiant. Il
cherche toute autre valeur d'abord comme un identifiant de jeton. Il essaie le
numéro de série en dernier, quand les deux premières recherches n'ont rien
donné.
Le serveur reconnaît l'empreinte d'identifiant quelle que soit la casse. Il
reconnaît aussi le numéro de série quelle que soit la casse, et il le
canonicalise comme le fait le résolveur du QR : il lit les lettres I et L
comme un 1, la lettre O comme un 0. Vous pouvez donc lui envoyer un
numéro recopié à la main depuis une étiquette.
Ce point d'entrée ne résout que les produits encore au catalogue de la marque. Un exemplaire détruit sur la chaîne, remplacé par une version ultérieure ou retiré sans remplacement répond 404.
#Les six valeurs de access_tier
Ces niveaux sont des publics différents, sans hiérarchie entre eux. Un recycleur n'est pas au-dessus d'un réparateur. Chacun des trois niveaux de métier hérite du niveau public et du niveau utilisateur final, puis ajoute ce que son métier demande.
| Valeur | Ce que le justificatif révèle |
|---|---|
public | identification du produit, conformité ESPR, REACH et marquage CE, pourcentage de recyclabilité, pourcentage de contenu recyclé, étiquettes, spécification générale de batterie. Ces champs figurent en clair dans le jeton signé, aucune divulgation n'est jointe. |
end_user | impact environnemental, circularité complète, matière principale, matière certifiée biologique, durabilité, efficacité énergétique, empreinte carbone |
repairer | nomenclature, notice de démontage, indice de réparabilité, état de santé de batterie |
recycler | composition matière, substances préoccupantes, notice de démontage, état de santé de batterie |
upstream | composition matière, substances préoccupantes, fabrication, chaîne d'approvisionnement |
authority | l'intégralité des champs du document |
Une marque peut remplacer ces règles par les siennes. Le tableau ci-dessus décrit ce qui s'applique à défaut de règles propres à la marque. Les mêmes règles s'appliquent ici et sur la lecture en JSON.
Le serveur refuse toute autre valeur en 422. Il renvoie le niveau réellement
servi dans le champ access_tier de la réponse et dans l'en-tête
X-DPP-Access-Tier. Lisez l'un des deux plutôt que de le supposer.
#Corps de la requête
Aucun. Cette requête n'a pas de corps.
#Requête d'exemple
Justificatif public du produit dont le numéro imprimé est EXEMP1E00001.
curl -s "https://api.sealtrust.io/v1/passport/EXEMP1E00001/vc?access_tier=public"const identifiant = "EXEMP1E00001";
const url = new URL(
`https://api.sealtrust.io/v1/passport/${encodeURIComponent(identifiant)}/vc`,
);
url.searchParams.set("access_tier", "public");
const response = await fetch(url, { method: "GET" });
if (response.status === 403) {
throw new Error(
"Appel refusé : exécutez cette requête depuis votre serveur, jamais depuis un navigateur.",
);
}
if (!response.ok) {
throw new Error(`SealTrust a répondu ${response.status}`);
}
const justificatif = await response.json();
console.log(justificatif.issuer, justificatif.access_tier);
console.log(justificatif.format, justificatif.vct);
const segments = justificatif.sd_jwt_vc.split("~");
console.log("Jeton signé :", segments[0]);
console.log("Segments de divulgation :", segments.slice(1, -1).length);import requests
from urllib.parse import quote
identifiant = "EXEMP1E00001"
response = requests.get(
f"https://api.sealtrust.io/v1/passport/{quote(identifiant, safe='')}/vc",
params={"access_tier": "public"},
timeout=30,
)
if response.status_code == 403:
raise SystemExit(
"Appel refusé : exécutez cette requête depuis votre serveur, jamais depuis un navigateur."
)
if not response.ok:
raise SystemExit(f"SealTrust a répondu {response.status_code}")
justificatif = response.json()
print(justificatif["issuer"], justificatif["access_tier"])
print(justificatif["format"], justificatif["vct"])
segments = justificatif["sd_jwt_vc"].split("~")
print("Jeton signé :", segments[0])
print("Segments de divulgation :", len(segments[1:-1]))Les trois onglets appellent la même adresse avec les mêmes valeurs. L'onglet
curl écrit la réponse brute sur la sortie standard. Les onglets TypeScript et
Python en extraient les mêmes champs, dans le même ordre.
#Réponse d'exemple
Code HTTP 200OK
Code HTTP 200.
Les valeurs ci-dessous sont fictives. Le jeton signé et les segments de divulgation sont raccourcis, un jeton réel fait plusieurs milliers de caractères.
{
"passport_id": 1,
"issuer": "did:web:api.sealtrust.io:brand:4242",
"vct": "https://schema.sealtrust.io/vct/digital-product-passport",
"access_tier": "public",
"format": "dc+sd-jwt",
"sd_jwt_vc": "eyJhbGciOiJFUzI1NiIsInR5cCI6ImRjK3NkLWp3dCIsImtpZCI6ImRpZDp3ZWI6YXBpLnNlYWx0cnVzdC5pbzpicmFuZDo0MjQyI2tleS0xIn0.RVhFTVBMRV9DSEFSR0VfVVRJTEU.RVhFTVBMRV9TSUdOQVRVUkU~"
}| Champ | Type | Présence | Description |
|---|---|---|---|
passport_id | integer | toujours | L'identifiant de la version du passeport à laquelle se rapporte ce justificatif. |
issuer | string | toujours | L'identifiant décentralisé did:web de la marque qui a signé. C'est lui qui mène à la clef publique de vérification. Toujours renseigné sur ce point d'entrée. |
vct | string | toujours | L'identifiant du modèle de justificatif. Vaut https://schema.sealtrust.io/vct/digital-product-passport à défaut de valeur enregistrée sur le passeport. |
access_tier | string | toujours | Le niveau réellement servi. |
format | string | toujours | Toujours dc+sd-jwt. C'est le type de média du justificatif à divulgation sélective. |
sd_jwt_vc | string | toujours | Le justificatif lui-même. Voir ci-dessous. |
#En-têtes de réponse à connaître
| En-tête | Contenu |
|---|---|
X-DPP-Access-Tier | le niveau réellement servi |
Cache-Control | no-store, max-age=0, quel que soit le niveau servi. Ne placez cette réponse derrière aucun cache partagé. |
#Lire le champ sd_jwt_vc
Le contenu de sd_jwt_vc est une suite de segments séparés par le caractère
~. Le dernier segment est toujours vide, donc la chaîne se termine par un ~.
<jeton signé>~<divulgation>~<divulgation>~Le premier segment est un jeton signé en trois parties, séparées par des points. L'en-tête et la charge utile sont encodés en base64url, sans remplissage. Vous les décodez sans clef.
L'en-tête porte trois valeurs.
| Valeur | Contenu |
|---|---|
alg | ES256. La signature est une signature ECDSA sur la courbe P-256. |
typ | dc+sd-jwt |
kid | L'identifiant de la clef qui a signé, sous la forme <did de la marque>#key-<numéro de version>. |
La charge utile porte les champs suivants.
| Champ | Contenu |
|---|---|
iss | L'identifiant did:web de la marque émettrice. Il vaut la même valeur que le champ issuer de la réponse. |
vct | L'identifiant du modèle de justificatif. |
iat | La date d'émission, en secondes depuis le 1er janvier 1970. |
@context | ["https://www.w3.org/ns/credentials/v2", "https://schema.sealtrust.io/dpp/v1"] |
type | ["VerifiableCredential", "DigitalProductPassport"] |
issuer | Répétition de iss, attendue par le modèle de données des justificatifs vérifiables. |
validFrom | La date d'émission au format ISO 8601, à la seconde, en temps universel. |
credentialSubject | Les données du passeport. Les champs publics y figurent en clair. Les autres sont remplacés par des empreintes, sous la clef _sd. |
credentialSchema | Un objet à deux clefs, id qui reprend vct, et type qui vaut JsonSchema. |
product | L'identité du produit : uid_hash, token_id et name. Jamais masquée. |
brand | L'identité de la marque : name, lei_code, eori_number, website_url, postal_address, contact_email. Jamais masquée. Les valeurs non renseignées sont absentes. |
Un passeport peut porter sur un modèle de produit ou sur un exemplaire précis.
Quand la marque publie un passeport de modèle, il vaut pour tous les
exemplaires qui partagent le même code produit, et le justificatif émis à cette
publication porte uid_hash et token_id à null dans le bloc product :
il ne désigne aucun exemplaire en particulier.
Les segments suivants sont les divulgations. Chacun est un tableau de trois éléments encodé en base64url : un sel, le nom du champ, sa valeur. Vous les décodez sans clef. Leur nombre dépend du niveau demandé.
WyJFWEVNUExFMDAwMDAwMDAwMDAwMDAwMCIsInJlcGFpcmFiaWxpdHlfaW5kZXgiLDguMl0Ce segment d'exemple se décode en
["EXEMPLE0000000000000000", "repairability_index", 8.2].
Au niveau public, la réponse ne révèle rien de plus que les champs toujours
présents dans le document signé. La chaîne se réduit alors au jeton signé suivi
d'un ~. Chaque autre niveau ajoute les divulgations qui le concernent.
#Vérifier la signature vous-même
Le champ issuer porte un identifiant did:web. Il désigne un document
public qui contient les clefs publiques de la marque, exprimées en
JsonWebKey2020. La clef à utiliser est celle dont l'identifiant correspond au
kid de l'en-tête du jeton. Ce document ne contient que les clefs non
révoquées, donc une clef révoquée n'y figure plus.
Un identifiant de la forme did:web:api.sealtrust.io:brand:4242 se résout à
https://api.sealtrust.io/brand/4242/did.json. Un identifiant de la forme
did:web:id.exemple-sas.example se résout à
https://id.exemple-sas.example/.well-known/did.json. Une marque peut héberger
elle-même ce document sur son propre domaine, auquel cas la vérification de ses
passeports ne dépend d'aucun de nos serveurs.
Si vous préférez que la vérification soit faite pour vous, appelez
GET /v1/passport/{identifier}/vc/verify.
#Erreurs
Le corps d'une réponse d'erreur porte un champ detail.
| Code | Condition | Que faire |
|---|---|---|
| 401 | Vous demandez authority sans session. detail vaut Authority-tier access requires authentication. | Connectez-vous, puis présentez le jeton de session dans Authorization: Bearer. |
| 401 | Vous demandez repairer, recycler ou upstream sans session. detail vaut Professional-tier access requires authentication. | Connectez-vous, puis présentez le jeton de session dans Authorization: Bearer. Une clef d'API ne convient pas. |
| 403 | Vous demandez authority avec une session qui ne porte pas ce rôle. detail vaut Authority-tier access is restricted to market surveillance authorities. | Demandez un niveau qui correspond à votre situation. |
| 403 | Vous demandez un niveau professionnel sans accréditation active sur la marque du produit, sans accès à cette marque et sans le rôle d'autorité. detail commence par This tier is restricted to the product's brand. | Demandez à la marque de vous accréditer, puis redemandez le niveau qui correspond à votre métier. |
| 403 | L'appel porte un en-tête Origin ou Referer qui ne désigne pas un de nos domaines, ce qui arrive pour tout appel émis depuis une page web hébergée ailleurs. detail vaut Forbidden origin. | Appelez ce point d'entrée depuis votre serveur, jamais depuis le navigateur d'un visiteur. |
| 403 | L'appel porte un cookie de session sans en-tête Origin ni Referer. detail vaut Origin or Referer header required. | Présentez le jeton dans Authorization: Bearer au lieu du cookie de session. |
| 404 | Aucun produit au catalogue ne correspond à cet identifiant, sous aucune des trois formes acceptées. detail vaut Product not found. | Vérifiez l'identifiant. Un exemplaire détruit sur la chaîne, remplacé par une version ultérieure ou retiré donne cette même réponse. |
| 404 | Le produit existe, mais aucun passeport publié en visibilité publique ne lui est rattaché, ni directement, ni par son modèle. detail vaut No published passport found for this product. | Ne traitez pas cette réponse comme un échec. Ce produit n'a pas de passeport public. Un passeport réservé au propriétaire ou à la marque donne la même réponse. |
| 404 | Le passeport existe et il est public, mais aucun justificatif signé n'a encore été émis pour lui. detail commence par No VC issued for this passport yet. | Lisez le passeport en JSON avec GET /v1/passport/{identifier}. Publier une version d'un passeport émet son justificatif : demandez à la marque de republier la version en cours. |
| 404 | La marque du passeport n'est pas résolvable. detail vaut Brand not found. | Signalez-le au support. Aucune action de votre côté ne change cette réponse. |
| 422 | La valeur de access_tier ne fait pas partie des six acceptées. detail est une liste d'objets qui nomment le paramètre en cause. | Corrigez la valeur. Les six valeurs acceptées sont listées plus haut. |
| 429 | Le plafond de 60 appels par 60 secondes est atteint pour votre adresse réseau, sur l'ensemble des chemins /passport. detail vaut Rate limit exceeded: 60 requests per 60s. | Attendez le nombre de secondes indiqué par Retry-After, puis réessayez. Mettez la réponse en cache de votre côté. |
| 500 | Une erreur inattendue s'est produite pendant le traitement de votre appel. detail vaut Internal Server Error. La réponse porte un en-tête X-Request-Id. | Réessayez. Si l'erreur persiste, contactez le support en indiquant la valeur de X-Request-Id. |
#Voir aussi
GET /passport/{identifier}/vc/preview, voir, sans signature, ce qu'un niveau d'accès exposerait.GET /passport/{identifier}/vc/verify, contrôler la signature du justificatif et lire les données révélées.GET /brand/{brand_id}/did.json, récupérer les clefs publiques de signature d'une marque.- Publier un passeport numérique de produit, publier, choisir qui voit quels champs, exporter et faire vérifier.
Cette page vous a-t-elle été utile ?
Votre réponse ouvre un courriel pré-rempli dans votre messagerie, à destination de contact@sealtrust.io. Vous le relisez avant de l'envoyer.