# GET /passport/01/{gtin}

Lire le passeport numérique publié pour un modèle de produit, à partir de son GTIN. Aucune clef d'API pour le niveau public.

Source : https://docs.sealtrust.io/reference/get-passport-gtin/

---

Vous lisez le passeport numérique publié pour un modèle de produit, à partir de
son GTIN. Le GTIN, Global Trade Item Number, est le numéro d'article commercial
imprimé sous le code-barres. En quittant cette page, vous saurez récupérer le
contenu du passeport, son numéro de version, son empreinte et sa copie IPFS, et
vous saurez demander un niveau d'accès plus large que le niveau public.

Adresse complète :

```http
GET https://api.sealtrust.io/v1/passport/01/{gtin}
```

Le même point d'entrée répond aussi sans le préfixe `/v1`, à
`https://api.sealtrust.io/passport/01/{gtin}`. Les deux adresses appellent le
même code. Utilisez la forme `/v1` pour une nouvelle intégration.

> [!INFO] Ce point d'entrée décrit un modèle
> Le chemin `/01/{gtin}` porte un GTIN et aucun numéro de série. Il désigne donc
> une référence commerciale, et jamais un exemplaire physique. Le passeport rendu
> ici est celui qui est rattaché à un modèle et à aucune unité. Un passeport
> rattaché à un exemplaire n'est jamais servi à cette adresse, même quand son
> modèle porte ce GTIN.
>
> Trois choses sont donc absentes ici, parce qu'elles n'existent pas à ce
> niveau : la reconnaissance du propriétaire, l'état de fin de vie de l'objet, et
> le résumé de garantie. Pour ces informations, passez par le passeport d'un
> exemplaire.

## Autorisation

Aucune pour le niveau public, qui est le niveau par défaut. Ce point d'entrée
répond sans clef d'API.

Les niveaux `public` et `end_user` répondent sans compte. Les niveaux
`repairer`, `recycler`, `upstream` et `authority` exigent un
compte. Vous demandez un niveau par le paramètre `access_tier` décrit plus bas.
Vous vous authentifiez par un jeton de session présenté en
`Authorization: Bearer <jeton>`, ou par le cookie de session posé lors de la
connexion.

Une clef d'API partenaire ne donne accès à aucun de ces niveaux. Elle n'est pas
un jeton de session, elle est ignorée ici, et la réponse est celle d'un appelant
anonyme.

| Niveau demandé | Qui l'obtient |
| --- | --- |
| `public` | tout le monde, sans compte |
| `end_user` | tout le monde, sans compte |
| `repairer` | les comptes de la marque du produit, les partenaires portant une accréditation de réparateur active délivrée par cette marque, et les autorités de surveillance du marché |
| `recycler` | les comptes de la marque du produit, les partenaires portant une accréditation de recycleur active délivrée par cette marque, et les autorités de surveillance du marché |
| `upstream` | les comptes de la marque du produit et les autorités de surveillance du marché |
| `authority` | les comptes portant le rôle d'autorité de surveillance du marché |

## Plafond d'appels

60 appels par fenêtre de 60 secondes, comptés par adresse IP appelante.

Ce compteur est commun à toutes les adresses qui commencent par `/passport`. Les
appels que vous faites sur le passeport d'un exemplaire et sur les résumés de
preuve entament donc le même budget.

Chaque réponse porte trois en-têtes qui décrivent ce compteur.

