# GET /passport/01/{gtin}

Read the digital passport published for a product model, from its GTIN. No API key for the public tier.

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

---

You read the digital passport published for a product model, from its GTIN. The
GTIN, Global Trade Item Number, is the trade item number printed under the
barcode. By the end of this page, you will know how to retrieve the passport's
contents, its version number, its hash and its IPFS copy, and you will know how
to request an access tier wider than the public one.

Full address:

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

The same endpoint also answers without the `/v1` prefix, at
`https://api.sealtrust.io/passport/01/{gtin}`. Both addresses call the same
code. Use the `/v1` form for a new integration.

> [!INFO] This endpoint describes a model
> The path `/01/{gtin}` carries a GTIN and no serial number. It therefore
> designates a commercial reference, and never a physical item. The passport
> returned here is the one attached to a model and to no unit. A passport
> attached to an item is never served at this address, even when its model
> carries this GTIN.
>
> Three things are therefore absent here, because they do not exist at this
> level: owner recognition, the end-of-life state of the object, and the
> warranty summary. For that information, go through the passport of an item.

## Authorization

None for the public tier, which is the default tier. This endpoint answers
without an API key.

The `public` and `end_user` tiers answer without an account. The `repairer`,
`recycler`, `upstream` and `authority` tiers require an account. You request a
tier through the `access_tier` parameter described below. You authenticate with
a session token presented in `Authorization: Bearer <token>`, or with the
session cookie set at login.

A partner API key gives access to none of these tiers. It is not a session
token, it is ignored here, and the response is the one an anonymous caller
gets.

| Tier requested | Who gets it |
| --- | --- |
| `public` | everyone, without an account |
| `end_user` | everyone, without an account |
| `repairer` | the accounts of the product's brand, the partners holding an active repairer accreditation issued by that brand, and market surveillance authorities |
| `recycler` | the accounts of the product's brand, the partners holding an active recycler accreditation issued by that brand, and market surveillance authorities |
| `upstream` | the accounts of the product's brand and market surveillance authorities |
| `authority` | the accounts carrying the market surveillance authority role |

## Rate limit

60 calls per 60 second window, counted per calling IP address.

This counter is shared by every address that starts with `/passport`. The calls
you make on the passport of an item and on the proof summaries therefore eat
into the same budget.

Every response carries three headers that describe this counter.

| Header | Contents |
| --- | --- |
| `X-RateLimit-Limit` | the limit applied over the window |
| `X-RateLimit-Remaining` | what is left to you in the current window |
| `X-RateLimit-Reset` | the timestamp of the end of the window, in seconds |

This counter is independent of the daily quota of an API key. This call eats
into neither that daily quota, nor the monthly product quota of your plan.

## Path and query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `gtin` | `string` | yes | The model's GTIN, in GTIN-8, GTIN-12, GTIN-13 or GTIN-14 format, separators included. Its last digit must be the check digit of the digits that precede it. The value is reduced to fourteen digits before the lookup. |
| `access_tier` | `string` | no | The data access tier, in the sense of the ESPR regulation. Default value `public`. The six accepted values are `public`, `end_user`, `repairer`, `recycler`, `upstream` and `authority`. Any other value returns 422. |

### Writing the GTIN

The GTIN you send is reduced to its canonical 14 digit form before the lookup.
Every character that is not a digit is removed, then the result is padded with
zeros on the left up to 14 digits.

These three spellings therefore designate the same model: `3701234567890`,
`03701234567890` and `3-701234-567890`. They all give the same canonical form,
`03701234567890`. A value that contains no digit, or that contains more than
fourteen, returns 404.

The last digit of a GTIN is a check digit, computed from those that precede it.
We check it, and a GTIN whose last digit does not match returns 400. Copy the
code printed on the product, digit for digit.

The lookup finds the model even if the brand registered its GTIN in a shorter
form, as GTIN-8, GTIN-12 or GTIN-13.

### Choosing the access tier

`access_tier` selects the sections of the passport you receive. These tiers form
six distinct audiences. A repairer and a recycler receive different sections,
decided by the trade of each.

