Méthode GET/timeline/{identifier}

Lire l'historique public d'un produit : ses vérifications et ses changements de propriétaire, à partir du numéro imprimé, de l'identifiant de jeton ou de l'empreinte de puce. Point d'entrée public.

Sur cette page

Vous lisez l'historique d'un seul produit. En quittant cette page, vous saurez récupérer la liste de ses vérifications et de ses changements de propriétaire, triée du plus récent au plus ancien, ainsi que la fiche du produit auquel cet historique appartient.

Adresse complète :

HTTP
GET https://api.sealtrust.io/v1/timeline/{identifier}

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

#Autorisation

Aucune. Ce point d'entrée est public.

Vous n'avez pas besoin de clef d'API. Si vous en envoyez une dans l'en-tête Authorization, nous la décodons comme un jeton de session de la console. Une clef d'API n'est pas un jeton de session : la lecture échoue en silence, et nous traitons l'appel comme un appel anonyme. Vous recevez donc la même réponse avec ou sans clef d'API.

Un jeton de session de la console change en revanche la réponse. Nous le lisons dans l'en-tête Authorization comme dans le cookie de session posé par la console. Un seul compte reçoit les adresses e-mail des AUTRES en clair : l'administrateur de la marque qui a émis ce produit. Un administrateur d'une autre marque reçoit la projection anonymisée, exactement comme un visiteur. Un superadmin SealTrust reçoit le clair sur tous les produits, parce que c'est le compte d'exploitation.

Les mêmes comptes, et eux seuls, reçoivent les adresses de portefeuille dans from_address et to_address.

Sur un appel anonyme, vous recevez une projection anonymisée :

  • nous ne rendons pas les adresses de portefeuille, from_address et to_address valent null ;
  • nous masquons les adresses e-mail : la valeur rendue garde les deux premiers caractères de la partie locale, puis ..., puis six caractères stables, par exemple ma...3f9c1d.

#Plafond d'appels

600 appels par tranche de 60 secondes, comptés par adresse IP appelante. La fenêtre est fixe. Le plafond est large parce que des centaines de visiteurs d'un salon ou d'un réseau mobile partagent souvent une même adresse.

Les appels sur /v1/timeline/… et sur /timeline/… alimentent le même compteur. Passer d'une forme à l'autre ne relève donc pas le plafond.

Chaque réponse porte X-RateLimit-Limit, X-RateLimit-Remaining et X-RateLimit-Reset, qui décrivent ce plafond. Un dépassement renvoie 429, avec ces trois en-têtes et un Retry-After en secondes.

#Paramètres de chemin et de requête

NomTypeObligatoireDescription
identifierstringouiL'identifiant du produit. Trois formes sont acceptées, voir ci-dessous.
langstringnonLa langue du nom de catégorie : fr ou en. À défaut, le serveur lit l'en-tête Accept-Language, puis retombe sur en.

Un seul paramètre de requête, lang, et il est optionnel. Il ne change qu'une chose dans la réponse : la langue de category_name. Tout le reste est identique quelle que soit sa valeur.

Le serveur choisit la langue dans cet ordre : le paramètre lang s'il vaut fr ou en, sinon le premier tag reconnu de l'en-tête Accept-Language, sinon en. Une valeur que le serveur ne reconnaît pas est ignorée sans erreur : vous obtenez en, et non un 422.

#Les trois formes d'identifiant acceptées

Ce paramètre accepte trois formes. Vous envoyez celle que vous avez sous la main.

FormeÀ quoi elle ressembleOù vous la trouvez
Numéro de série12 caractères, chiffres et lettres majuscules, dans un alphabet qui exclut I, L, O et UImprimé sur le produit, c'est ce que porte son QR
Identifiant de jetonUne suite de chiffres, souvent très longueRendu par nos réponses dans le champ token_id
Empreinte de puce0x suivi de 64 caractères hexadécimauxRendue par nos réponses dans le champ uid_hash

Nous reconnaissons le numéro de série quelle que soit la casse. Nous lisons les caractères I et L comme un 1, et le caractère O comme un 0, pour accepter un numéro recopié à la main depuis une étiquette. Nous ne rattrapons pas le U : il ne fait partie ni de l'alphabet des numéros ni des caractères traduits, et un identifiant qui en contient ne désigne aucun produit.

#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

Lecture de l'historique du produit dont le numéro imprimé est EXEMP1E00001.

curl -i https://api.sealtrust.io/v1/timeline/EXEMP1E00001

#Réponse d'exemple

Code HTTP 200OK

Code HTTP 200.

Ce produit a été frappé, il n'a pas encore été réclamé par un client, et il a été scanné une fois par QR.