| En-tête | Contenu |
| --- | --- |
| `X-RateLimit-Limit` | le plafond appliqué sur la fenêtre |
| `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 |

Ce compteur est indépendant du quota quotidien d'une clef d'API. Cet appel
n'entame ni ce quota quotidien, ni le quota mensuel de produits de votre offre.

## Paramètres de chemin et de requête

| Nom | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `gtin` | `string` | oui | Le GTIN du modèle, aux formats GTIN-8, GTIN-12, GTIN-13 ou GTIN-14, séparateurs compris. Son dernier chiffre doit être la clef de contrôle des chiffres qui le précèdent. La valeur est ramenée à quatorze chiffres avant la recherche. |
| `access_tier` | `string` | non | Le niveau d'accès aux données, au sens du règlement ESPR. Valeur par défaut `public`. Les six valeurs acceptées sont `public`, `end_user`, `repairer`, `recycler`, `upstream` et `authority`. Toute autre valeur renvoie 422. |

### Écrire le GTIN

Le GTIN que vous envoyez est ramené à sa forme canonique de 14 chiffres avant la
recherche. Tous les caractères qui ne sont pas des chiffres sont retirés, puis le
résultat est complété par des zéros à gauche jusqu'à 14 chiffres.

Ces trois écritures désignent donc le même modèle : `3701234567890`,
`03701234567890` et `3-701234-567890`. Elles donnent toutes la même forme
canonique, `03701234567890`. Une valeur qui ne contient aucun chiffre, ou qui en
contient plus de quatorze, renvoie 404.

Le dernier chiffre d'un GTIN est une clef de contrôle, calculée à partir de ceux
qui le précèdent. Nous la vérifions, et un GTIN dont le dernier chiffre ne
correspond pas renvoie 400. Recopiez le code imprimé sur le produit, chiffre
pour chiffre.

La recherche retrouve le modèle même si la marque a enregistré son GTIN sous une
forme plus courte, en GTIN-8, GTIN-12 ou GTIN-13.

### Choisir le niveau d'accès

`access_tier` sélectionne les sections du passeport que vous recevez. Ces niveaux
forment six destinataires distincts. Un réparateur et un recycleur reçoivent des
sections différentes, décidées par le métier de chacun.

Les niveaux `repairer`, `recycler` et `upstream` donnent chacun les sections de
leur métier, et rien de plus. Ce sont des publics distincts, et aucun ne
contient les autres : une accréditation de recycleur n'ouvre pas ce que voit
le réparateur, et n'ouvre pas non plus la fabrication ni la chaîne
d'approvisionnement du fournisseur amont.

| Valeur | Ce qu'elle ajoute |
| --- | --- |
| `public` | identification du produit, conformité déclarée, taux de recyclabilité et de contenu recyclé, étiquettes libres de la marque (`labels`), spécification générale pour une batterie |
| `end_user` | tout le niveau public, plus impact environnemental, circularité complète, matière principale, mention de matière certifiée biologique (`materials.certified_organic`), durabilité, efficacité énergétique, empreinte carbone |
| `repairer` | tout le niveau `end_user`, plus nomenclature des composants, notice de démontage, indice de réparabilité, état de santé pour une batterie |
| `recycler` | tout le niveau `end_user`, plus composition des matériaux, substances préoccupantes, notice de démontage, état de santé pour une batterie |
| `upstream` | tout le niveau `end_user`, plus composition des matériaux, substances préoccupantes, données de fabrication et de chaîne d'approvisionnement |
| `authority` | l'intégralité du passeport, sans filtrage |

Une marque peut redéfinir ces règles pour ses propres produits. Le tableau
ci-dessus donne le comportement par défaut, appliqué tant qu'une marque n'a rien
redéfini.

### En-têtes de requête

Aucun en-tête n'est obligatoire pour le niveau public.

| En-tête | Obligatoire | Description |
| --- | --- | --- |
| `Authorization` | non | `Bearer <jeton de session>`. Obligatoire seulement pour les niveaux `repairer`, `recycler`, `upstream` et `authority`. |

## Corps de la requête

Aucun. Cette requête n'a pas de corps.

## Requête d'exemple

Lecture du passeport de référence publié pour le GTIN `03701234567890`, au
niveau public.

:::onglets
```bash title="curl"
curl -i "https://api.sealtrust.io/v1/passport/01/03701234567890?access_tier=public"
```
```typescript
const gtin = "03701234567890";

const url = new URL(
  `https://api.sealtrust.io/v1/passport/01/${encodeURIComponent(gtin)}`,
);
url.searchParams.set("access_tier", "public");

const response = await fetch(url, { method: "GET" });
const passeport = await response.json();

console.log(response.status);
console.log(JSON.stringify(passeport, null, 2));
```
```python
import requests

gtin = "03701234567890"

response = requests.get(
    f"https://api.sealtrust.io/v1/passport/01/{gtin}",
    params={"access_tier": "public"},
    timeout=30,
)

print(response.status_code)
print(response.json())
```
:::

Pour un niveau qui exige un compte, ajoutez l'en-tête d'autorisation et changez
la valeur du paramètre.

:::onglets
```bash title="curl"
curl -i \
  -H "Authorization: Bearer votre-jeton-de-session" \
  "https://api.sealtrust.io/v1/passport/01/03701234567890?access_tier=recycler"
```
```typescript
const gtin = "03701234567890";

const url = new URL(
  `https://api.sealtrust.io/v1/passport/01/${encodeURIComponent(gtin)}`,
);
url.searchParams.set("access_tier", "recycler");

const response = await fetch(url, {
  method: "GET",
  headers: { Authorization: "Bearer votre-jeton-de-session" },
});
const passeport = await response.json();

console.log(response.status);
console.log(JSON.stringify(passeport, null, 2));
```
```python
import requests

gtin = "03701234567890"