The `repairer`, `recycler` and `upstream` tiers each give the sections of their
trade, and nothing more. They are distinct audiences, and none of them
contains the others: a recycler accreditation does not open what the repairer
sees, and does not open manufacturing or the upstream supplier's supply chain
either.

| Value | What it adds |
| --- | --- |
| `public` | product identification, declared compliance, recyclability and recycled content rates, the brand's free-form labels (`labels`), general specification for a battery |
| `end_user` | the whole public tier, plus environmental impact, full circularity, primary material, certified organic material statement (`materials.certified_organic`), durability, energy efficiency, carbon footprint |
| `repairer` | the whole `end_user` tier, plus component bill of materials, disassembly instructions, repairability index, state of health for a battery |
| `recycler` | the whole `end_user` tier, plus material composition, substances of concern, disassembly instructions, state of health for a battery |
| `upstream` | the whole `end_user` tier, plus material composition, substances of concern, manufacturing and supply chain data |
| `authority` | the entire passport, with no filtering |

A brand can redefine these rules for its own products. The table above gives the
default behavior, applied as long as a brand has redefined nothing.

### Request headers

No header is required for the public tier.

| Header | Required | Description |
| --- | --- | --- |
| `Authorization` | no | `Bearer <session token>`. Required only for the `repairer`, `recycler`, `upstream` and `authority` tiers. |

## Request body

None. This request has no body.

## Example request

Reading the reference passport published for the GTIN `03701234567890`, at the
public tier.

:::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())
```
:::

For a tier that requires an account, add the authorization header and change the
value of the parameter.

:::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] The TypeScript SDK does not cover this endpoint
> `@sealtrust-io/sdk` exposes no method for this address. The examples above use
> `fetch`, available with no dependency.

## Example response

HTTP code `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"
}
```

When several published and public versions coexist for this model, the one
carrying the highest version number is the one returned to you.

The response counts fifteen fields and nothing else.

| Field | Type | Description |
| --- | --- | --- |
| `id` | `integer` | The number of this passport version. |
| `product_id` | `null` | This field is always `null` here. A reference passport is attached to no item. |
| `product_model_id` | `integer` | The number of the model this passport is attached to. This endpoint searches only among the passports attached to a model, so this field is never `null` here. |
| `gtin` | `string` | The GTIN you requested, reduced to fourteen digits. |
| `level` | `string` | Always equals `model` on this endpoint. |
| `brand_id` | `integer` | The number of the brand that publishes this passport. |
| `schema_version` | `string` | The version of the passport's data schema. |
| `passport_version` | `integer` | The passport's version number. A correction is published under a higher version number, and the already published version stays as it is. |
| `data` | `object` | The passport's contents, filtered according to the tier requested. See below. |
| `data_hash` | `string \| null` | The SHA-256 hash of the passport's full contents, in hexadecimal. `null` when no hash has been recorded for this version. |
| `ipfs_uri` | `string \| null` | The `ipfs://` address of the published copy of the passport. Always `null` at the `public` and `end_user` tiers, which do not receive this address. `null` too when no copy has been deposited. |
| `visibility` | `string` | Always equals `public` here. This endpoint serves only the passports whose visibility is public. |
| `published_at` | `string` | Date and time this version was published, in the format ISO 8601. This endpoint serves only published passports, so this field is never `null` here. |
| `product_name` | `string` | The name of the model that carries this GTIN. |
| `brand_name` | `string` | The name of the brand that publishes this passport. |

### Response headers

A `200` response carries `X-DPP-Access-Tier`, in addition to `Cache-Control`,
`X-Request-Id` and the `X-RateLimit-*` family that every response carries.

| Header | Contents |
| --- | --- |
| `X-DPP-Access-Tier` | the access tier that was used to filter the response |
| `Cache-Control` | `no-store, max-age=0`, whatever the tier served. Do not place this response behind any shared cache. |