JSON
{
  "token_id": "7719472615821079694904732333912527190217998977709370935963838933860875309329",
  "serial": "H897RFWJ4972",
  "product_name": "Sac modèle 1",
  "brand_id": 42,
  "brand_code": "7K3QXW9M2A",
  "brand_name": "Exemple SAS",
  "brand_hide_powered_by": false,
  "brand_app_url": null,
  "category_id": 7,
  "category_name": "Maroquinerie",
  "metadata_uri": "ipfs://exemple-de-contenu-non-reel",
  "image_url": "https://exemple-sas.test/images/sac-modele-1.jpg",
  "current_owner_email": null,
  "current_owner_is_vault": true,
  "identity_included": true,
  "timeline": [
    {
      "type": "verify",
      "token_id": "7719472615821079694904732333912527190217998977709370935963838933860875309329",
      "uid_hash": "0x1111111111111111111111111111111111111111111111111111111111111111",
      "contract_address": "0x2222222222222222222222222222222222222222",
      "timestamp": "2026-08-18T14:02:11.482000Z",
      "signature": "signature-exemple",
      "is_valid": true,
      "source": "qr",
      "from_address": null,
      "to_address": null,
      "from_email": null,
      "to_email": null,
      "from_display": null,
      "to_display": null,
      "comment": "Scanned",
      "event_id": null
    },
    {
      "type": "transfer",
      "token_id": "7719472615821079694904732333912527190217998977709370935963838933860875309329",
      "uid_hash": "0x1111111111111111111111111111111111111111111111111111111111111111",
      "contract_address": "0x2222222222222222222222222222222222222222",
      "timestamp": "2026-08-12T09:30:00.000000Z",
      "signature": null,
      "is_valid": null,
      "source": null,
      "from_address": null,
      "to_address": null,
      "from_email": "Mint",
      "to_email": null,
      "from_display": "Mint",
      "to_display": "Vault",
      "from_role": "mint",
      "to_role": "vault",
      "comment": "Factory mint",
      "event_id": null
    }
  ],
  "contract_address": "0x2222222222222222222222222222222222222222"
}

La réponse compte quinze champs et rien d'autre. Vous recevez null pour les champs sans valeur, ils ne disparaissent pas de la réponse.

ChampTypeDescription
token_idstringL'identifiant du jeton sur la chaîne, rendu sous forme de texte. Vaut la chaîne vide quand le produit n'a pas encore d'identifiant de jeton.
serialstring ou nullLe numéro de série imprimé sur le produit, quel que soit l'identifiant utilisé dans l'adresse (numéro de série, identifiant de jeton ou empreinte de puce). C'est lui qu'attend la revendication par numéro de série. null pour un produit qui n'en a pas.
product_namestringLe nom du produit, ou null.
brand_idintegerDéprécié : le numéro interne de la marque, gardé pendant la transition, ou null si le produit n'est rattaché à aucune. Lisez brand_code.
brand_codestringLe code public de la marque, dix caractères, ou null si le produit n'est rattaché à aucune. C'est l'identifiant à citer et à conserver.
brand_namestringLe nom de la marque, ou null si le produit n'est rattaché à aucune.
brand_hide_powered_bybooleantrue quand la mention « Powered by SealTrust » doit disparaître. Deux conditions, et il faut les deux : l'offre de la marque comprend la marque blanche et la marque a choisi de masquer la mention dans sa console. Par défaut la mention reste affichée, y compris pour une marque qui vient de souscrire à l'offre Inside sans rien avoir décoché.
brand_app_urlstring ou nullL'adresse de l'application mobile de la marque, quand elle en a une. null sinon. Les pages publiques proposent la sienne quand elle est renseignée, la nôtre sinon.
category_idinteger ou nullL'identifiant de la catégorie du produit. null quand aucune catégorie n'est rattachée. Ce champ a longtemps rendu null sur tous les produits, y compris ceux qui avaient bien une catégorie : il était déclaré dans la forme de la réponse et jamais rempli. Corrigé le 31 août 2026.
category_namestring ou nullLe nom de la catégorie du produit, dans la langue de l'appelant : voir le paramètre lang plus haut. null quand aucune catégorie n'est rattachée.
metadata_uristringL'adresse des métadonnées du produit, ou null.
image_urlstringL'adresse de l'image du produit, ou null. C'est la copie allégée de la photo (WebP, 800 pixels au plus sur le grand côté, 100 Ko au plus, sans données EXIF) quand elle existe, sinon l'original. Une adresse d'un autre site est rendue telle quelle.
current_owner_emailstringL'adresse e-mail du propriétaire actuel, masquée. null quand aucun propriétaire n'est connu.
current_owner_is_vaultbooleantrue quand le produit est encore détenu par le coffre de la marque, donc pas encore réclamé par un client.
identity_includedbooleantrue quand la pièce a son identité : revendication, transfert, revente. Une pièce créée sur l'offre Conformité + Identité la garde, même si sa marque passe ensuite sur l'offre Conformité. false pour une pièce sans identité : elle ne se revendique ni ne se transfère, et la page publique n'en propose rien. null quand la réponse ne le dit pas, ce qui ne vaut jamais un refus.
timelineobject[]Les événements, du plus récent au plus ancien. Voir le tableau ci-dessous.
contract_addressstringL'adresse du contrat qui porte ce produit sur la chaîne, ou null.

