Méthode GET/passport /{identifier} /proof
Rassembler en un appel toutes les preuves publiques d'un passeport : empreinte du contenu, copie IPFS, ancrage sur Base, sceau de version et état du justificatif signé. Point d'entrée public.
Sur cette page
- Autorisation
- Plafond d'appels
- Paramètres de chemin et de requête
- En-têtes
- Corps de la requête
- Requête d'exemple
- Réponse d'exemple
- Le bloc anchor, la référence de l'article
- Le bloc passport_anchor, la date du document
- Le bloc seal, le sceau de la version
- Le bloc vc, le justificatif signé
- La copie IPFS
- Erreurs
- Voir aussi
Vous rassemblez en un seul appel les preuves publiques attachées au passeport d'un produit. En quittant cette page, vous saurez demander ces preuves à partir d'un identifiant d'article, lire ce que chaque bloc établit réellement, et distinguer une preuve absente d'une preuve en défaut.
Adresse complète :
GET https://api.sealtrust.io/v1/passport/{identifier}/proofLe même point d'entrée répond aussi sans le préfixe /v1, à
https://api.sealtrust.io/passport/{identifier}/proof. Les deux adresses
appellent le même code. Utilisez la forme /v1 pour une nouvelle intégration.
Ce point d'entrée ne renvoie aucun contenu du passeport. Il renvoie les
éléments qui permettent de vérifier ce contenu. Pour lire le passeport
lui-même, appelez GET /v1/passport/{identifier}.
#Autorisation
Aucune, point d'entrée public. Vous n'envoyez ni clef d'API, ni session, ni en-tête d'origine. La réponse est la même pour tout le monde.
Vous recevez ici uniquement les passeports dont la visibilité est publique. Un passeport réservé au propriétaire ou réservé à la marque ne vous est jamais rendu par ce point d'entrée.
#Plafond d'appels
60 appels par tranche de 60 secondes, comptés par adresse réseau appelante.
Ce compteur est commun à tous les chemins qui commencent par /passport. Les
appels que vous adressez à l'un d'eux entament donc le budget des autres. Le
préfixe /v1 ne crée pas un second budget : /v1/passport/1042/proof et
/passport/1042/proof 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 |
Un refus 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 | L'article dont vous voulez les preuves. Trois formes sont acceptées, voir ci-dessous. |
Ce point d'entrée n'a aucun paramètre de requête.
identifier accepte trois formes, essayées dans cet ordre.
| Forme | Aspect | Provenance |
|---|---|---|
| Empreinte d'identifiant | 0x suivi de 64 caractères hexadécimaux | l'empreinte de l'identifiant unique de l'exemplaire. Sur un article NFC elle vient de l'identifiant de la puce. Sur un article QR seul, le serveur la tire au hasard à la frappe. |
| Identifiant de jeton | un nombre écrit en décimal | l'identifiant de l'article sur la chaîne |
| Numéro de série imprimé | 12 caractères | ce que porte le QR code sur le produit, dans l'adresse /p/{serial} |
Vous pouvez écrire le numéro de série en majuscules ou en minuscules. Nous
ramenons les caractères qui se ressemblent à une forme unique avant la
recherche, donc un I ou un L saisi à la main retrouve le 1, et un O
retrouve le 0.
Ce point d'entrée ne résout que les articles encore au catalogue de la marque. Un article détruit sur la chaîne, remplacé par une version ultérieure ou archivé répond 404.
#En-têtes
Aucun en-tête n'est requis.
#Corps de la requête
Aucun. Cette requête n'a pas de corps.
#Requête d'exemple
Preuves du passeport de l'article dont l'identifiant de jeton est 1042.
curl -i https://api.sealtrust.io/v1/passport/1042/proofconst reponse = await fetch(
"https://api.sealtrust.io/v1/passport/1042/proof",
);
if (reponse.status === 404) {
console.log("Aucun passeport public pour cet identifiant.");
} else if (reponse.ok) {
const preuves = await reponse.json();
console.log(preuves.passport_version, preuves.data_hash);
if (preuves.anchor && preuves.anchor.anchored === true) {
console.log("Lot ancré sur", preuves.anchor.chain);
console.log(preuves.anchor.merkle_root);
} else if (preuves.anchor) {
console.log("Pas d'ancrage de lot. Référence :", preuves.anchor.proves);
}
if (preuves.passport_anchor) {
console.log(
"Document daté au plus tard le",
preuves.passport_anchor.anchored_at,
);
console.log(
"Contenu inchangé :",
preuves.passport_anchor.data_hash_matches,
);
}
console.log("Scellé :", preuves.seal.sealed);
console.log("Justificatif signé :", preuves.vc.issued);
} else {
console.log(reponse.status, await reponse.json());
}import requests
response = requests.get(
"https://api.sealtrust.io/v1/passport/1042/proof",
timeout=30,
)
if response.status_code == 404:
print("Aucun passeport public pour cet identifiant.")
elif response.ok:
preuves = response.json()
print(preuves["passport_version"], preuves.get("data_hash"))
ancrage = preuves.get("anchor")
if ancrage and ancrage.get("anchored") is True:
print("Lot ancré sur", ancrage["chain"])
print(ancrage.get("merkle_root"))
elif ancrage:
print("Pas d'ancrage de lot. Référence :", ancrage.get("proves"))
document = preuves.get("passport_anchor")
if document:
print("Document daté au plus tard le", document["anchored_at"])
print("Contenu inchangé :", document["data_hash_matches"])
print("Scellé :", preuves["seal"]["sealed"])
print("Justificatif signé :", preuves["vc"]["issued"])
else:
print(response.status_code, response.json())#Réponse d'exemple
Code HTTP 200OK
Code HTTP 200.
{
"passport_version": 3,
"data_hash": "1111111111111111111111111111111111111111111111111111111111111111",
"ipfs_uri": "ipfs://bafybeiexemple00000000000000000000000000000000000000000000",
"ipfs_gateway_url": "https://ipfs.io/ipfs/bafybeiexemple00000000000000000000000000000000000000000000",
"anchor": {
"chain": "base",
"chain_id": 8453,
"type": "merkle_batch",
"tx_hash": "0x2222222222222222222222222222222222222222222222222222222222222222",
"basescan_url": "https://basescan.org/tx/0x2222222222222222222222222222222222222222222222222222222222222222",
"merkle_root": "0x3333333333333333333333333333333333333333333333333333333333333333",
"anchored": true,
"proves": "batch_inclusion"
},
"passport_anchor": {
"chain": "base",
"chain_id": 8453,
"tx_hash": "0x4444444444444444444444444444444444444444444444444444444444444444",
"basescan_url": "https://basescan.org/tx/0x4444444444444444444444444444444444444444444444444444444444444444",
"merkle_root": "0x5555555555555555555555555555555555555555555555555555555555555555",
"leaf": "0x6666666666666666666666666666666666666666666666666666666666666666",
"leaf_index": 2,
"proof": [
"0x7777777777777777777777777777777777777777777777777777777777777777",
"0x8888888888888888888888888888888888888888888888888888888888888888"
],
"anchored_at": "2026-08-14T02:15:09+00:00",
"data_hash_matches": true,
"proves": "content_existed_at_or_before_tx"
},
"seal": {
"sealed": true,
"sealed_at": "2026-08-13T09:41:22+00:00",
"algorithm": "st-dpp-chain-v1",
"version_hash": "9999999999999999999999999999999999999999999999999999999999999999",
"prev_version_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"linked": true,
"chain_link_match": true
},
"vc": {
"issued": true,
"vct": "https://schema.sealtrust.io/vct/digital-product-passport",
"issued_at": "2026-08-13T09:41:25+00:00"
},
"verifications": {
"count": 47,
"last_verified_at": "2026-08-19T18:03:44+00:00"
}
}passport_version, seal et vc sont toujours présents. Nous omettons les
autres champs de premier niveau quand la preuve correspondante n'existe pas.
Une absence signifie que cette preuve n'est pas disponible. Traitez-la comme
une information, au même titre qu'une valeur.
| Champ | Type | Présence | Description |
|---|---|---|---|
passport_version | integer | toujours | Le numéro de version du passeport publié auquel se rapportent toutes les preuves ci-dessous. |
data_hash | string | si enregistrée | L'empreinte SHA-256 du contenu complet du passeport, 64 caractères hexadécimaux sans préfixe 0x. |
ipfs_uri | string | si copie vérifiée | L'adresse IPFS de la copie publique du passeport. |
ipfs_gateway_url | string | si copie vérifiée | La même copie, sous forme d'adresse web ouvrable dans un navigateur. |
anchor | object | si l'article a une référence sur la chaîne | La référence sur la chaîne qui concerne l'ARTICLE. Voir ci-dessous. |
passport_anchor | object | si la version a été ancrée | L'ancrage qui date le DOCUMENT. Voir ci-dessous. |
seal | object | toujours | Le sceau de la version et sa place dans la suite des versions. Voir ci-dessous. |
vc | object | toujours | L'état du justificatif signé attaché au passeport. Voir ci-dessous. |
verifications | object | si le compte est supérieur à zéro | Le nombre de vérifications réussies enregistrées pour cet exemplaire, par QR comme par NFC, et la date de la dernière. Absent aussi quand l'exemplaire ne porte pas d'empreinte d'identifiant. |
Le passeport servi ici porte soit sur cet exemplaire précis, soit sur son
modèle. Nous cherchons d'abord un passeport rattaché à l'exemplaire. À défaut,
nous servons le passeport publié pour son modèle, partagé par tous les
exemplaires qui portent le même code produit. Dans ce second cas, data_hash,
ipfs_uri, ipfs_gateway_url, passport_anchor, seal et vc décrivent le
document du modèle. anchor et verifications restent propres à l'exemplaire
que vous avez demandé.
La réponse porte aussi l'en-tête Cache-Control: no-store, max-age=0. Ne
mettez cette réponse dans aucun cache partagé. Pour réduire le nombre de vos
appels, gardez le résultat dans votre propre cache applicatif, avec la durée de
fraîcheur que votre usage tolère.
#Le bloc anchor, la référence de l'article
Ce bloc est présent quand l'article porte une référence sur la chaîne. Il
recouvre deux situations différentes, et c'est le champ anchored qui les
sépare.
| Champ | Type | Description |
|---|---|---|
chain | string | Le réseau, en forme lisible par une machine. base en production. |
chain_id | integer | L'identifiant du réseau. 8453 pour Base en production. |
type | string | merkle_batch ou mint_transaction. |
tx_hash | string | La transaction concernée. |
basescan_url | string | Le lien direct vers cette transaction sur l'explorateur public du réseau. |
merkle_root | string | La racine du lot inscrite sur la chaîne. Présent uniquement quand type vaut merkle_batch et que la racine est enregistrée. |
anchored | boolean | true uniquement quand le lot de l'article a été inscrit sur la chaîne. |
proves | string | batch_inclusion quand le lot est ancré, token_minted sinon. |
anchored: true veut dire que le lot auquel appartient l'article a été inscrit
sur la chaîne. Vous obtenez la preuve d'appartenance elle-même par
GET /v1/verify/merkle/{identifier}, lorsque ce bloc porte aussi
merkle_root. Sans merkle_root, cet appel répond 404 et detail vaut
No Merkle anchor for this product.
anchored: false veut dire que le lot de l'article n'a jamais été inscrit. Le
bloc porte alors la transaction de frappe de l'article. Elle démontre que le
jeton existe sur la chaîne. Elle ne démontre rien sur un lot, et rien sur le
contenu du passeport.
Dans les deux cas, cette référence ne porte aucun engagement sur le contenu du
passeport. L'engagement sur le contenu se lit dans passport_anchor et dans
seal.
#Le bloc passport_anchor, la date du document
Ce bloc est présent quand cette version précise du passeport a été inscrite sur la chaîne. Il établit une seule chose : le contenu existait au plus tard au moment de cette transaction.
| Champ | Type | Description |
|---|---|---|
type | string | Toujours passport_anchor. Il distingue cet ancrage de celui du bloc anchor, qui porte un lot d'articles. |
anchored | boolean | Toujours true. Le bloc n'existe que lorsque la version a été inscrite sur la chaîne. |
chain | string | Le réseau, en forme lisible par une machine. |
chain_id | integer ou null | L'identifiant du réseau. null sur un ancrage antérieur à l'enregistrement du réseau. chain indique alors le réseau de production. |
tx_hash | string | La transaction qui porte la racine. |
basescan_url | string | Le lien direct vers cette transaction sur l'explorateur public du réseau. |
merkle_root | string | La racine inscrite sur la chaîne, 0x suivi de 64 caractères hexadécimaux. |
leaf | string | L'empreinte de cette version dans l'arbre, 0x suivi de 64 caractères hexadécimaux. |
leaf_index | integer | La position de cette empreinte dans la liste des empreintes inscrites. Le comptage démarre à 0. |
proof | string[] | Les empreintes voisines à combiner avec leaf, de bas en haut, pour retrouver merkle_root. La liste est vide quand l'inscription ne couvrait qu'une version. |
anchored_at | string ou null | La date de l'inscription, au format ISO 8601. |
data_hash_matches | boolean | true quand le passeport enregistré aujourd'hui correspond encore à ce qui a été inscrit. |
proves | string | Toujours content_existed_at_or_before_tx. |
Vous pouvez refaire la vérification d'appartenance sans nous faire confiance.
Vous partez de leaf. Pour chaque élément de proof, dans l'ordre, vous mettez
les deux valeurs de 32 octets côte à côte, la plus petite des deux d'abord, puis
vous appliquez keccak256 à la concaténation. Le résultat devient la nouvelle
valeur de travail. Après le dernier élément de proof, vous devez obtenir
exactement merkle_root. C'est la convention de vérification d'OpenZeppelin,
avec des voisins triés à chaque étage. Ouvrez ensuite basescan_url pour lire
la transaction qui a inscrit cette racine.
L'absence de passport_anchor est courante et normale. Publier une version ne
l'inscrit pas sur la chaîne. L'inscription est une opération distincte, faite
par passages groupés, et beaucoup de passeports publiés ne portent jamais ce
bloc. Ne concluez donc rien de son absence sur la validité du passeport. Le
bloc seal, lui, est toujours présent et couvre les versions non inscrites.
#Le bloc seal, le sceau de la version
Ce bloc est toujours présent. Il tient sur les versions que passport_anchor
ne couvre pas.
| Champ | Type | Présence | Description |
|---|---|---|---|
sealed | boolean | toujours | false quand la version n'a jamais été scellée. Le bloc s'arrête alors là. |
sealed_at | string | si sealed | La date du scellement, au format ISO 8601. |
algorithm | string | si sealed | La version de l'algorithme de chaînage. Vaut st-dpp-chain-v1. |
version_hash | string ou null | si sealed | L'empreinte de ce maillon, 64 caractères hexadécimaux. |
prev_version_hash | string ou null | si sealed | L'empreinte du maillon précédent. null pour la première version publiée. |
linked | boolean | si sealed | true quand cette version porte une empreinte de maillon. |
reason | string | si linked est false | Vaut sealed_before_chain. La version a été publiée avant l'existence du chaînage, donc aucun maillon n'est fabriqué après coup. Le bloc s'arrête là. |
chain_link_match | boolean | si linked | true quand le passeport enregistré aujourd'hui produit encore exactement le maillon stocké. |
chain_link_match est recalculé à chaque appel à partir du contenu enregistré.
false veut dire que la version a été modifiée après sa publication.
#Le bloc vc, le justificatif signé
Ce bloc est toujours présent.
| Champ | Type | Présence | Description |
|---|---|---|---|
issued | boolean | toujours | true quand un justificatif signé a été émis pour ce passeport. |
vct | string | si enregistré | L'identifiant du modèle de justificatif. Vaut aujourd'hui https://schema.sealtrust.io/vct/digital-product-passport. |
issued_at | string | si enregistrée | La date d'émission, au format ISO 8601. |
#La copie IPFS
ipfs_uri et ipfs_gateway_url désignent la copie publique du passeport. Le
contenu à cette adresse est la vue publique du passeport. Son empreinte diffère
donc de data_hash, qui porte sur le contenu complet.
Vous ne recevez ces deux champs que lorsque nous avons récupéré la copie et vérifié qu'elle est exactement le passeport public que la marque publie aujourd'hui. Leur absence peut donc signifier trois choses : aucune copie n'a été déposée, la copie n'a pas pu être récupérée au moment de l'appel, ou son contenu ne correspond plus à ce que la marque publie. Une marque qui change ses règles d'accès change ce que montre son passeport public, donc une copie déposée avant ce changement cesse d'être annoncée tant qu'une nouvelle n'a pas été déposée. Ne concluez rien de leur seule absence.
L'hôte de ipfs_gateway_url est celui d'une passerelle publique et peut
changer. Ne le codez pas en dur. Utilisez l'adresse rendue telle quelle, ou
ipfs_uri avec la passerelle de votre choix.
#Erreurs
Le corps d'une réponse d'erreur porte un champ detail.
| Code | Condition | Que faire |
|---|---|---|
| 404 | Aucun article au catalogue ne correspond à cet identifiant, sous aucune des trois formes acceptées. detail vaut Product not found. | Vérifiez l'identifiant. Un article détruit sur la chaîne, remplacé par une version ultérieure ou archivé ne se résout plus et donne cette même réponse. |
| 404 | L'article 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. Cet article n'a pas de passeport public. Un passeport réservé au propriétaire ou à la marque donne la même réponse. |
| 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. |
Une lecture d'ancrage ou de copie IPFS qui échoue ne produit pas d'erreur. Le bloc concerné est absent, et les autres preuves sont servies normalement.
#Voir aussi
GET /passport/{identifier}/verify, contrôler l'intégrité du passeport publié d'un article.GET /verify/merkle/{identifier}, récupérer la preuve d'appartenance d'un article au lot ancré sur Base.GET /passport/{identifier}, lire le passeport publié d'un article.- Confiance et preuves, ce que chaque preuve établit et comment un tiers refait la vérification.
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.