Only `X-DPP-Access-Tier` is specific to the `200` response. An error response
does not carry it. `Cache-Control`, `X-Request-Id` and the `X-RateLimit-*`
family come with error responses too.

### Reading the `data` field

`data` carries the passport's contents, in the form of named sections. The
sections present depend on the tier requested, on the rules defined by the
brand, and on what the brand has actually filled in. A section absent from the
passport does not appear, and a section your tier does not cover does not appear
either.

The filtering goes down inside the sections. In the example above, the
`compliance` section is present at the public tier, but it shows only the
compliance statements open at that tier. Never conclude that a field does not
exist because it is absent from your response.

> [!ATTENTION] `data_hash` does not match the `data` you receive
> The hash covers the passport's full contents, before any filtering. The `data`
> field you receive is filtered according to your access tier. If you recompute
> a hash over the `data` received at the public tier, it will not match, and
> that is not the sign of tampering.
>
> To check the integrity and the anchoring of this version, use the proof
> summary, at the address `GET /v1/passport/01/{gtin}/proof`.

## Errors

The body of an error response carries a `detail` field.

| Code | Condition | What to do |
| --- | --- | --- |
| 400 | The last digit of the GTIN sent is not the check digit of the digits that precede it. That is the only cause of this code on this endpoint: a value with no digit at all, or with more than fourteen digits, answers 404 and not 400. `detail` equals `Invalid GTIN: the check digit does not match.` | Copy the code printed on the product, digit for digit, without adding or omitting any. |
| 401 | You request `access_tier=authority` without being authenticated. `detail` equals `Authority-tier access requires authentication`. | Present a valid session token in the `Authorization` header. |
| 401 | You request `access_tier=repairer`, `recycler` or `upstream` without being authenticated. `detail` equals `Professional-tier access requires authentication`. | Present a valid session token in the `Authorization` header. A partner API key does not work here. |
| 403 | You request `access_tier=authority` with an account that does not carry the authority role. `detail` equals `Authority-tier access is restricted to market surveillance authorities`. | Request a tier that matches your account. |
| 403 | You request a professional tier with an account that is not entitled to it on this brand. `detail` starts with `This tier is restricted to the product's brand`. | Ask the product's brand for an active accreditation of the matching trade, then retry. |
| 404 | `detail` equals `Unknown GS1 Digital Link`. Three situations give this same response: the GTIN sent contains no digit or contains more than fourteen, no model carries this GTIN, or no public reference passport is published for this model. | Check the GTIN. If the GTIN is right, ask the brand to publish the reference passport of this model. The response is deliberately identical in all three cases, so it will not tell you which one applies. |
| 422 | The value of `access_tier` is not one of the six accepted values. `detail` carries the list of validation errors, with the name of the parameter at fault. | Correct the value of the parameter. |
| 429 | The limit of 60 calls per 60 seconds on the `/passport` addresses is exceeded. `detail` equals `Rate limit exceeded: 60 requests per 60s`. The response carries `Retry-After` and the `X-RateLimit-*` family. | Wait the number of seconds given by `Retry-After`, then retry. |
| 500 | An unexpected error occurred while processing your call. `detail` equals `Internal Server Error`. | Retry. If the error persists, contact support, giving the time of the call and the value of the `X-Request-Id` header, which this response carries like all the others. |

### Order of the checks

The `authority` tier check happens before the passport lookup. A call with
`access_tier=authority` and no authentication therefore returns 401, even if the
GTIN is unknown.

The professional tier checks happen after the lookup. A call with
`access_tier=recycler` on an unknown GTIN therefore returns 404, and never 401.

## See also

- [`GET /passport/01/{gtin}/proof`](/en/reference/get-passport-gtin-proof/),
  gather the public proofs of the passport announced by a GTIN.
- [`GET /passport/{identifier}`](/en/reference/get-passport-identifier/),
  read the published passport of an item.
- [`GET /01/{gtin}`](/en/reference/get-gs1-gtin/),
  resolve a GS1 link that carries only a GTIN.
- [Core concepts](/en/notions/),
  tell model, batch and item apart before ordering a single label.
