Méthode GET/passport /{identifier} /verify
Contrôler l'intégrité du passeport publié d'un article : empreinte enregistrée, copie publique immuable et sceau de version. Point d'entrée public.
Sur cette page
Vous contrôlez qu'un passeport publié n'a pas été modifié depuis sa publication. En quittant cette page, vous saurez demander ce contrôle à partir de n'importe quel identifiant d'article, lire les trois verdicts que la réponse rend, et distinguer un passeport altéré d'un contrôle qui n'a pas pu aboutir.
Adresse complète :
GET https://api.sealtrust.io/v1/passport/{identifier}/verifyLe même point d'entrée répond aussi sans le préfixe /v1, à
https://api.sealtrust.io/passport/{identifier}/verify. Les deux adresses
appellent le même code. Utilisez la forme /v1 pour une nouvelle intégration.
#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.
#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/0ABCDEFGHJKM/verify et /passport/0ABCDEFGHJKM/verify
remplissent le même compteur.
Prévoyez un délai d'attente d'au moins 30 secondes côté client. Pendant votre
appel, ce point d'entrée va chercher la copie publique immuable sur des
passerelles publiques. Il en interroge plusieurs l'une après l'autre, chacune
avec sa propre limite de temps, donc un premier appel sur une copie que le
serveur n'a encore jamais lue peut durer une vingtaine de secondes. Les appels
suivants sur la même copie répondent sans aller la rechercher. Quand aucune
passerelle ne répond, la réponse reste 200 et ipfs_match vaut null.
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 contrôler le passeport. 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'article | 0x suivi de 64 caractères hexadécimaux | Pour un article NFC, l'empreinte de l'identifiant lu sur la puce. Pour un article QR, une empreinte que le serveur tire au hasard au moment de la frappe. Les deux ont la même forme et vous les utilisez de la même façon. |
| Identifiant de jeton | un entier de 256 bits écrit en décimal, 77 ou 78 chiffres | L'identifiant de l'article sur la chaîne. Traitez-le comme une chaîne de caractères : il dépasse un entier 64 bits. |
| Numéro de série imprimé | 12 caractères | Ce que porte le QR code sur le produit, dans l'adresse /p/{serial}. |
Le serveur reconnaît l'empreinte d'article sans distinction de casse. Il
reconnaît le numéro de série de la même façon, et il ramène les caractères qui
se ressemblent à une forme unique avant de chercher : un I ou un L que vous
saisissez à la main retrouve le 1, un O retrouve le 0.
Ce point d'entrée n'accepte pas le numéro de certificat d'authenticité. Vous
l'employez sur GET /certificate/{identifier}.
#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
Contrôle d'intégrité du passeport de l'article dont le numéro de série imprimé
est 0ABCDEFGHJKM. Les exemples utilisent cette forme parce qu'elle tient sur
12 caractères. Un identifiant de jeton s'écrit au même endroit dans l'adresse,
sur 77 ou 78 chiffres. Les trois exemples posent le même délai d'attente de 30
secondes, pour la raison donnée plus haut.
curl -i --max-time 30 https://api.sealtrust.io/v1/passport/0ABCDEFGHJKM/verifyconst reponse = await fetch(
"https://api.sealtrust.io/v1/passport/0ABCDEFGHJKM/verify",
{ signal: AbortSignal.timeout(30000) },
);
if (reponse.status === 404) {
console.log("Aucun passeport public à contrôler pour cet article.");
} else if (reponse.ok) {
const controle = await reponse.json();
console.log(controle.db_hash_match);
console.log(controle.ipfs_match, controle.ipfs_uri);
console.log(controle.seal.sealed, controle.seal.chain_link_match);
} else {
console.log(reponse.status, await reponse.json());
}import requests
response = requests.get(
"https://api.sealtrust.io/v1/passport/0ABCDEFGHJKM/verify",
timeout=30,
)
if response.status_code == 404:
print("Aucun passeport public à contrôler pour cet article.")
elif response.ok:
controle = response.json()
print(controle["db_hash_match"])
print(controle["ipfs_match"], controle["ipfs_uri"])
print(controle["seal"]["sealed"], controle["seal"]["chain_link_match"])
else:
print(response.status_code, response.json())#Réponse d'exemple
Code HTTP 200OK
Code HTTP 200.
{
"db_hash_match": true,
"ipfs_match": true,
"ipfs_uri": "ipfs://bafybeiaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"ipfs_gateway_url": "https://passerelle.exemple.invalid/ipfs/bafybeiaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"data_hash": "1111111111111111111111111111111111111111111111111111111111111111",
"computed_hash": "1111111111111111111111111111111111111111111111111111111111111111",
"passport_version": 3,
"seal": {
"sealed": true,
"sealed_at": "2026-05-14T09:12:44+00:00",
"algorithm": "st-dpp-chain-v1",
"version_hash": "2222222222222222222222222222222222222222222222222222222222222222",
"prev_version_hash": "3333333333333333333333333333333333333333333333333333333333333333",
"linked": true,
"chain_link_match": true
}
}La réponse compte huit champs et rien d'autre.
| Champ | Type | Description |
|---|---|---|
db_hash_match | boolean ou null | true quand les données enregistrées du passeport correspondent encore à l'empreinte enregistrée avec elles. null quand aucune empreinte n'a été enregistrée pour cette version. |
ipfs_match | boolean ou null | true quand la copie publique immuable correspond à la version publique du passeport. false quand elle en diffère. null quand aucune copie n'existe, ou quand aucune passerelle n'a répondu. |
ipfs_uri | string ou null | L'adresse ipfs:// de la copie publique immuable. Renseignée uniquement quand cette copie est le passeport public que la marque publie aujourd'hui, voir ci-dessous. |
ipfs_gateway_url | string ou null | La même copie, sous forme d'adresse HTTP ouvrable dans un navigateur. Renseignée aux mêmes conditions que ipfs_uri. |
data_hash | string ou null | L'empreinte enregistrée avec cette version du passeport, 64 caractères hexadécimaux. null quand aucune empreinte n'a été enregistrée. |
computed_hash | string | L'empreinte recalculée au moment de votre appel à partir des données enregistrées, 64 caractères hexadécimaux. Elle porte sur les données complètes du passeport, y compris les champs que ce point d'entrée ne rend pas et que la version publique du passeport ne rend pas non plus. Vous ne pouvez donc pas la reproduire vous-même à partir de données publiques. |
passport_version | integer | Le numéro de version du passeport contrôlé. Il démarre à 1 et augmente d'une unité à chaque nouvelle version du passeport. |
seal | object | Le sceau de cette version et sa place dans la chaîne des versions, voir ci-dessous. |
#Quel passeport le serveur contrôle
Le contrôle porte sur la dernière version publiée dont la visibilité est publique. Le serveur cherche d'abord le passeport propre à l'article. À défaut, il contrôle le passeport du modèle, partagé par tous les articles du modèle.
La réponse ne dit pas laquelle des deux portées a répondu. Les deux numérotent
leurs versions séparément, donc passport_version peut valoir 1 dans les deux
cas.
Le serveur ne contrôle jamais ici un passeport réservé au propriétaire ni un passeport réservé à la marque. La réponse est alors 404, comme si aucun passeport n'était publié.
#Quand le serveur vous rend l'adresse ipfs_uri
Vous recevez l'adresse de la copie publique lorsque son contenu est exactement
le passeport public que la marque publie aujourd'hui. Sinon, ipfs_uri et
ipfs_gateway_url valent null.
Une marque qui change ses règles d'accès change ce que montre son passeport
public. Une copie déposée avant ce changement n'est donc plus annoncée tant
que la marque n'en a pas déposé une nouvelle. Ne lisez jamais ces deux null
comme un verdict sur la copie.
ipfs_match à null ne dit rien sur l'intégrité de la copie. Réessayez plus
tard avant de conclure.
#Le bloc seal
| Champ | Type | Description |
|---|---|---|
sealed | boolean | false quand la version n'est pas scellée. Le bloc s'arrête alors là et ne porte aucun autre champ. |
sealed_at | string | La date et l'heure du scellement, au format ISO 8601. |
algorithm | string | La version de l'algorithme de chaînage. Vaut aujourd'hui st-dpp-chain-v1. |
version_hash | string ou null | L'empreinte scellée de cette version, 64 caractères hexadécimaux. |
prev_version_hash | string ou null | L'empreinte scellée de la version précédente du même passeport. null pour la toute première version. |
linked | boolean | true quand cette version porte une empreinte scellée et prend donc sa place dans la chaîne. |
reason | string | Présent uniquement quand linked vaut false. Vaut alors sealed_before_chain : vous avez publié cette version avant l'existence du chaînage, et le serveur n'en fabrique aucun après coup. |
chain_link_match | boolean | Présent uniquement quand linked vaut true. false veut dire que les données enregistrées ne correspondent plus à ce qui a été scellé. |
Le bloc seal prend donc trois formes, et vous devez pouvoir les distinguer
sans rien déduire d'un champ absent.
{ "sealed": false }{
"sealed": true,
"sealed_at": "2025-11-02T08:30:00+00:00",
"algorithm": "st-dpp-chain-v1",
"version_hash": null,
"prev_version_hash": null,
"linked": false,
"reason": "sealed_before_chain"
}{
"sealed": true,
"sealed_at": "2026-05-14T09:12:44+00:00",
"algorithm": "st-dpp-chain-v1",
"version_hash": "2222222222222222222222222222222222222222222222222222222222222222",
"prev_version_hash": "3333333333333333333333333333333333333333333333333333333333333333",
"linked": true,
"chain_link_match": true
}#Quel verdict lire en premier
chain_link_match à false est le signal qu'une version scellée a été
modifiée après sa publication. C'est le verdict le plus fort de cette réponse.
Il vient d'un recalcul fait au moment de votre appel.
ipfs_match à false porte le même genre de signal sur la copie publique.
#Erreurs
Le corps d'une réponse d'erreur porte un champ detail.
| Code | Condition | Que faire |
|---|---|---|
| 404 | Aucun article 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 public n'est publié pour lui ni pour son modèle. detail vaut No published passport found for this product. | Ne traitez pas cette réponse comme un échec du contrôle. Il n'y a rien à contrôler. Un passeport réservé au propriétaire ou à la marque donne aussi cette réponse. |
| 429 | Le plafond de 60 appels par 60 secondes est atteint pour votre adresse réseau, tous chemins commençant par /passport confondus. detail vaut Rate limit exceeded: 60 requests per 60s. | Attendez le nombre de secondes indiqué par Retry-After, puis réessayez. |
| 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 passerelle injoignable ne produit pas d'erreur HTTP. La réponse reste 200
et ipfs_match vaut null.
#Voir aussi
GET /passport/{identifier}/proof, rassembler les preuves publiques du passeport d'un article.GET /passport/{identifier}, lire le passeport publié d'un article.GET /certificate/{identifier}, lire le certificat d'authenticité 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.