Le tableau timeline n'est pas paginé et n'a pas de taille maximale. Il contient toutes les vérifications et tous les mouvements enregistrés pour ce produit. Un produit très scanné rend donc une réponse volumineuse. Dimensionnez votre lecture en conséquence.

#Un événement de la chronologie

Chaque entrée compte vingt-deux champs. Les champs qui n'ont pas de sens pour le type d'événement valent null.

ChampTypeDescription
typestringverify pour une vérification, transfer pour un mouvement de propriété, event pour une étape de la vie du produit.
token_idstringL'identifiant du jeton concerné.
uid_hashstringL'empreinte de puce concernée, 0x suivi de 64 caractères hexadécimaux.
contract_addressstringL'adresse du contrat concerné.
timestampstringDate et heure de l'événement, en temps universel, au format ISO 8601.
signaturestringLa signature enregistrée avec la vérification. null sur un mouvement de propriété.
is_validbooleanLe résultat de la vérification. null sur un mouvement de propriété.
sourcestringD'où vient la vérification. Les valeurs écrites aujourd'hui sont qr, sdm-url et sdm-json. null sur un mouvement de propriété.
from_addressstringToujours null sur un appel public.
to_addressstringToujours null sur un appel public.
from_emailstringL'adresse e-mail de la partie qui cède, masquée. Vaut Mint quand l'événement est la frappe du produit.
to_emailstringL'adresse e-mail de la partie qui reçoit, masquée.
from_displaystringUn libellé prêt à afficher pour la partie qui cède. Mint pour la frappe, Vault pour le coffre de la marque, sinon l'adresse e-mail masquée ou une adresse de portefeuille tronquée.
to_displaystringLe même libellé, pour la partie qui reçoit.
from_rolestring ou nullmint quand la partie qui cède est la frappe, vault quand c'est le coffre de la marque, null sinon. Une page traduit ce rôle plutôt que from_display, écrit en anglais.
to_rolestring ou nullLe même rôle, pour la partie qui reçoit.
commentstringUne phrase courte en anglais qui résume l'événement : Scanned, Scanned by <e-mail masqué>, Transfer, Transferred from <e-mail masqué> to <e-mail masqué> ou Factory mint.
event_idintegerL'identifiant de l'étape de vie, sur une entrée de type event. null ailleurs.
event_typestringLa nature de l'étape : quality_control, certification, warranty_activation, after_sale_service, et d'autres selon ce que la marque enregistre. Traduisez à partir de cette clé. null hors d'une entrée event.
labelstringLe titre de l'étape, tel que la marque l'a écrit. Un repli lisible, pas une valeur à interpréter. null hors d'une entrée event.
proof_levelstringSur quoi repose cette étape. null quand la marque ne l'a pas renseigné.
metaobjectLes détails propres à l'étape. Les adresses de portefeuille en sont retirées, et l'adresse de la personne qui a agi y est masquée. null quand il n'y a rien à dire.
occurrencesintegerLe nombre de vérifications que cette entrée représente. Vaut 1 partout ailleurs.
first_timestampstringLa date de la plus ancienne vérification du groupe, quand occurrences dépasse 1. null sinon.

#Erreurs

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

CodeConditionQue faire
400L'identifiant envoyé n'a la forme d'aucune des trois formes acceptées : il contient autre chose que des chiffres et des lettres, ou il dépasse 64 caractères. detail vaut Invalid UID hash format (must be 0x + 64 hex characters).Envoyez un numéro de série, un identifiant de jeton ou une empreinte de puce. Vérifiez qu'aucun espace ni caractère de ponctuation ne traîne.
400L'identifiant commence par 0x et fait 66 caractères, mais il contient un caractère qui n'est pas hexadécimal. Même valeur de detail.Une empreinte de puce n'accepte que les chiffres 0 à 9 et les lettres a à f.
404L'identifiant est bien formé, mais aucun produit ne lui correspond, ou aucun événement n'a été enregistré pour lui. detail vaut No events found for this UID.Vérifiez le numéro recopié. Un produit retiré du catalogue répond avec l'autre message 404, décrit à la ligne suivante. Un produit détruit interrogé par son numéro imprimé ou par son identifiant de jeton répond ici.
404Des événements existent pour cet identifiant, mais aucun produit encore en catalogue ne s'y rattache. detail vaut Product not found for this UID.Le produit a été retiré du catalogue. Son historique n'est plus servi.
404L'appel arrive sur le nom de domaine vérifié d'une marque, et le produit appartient à une autre marque. detail vaut No events found for this UID.Appelez cette adresse sur le domaine de la marque concernée, ou sur api.sealtrust.io. Le message est le même que pour un identifiant inconnu, pour ne pas confirmer qu'il existe.
429Vous avez fait plus de 600 appels depuis votre adresse IP dans la fenêtre de 60 secondes en cours. detail vaut Rate limit exceeded: 600 requests per 60s.Attendez le nombre de secondes indiqué par Retry-After, puis réessayez.
500Une 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

Votre réponse ouvre un courriel pré-rempli dans votre messagerie, à destination de contact@sealtrust.io. Vous le relisez avant de l'envoyer.

Proposer une correctionSignaler un problème