Méthode GET/passport /{identifier}
Lire le passeport numérique publié d'un produit à partir de son numéro imprimé, de son identifiant de jeton ou de son empreinte de puce, au niveau d'accès demandé. Point d'entrée public.
Sur cette page
- Autorisation
- Plafond d'appels
- Paramètres de chemin et de requête
- Les trois formes d'identifiant acceptées
- Les six valeurs de access_tier
- En-têtes de réponse à connaître
- Corps de la requête
- Requête d'exemple
- Réponse d'exemple
- Les champs de la réponse
- Le bloc warranty
- Le bloc evidence
- Le bloc lifecycle
- Le bloc integrity
- La réponse en JSON-LD
- Erreurs
- Voir aussi
Vous lisez le passeport numérique publié d'un seul produit. En quittant cette page, vous saurez récupérer ses données au niveau d'accès que vous demandez, lire sa garantie, savoir sur quelle base chaque section peut être crue, et reconnaître un produit retiré du catalogue.
Adresse complète :
GET https://api.sealtrust.io/v1/passport/{identifier}Le même point d'entrée répond aussi sans le préfixe /v1, à
https://api.sealtrust.io/passport/{identifier}. Les deux adresses appellent
le même code. Utilisez la forme /v1 pour une nouvelle intégration.
#Autorisation
Aucune pour les niveaux public et end_user. Ce point d'entrée est public.
Une clef d'API partenaire n'ouvre rien ici. Le jeton reçu dans l'en-tête
Authorization est décodé comme un jeton de session de compte utilisateur, et
une clef d'API n'en est pas un : la lecture échoue en silence et l'appel se
poursuit comme un appel anonyme.
Quatre valeurs du paramètre access_tier exigent en revanche une session de
compte, présentée 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 de réparateur sur la marque du produit |
recycler | une session, et une accréditation de recycleur sur la marque du produit |
upstream | une session ayant accès à la marque du produit, ou le rôle d'autorité |
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 ses propres produits. Une session portant le rôle d'autorité de surveillance du marché les ouvre également.
#Plafond d'appels
60 appels par tranche de 60 secondes, comptés par adresse IP appelante. La
fenêtre est fixe. Ce plafond est partagé par toutes les adresses qui commencent
par /passport, et les formes /passport/… et /v1/passport/… alimentent le
même compteur.
Chaque réponse acceptée porte trois en-têtes qui décrivent ce compteur.
| 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 |
Un dépassement renvoie 429, avec les mêmes trois en-têtes et un Retry-After
en secondes.
#Paramètres de chemin et de requête
| Nom | Type | Obligatoire | Description |
|---|---|---|---|
identifier | string | oui | L'identifiant du produit. 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. |
verify_integrity | boolean | non | Vaut false par défaut. À true, le serveur récupère la copie IPFS du passeport, compare son empreinte, et ajoute un bloc integrity à la réponse. |
format | string | non | Absent par défaut, le serveur rend alors le JSON décrit plus bas. La valeur jsonld rend le même contenu filtré, exprimé en Schema.org et GS1. Le serveur ignore toute autre valeur et rend la réponse par défaut. |
#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 de puce | 0x suivi de 64 caractères hexadécimaux | Rendue par nos réponses dans le champ uid_hash |
Le serveur reconnaît l'empreinte de puce quelle que soit la casse. Il
reconnaît le numéro de série de la même façon, et il le canonicalise comme le
fait le résolveur du QR : il lit les lettres I et L comme un 1, et la
lettre O comme un 0. Vous pouvez donc recopier à la main le numéro lu sur
une étiquette, même si vous confondez ces caractères.
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 de puce. Il
cherche toute autre valeur d'abord comme un identifiant de jeton, puis, si
cette recherche ne donne rien, comme un numéro de série.
#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 qu'elle ajoute aux champs de data |
|---|---|
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 |
end_user | impact environnemental, circularité complète, matière principale, coton biologique certifié, 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 données, sans filtrage |
Une marque peut remplacer ces règles par les siennes, par catégorie de produit. Le tableau ci-dessus décrit ce qui s'applique à défaut de règles propres à la marque.
Le serveur refuse toute autre valeur en 422. Il renvoie le niveau réellement
servi dans le champ access_tier et dans l'en-tête X-DPP-Access-Tier de la
réponse JSON par défaut. Lisez l'un des deux plutôt que de le supposer. Avec
format=jsonld, ni ce champ ni cet en-tête n'existent, voir plus bas.
#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é. |
Le serveur ne pose X-DPP-Access-Tier que sur la réponse JSON par défaut.
Cache-Control porte la même valeur sur les deux formats.
Aucun en-tête n'est obligatoire dans la requête.
#Corps de la requête
Aucun. Cette requête n'a pas de corps.
#Requête d'exemple
Lecture du passeport public du produit dont le numéro imprimé est
EXEMP1E00001. Les trois exemples font le même appel, arrêtent le programme
sur une réponse d'erreur, puis affichent les trois mêmes valeurs :
passport_version, access_tier et data.product_identity.
curl --fail-with-body -s \
"https://api.sealtrust.io/v1/passport/EXEMP1E00001?access_tier=public" \
| jq '{passport_version, access_tier, product_identity: .data.product_identity}'const identifiant = "EXEMP1E00001";
const url = new URL(
`https://api.sealtrust.io/v1/passport/${encodeURIComponent(identifiant)}`,
);
url.searchParams.set("access_tier", "public");
const response = await fetch(url, { method: "GET" });
if (!response.ok) {
throw new Error(`SealTrust a répondu ${response.status}`);
}
const passeport = await response.json();
console.log({
passport_version: passeport.passport_version,
access_tier: passeport.access_tier,
product_identity: passeport.data.product_identity,
});import requests
from urllib.parse import quote
identifiant = "EXEMP1E00001"
response = requests.get(
f"https://api.sealtrust.io/v1/passport/{quote(identifiant, safe='')}",
params={"access_tier": "public"},
timeout=30,
)
response.raise_for_status()
passeport = response.json()
print(
{
"passport_version": passeport["passport_version"],
"access_tier": passeport["access_tier"],
"product_identity": passeport["data"]["product_identity"],
}
)Dans l'exemple curl, --fail-with-body renvoie un code de sortie non nul
quand le serveur répond une erreur, et affiche quand même le corps. L'outil
jq ne sert qu'à lire le JSON dans le terminal, il ne participe pas à l'appel.
#Réponse d'exemple
Code HTTP 200OK
Code HTTP 200.
Ce produit est encore au catalogue, il n'a pas été réclamé par un client, et le passeport est demandé au niveau public.
{
"id": 1,
"product_id": 1,
"brand_id": 42,
"schema_version": "1.0",
"passport_version": 3,
"data": {
"product_identity": {
"gtin": "03701234567890",
"model": "Cartable Exemple 32",
"brand": "Exemple SAS",
"made_in": "FR"
},
"compliance": {
"eu_espr": true,
"reach": true,
"ce_marking": false
},
"circularity": {
"recyclability_percentage": 62,
"recycled_content_percentage": 0
}
},
"data_hash": "0000000000000000000000000000000000000000000000000000000000000000",
"ipfs_uri": null,
"ipfs_gateway_url": null,
"visibility": "public",
"access_tier": "public",
"is_owner": false,
"published_at": "2026-08-01T09:00:00+00:00",
"product_name": "Cartable Exemple 32",
"brand_name": "Exemple SAS",
"image_url": "https://exemple-sas.test/images/cartable-32.jpg",
"gtin": "03701234567890",
"gs1_digital_link": "https://id.gs1.org/01/03701234567890/21/EXEMP1E00001",
"warranty": {
"status": "active",
"ends_at": "2028-08-01T09:00:00+00:00",
"duration_months": 24,
"transferable": true,
"remaining_days": 730
},
"evidence": {
"sections": {
"identity": "verified",
"integrity": "declared",
"composition": "declared",
"substances_of_concern": "declared"
},
"legend": {
"declared": "Stated by the brand. Recorded, dated and attributable, but not independently checked.",
"verified": "Checked mechanically against a public record; no declaration involved."
},
"derived": true,
"note": "Statuses are computed by SealTrust from verifiable facts. A brand cannot set them."
}
}Le domaine du champ gs1_digital_link est celui du résolveur configuré pour
votre intégration. https://id.gs1.org n'est que la valeur de repli, utilisée
quand aucun résolveur n'est configuré. Ne codez pas ce domaine en dur, lisez la
valeur renvoyée.
#Les champs de la réponse
| Champ | Type | Description |
|---|---|---|
id | integer | L'identifiant de la version de passeport servie. |
product_id | integer | L'unité à laquelle ce passeport est attaché, ou null quand le passeport porte sur le modèle et vaut pour tous ses exemplaires. |
brand_id | integer | Le numéro de la marque à laquelle le passeport appartient. |
schema_version | string | La version du schéma de données du passeport. |
passport_version | integer | Le numéro de version publiée. Il augmente à chaque nouvelle publication. |
data | object | Les données du passeport, filtrées selon le niveau servi. Sa forme dépend de la catégorie de produit. |
data_hash | string ou null | L'empreinte des données complètes de cette version, 64 caractères hexadécimaux. null quand aucune empreinte n'a été enregistrée pour cette version. |
ipfs_uri | string | L'adresse IPFS de la copie du passeport. Toujours null aux niveaux public et end_user. |
ipfs_gateway_url | string | L'adresse HTTP par laquelle cette copie se lit. Toujours null aux niveaux public et end_user. |
visibility | string | La visibilité de la version servie : public, ou owner_only quand le propriétaire actuel est authentifié. La visibilité brand_only n'est jamais servie ici. |
access_tier | string | Le niveau réellement servi, qui peut différer du niveau demandé pour le propriétaire du produit. |
is_owner | boolean | true quand l'appel est authentifié et que le compte est le propriétaire actuel de l'unité. |
published_at | string | Date et heure de publication de cette version, au format ISO 8601, ou null. |
product_name | string ou null | Le nom du produit. null quand aucun nom n'a été enregistré sur l'article. |
brand_name | string | Le nom de la marque, ou null si le produit n'est rattaché à aucune. |
image_url | string | La photographie du modèle, ou null. |
gtin | string | Le GTIN du modèle, ramené à 14 chiffres. null quand le modèle n'en porte pas, ou quand la valeur enregistrée n'est pas un GTIN valide. |
gs1_digital_link | string | Le lien GS1 Digital Link qui identifie cet exemplaire, de la forme <domaine de résolution>/01/<gtin sur 14 chiffres>/21/<numéro de série>. null quand le GTIN ou le numéro de série manque. |
warranty | object | Le résumé de garantie, ou null quand le produit n'en a pas. Voir ci-dessous. |
evidence | object | Sur quelle base chaque section peut être crue. Voir ci-dessous. Absent si son calcul échoue. |
lifecycle | object | Présent uniquement quand l'unité est détruite ou sortie du catalogue. Voir ci-dessous. |
integrity | object | Présent uniquement quand verify_integrity=true et que le lien IPFS est servi à votre niveau. Voir ci-dessous. |
#Le bloc warranty
| Champ | Type | Description |
|---|---|---|
status | string | active, expiring_soon, expired ou void. Recalculé à chaque lecture. |
ends_at | string | Date de fin, au format ISO 8601, ou null pour une garantie à vie. |
duration_months | integer | La durée annoncée, en mois. |
transferable | boolean | true quand la garantie suit le produit lors d'un changement de propriétaire. |
remaining_days | integer | Jours entiers restants. Négatif quand la garantie est passée. null pour une garantie à vie ou annulée. |
#Le bloc evidence
Trois valeurs existent, et elles sont calculées par SealTrust. Une marque ne peut pas les choisir.
| Valeur | Ce qu'elle dit |
|---|---|
verified | Vérifié mécaniquement contre un registre public, sans déclaration de personne. |
document_backed | Un document tiers est joint et peut être récupéré. Son contenu n'a pas été audité par SealTrust. |
declared | Déclaré par la marque. Enregistré, daté, attribuable, non vérifié de façon indépendante. |
Quatre sections portent une de ces valeurs : identity, integrity,
composition et substances_of_concern. La section identity passe à
verified quand l'unité porte un identifiant de jeton sur la chaîne. La
section integrity passe à verified quand l'empreinte de cette version a été
ancrée et correspond toujours aux données enregistrées. Le bloc porte en plus
legend, qui redit le sens des valeurs présentes, derived à true, et
note.
#Le bloc lifecycle
Il n'apparaît que si l'unité est détruite ou sortie du catalogue. Son passeport reste servi pour que l'identifiant continue de résoudre.
{
"lifecycle": {
"status": "superseded",
"is_burned": false,
"superseded": true,
"note": "This unit is superseded or withdrawn; its passport is retained so the identifier stays resolvable (EN 18219 §4.2.2 persistence)."
}
}Lisez is_burned avant status.
Le champ status vaut superseded quand l'unité a été remplacée par une autre,
et archived quand elle a été retirée sans remplacement. Le champ superseded
ne vaut true que pour le premier cas.
Le bloc apparaît aussi quand l'unité a été détruite, c'est-à-dire quand
is_burned vaut true. Dans ce cas status porte l'état courant du produit,
qui peut être null ou une valeur active. Ne déduisez donc jamais la
destruction de la valeur de status.
#Le bloc integrity
{
"integrity": {
"ipfs_fetched": true,
"ipfs_hash": "1111111111111111111111111111111111111111111111111111111111111111",
"expected_hash": "1111111111111111111111111111111111111111111111111111111111111111",
"match": true
}
}| Champ | Type | Description |
|---|---|---|
ipfs_fetched | boolean | true quand le serveur a réussi à lire la copie IPFS. |
ipfs_hash | string | L'empreinte du contenu réellement lu sur IPFS. |
expected_hash | string | L'empreinte attendue pour ce contenu. |
match | boolean | Le verdict de la comparaison. |
expected_hash est l'empreinte de la projection PUBLIQUE du passeport, celle
qui est déposée sur IPFS. Elle diffère de data_hash, qui couvre les données
complètes, y compris les champs réservés aux niveaux professionnels. Les deux
valeurs coïncident seulement quand le passeport ne porte aucun champ non
public. Ne comparez donc jamais expected_hash et data_hash.
Le champ match vaut true quand la copie IPFS correspond, false quand elle
diffère, et null quand la copie n'a pas pu être récupérée. Dans ce dernier cas
ipfs_fetched vaut false, un champ error remplace les deux empreintes, et
null signifie que rien n'a pu être conclu.
#La réponse en JSON-LD
Avec format=jsonld, la réponse porte le type de contenu
application/ld+json. C'est un document Schema.org et GS1 dont les champs sont
filtrés par le même niveau d'accès. Il ne contient ni passport_version, ni
data_hash, ni les blocs warranty, evidence, lifecycle et integrity
décrits ci-dessus : la garantie y est exprimée en WarrantyPromise, et les
autres blocs n'y figurent pas.
Deux autres différences comptent pour votre intégration.
Le document ne porte pas de champ access_tier. Le serveur ne renvoie pas non
plus l'en-tête X-DPP-Access-Tier. Pour connaître le niveau réellement servi,
appelez sans format, ou tenez-vous-en au niveau que vous avez demandé.
Le serveur ignore verify_integrity dans ce format. Il rend le document JSON-LD
avant de calculer le bloc integrity, donc ce paramètre ne change rien à la
réponse et aucune erreur ne vous le signale.
#Erreurs
Le corps d'une réponse d'erreur porte un champ detail.
| Code | Condition | Que faire |
|---|---|---|
| 401 | access_tier=authority est demandé sans session valide. detail vaut Authority-tier access requires authentication. | Connectez-vous avec un compte portant le rôle d'autorité de surveillance du marché. Une clef d'API partenaire ne convient pas. |
| 401 | access_tier vaut repairer, recycler ou upstream, et l'appel ne porte aucune session valide. detail vaut Professional-tier access requires authentication. | Présentez un jeton de session de compte, ou demandez le niveau public ou end_user. |
| 403 | access_tier=authority est demandé par un compte connecté qui ne porte pas ce rôle. detail vaut Authority-tier access is restricted to market surveillance authorities. | Demandez le niveau qui correspond à votre habilitation. |
| 403 | Un niveau professionnel est demandé par un compte connecté qui n'a ni accès à la marque du produit, ni l'accréditation correspondante sur cette marque. detail vaut This tier is restricted to the product's brand, partners holding the matching accreditation, and market-surveillance authorities. | Demandez à la marque l'accréditation qui correspond à votre métier, puis demandez le niveau de ce métier. |
| 404 | Aucun produit ne correspond à l'identifiant, sous aucune des trois formes acceptées. detail vaut Product not found. | Vérifiez le numéro recopié. Un produit détruit ou retiré du catalogue reste résolu ici, donc cette réponse veut bien dire que l'identifiant est inconnu. |
| 404 | Le produit existe, mais aucune version de passeport publiée ne lui correspond. detail vaut No published passport found for this product. | La marque doit publier une version. Un brouillon non publié n'est jamais servi, et une version en visibilité brand_only non plus. |
| 422 | Une valeur de paramètre est refusée : un access_tier qui n'est pas une des six valeurs, ou un verify_integrity qui n'est pas un booléen. detail est une liste, chaque entrée portant loc, type et msg. | Lisez loc pour savoir quel paramètre est en cause, puis corrigez sa valeur. |
| 429 | Plus de 60 appels ont été faits depuis votre adresse IP vers une adresse /passport dans la fenêtre de 60 secondes en cours. detail vaut Rate limit exceeded: 60 requests per 60s. | Attendez le nombre de secondes indiqué par l'en-tête Retry-After, puis réessayez. |
| 500 | Une erreur inattendue s'est produite pendant le traitement de votre appel. detail vaut Internal Server Error. | Réessayez. Si l'erreur persiste, contactez le support en indiquant l'heure de l'appel et la valeur de l'en-tête X-Request-Id de la réponse. |
#Voir aussi
GET /passport/01/{gtin}, lire le passeport publié d'un modèle, à partir de son GTIN.GET /passport/{identifier}/verify, contrôler l'intégrité du passeport publié d'un article.GET /passport/{identifier}/proof, rassembler les preuves publiques du passeport d'un article.GET /passport/{identifier}/vc, récupérer le justificatif signé du passeport, au format SD-JWT-VC.- 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.