Remplir le catalogue par l'API
Créer ou compléter des modèles, des lots et des passeports brouillons depuis votre plateforme, lire le score de complétude, et agir pour plusieurs marques avec une clef revendeur. Droits catalog:read et catalog:write.
Sur cette page
- Ce qu'il vous faut
- Les dix points d'entrée
- Nommer la marque
- Quatre règles valent pour chaque écriture
- Créer ou compléter un modèle
- Créer ou compléter un lot
- Créer ou compléter le passeport brouillon
- Le passeport d'un lot
- L'offre d'une marque
- Le code à imprimer
- Lire le score de complétude
- Une clef pour plusieurs marques : la clef revendeur
- Frapper, vendre et recevoir des webhooks pour une marque cliente
- Plafonds
- Erreurs
- Voir aussi
Votre plateforme connaît déjà vos produits. Cette page explique comment les envoyer dans SealTrust sans que personne ne les ressaisisse : les modèles, les lots de production et le brouillon du passeport de chaque modèle. Vous envoyez ce que vous avez. La marque complète le reste dans la console, puis publie.
#Ce qu'il vous faut
- Une clef d'API qui porte le droit
catalog:writepour écrire, etcatalog:readpour relire. Vous la créez dans la console, Paramètres puis Développeurs. - Une offre qui comprend l'accès API. Pour les passeports, l'offre de la marque visée doit aussi comprendre le passeport numérique.
#Les dix points d'entrée
Chaque adresse nomme la marque visée dans son chemin. Toutes existent aussi avec
le préfixe /v1, qui est la forme recommandée.
| Méthode et chemin | Ce qu'il fait | Droit |
|---|---|---|
GET /partner/catalog/brands | les marques pour lesquelles votre clef peut agir | catalog:read ou catalog:write |
PUT /partner/catalog/brands/{brand_code}/models | crée ou complète un modèle, repéré par son SKU | catalog:write |
GET /partner/catalog/brands/{brand_code}/models | un modèle avec ?sku=, sinon la liste des modèles | catalog:read |
GET /partner/catalog/brands/{brand_code}/readiness?sku= | le score de complétude d'un modèle | catalog:read |
PUT /partner/catalog/brands/{brand_code}/batches | crée ou complète un lot, repéré par son code | catalog:write |
PUT /partner/catalog/brands/{brand_code}/passports | crée ou complète le passeport brouillon d'un modèle, ou d'un de ses lots avec batch_code | catalog:write |
GET /partner/catalog/brands/{brand_code}/passports?sku= | la dernière version du passeport de ce modèle, ou de l'un de ses lots avec &batch_code= | catalog:read |
GET /partner/catalog/brands/{brand_code}/offer | l'offre de la marque : Conformité, ou Conformité + Identité | catalog:read ou catalog:write |
PUT /partner/catalog/brands/{brand_code}/offer | change l'offre d'une de vos marques clientes | catalog:write |
GET /partner/catalog/brands/{brand_code}/codes?sku= | le lien et le QR code à imprimer, pour un modèle ou un lot | catalog:read |
Le SKU passe dans le corps ou dans la requête, jamais dans le chemin : un SKU peut contenir une barre oblique.
#Nommer la marque
Chaque marque a un code public de dix caractères : brand_code, par exemple
7K3QXW9M2A. Ce code est fait de chiffres et de lettres, sans I, L, O ni U.
Les majuscules et les minuscules se valent. GET /partner/catalog/brands donne
le code de chaque marque pour laquelle votre clef peut agir. Mettez ce code
dans le chemin.
Les réponses portent aussi brand_id, le numéro interne de la marque. Ce champ
est déprécié : lisez brand_code. Un numéro envoyé à la place du code est
encore accepté pour l'instant, mais ne construisez rien dessus.
#Quatre règles valent pour chaque écriture
Rejouer ne change rien. Le SKU d'un modèle et le code d'un lot servent de
clef. Envoyer deux fois la même chose laisse le même état. La deuxième réponse
porte changed: false. Après une coupure réseau, rejouez sans crainte : aucun
en-tête Idempotency-Key n'est nécessaire, et aucun doublon n'est possible.
Cela vaut aussi quand votre nouvel essai arrive alors que le premier appel
tourne encore : un seul brouillon est ouvert.
Un champ absent n'efface rien, une liste envoyée remplace la liste. Un champ
absent, ou envoyé à null, garde sa valeur, et un objet se complète clé par
clé : ce que la marque a saisi dans les autres clés reste en place. Une liste,
elle, est remplacée en entier. Si la marque a ajouté un fournisseur dans la
console et que votre envoi suivant contient suppliers, c'est votre liste qui
reste, et l'ajout de la marque disparaît. Avant de renvoyer une liste, relisez
le brouillon par GET /partner/catalog/brands/{brand_code}/passports?sku= et
renvoyez la liste complète, ou n'envoyez pas la liste. Pour vider un champ,
passez par la console.
Rien n'est publié, rien de scellé n'est réécrit. Un passeport envoyé par l'API reste un brouillon privé. La publication reste un geste de la marque, dans la console. Si la marque a déjà scellé une version, votre envoi suivant ouvre une nouvelle version brouillon par-dessus : la version scellée ne bouge jamais.
Chaque écriture laisse une trace. SealTrust inscrit chaque écriture dans son journal d'audit, comme pour une modification faite dans la console. Le journal note la clef qui a écrit, la marque pour laquelle elle a agi, et chaque champ modifié avec sa valeur avant et après. L'écriture d'un modèle apparaît aussi dans l'historique de ce modèle dans la console, avec l'origine « API » et le préfixe de la clef pour auteur. Une écriture qui ne change rien n'y laisse rien. Chaque appel, lecture comprise, est aussi inscrit au journal d'utilisation de la clef, avec la marque visée dans son chemin.
#Créer ou compléter un modèle
Le corps accepte les champs d'un modèle de la console. sku est obligatoire.
name n'est obligatoire qu'à la création. Un GTIN dont la clef de contrôle est
fausse est refusé en 422, et tout champ inconnu aussi.
primary_image_url est l'image que nous recopions sur IPFS à la création des pièces. Elle doit être une adresse http ou https vers un serveur public. Une adresse de réseau privé, locale ou sans nom de domaine complet est refusée en 422. Si le nom pointe vers une adresse privée au moment de la création des pièces, l'image n'est pas recopiée et la pièce est créée quand même.
primary_image_url peut aussi être une clé de la médiathèque de la marque
visée, de la forme brands/{id}/…. Une clé d'une autre marque est refusée en
422. Toute valeur qui n'est ni une adresse ni une clé, par exemple
javascript:alert(1) ou un texte libre, est refusée en 422 aussi.
weight_grams, volume_cm3 et default_warranty_months valent 0 ou plus.
Une valeur négative est refusée en 422.
Les six liens d'instructions (repair_instructions_url,
maintenance_instructions_url, safety_instructions_url, user_manual_url,
spare_parts_url, disassembly_instructions_url) sont des adresses web
complètes, qui commencent par https:// ou http://. Un chemin relatif, un
texte libre, une adresse javascript: ou data: sont refusés en 422.
identity_level vaut unit : chaque pièce reçoit son propre jeton et son
propre QR code, pour l'authentification, le propriétaire, la revente et la
déclaration de vol, et sa page affiche le passeport de son lot, sinon celui du
modèle. Pour qu'une pièce frappée par POST /v1/partner/mint/batch soit
rattachée ainsi, nommez sur sa ligne model_sku, et batch_code si elle
appartient à un lot. Un modèle créé sans ce champ est au niveau unit, comme par tout autre
chemin. Envoyer model répond 422. Un envoi sans ce champ ne change jamais le
niveau d'un modèle existant.
curl -X PUT https://api.sealtrust.io/v1/partner/catalog/brands/7K3QXW9M2A/models \
-H "Authorization: Bearer st_live_0000000000000000000000000000000000000000000000" \
-H "Content-Type: application/json" \
-d '{"sku": "BAG-01", "name": "Canvas tote", "gtin": "4006381333931"}'La réponse vaut 201 à la création, 200 sinon.
{
"created": true,
"changed": true,
"model": {
"id": 301,
"brand_code": "7K3QXW9M2A",
"sku": "BAG-01",
"name": "Canvas tote",
"gtin": "4006381333931"
}
}Le modèle rendu porte tous ses champs. Cet exemple n'en montre que cinq.
Le gabarit du passeport, et donc le score de complétude, se déduit de la
catégorie du modèle (category_id). Pour une batterie, choisissez la catégorie
« Battery » : le modèle est alors noté contre le règlement (UE) 2023/1542 sur les
batteries, et non contre l'électronique grand public. Vous pouvez aussi nommer le
gabarit vous-même avec playbook_key, par exemple "playbook_key": "battery".
Ce champ prime sur la catégorie. Une valeur inconnue est refusée en 422.
#Créer ou compléter un lot
batch_code et model_sku sont obligatoires. Le SKU désigne un modèle de la
même marque. Les autres champs sont production_date (date au format
AAAA-MM-JJ), manufacturing_site, country_of_origin (deux lettres),
quantity_planned et notes.
curl -X PUT https://api.sealtrust.io/v1/partner/catalog/brands/7K3QXW9M2A/batches \
-H "Authorization: Bearer st_live_0000000000000000000000000000000000000000000000" \
-H "Content-Type: application/json" \
-d '{"batch_code": "L-2026-09", "model_sku": "BAG-01", "country_of_origin": "FR"}'Deux refus protègent ce qui est déjà établi. Un lot ne change pas de modèle par l'API. Un lot ancré sur la chaîne ne change plus du tout : ses faits sont publiés.
Le lot rendu porte lot_passport_blocker. Il vaut null quand le code de lot
peut porter un passeport de lot. Sinon, il dit pourquoi : le lien
/01/{gtin}/10/{lot} exige un code GS1 de 20 caractères au plus, pris dans un
jeu restreint (lettres, chiffres et quelques signes, sans espace ni barre oblique). Le lot est
créé quand même, car son code est aussi votre référence de production. Il
n'aura simplement jamais de passeport de lot : choisissez un code plus court si
vous en voulez un.
#Créer ou compléter le passeport brouillon
sku nomme le modèle. data suit la structure du passeport de la console.
Nous fusionnons data dans la dernière version : les objets se complètent clef
par clef, le reste remplace, et null garde la valeur en place.
curl -X PUT https://api.sealtrust.io/v1/partner/catalog/brands/7K3QXW9M2A/passports \
-H "Authorization: Bearer st_live_0000000000000000000000000000000000000000000000" \
-H "Content-Type: application/json" \
-d '{"sku": "BAG-01", "data": {"product_identity": {"name": "Canvas tote"}}}'La réponse porte le passeport, avec status à draft, et
visibility à brand_only. Il n'existe aucun champ pour publier : l'envoyer
est refusé en 422.
#Le passeport d'un lot
Ajoutez batch_code pour écrire le passeport d'un lot de ce modèle plutôt que
celui du modèle. C'est lui qui répond au lien /01/{gtin}/10/{lot}. Une
première version part du passeport publié du modèle, complété des informations
du lot. Le GTIN et le numéro du lot y sont toujours écrits : des données qui
nomment un autre lot sont refusées en 422, jamais écrasées. Le lot doit
appartenir au modèle nommé par sku, sinon la réponse est 404. Pour relire ce
passeport, ajoutez &batch_code= à la lecture.
curl -X PUT https://api.sealtrust.io/v1/partner/catalog/brands/7K3QXW9M2A/passports \
-H "Authorization: Bearer st_live_0000000000000000000000000000000000000000000000" \
-H "Content-Type: application/json" \
-d '{"sku": "BAG-01", "batch_code": "LOT-26A", "data": {"materials": {"cotton": 100}}}'La réponse porte batch_code et product_batch_id. product_model_id y vaut
null : un passeport de lot est rattaché à son lot.
#L'offre d'une marque
Chaque marque est sur l'offre Conformité (compliance) ou Conformité +
Identité (compliance_identity). La liste des marques porte l'offre de chacune.
GET .../offer la relit.
Avec une clef revendeur, PUT .../offer change l'offre d'une de vos marques
clientes, avec les mêmes règles que la console :
curl -X PUT https://api.sealtrust.io/v1/partner/catalog/brands/7K3QXW9M2A/offer \
-H "Authorization: Bearer st_live_0000000000000000000000000000000000000000000000" \
-H "Content-Type: application/json" \
-d '{"offer": "compliance"}'- Une marque ne change jamais sa propre offre, un revendeur non plus : la réponse est le même 403 que pour une marque hors de portée de la clef.
- Quitter l'offre Conformité + Identité alors que la marque a des pièces, ou
des lots en cours de création, répond 409
OFFER_CHANGE_NEEDS_CONFIRMATION, avecpiecesetbatches_in_flight. Les pièces sont gardées, mais leurs opérations d'identité s'arrêtent, et un lot en cours ne crée aucune pièce. Renvoyez avec"confirm_pieces_kept": true. - Une offre inconnue répond 422
UNKNOWN_OFFER. - La réponse dit
changed(faux si la marque avait déjà cette offre) etpieces_kept. Le changement est inscrit au journal, au nom de la clef.
Le détail des deux offres est sur la page des offres.
#Le code à imprimer
Une marque sur l'offre Conformité imprime le même code sur chaque produit d'un
modèle, ou d'un lot. GET .../codes?sku= le donne pour un modèle,
&batch_code= pour un lot :
curl "https://api.sealtrust.io/v1/partner/catalog/brands/7K3QXW9M2A/codes?sku=BAG-01&batch_code=LOT-26A" \
-H "Authorization: Bearer st_live_0000000000000000000000000000000000000000000000"link: le lien GS1 que porte le code, sur le domaine de la marque une fois celui-ci verrouillé.printable: vrai quand le code peut être imprimé.qr_pngetqr_png_downloaddonnent alors l'adresse de l'image, à ouvrir sans clef.- Sinon
reasondit pourquoi :ITEM_QR_ONLY(la marque est sur l'offre Conformité + Identité, chaque pièce porte son propre code),PASSPORT_NOT_PUBLISHED(la marque publie d'abord ce passeport dans la console),MODEL_HAS_NO_GTINouLOT_CODE_NOT_ENCODABLE(aucun lien GS1 possible).
#Lire le score de complétude
C'est le score que la console affiche, de 0 à 100, avec le détail de ce qui manque.
curl "https://api.sealtrust.io/v1/partner/catalog/brands/7K3QXW9M2A/readiness?sku=BAG-01" \
-H "Authorization: Bearer st_live_0000000000000000000000000000000000000000000000"#Une clef pour plusieurs marques : la clef revendeur
Une clef ordinaire agit pour sa marque, et pour elle seule.
Une clef revendeur agit pour la marque du revendeur et pour chacune des
marques clientes rattachées à son contrat revendeur. Vous nommez la marque
visée à chaque appel, dans le chemin. GET /partner/catalog/brands rend la
liste des marques permises, la vôtre en premier.
Elle fait pour une marque cliente tout ce que votre contrat vous permet : le catalogue, l'offre, les codes à imprimer, l'affichage du passeport, la frappe des pièces, la déclaration de vente et les webhooks.
Ce que la clef revendeur ne fait pas :
- Elle n'atteint aucune marque qui n'est pas rattachée à votre contrat. Une marque d'un autre revendeur, une marque sans lien, ou un code qui ne nomme aucune marque reçoivent tous le même 403.
- Elle suit votre contrat, relu à chaque appel. Sans contrat, elle n'atteint plus que votre propre marque.
La case « Clé revendeur » se coche à la création de la clef, dans la console. Elle est refusée pour une marque qui n'a pas de contrat revendeur.
#Frapper, vendre et recevoir des webhooks pour une marque cliente
Avec votre clé revendeur, vous frappez les pièces d'une marque cliente sans
clé de plus : mettez le code de la marque cliente dans le brand_code de
chaque ligne de POST /v1/partner/mint/batch. Toutes les lignes d'un lot
portent la même marque. Un lot qui en mélange plusieurs est refusé en 422
ONE_BRAND_PER_BATCH : envoyez un lot par marque. Le suivi du lot et la
liste de ses pièces, avec le lien à imprimer, se lisent avec la même clé.
Pour déclarer une vente, ajoutez brand_code au corps de
POST /v1/partner/sellout. Pour un webhook, ajoutez brand_code au corps de
POST /v1/partner/webhooks, et à la liste :
GET /v1/partner/webhooks?brand_code=7K3QXW9M2A. Sans brand_code, la clé
agit pour votre propre marque. N'envoyez pas brand_code et brand_id
ensemble : la requête est refusée en 422.
Ce sont les règles de la marque cliente qui s'appliquent : son offre (en offre Conformité, la marque n'a pas de pièces et la frappe est refusée), ses pièces de l'année et son droit aux webhooks. L'accès à l'API vient de votre offre de revendeur. Chaque écriture est tracée avec la marque visée et votre clé.
Un webhook que vous créez pour une marque cliente, par l'API ou dans la console, n'est envoyé que tant que votre contrat de revendeur existe et que la marque est toujours votre cliente. Quand l'un des deux s'arrête, votre adresse ne reçoit plus rien de cette marque, relances comprises. Changer de clé ne change rien : vos webhooks continuent d'arriver.
Une clé créée sur la marque cliente elle-même, dans la console, fonctionne toujours, pour cette marque seule.
#Plafonds
Le plafond de débit est celui de toute l'API partenaire, décrit dans la vue d'ensemble. Le quota quotidien de la clef compte une unité par écriture qui crée ou modifie quelque chose. Une écriture rejouée qui ne change rien ne coûte rien.
#Erreurs
| Code | Condition | Que faire |
|---|---|---|
| 401 | Clef absente, mal formée ou inconnue. | Envoyez Authorization: Bearer <votre clef>. |
| 403 | Le droit manque. Le message le nomme, par exemple Missing required scope: catalog:write. | Créez une clef qui porte ce droit. |
| 403 | Votre clef ne peut pas agir pour cette marque. Message This API key cannot act for this brand. | Vérifiez le code de la marque avec GET /partner/catalog/brands. |
| 403 | L'offre ne comprend pas l'accès API, ou pas le passeport numérique. detail porte FEATURE_NOT_AVAILABLE. | Contactez-nous pour changer d'offre. |
| 403 | La création d'un modèle ou d'un lot est suspendue pour une facture mensuelle impayée. detail porte BILLING_SUSPENDED. Les passeports déjà publiés restent en ligne, et la mise à jour d'un modèle ou d'un lot existant reste possible. | Réglez la facture. La suspension est levée dès le paiement. |
| 404 | Aucun modèle de cette marque ne porte ce SKU, ou le modèle n'a pas encore de passeport. | Créez d'abord le modèle. |
| 404 | category_id inconnu. | Utilisez un identifiant de catégorie existant. |
| 409 | Le lot appartient à un autre modèle, ou il est ancré sur la chaîne. | Faites ce changement dans la console. |
| 409 | Le nouveau GTIN est déjà publié par une autre marque. | Vérifiez le GTIN. |
| 409 | Un lot de ce modèle a un passeport de lot publié : le GTIN est imprimé dans son lien GS1 et scellé dans ses données, il ne change plus. | Gardez le GTIN actuel. |
| 409 | Deux écritures ont ouvert une version du même passeport au même instant, deux fois de suite. Cet appel n'a rien écrit. | Renvoyez la requête. |
| 409 | OFFER_CHANGE_NEEDS_CONFIRMATION : la marque a des pièces, ou des lots en cours de création. | Renvoyez avec "confirm_pieces_kept": true si c'est voulu. |
| 422 | UNKNOWN_OFFER : l'offre demandée n'existe pas. | Envoyez compliance ou compliance_identity. |
| 422 | Corps invalide : champ inconnu, name absent à la création, GTIN à la clef fausse, image hors d'un serveur public ou clé d'image d'une autre marque, poids, volume ou garantie négatif, lien d'instructions qui n'est pas une adresse web, pays qui n'est pas deux lettres. | Le corps de la réponse nomme le champ fautif. |
| 429 | Plafond de débit ou quota quotidien atteint. | Attendez le délai indiqué par Retry-After, ou minuit en temps universel pour le quota. |
| 503 | Le comptage des appels est momentanément indisponible. Rien n'a été écrit. | Réessayez dans quelques secondes. |
#Voir aussi
- API partenaire, vue d'ensemble, clefs, droits et plafonds.
- SDK TypeScript, qui ne couvre pas encore ces points d'entrée dans sa version publiée.
- Clés d'API et webhooks, créer la clef dans la console.
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.