response = requests.get(
    f"https://api.sealtrust.io/v1/passport/01/{gtin}",
    params={"access_tier": "recycler"},
    headers={"Authorization": "Bearer votre-jeton-de-session"},
    timeout=30,
)

print(response.status_code)
print(response.json())
```
:::

> [!INFO] Le SDK TypeScript ne couvre pas ce point d'entrée
> `@sealtrust-io/sdk` n'expose aucune méthode pour cette adresse. Les exemples
> ci-dessus utilisent `fetch`, disponible sans dépendance.

## Réponse d'exemple

Code HTTP `200`.

```json
{
  "id": 4821,
  "product_id": null,
  "product_model_id": 317,
  "gtin": "03701234567890",
  "level": "model",
  "brand_id": 12,
  "schema_version": "1.0",
  "passport_version": 3,
  "data": {
    "product_identity": {
      "gtin": "03701234567890",
      "model": "Sac Modèle Exemple",
      "brand": "Exemple SAS",
      "made_in": "FR",
      "production_facility": "Atelier Exemple, Nantes"
    },
    "compliance": {
      "eu_espr": true,
      "reach": true,
      "ce_marking": true
    },
    "circularity": {
      "recyclability_percentage": 62,
      "recycled_content_percentage": 0
    }
  },
  "data_hash": "4444444444444444444444444444444444444444444444444444444444444444",
  "ipfs_uri": null,
  "visibility": "public",
  "published_at": "2026-05-14T09:12:44.201000+00:00",
  "product_name": "Sac Modèle Exemple",
  "brand_name": "Exemple SAS"
}
```

Quand plusieurs versions publiées et publiques coexistent pour ce modèle, c'est
celle qui porte le plus grand numéro de version qui vous est rendue.

La réponse compte quinze champs et rien d'autre.

| Champ | Type | Description |
| --- | --- | --- |
| `id` | `integer` | Le numéro de cette version de passeport. |
| `product_id` | `null` | Ce champ vaut toujours `null` ici. Un passeport de référence n'est rattaché à aucun exemplaire. |
| `product_model_id` | `integer` | Le numéro du modèle auquel ce passeport est rattaché. Ce point d'entrée ne cherche que parmi les passeports rattachés à un modèle, donc ce champ n'est jamais `null` ici. |
| `gtin` | `string` | Le GTIN que vous avez demandé, ramené à quatorze chiffres. |
| `level` | `string` | Vaut toujours `model` sur ce point d'entrée. |
| `brand_id` | `integer` | Le numéro de la marque qui publie ce passeport. |
| `schema_version` | `string` | La version du schéma de données du passeport. |
| `passport_version` | `integer` | Le numéro de version du passeport. Une correction se publie sous un numéro de version plus grand, et la version déjà publiée reste telle quelle. |
| `data` | `object` | Le contenu du passeport, filtré selon le niveau demandé. Voir plus bas. |
| `data_hash` | `string \| null` | L'empreinte SHA-256 du contenu complet du passeport, en hexadécimal. `null` quand aucune empreinte n'a été enregistrée pour cette version. |
| `ipfs_uri` | `string \| null` | L'adresse `ipfs://` de la copie publiée du passeport. Toujours `null` aux niveaux `public` et `end_user`, qui ne reçoivent pas cette adresse. `null` aussi quand aucune copie n'a été déposée. |
| `visibility` | `string` | Vaut toujours `public` ici. Ce point d'entrée ne sert que les passeports dont la visibilité est publique. |
| `published_at` | `string` | Date et heure de publication de cette version, au format ISO 8601. Ce point d'entrée ne sert que des passeports publiés, donc ce champ n'est jamais `null` ici. |
| `product_name` | `string` | Le nom du modèle qui porte ce GTIN. |
| `brand_name` | `string` | Le nom de la marque qui publie ce passeport. |

### En-têtes de la réponse

Une réponse `200` porte `X-DPP-Access-Tier`, en plus de `Cache-Control`,
`X-Request-Id` et de la famille `X-RateLimit-*` que porte toute réponse.

| En-tête | Contenu |
| --- | --- |
| `X-DPP-Access-Tier` | le niveau d'accès qui a servi à filtrer la réponse |
| `Cache-Control` | `no-store, max-age=0`, quel que soit le niveau servi. Ne placez cette réponse derrière aucun cache partagé. |

Seul `X-DPP-Access-Tier` est propre à la réponse `200`. Une réponse d'erreur
ne le porte pas. `Cache-Control`, `X-Request-Id` et la famille `X-RateLimit-*`
accompagnent aussi les réponses d'erreur.

### Lire le champ `data`

