# GET /certificate/{identifier}

Lire le certificat d'authenticité d'un produit à partir de son numéro de certificat, de son empreinte d'UID, de son identifiant de jeton ou du numéro de série imprimé. Point d'entrée public.

Source : https://docs.sealtrust.io/reference/get-certificate/

---

Vous lisez le certificat d'authenticité d'un produit. En quittant cette page,
vous saurez quel identifiant envoyer, comment lire l'état du certificat, et
quelles réponses attendre quand le produit ou le certificat n'existe pas.

Adresse complète :

```http
GET https://api.sealtrust.io/v1/certificate/{identifier}
```

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

## Autorisation

Aucune, point d'entrée public. N'envoyez ni clef d'API ni jeton de session.

La réponse ne porte aucun identifiant interne de marque ni de produit. Elle
donne le numéro de certificat, l'état, les dates, le nom du produit, le nom de
la marque et son habillage. Elle ne donne ni numéro de marque, ni numéro de
produit, ni adresse de contrat, ni adresse du propriétaire.

> [!INFO] Appelez ce point d'entrée depuis votre serveur
> Le navigateur n'autorise les appels croisés que depuis les sites SealTrust.
> Une page web hébergée sur votre propre domaine verra sa requête bloquée par le
> navigateur. Passez par votre serveur, ou par une application mobile, où cette
> règle ne s'applique pas.

## Plafond d'appels

60 appels par tranche de 60 secondes, comptés par adresse IP.

Ce compteur est commun à toutes les adresses qui commencent par `/certificate`,
avec ou sans le préfixe `/v1`. La lecture du certificat et le téléchargement de
son PDF sont comptés dans 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 les mêmes trois en-têtes, `X-RateLimit-Remaining` à
`0`, et `Retry-After` valant `60`.

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

| Nom | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `identifier` | `string` | oui | Le produit ou le certificat à lire. Quatre formes sont acceptées, décrites ci-dessous. |

Ce point d'entrée n'a aucun paramètre de requête.

### Les quatre formes d'identifiant

| Forme | À quoi elle ressemble |
| --- | --- |
| Numéro de certificat | Une chaîne qui commence par `ST-CERT-`, suivie de 12 caractères. C'est le champ `certificate_number` que rend cette même réponse. |
| Empreinte d'UID | `0x` suivi de 64 caractères hexadécimaux, soit 66 caractères en tout. La casse n'a pas d'importance. |
| Identifiant de jeton | Le nombre entier du jeton, écrit en chiffres. Il compte 77 ou 78 chiffres. |
| Numéro de série imprimé | Les 12 caractères portés par l'étiquette du produit, ceux que l'on retrouve dans l'adresse `/p/{serial}`. |

Le serveur cherche d'abord un numéro de certificat. S'il ne trouve pas, il
regarde la forme de la chaîne : `0x` suivi de 64 caractères hexadécimaux est
traité comme une empreinte d'UID, toute autre forme comme un identifiant de
jeton. En dernier recours il cherche un numéro de série imprimé.

Le serveur retire les espaces de début et de fin avant la recherche, quelle que
soit la forme.

Le serveur ignore la casse du numéro de série et ramène les caractères que l'on
confond à la lecture à leur forme canonique avant la recherche : `I` et `L`
valent `1`, `O` vaut `0`. Vous retrouvez donc un numéro recopié à la main depuis
une étiquette même si la personne a saisi la lettre `O` quand l'étiquette porte
le chiffre `0`.

> [!ATTENTION] Un produit détruit ou retiré du catalogue ne se résout plus
> L'empreinte d'UID, l'identifiant de jeton et le numéro de série ne trouvent
> que les produits encore en catalogue. Un produit détruit, remplacé par une
> version ultérieure ou archivé répond 404. Le numéro de certificat, lui, reste
> résolu dans tous les cas.

### En-têtes

