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

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 :

HTTP
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 le niveau public, le niveau par défaut. Ce point d'entrée est public à ce niveau.

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.

Les cinq autres 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
publicrien Pour un passeport batterie, s'y ajoutent les champs que le point 1 de l'annexe XIII rend publics : substances dangereuses, matières premières critiques, empreinte carbone et sa classe, rapport de diligence raisonnable, contenu recyclé après consommation par métal et part de contenu renouvelable. À l'inverse, les références de pièces, l'état de la batterie et la durée de vie en cycles en sont retirés : les points 2 et 4 les réservent aux personnes ayant un intérêt légitime. Pour un passeport textile, s'y ajoutent le nom et le pourcentage de chaque matière, la composition en fibres que le règlement (UE) n° 1007/2011 impose sur l'étiquette. Pour un passeport chaussure, la matière de la tige, de la doublure, de la première de propreté et de la semelle, que la directive 94/11/CE fait figurer sur la chaussure.
end_userune session, quel que soit le compte
repairerune session, et une accréditation de réparateur sur la marque du produit
recyclerune session, et une accréditation de recycleur sur la marque du produit
upstreamune session d'administrateur de la marque du produit, ou le rôle d'autorité
authorityune session portant le rôle d'autorité de surveillance du marché

Une session d'administrateur de 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. Un compte client, réparateur ou recycleur qui reste rattaché à la marque, par exemple un ancien administrateur, n'en fait pas partie : il reçoit 403, ou le seul niveau de son accréditation.

#Plafond d'appels

600 appels par tranche de 60 secondes, comptés par adresse IP appelante. La fenêtre est fixe. Ce plafond est partagé par toutes les lectures (GET) dont l'adresse commence 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êteContenu
X-RateLimit-Limitle plafond appliqué sur la fenêtre, ici 600
X-RateLimit-Remainingce qu'il vous reste dans la fenêtre en cours
X-RateLimit-Resetl'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

NomTypeObligatoireDescription
identifierstringouiL'identifiant du produit. Trois formes sont acceptées, voir ci-dessous.
access_tierstringnonLe niveau d'accès demandé. Vaut public par défaut. Six valeurs acceptées, listées plus bas.
verify_integritybooleannonVaut 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.
formatstringnonAbsent 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 ressembleOù vous la trouvez
Numéro de série12 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 jetonUne suite de chiffres, souvent très longueRendu par nos réponses dans le champ token_id
Empreinte de puce0x suivi de 64 caractères hexadécimauxRendue 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.

ValeurCe qu'elle ajoute aux champs de data
publicidentification du produit, conformité ESPR, REACH et marquage CE, pourcentage de recyclabilité, pourcentage de contenu recyclé, étiquettes, spécification générale de batterie, marquages des articles 13(4) et 13(5), agent extincteur utilisable, lien vers la déclaration UE de conformité et son contenu structuré quand la marque l'a rempli, information sur la gestion des déchets, et pour un textile ou une chaussure les mentions d'étiquette décrites plus haut
end_userimpact environnemental, circularité complète, matière principale, matière certifiée biologique, durabilité, efficacité énergétique, empreinte carbone
repairernomenclature, notice de démontage, indice de réparabilité, état de santé de batterie
recyclercomposition matière, substances préoccupantes, notice de démontage, état de santé de batterie
upstreamcomposition matière, substances préoccupantes, fabrication, chaîne d'approvisionnement
authorityl'intégralité des données, sans filtrage

Les champs que la console écrit à la racine du passeport ont chacun leur propre niveau, nommé un par un : voir Les règles d'accès au passeport.

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êteContenu
X-DPP-Access-Tierle niveau réellement servi
Cache-Controlpublic, max-age=60, s-maxage=300 au niveau public, private, no-store à tout autre niveau. Seule la réponse publique, la même pour tout appelant anonyme, peut être gardée par un cache.

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}'

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. Ses données ne décrivent aucune matière et ne déclarent aucune substance préoccupante, donc le bloc evidence ne note que l'exemplaire.