`data` porte le contenu du passeport, sous forme de sections nommées. Les
sections présentes dépendent du niveau demandé, des règles définies par la
marque, et de ce que la marque a réellement renseigné. Une section absente du
passeport n'apparaît pas, et une section que votre niveau ne couvre pas
n'apparaît pas non plus.

Le filtrage descend à l'intérieur des sections. Dans l'exemple ci-dessus, la
section `compliance` est présente au niveau public, mais elle ne montre que les
mentions de conformité ouvertes à ce niveau. Ne concluez jamais qu'un champ
n'existe pas parce qu'il est absent de votre réponse.

> [!ATTENTION] `data_hash` ne correspond pas au `data` que vous recevez
> L'empreinte porte sur le contenu complet du passeport, avant tout filtrage.
> Le champ `data` que vous recevez est filtré selon votre niveau d'accès. Si
> vous recalculez une empreinte sur le `data` reçu au niveau public, elle ne
> correspondra pas, et ce n'est pas le signe d'une altération.
>
> Pour vérifier l'intégrité et l'ancrage de cette version, utilisez le résumé de
> preuve, à l'adresse `GET /v1/passport/01/{gtin}/proof`.

## Erreurs

Le corps d'une réponse d'erreur porte un champ `detail`.

| Code | Condition | Que faire |
| --- | --- | --- |
| 400 | Le dernier chiffre du GTIN envoyé n'est pas la clef de contrôle des chiffres qui le précèdent. `detail` vaut `Invalid GTIN: the check digit does not match.` C'est la seule cause de ce code sur ce point d'entrée : une valeur sans aucun chiffre, ou de plus de quatorze chiffres, renvoie 404 et non 400. | Recopiez le code imprimé sur le produit, chiffre pour chiffre, sans en ajouter ni en omettre. |
| 401 | Vous demandez `access_tier=authority` sans être authentifié. `detail` vaut `Authority-tier access requires authentication`. | Présentez un jeton de session valide dans l'en-tête `Authorization`. |
| 401 | Vous demandez `access_tier=repairer`, `recycler` ou `upstream` sans être authentifié. `detail` vaut `Professional-tier access requires authentication`. | Présentez un jeton de session valide dans l'en-tête `Authorization`. Une clef d'API partenaire ne convient pas ici. |
| 403 | Vous demandez `access_tier=authority` avec un compte qui ne porte pas le rôle d'autorité. `detail` vaut `Authority-tier access is restricted to market surveillance authorities`. | Demandez un niveau qui correspond à votre compte. |
| 403 | Vous demandez un niveau professionnel avec un compte qui n'y a pas droit sur cette marque. `detail` commence par `This tier is restricted to the product's brand`. | Demandez à la marque du produit une accréditation active du métier correspondant, puis réessayez. |
| 404 | `detail` vaut `Unknown GS1 Digital Link`. Trois situations donnent cette même réponse : le GTIN envoyé ne contient aucun chiffre ou en contient plus de quatorze, aucun modèle ne porte ce GTIN, ou aucun passeport de référence public n'est publié pour ce modèle. | Vérifiez le GTIN. Si le GTIN est bon, demandez à la marque de publier le passeport de référence de ce modèle. La réponse est volontairement identique dans les trois cas, donc elle ne vous dira pas laquelle s'applique. |
| 422 | La valeur de `access_tier` ne fait pas partie des six valeurs acceptées. `detail` porte la liste des erreurs de validation, avec le nom du paramètre en cause. | Corrigez la valeur du paramètre. |
| 429 | Le plafond de 60 appels par 60 secondes sur les adresses `/passport` est dépassé. `detail` vaut `Rate limit exceeded: 60 requests per 60s`. La réponse porte `Retry-After` et la famille `X-RateLimit-*`. | 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`. | 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`, que porte cette réponse comme toutes les autres. |

### Ordre des contrôles

Le contrôle du niveau `authority` a lieu avant la recherche du passeport. Un
appel `access_tier=authority` sans authentification renvoie donc 401, même si le
GTIN est inconnu.

Les contrôles des niveaux professionnels ont lieu après la recherche. Un appel
`access_tier=recycler` sur un GTIN inconnu renvoie donc 404, et jamais 401.

## Voir aussi

- [`GET /passport/01/{gtin}/proof`](/reference/get-passport-gtin-proof/),
  rassembler les preuves publiques du passeport annoncé par un GTIN.
- [`GET /passport/{identifier}`](/reference/get-passport-identifier/),
  lire le passeport publié d'un article.
- [`GET /01/{gtin}`](/reference/get-gs1-gtin/),
  résoudre un lien GS1 qui ne porte qu'un GTIN.
- [Notions de base](/notions/),
  distinguer modèle, lot et article avant de commander la moindre étiquette.