| Nom | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `Accept` | `string` | non | S'il contient `text/html`, la réponse est une redirection 307 vers la page publique du certificat, lisible par un humain. Toute autre valeur, dont `*/*` et `application/json`, donne le JSON décrit plus bas. |

`curl`, `requests` et `fetch` envoient `*/*` par défaut et reçoivent donc le
JSON. La redirection existe pour qu'un lien de certificat partagé et ouvert dans
un navigateur affiche la page publique du certificat.

## Corps de la requête

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

## Requête d'exemple

Lecture du certificat portant le numéro `ST-CERT-000000000000`.

:::onglets
```bash title="curl"
curl -i -H "Accept: application/json" https://api.sealtrust.io/v1/certificate/ST-CERT-000000000000
```
```typescript
const response = await fetch(
  "https://api.sealtrust.io/v1/certificate/ST-CERT-000000000000",
  {
    method: "GET",
    headers: {
      Accept: "application/json",
    },
  },
);

console.log(response.status);
console.log(response.headers.get("X-RateLimit-Remaining"));
console.log(await response.json());
```
```python
import requests

response = requests.get(
    "https://api.sealtrust.io/v1/certificate/ST-CERT-000000000000",
    headers={
        "Accept": "application/json",
    },
    timeout=30,
)

print(response.status_code)
print(response.headers["X-RateLimit-Remaining"])
print(response.json())
```
:::

Le SDK TypeScript `@sealtrust-io/sdk` ne couvre pas ce point d'entrée. L'exemple
ci-dessus utilise `fetch`, disponible sans dépendance.

Les trois autres formes d'identifiant s'écrivent de la même façon.

```bash
# Empreinte d'UID
curl -i -H "Accept: application/json" https://api.sealtrust.io/v1/certificate/0x0000000000000000000000000000000000000000000000000000000000000000

# Identifiant de jeton
curl -i -H "Accept: application/json" https://api.sealtrust.io/v1/certificate/10000000000000000000000000000000000000000000000000000000000000000000000000000

# Numéro de série imprimé
curl -i -H "Accept: application/json" https://api.sealtrust.io/v1/certificate/00000000ABCD
```

## Réponse d'exemple

Code HTTP `200`.

```json
{
  "certificate_number": "ST-CERT-000000000000",
  "status": "active",
  "issued_at": "2026-03-04T10:22:07.415000Z",
  "expires_at": null,
  "issuer_name": "Exemple SAS",
  "product_name": "Sac cabas modèle 1",
  "brand_name": "Exemple SAS",
  "brand_logo_url": "https://exemple-sas.test/logo.svg",
  "brand_primary_color": "#1F2937",
  "brand_hide_powered_by": false,
  "custom_fields": {
    "atelier": "Atelier 3",
    "matiere": "cuir pleine fleur"
  }
}
```

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

| Champ | Type | Description |
| --- | --- | --- |
| `certificate_number` | `string` | Le numéro du certificat. C'est la valeur à réutiliser comme `identifier` pour retrouver ce certificat directement. |
| `status` | `string` | L'état du certificat. Voir ci-dessous. |
| `issued_at` | `string` | Date et heure d'émission, en temps universel, au format ISO 8601. |
| `expires_at` | `string` ou `null` | Date de fin de validité. Aucun certificat émis par la plateforme n'en porte aujourd'hui, la valeur est toujours `null`. Ne construisez pas votre intégration sur une date de fin. |
| `issuer_name` | `string` ou `null` | Le nom de la marque qui a émis le certificat. Le serveur calcule ce champ à la lecture et y place toujours le nom de la marque. `null` quand le certificat n'est rattaché à aucune marque. |
| `product_name` | `string` ou `null` | Le nom du produit couvert par le certificat. |
| `brand_name` | `string` ou `null` | Le nom de la marque émettrice. |
| `brand_logo_url` | `string` ou `null` | L'adresse du logo de la marque, pour afficher le certificat aux couleurs de la marque. |
| `brand_primary_color` | `string` ou `null` | La couleur principale de la marque. |
| `brand_hide_powered_by` | `boolean` | `true` quand l'offre de la marque comprend la marque blanche. La page du certificat masque alors la mention SealTrust. La valeur par défaut est `false`, donc un champ absent veut dire que la mention reste affichée. |
| `custom_fields` | `object` ou `null` | Les champs libres que la marque a renseignés au moment d'émettre le certificat. `null` quand elle n'en a renseigné aucun. Le contenu est propre à chaque marque, aucune clef n'est imposée. |