JSON
{
  "id": 1,
  "product_id": 1,
  "brand_code": "K7M2QF9XBN",
  "brand_id": 42,
  "schema_version": "1.0",
  "passport_version": 3,
  "data": {
    "product_identity": {
      "gtin": "03701234567891",
      "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,
  "identity_included": true,
  "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": "03701234567891",
  "gs1_digital_link": "https://id.gs1.org/01/03701234567891/21/EXEMP1E00001",
  "passport_service_provider": null,
  "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"
    },
    "legend": {
      "declared": "Stated by the brand. Recorded, dated and attributable, but not independently checked.",
      "verified": "Rests on an on-chain reference that anyone can re-check independently. SealTrust records it and does not re-query the chain on each request."
    },
    "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

ChampTypeDescription
idintegerL'identifiant de la version de passeport servie.
product_idintegerL'unité à laquelle ce passeport est attaché, ou null quand le passeport porte sur le lot ou sur le modèle et vaut pour tous leurs exemplaires. Un exemplaire sans passeport propre reçoit celui de son lot de production, à défaut celui de son modèle.
brand_codestringL'identifiant public de la marque, dix caractères. C'est celui à citer et à conserver.
brand_idintegerLe numéro interne de la marque. ⚠️ Conservé pour ne pas rompre les intégrations existantes ; préférez brand_code.
schema_versionstringLa version du schéma de données du passeport.
passport_versionintegerLe numéro de version publiée. Il augmente à chaque nouvelle publication.
dataobjectLes données du passeport, filtrées selon le niveau servi. Sa forme dépend de la catégorie de produit.
data_hashstring ou nullL'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_uristringL'adresse IPFS de la copie du passeport. Voir la note ci-dessous : renseignée aux niveaux public et end_user pour les passeports publiés depuis le 14 juillet 2026, null pour les plus anciens.
ipfs_gateway_urlstringL'adresse HTTP par laquelle cette copie se lit. Suit exactement la même règle que ipfs_uri.
visibilitystringLa 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_tierstringLe niveau réellement servi, qui peut différer du niveau demandé pour le propriétaire du produit.
is_ownerbooleantrue quand l'appel est authentifié et que le compte est le propriétaire actuel de l'unité.
identity_includedbooleantrue quand l'unité a son identité : un propriétaire, une puce, la revendication et le transfert. Une unité créée sur l'offre Conformité + Identité la garde, même si sa marque passe ensuite sur l'offre Conformité. false pour une unité sans identité. null quand la réponse ne le dit pas, ce qui ne vaut jamais un refus.
available_tiersarray de stringLes niveaux que VOTRE appel peut demander sur ce passeport, dans l'ordre public, end_user, repairer, recycler, upstream, authority : ["public"] sans authentification, end_user en plus pour un compte connecté, le métier accrédité par la marque pour un partenaire, tous pour une autorité. La liste ne donne aucun droit : chaque niveau demandé reste vérifié. Une réponse qui la porte pour un compte connecté ne doit aller dans aucun cache partagé.
published_atstringDate et heure de publication de cette version, au format ISO 8601, ou null.
product_namestring ou nullLe nom du produit. null quand aucun nom n'a été enregistré sur l'article.
brand_namestringLe nom de la marque, ou null si le produit n'est rattaché à aucune.
image_urlstring | nullL'adresse complète de la photographie du modèle de la pièce : sa photo principale, ou à défaut la première image de sa médiathèque. Calculée comme sur le passeport du modèle et du lot. null quand le modèle n'en a pas, ou quand il appartient à une autre marque que ce passeport. C'est la copie allégée de la photo (WebP, 800 pixels au plus sur le grand côté, 100 Ko au plus, sans données EXIF) quand elle existe, sinon l'original. Une adresse d'un autre site est rendue telle quelle.
gtinstringLe 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_linkstringLe 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.
passport_service_providerobject ou nullLe prestataire de services de passeport qui tient la copie de sauvegarde de cette version (règlement (UE) 2024/1781, article 10(4) et annexe III point (l)) : identifier, sa référence, name, sa raison sociale, et backed_up_at, la date de la copie au format ISO 8601. null tant que la copie de cette version n'existe pas, ou quand sa dernière vérification a échoué. Hors de data, donc hors de l'empreinte data_hash.
warrantyobjectLe résumé de garantie, ou null quand le produit n'en a pas. Voir ci-dessous.
evidenceobjectSur quelle base chaque section peut être crue. Voir ci-dessous. Absent si son calcul échoue.
lifecycleobjectPrésent uniquement quand l'unité est détruite ou sortie du catalogue. Voir ci-dessous.
integrityobjectPrésent uniquement quand verify_integrity=true et que le lien IPFS est servi à votre niveau. Voir ci-dessous.

#Le bloc warranty

ChampTypeDescription
statusstringactive, expiring_soon, expired ou void. Recalculé à chaque lecture.
ends_atstringDate de fin, au format ISO 8601, ou null pour une garantie à vie.
duration_monthsintegerLa durée annoncée, en mois.
transferablebooleantrue quand la garantie suit le produit lors d'un changement de propriétaire.
remaining_daysintegerJours 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.

ValeurCe qu'elle dit
verifiedRepose sur une référence inscrite sur une chaîne publique, que n'importe qui peut recouper. SealTrust l'enregistre et ne réinterroge pas la chaîne à chaque requête.
document_backedUn document tiers est joint et peut être récupéré. Son contenu n'a pas été audité par SealTrust.
declaredDéclaré par la marque. Enregistré, daté, attribuable, non vérifié de façon indépendante.

Quatre sections peuvent porter une de ces valeurs : identity, integrity, composition et substances_of_concern. Seules les sections que le passeport contient réellement en reçoivent une.

identity et integrity sont toujours présentes, parce qu'elles portent sur l'exemplaire lui-même. 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.

composition et substances_of_concern n'apparaissent que si les données du passeport les portent. Un passeport qui ne décrit aucune matière ne reçoit aucune mention de composition, et sections compte alors deux entrées. Un bloc de matières resté vide (lignes sans nom, sans part et sans origine) ne décrit aucune matière. Le nombre d'entrées va donc de deux à quatre selon le passeport servi.

Le bloc porte en plus legend, qui redit le sens des valeurs présentes, derived à true, et note.

N'affichez une mention que pour les sections que sections nomme. Une section absente n'est ni vérifiée ni infirmée, elle n'est simplement pas notée.

#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.

JSON
{
  "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

JSON
{
  "integrity": {
    "ipfs_fetched": true,
    "ipfs_hash": "1111111111111111111111111111111111111111111111111111111111111111",
    "expected_hash": "1111111111111111111111111111111111111111111111111111111111111111",
    "match": true
  }
}
ChampTypeDescription
ipfs_fetchedbooleantrue quand le serveur a réussi à lire la copie IPFS.
ipfs_hashstringL'empreinte du contenu réellement lu sur IPFS.
expected_hashstringL'empreinte attendue pour ce contenu.
matchbooleanLe 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. Le prestataire de la copie de sauvegarde y figure sous espr:passportServiceProvider (identifier, name, espr:backedUpAt), dans les mêmes conditions que passport_service_provider, et il est absent tant que la copie n'existe 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.

CodeConditionQue faire
401access_tier=end_user est demandé sans session valide. detail vaut End-user-tier access requires authentication.Connectez-vous avec n'importe quel compte, ou demandez le niveau public.
401access_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.
401access_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.
403access_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.
403Un niveau professionnel est demandé par un compte connecté qui n'est ni administrateur de la marque du produit, ni titulaire de 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.
404Aucun 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.
404Le 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.
404L'appel arrive sur le nom de domaine vérifié d'une marque, et le produit appartient à une autre marque. detail vaut Product not found.Appelez cette adresse sur le domaine de la marque concernée, ou sur api.sealtrust.io. Le message est le même que pour un identifiant inconnu, pour ne pas confirmer qu'il existe.
422Une 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.
429Plus de 600 appels ont été faits depuis votre adresse IP vers une lecture /passport dans la fenêtre de 60 secondes en cours. detail vaut Rate limit exceeded: 600 requests per 60s.Attendez le nombre de secondes indiqué par l'en-tête Retry-After, puis réessayez.
500Une 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.

#Pourquoi la copie IPFS n'est pas toujours donnée au niveau public

Une copie IPFS se lit par quiconque connaît son identifiant de contenu. Jusqu'au 14 juillet 2026, nous y déposions le passeport complet, champs réservés compris. Donner l'adresse à un lecteur public aurait contourné les niveaux d'accès, donc elle était masquée pour tout le monde sauf les niveaux authentifiés.

Depuis cette date, nous ne déposons que la projection publique du passeport : la copie ne contient plus rien de réservé, et son adresse est donnée à tout le monde. Les passeports publiés avant cette date gardent une copie de données complètes, définitivement, puisqu'un identifiant de contenu ne se retire pas. Leur adresse reste donc réservée aux niveaux authentifiés.

Mesuré en production le 12 septembre 2026 : sur seize passeports portant une copie IPFS, cinq sont antérieurs à ce changement.

#Voir aussi

Votre réponse ouvre un courriel pré-rempli dans votre messagerie, à destination de contact@sealtrust.io. Vous le relisez avant de l'envoyer.

Proposer une correctionSignaler un problème