### Comment lire `status`

Le serveur calcule l'état à la lecture. La valeur stockée en base n'est pas
recopiée telle quelle.

`status` vaut `active` ou `revoked`.

- Un certificat révoqué est rendu `revoked` pour toujours. La révocation est un
  acte délibéré et elle prime sur toute autre règle. Aucun point d'entrée ne
  rend un certificat révoqué à l'état `active`.
- Tout autre certificat est rendu `active`.

Le vocabulaire de l'API contient une troisième valeur, `expired`. Le serveur la
calcule à la lecture à partir de `expires_at`. Comme aucun certificat ne porte
de date de fin aujourd'hui, l'API ne la renvoie pas. Acceptez-la dans votre code
pour rester robuste si elle apparaît un jour, et ne construisez aucune règle
métier sur sa présence.

> [!INFO] Un certificat révoqué répond 200
> Quand un produit porte plusieurs certificats, le serveur rend le plus récent
> qui est encore valide. S'il n'en existe aucun de valide, il rend quand même le
> plus récent des autres, avec son état réel. Vous recevez donc `revoked` en
> clair. Le serveur ne répond pas 404 dans ce cas. Un 404 laisserait croire que
> le certificat n'a jamais existé.

### Redirection vers la page lisible

Si votre requête annonce `text/html` dans l'en-tête `Accept`, la réponse est un
`307` dont l'en-tête `Location` pointe vers la page publique du certificat. Le
serveur ne renvoie aucun corps JSON dans ce cas.

## Erreurs

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

| Code | Condition | Que faire |
| --- | --- | --- |
| 404 | Le chemin demandé ne correspond à aucune route, par exemple parce que l'identifiant contient une barre oblique non encodée. `detail` vaut `Not Found`. | Encodez l'identifiant avant de le placer dans l'adresse. |
| 404 | Aucun produit ne correspond à cet identifiant, ou le produit correspondant a été détruit, remplacé ou archivé. `detail` vaut `Product not found`. | Vérifiez la forme de l'identifiant. Un numéro de série se saisit tel qu'il figure sur l'étiquette, sur 12 caractères. |
| 404 | Le produit existe, mais aucun certificat n'a jamais été émis pour lui. `detail` vaut `No certificate found for this product`. | Le produit peut être authentique sans porter de certificat. Utilisez le passeport du produit pour l'afficher. |
| 429 | Le plafond de 60 appels par 60 secondes est atteint pour votre adresse IP. `detail` vaut `Rate limit exceeded: 60 requests per 60s`. Les en-têtes `Retry-After` et la famille `X-RateLimit-*` accompagnent la réponse. | Attendez le nombre de secondes indiqué par `Retry-After`, puis réessayez. Ce compteur est partagé avec le téléchargement du PDF. |
| 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. |

## Voir aussi

- [`GET /certificate/{identifier}/download`](/reference/get-certificate-download/),
  télécharger le certificat d'authenticité au format PDF.
- [`GET /p/{serial}`](/reference/get-p-serial/),
  traduire le numéro de série imprimé en adresse de page consommateur.
- [`GET /resolve/{identifier}`](/reference/get-resolve/),
  lire en un appel tout ce qu'une page produit affiche.
- [Notions de base](/notions/),
  distinguer modèle, lot et article avant de commander la moindre étiquette.
