Journal des changements
Ce qui a changé dans l'API partenaire et dans les notifications, par date, avec le geste exact à faire quand une entrée casse un appel qui passait avant.
En quittant cette page, vous saurez ce qui a changé dans l'API partenaire et dans les notifications, à quelle date, et ce que vous avez à faire de votre côté quand un changement refuse un appel qui passait avant. Vous saurez aussi pourquoi le numéro de version que vous appelez ne bouge pas alors que ces entrées s'accumulent.
Lisez cette page en entier la première fois. Ensuite, revenez-y avant chaque évolution de votre intégration et arrêtez-vous à la première date que vous connaissez déjà.
#Comment cette page est faite
Vous lisez les entrées de la plus récente à la plus ancienne. La date portée par une entrée est celle de la mise en service du changement.
Une entrée commence par Rupture de compatibilité quand un appel qui passait avant est refusé après. C'est le seul cas où vous avez du travail. Les autres entrées décrivent un comportement qui s'ajoute ou une réponse qui devient plus précise, et votre intégration continue de fonctionner sans retouche.
Chaque entrée dit trois choses : ce qui change, la réponse exacte que vous recevez maintenant, et le geste à faire. Aucune entrée ne renvoie ailleurs pour le geste à faire.
Cette page couvre tous les points d'entrée que ce site documente : l'API partenaire à clef, les points d'entrée publics sans clef, les lectures de passeport authentifiées, les notifications envoyées à vos adresses et le portail partenaire. Elle ne couvre pas la console, dont les écrans évoluent sans contrat à tenir envers votre code.
#Pourquoi la version ne bouge pas
Le point d'entrée GET /v1/version répond toujours la même chose.
{
"version": "1.0.0",
"api_version": "v1"
}Les entrées ci-dessous s'inscrivent toutes dans la version 1. Le jour où une
évolution ne pourra pas y tenir, elle s'ajoutera sous /v2, et la version 1
gardera son comportement.
Les points d'entrée métier existent à deux adresses qui appellent le même
code : avec le préfixe /v1, et sans aucun préfixe. Appelez
GET /v1/version quand vous voulez la version de contrat. C'est le seul point
d'entrée de version que ce site documente.
Les deux adresses appellent le même code, donc elles reçoivent en même temps tous les changements de comportement listés ici. Une seule entrée fait exception, celle du 16 août 2026, qui ne concernait que les adresses sans préfixe.
Sur cette page
- Comment cette page est faite
- Pourquoi la version ne bouge pas
- 8 octobre 2026
- Une pièce garde son identité quand sa marque change d'offre
- Le serveur MCP d'administration s'ajoute à Claude avec votre compte
- 6 octobre 2026
- Rupture de compatibilité : chaque notification est signée, le secret est obligatoire
- Un réessai suit l'abonnement tel qu'il est au moment de partir
- Le serveur MCP s'ajoute à Claude et à ChatGPT par une adresse
- Le catalogue par clef relit les lots, liste les passeports, prévisualise et donne les gabarits
- 5 octobre 2026
- La liste des produits du propriétaire montre la photo du modèle
- Revendiquer par numéro de série une pièce qu'on possède déjà
- Le justificatif signé d'un modèle ou d'un lot a son adresse
- 30 septembre 2026
- La taille, la couleur et le poids d'un passeport sont publics
- Le justificatif signé divulgue ce que montre la page
- Rupture de compatibilité : un numéro de marque s'écrit en chiffres seuls
- Les codes d'achat s'émettent en masse par l'API
- La vérification d'un QR signé ne dit plus « authentique »
- La lecture publique d'un produit donne sa date d'enregistrement et l'état de son certificat
- Le certificat en PDF ne dit plus « authentique, vérifié blockchain »
- 29 septembre 2026
- Une marque se nomme par son code public dans l'API partenaire
- L'adresse à coller dans votre ERP nomme la marque par son code public
- L'espace du propriétaire donne le code public de la marque
- La composition d'un textile et les matières d'une chaussure sont publiques
- Un bloc de matières vide n'est plus noté comme une composition déclarée
- La photo du produit est servie en copie allégée
- Aucune offre ne refuse plus une pièce pour un volume mensuel
- 28 septembre 2026
- La clef revendeur frappe, vend et gère les webhooks de ses marques clientes
- Le passeport d'un modèle ou d'un lot porte la photographie du produit
- 27 septembre 2026
- Deux offres par marque : Conformité, ou Conformité + Identité
- Le QR code d'un modèle ou d'un lot revient pour l'offre Conformité
- Un QR code à imprimer porte le domaine de la marque une fois ce domaine définitif
- 26 septembre 2026
- Le passeport dit les niveaux qui vous sont ouverts
- Rupture de compatibilité. GET /resolve/{identifier} sert le niveau public
- Rupture de compatibilité. Le niveau d'accès end_user demande un compte connecté
- Rupture de compatibilité. Le portail partenaire répond 404 pour le produit d'une autre marque
- Rupture de compatibilité. Les niveaux de métier sont réservés aux administrateurs de la marque
- Afficher le passeport dans votre propre page
- Un passeport par lot de production
- Remplir le catalogue par l'API, et une clef pour plusieurs marques
- Rupture de compatibilité. Seul le QR code d'un exemplaire se génère
- Un exemplaire par pièce
- 30 août 2026
- Le score de conformité d'une batterie se mesure sur la liste de la Commission
- La chronologie d'un produit ne montre ses adresses qu'à sa marque
- 29 août 2026
- La résolution dit sur quelle base croire chaque section du passeport
- 26 août 2026
- Rupture de compatibilité. Le niveau d'accès value_chain n'existe plus
- Le portail partenaire annonce le métier qu'il a servi
- L'image publique d'un exemplaire remonte à son modèle
- 23 août 2026
- Le suivi d'un lot dit enfin qu'un lot a échoué
- Les en-têtes de débit ne sont plus émis deux fois
- 22 août 2026
- Le certificat public nomme la marque émettrice
- Les refus d'authentification répondent en anglais
- Le portail partenaire a un plafond d'appels
- 21 août 2026
- L'envoi d'un lot crée maintenant des produits
- 20 août 2026
- Rupture de compatibilité. L'API refuse les champs owner_email et contract_address
- Rupture de compatibilité. Rejouer une clef d'idempotence avec un lot différent répond 409
- Rupture de compatibilité. Le suivi de lot exige le droit mint:batch
- Rupture de compatibilité. Modifier un abonnement aux notifications exige que votre offre les comprenne
- Un corps JSON illisible répond 400
- Les huit points d'entrée à clef sont plafonnés en débit
- Vos abonnements aux notifications restent lisibles et supprimables quelle que soit votre offre
- 16 août 2026
- Les adresses sans préfixe deviennent des alias permanents
- 14 août 2026
- Un fichier gzip abîmé répond 400
- Le suivi de lot rend quatre champs de plus quand la file a oublié votre lot
- 13 août 2026
- Une intervention du portail partenaire porte un niveau de preuve
- 11 août 2026
- Rupture de compatibilité. Supprimer un abonnement demande de retaper son adresse
- Chaque livraison porte le type d'événement
- 14 juillet 2026
- Deux en-têtes s'ajoutent à chaque livraison
- La signature porte les octets exacts qui vous sont envoyés
- 12 juillet 2026
- Les points d'entrée d'abonnement exigent des droits
- 15 mars 2026
- Le préfixe /v1 apparaît
- Ce que cette page ne fait pas
- Changement
#Une pièce garde son identité quand sa marque change d'offre
Une pièce créée sur l'offre Conformité + Identité garde ses fonctions d'identité quand sa marque passe sur l'offre Conformité : la revendication avec son code d'achat, la fin d'une revendication commencée, les transferts (les commencer, les accepter, les refuser), la lecture de sa puce NFC, la demande de réparation et l'espace du propriétaire. Avant, ces appels répondaient
403OFFER_EXCLUDES_IDENTITYpour toute pièce d'une marque en offre Conformité.Détail
La réponse que vous recevez maintenant. Ces appels répondent comme sur l'offre Conformité + Identité.
GET /timeline/{identifier}etGET /my-productsportentidentity_includedàtruepour ces pièces. Créer une pièce, commander un encodage de puces et émettre un nouveau code d'achat répondent toujours403OFFER_EXCLUDES_IDENTITYsur l'offre Conformité.Ce que vous faites. Rien. Si votre intégration masquait la revendication ou le transfert d'après l'offre de la marque, lisez plutôt
identity_includedde la pièce. - Changement
#Le serveur MCP d'administration s'ajoute à Claude avec votre compte
Le serveur d'administration, qui prépare le catalogue d'une marque sans jamais publier, est servi à l'adresse
https://mcp.sealtrust.io/admin/mcp. Vous l'ajoutez comme connecteur personnalisé dans Claude, vous vous connectez à la console SealTrust, vous choisissez une marque et ce que l'assistant peut faire. Aucune clé à copier. Le programme lancé sur votre poste avec une clé reste disponible et ne change pas.Détail
La réponse que vous recevez maintenant. Sans jeton,
POST /admin/mcprépond 401 avec un en-têteWWW-Authenticatequi donne l'adresse des métadonnées de la ressource. Claude suit cette adresse, s'enregistre, puis vous envoie sur la page « Connecter un assistant IA » de la console. Un jeton vaut 30 minutes, une connexion 90 jours au plus. Au-delà de 60 appels d'outil par minute et par connexion, la réponse est 429 avec un en-têteRetry-After. Un compte de l'équipe SealTrust ne peut pas être connecté. « Préparer des brouillons » n'est jamais coché d'avance, et changer ou réinitialiser votre mot de passe met fin à vos connexions. Le détail est dans Brancher le serveur MCP.Ce que vous faites. Rien pour une intégration existante. Pour mettre fin à une connexion, ouvrez Paramètres, puis Développeurs, carte « Assistants IA connectés ».
- Rupture de compatibilité
#chaque notification est signée, le secret est obligatoire
Un abonnement aux notifications a maintenant toujours un secret de signature, et nous refusons d'envoyer une livraison qui ne serait pas signée. Sur
POST /v1/partner/webhooks, unsecretfourni compte de 32 à 128 caractères. Sanssecret, nous en générons un de 43 caractères. SurPUT /v1/partner/webhooks/{webhook_id}, le secret ne s'efface plus :null, une chaîne vide ou un secret de moins de 32 caractères sont refusés.Détail
La réponse que vous recevez maintenant. Un 422 pour un secret trop court ou vide, et pour un secret
nulldans une modification, aveclocqui nommesecret. Une création sans secret répond 201 avec un champsecreten plus : c'est la seule fois qu'il est lisible. Une création avec votre secret ne le renvoie pas, comme avant.Ce que vous faites. Si votre secret fait moins de 32 caractères, prenez-en un plus long. Si vous créez sans secret, lisez le champ
secretde la réponse et configurez-le sur votre récepteur. Pour garder le secret actuel dans une modification, omettez le champ au lieu d'envoyernull. - Changement
#Un réessai suit l'abonnement tel qu'il est au moment de partir
Un réessai relit l'abonnement juste avant d'être envoyé. Il part vers l'adresse actuelle, signé avec le secret actuel. Il est abandonné sans envoi quand l'abonnement a été supprimé, éteint, désabonné de l'événement, ou quand votre offre ne comprend plus les notifications. Avant, un réessai déjà programmé partait vers l'ancienne adresse avec l'ancien secret.
Détail
La réponse que vous recevez maintenant. Après un changement de secret, les réessais en attente arrivent signés avec le nouveau secret.
Ce que vous faites. Rien, si votre récepteur accepte les deux secrets pendant une bascule, comme cette documentation le conseille.
- Changement
#Le serveur MCP s'ajoute à Claude et à ChatGPT par une adresse
Le serveur MCP est servi à l'adresse
https://mcp.sealtrust.io/mcp, sans compte et sans clef, en plus du paquet npm. Il porte les mêmes sept outils, avec les mêmes descriptions, et se colle tel quel comme connecteur personnalisé dans Claude ou en mode développeur dans ChatGPT.Détail
La réponse que vous recevez maintenant. Le transport est le HTTP diffusable de la spécification MCP, sans session : chaque message est un
POSTindépendant, et unGETou unDELETErépond 405. Une requête qui porte un en-têteOrigind'un autre site que Claude ou ChatGPT répond 403. Au-delà de 300 requêtes par minute et par adresse, ou de 120 appels d'outil par minute et par client, la réponse est 429 avec un en-têteRetry-After. Le détail est dans Claude et ChatGPT en 30 secondes.Ce que vous faites. Rien si vous utilisez le paquet npm : il ne change pas. Pour un assistant en ligne, collez l'adresse au lieu d'installer quoi que ce soit.
- Changement
#Le catalogue par clef relit les lots, liste les passeports, prévisualise et donne les gabarits
Cinq points d'entrée s'ajoutent à l'API du catalogue, tous avec le droit
catalog:read:Détail
GET /partner/catalog/brands/{brand_code}/batches, un lot avec?batch_code=ou la liste des lots ;GET /partner/catalog/brands/{brand_code}/passports/list, la dernière version de chaque passeport de modèle et de lot, sans son contenu ;POST /partner/catalog/brands/{brand_code}/passports/preview, ce que chaque public verra d'un brouillon, sans rien écrire ;GET /partner/catalog/brands/{brand_code}/templatesetGET /partner/catalog/brands/{brand_code}/templates/{template_key}, les gabarits de passeport.
L'écriture du passeport brouillon accepte un champ de plus,
only_if_draft. Àtrue, elle ne complète que le brouillon ouvert : une dernière version scellée ou publiée est refusée en 409, et aucune version du tout en 404.La réponse que vous recevez maintenant. Les mêmes réponses qu'avant sur les points d'entrée existants. Sans
only_if_draft, un envoi sur une version scellée ouvre toujours la version suivante.Ce que vous faites. Rien. Le détail est sur la page Remplir le catalogue par l'API.
- Changement
#La liste des produits du propriétaire montre la photo du modèle
GET /my-productsrendaitmedia: []pour une pièce frappée à partir d'un modèle quand la photo de ce modèle n'existe que comme image de couverture, sans média rattaché. La page publique du même produit montrait pourtant cette photo.Détail
La réponse que vous recevez maintenant. Quand la liste
mediad'une pièce ne contient aucune image, l'image de couverture du modèle y est ajoutée en premier, avec l'identifiant0,media_typeàimageet l'adresse publique de la photo. Une pièce qui a sa propre photo garde exactement sa liste.Ce que vous faites. Rien. Si vous preniez la première image de
mediacomme vignette, elle apparaît désormais. Ne cherchez pas l'entrée d'identifiant0dans la médiathèque de la marque : elle n'a pas d'enregistrement propre. - Changement
#Revendiquer par numéro de série une pièce qu'on possède déjà
POST /claims/from-serialrépondait409« Already owned » ou « Already claimed » au propriétaire lui-même, comme à un inconnu.Détail
La réponse que vous recevez maintenant. Quand le compte appelant est le détenteur enregistré de la pièce, la réponse est
409avecdetail« ALREADY_YOURS: you already own this product ». Tout autre compte reçoit exactement la réponse d'avant : la pièce a un propriétaire, jamais lequel.Ce que vous faites. Lisez le code avant les deux points. Sur
ALREADY_YOURS, dites à la personne que le produit est déjà dans son espace, sans l'envoyer vers la marque. - Changement
#Le justificatif signé d'un modèle ou d'un lot a son adresse
Le justificatif signé du passeport d'un modèle se lit à
GET /passport/01/{gtin}/vc, et celui du passeport d'un lot àGET /passport/01/{gtin}/10/{lot}/vc. Chacun a aussi sa forme/vc/verifyet sa forme/vc/preview, avec les mêmes niveaux d'accès que l'adresse d'un exemplaire. Jusqu'ici, ces justificatifs étaient signés à la publication mais ne se lisaient qu'à travers l'un des exemplaires du modèle : ceux d'une marque à l'offre Conformité, qui n'enregistre aucun exemplaire, ne se lisaient pas.Détail
La réponse que vous recevez maintenant. Ces adresses répondaient 404. Elles répondent maintenant comme
GET /passport/{identifier}/vcet ses deux voisines, avec en pluslevel(modeloubatch),gtinet, pour un lot,batch_code.Ce que vous faites. Rien. Pour vérifier le passeport d'un modèle ou d'un lot, appelez la nouvelle adresse.
- Changement
#La taille, la couleur et le poids d'un passeport sont publics
Les champs
size,coloretweightécrits à la racine d'un passeport sont maintenant rendus au niveaupublic, surGET /passport/{identifier}, sur la copie publique et dans le justificatif signé. Ils étaient réservés aux autorités. Une marque qui a ses propres règles d'accès garde son choix.Détail
La réponse que vous recevez maintenant. Ces trois champs, quand le passeport les porte, dans la réponse publique.
Ce que vous faites. Rien.
- Changement
#Le justificatif signé divulgue ce que montre la page
GET /passport/{identifier}/vcet sa présentation par niveau suivent maintenant exactement les règles deGET /passport/{identifier}: le groupe de produits est lu dans le passeport, donc les mentions d'étiquette d'un textile (composition en fibres) et d'une chaussure y sont publiques, et l'annexe XIII d'une batterie y ouvre et y ferme les mêmes champs. Une liste est divulguée ligne par ligne et champ par champ, comme la page la découpe.Détail
La réponse que vous recevez maintenant. Au niveau
public, le justificatif d'un textile portecompositionavecmaterialetpercentagede chaque ligne. Il ne les portait pas. Celui d'une batterie ne porte plus les références de pièces, l'état de la batterie ni la durée de vie en cycles.Ce que vous faites. Rien. Un justificatif déjà émis garde ses divulgations ; il est réémis à la prochaine publication du passeport.
- Rupture de compatibilité
#un numéro de marque s'écrit en chiffres seuls
Un numéro de marque (
brand_id,parent_brand_id) est maintenant lu d'une seule façon partout : un entier JSON, ou une chaîne faite uniquement de chiffres. Un code de marque (brand_code) est un code public de dix caractères, ou, pendant la transition, des chiffres. Avant, l'API convertissait d'autres écritures sans le dire :5.0,"+5"," 5","5.0","0_5"ettrue, ce dernier lu comme la marque 1. La règle vaut pour le chemin, les paramètres de l'adresse, le corps et chaque ligne d'un lot, sur toutes les routes.Détail
La réponse que vous recevez maintenant. Une valeur mal écrite reçoit un 422 dont
detail.codevautBRAND_REF_NOT_WELL_FORMED.detail.referencesdit où se trouve la valeur, sans la répéter. Dans un lot envoyé en CSV, la ligne fautive est signalée dans le refus 400 habituel, et son message commence parBRAND_REF_NOT_WELL_FORMED. Le lot entier est refusé et rien n'est créé.Ce que vous faites. Envoyez le numéro en chiffres seuls,
5ou"5", ou mieux, lebrand_codeque donneGET /v1/partner/catalog/brands. Si votre code produit un nombre décimal, convertissez-le en entier avant l'envoi. - Changement
#Les codes d'achat s'émettent en masse par l'API
Une clef qui porte le nouveau droit
claim_codes:issueémet les codes d'achat de la règle « code d'achat exigé » pour une liste de pièces, 500 au plus par appel :POST /partner/claim-codes/brands/{brand_code}/issue. Elle lit leur état, jamais le code, avecPOST /partner/claim-codes/brands/{brand_code}/status.POST /partner/mint/batch?issue_purchase_codes=truedemande un code par pièce au moment de la frappe, etGET /partner/mint/batch/{job_id}/itemsles donne une seule fois, danspurchase_code.Détail
La réponse que vous recevez maintenant. Chaque code n'apparaît qu'une fois. Une pièce dont le code a déjà servi reçoit un 409
PURCHASE_CODE_ALREADY_USED, sauf avec"replace_used": true. Une pièce d'une autre marque reçoit le même 404PIECE_NOT_FOUNDqu'une pièce inconnue. La réponse dePOST /partner/mint/batchporte un sixième champ,issue_purchase_codes.Ce que vous faites. Rien si vous n'utilisez pas les codes d'achat. Sinon, cochez
claim_codes:issuesur une clef dédiée, jamais coché par défaut, et lisez Émettre les codes d'achat. - Changement
#La vérification d'un QR signé ne dit plus « authentique »
GET /qr/verifyne répond plus « Authentic product: QR code and blockchain verified. ». Un QR signé prouve que la marque a enregistré ce numéro et que la chaîne le confirme, pas que l'objet en main est l'original : un QR code se photocopie. Le refus ne dit plus « Invalid product » : c'est le code qui ne correspond pas, rien n'est connu du produit lui-même.Détail
La réponse que vous recevez maintenant. Le même champ
valid.messagevaut « Registered number: the QR signature and the on-chain record match. A QR code can be copied: it does not prove the item in hand is the original. » ou « Unrecognised code: the QR signature or the on-chain record does not match. ».Ce que vous faites. Rien si vous lisez
valid, comme cette page le demande. Si vous affichiezmessage, n'affichez jamais « authentique » à partir de cette réponse. - Changement
#La lecture publique d'un produit donne sa date d'enregistrement et l'état de son certificat
GET /products/{uid}/publicrend deux champs de plus.registered_atporte la date de création de l'enregistrement du produit, sous un nom qui dit ce qu'elle est.certificate_statusporte l'état du certificat d'authenticité en vigueur, lu exactement commeGET /resolve/{identifier}le lit :active, ounullsans certificat en vigueur.verified_atreste, avec la même valeur queregistered_at.Détail
La réponse que vous recevez maintenant. Seize champs au lieu de quatorze. Rien d'autre ne change.
Ce que vous faites. Rien d'obligatoire. Si vous affichiez
verified_atcomme une date de vérification, lisezregistered_atet écrivez « enregistré le » : personne n'a vérifié l'objet à cette date. - Changement
#Le certificat en PDF ne dit plus « authentique, vérifié blockchain »
Le sceau en filigrane de
GET /certificate/{identifier}/downloaddit maintenantENREGISTRÉetSUR UNE BLOCKCHAIN PUBLIQUE(en anglaisREGISTEREDetON A PUBLIC BLOCKCHAIN). Il disaitAUTHENTIQUEetVÉRIFIÉ BLOCKCHAIN. Une chaîne publique prouve qu'un enregistrement a été fait, pas que l'objet en main est l'original. Le pied de page par défaut suit la même règle. Un certificat révoqué ou expiré n'a plus de sceau : il portait la même coche qu'un certificat valide.Détail
La réponse que vous recevez maintenant. Un PDF dont le sceau et le pied de page ont changé de texte. Le reste du document est identique.
Ce que vous faites. Rien, sauf si vous comparez le texte du PDF à une valeur attendue.
- Changement
#Une marque se nomme par son code public dans l'API partenaire
Chaque marque a un code public de dix caractères,
brand_code, par exemple7K3QXW9M2A. L'API partenaire nomme maintenant la marque par ce code : dans le chemin des routes/partner/catalog/brands/{brand_code}/..., dans le corps dePOST /partner/selloutet dePOST /partner/webhooks, dans la listeGET /partner/webhooks?brand_code=, et sur chaque ligne dePOST /partner/mint/batch.GET /partner/catalog/brandsdonne le code de chaque marque pour laquelle votre clef peut agir. Les routes publiquesGET /brands/{brand_code}/brandingetGET /brand/{brand_code}/pubkeyacceptent aussi le code.Détail
La réponse que vous recevez maintenant. Les réponses de l'API partenaire, du portail partenaire, de
/sdm/verifyet des clefs publiques qui rendaientbrand_idrendent aussibrand_code.brand_idy est déprécié. Un code qui ne nomme aucune marque reçoit le même 403 qu'une marque que la clef ne sert pas. Une requête qui envoiebrand_codeetbrand_idensemble est refusée : en 422 pour une vente ou un abonnement, en 400 pour une ligne de lot.Ce que vous faites. Rien dans l'immédiat : le numéro
brand_idest encore accepté partout où il l'était. Remplacez-le parbrand_codeà votre prochaine évolution.GET /brand/{brand_id}/did.jsongarde le numéro, parce qu'il fait partie de l'identifiantdid:webdéjà signé dans les justificatifs émis. - Changement
#L'adresse à coller dans votre ERP nomme la marque par son code public
Shopify, WooCommerce, HubSpot et Akeneo envoient leurs événements à l'adresse
/webhooks/integrations/{provider}/{brand_code}. La console, dans Réglages > Intégrations, affiche maintenant cette adresse avec le code public de la marque, sur la carte de chaque connecteur et dans l'assistant de création.Détail
La réponse que vous recevez maintenant. Une adresse dont le code ne nomme aucune marque reçoit le même 404 qu'une marque sans connecteur actif. L'adresse qui porte le numéro de la marque continue de fonctionner.
Ce que vous faites. Rien : une adresse déjà collée dans votre ERP continue de fonctionner. Pour un nouveau connecteur, collez l'adresse que la console affiche.
- Changement
#L'espace du propriétaire donne le code public de la marque
Les réponses de l'espace du propriétaire qui rendaient
brand_idrendent aussibrand_code:GET /my-products, son historique, la liste des marquesGET /my-products/products/brands, les routes/ownership/..., les rachats, les retours, les messages et les codes de remise/custody/repair-codes. L'exportGET /my-products/export/csvgagne une colonnebrand_code, placée juste aprèsbrand_id.Détail
La réponse que vous recevez maintenant.
brand_idy est déprécié.GET /my-productsaccepte le filtre?brand_code=.Ce que vous faites. Rien dans l'immédiat :
brand_idest encore rendu. Lisezbrand_codeà votre prochaine évolution. Si vous lisez l'export par la position des colonnes, décalez de un toutes les colonnes qui suiventbrand_id. - Changement
#La composition d'un textile et les matières d'une chaussure sont publiques
dataau niveaupublicdeGET /passport/{identifier},GET /passport/01/{gtin},GET /passport/01/{gtin}/10/{lot}etGET /resolve/{identifier}porte maintenant, pour un passeport textile, le nom et le pourcentage de chaque matière (materials.<ligne>.nameetmaterials.<ligne>.percentage), et pour un passeport chaussure le nom de la matière de la tige, de la doublure, de la première de propreté et de la semelle. Ce sont des mentions d'étiquette : règlement (UE) n° 1007/2011 pour la composition en fibres, directive 94/11/CE pour la chaussure. Elles restent publiques quelles que soient les règles d'accès de la marque.Détail
La réponse que vous recevez maintenant. Un bloc
materialspeut apparaître dansdataau niveaupublic. L'origine des matières n'en fait pas partie.Ce que vous faites. Rien. Si vous affichiez « composition réservée » faute de
materials, affichez le bloc quand il est présent. - Changement
#Un bloc de matières vide n'est plus noté comme une composition déclarée
Le bloc
evidencedeGET /passport/{identifier}, deGET /passport/01/{gtin}, deGET /passport/01/{gtin}/10/{lot}et deGET /resolve/{identifier}notaitcomposition: "declared"dès que le passeport portait un blocmaterials, même quand toutes ses lignes étaient vides : un gabarit enregistré tel quel suffisait.Détail
La réponse que vous recevez maintenant.
compositionn'apparaît que si une ligne de matière porte au moins un nom, une part ou une origine. Sinon la clef est absente desections, comme pour un passeport sans matières. Un chiffre laissé vide par la marque n'est jamais rendu comme0.Ce que vous faites. Rien. Traitez l'absence de
compositioncomme vous le faites déjà : la marque n'a rien déclaré. - Changement
#La photo du produit est servie en copie allégée
image_urldes passeports (GET /passport/{identifier},GET /passport/01/{gtin},GET /passport/01/{gtin}/10/{lot}et les ensembles partenaires correspondants), deGET /products/{uid}/public, deGET /qr/verifyet deGET /timeline/{identifier}, ainsi queurldes images demediadansGET /resolve/{identifier}, désignent maintenant une copie allégée de la photo au lieu du fichier d'origine.Détail
La réponse que vous recevez maintenant. Une adresse qui se termine par
.photo.webp: une image WebP de 800 pixels au plus sur le grand côté, de 100 Ko au plus, sans données EXIF. Une photo qui n'a pas encore sa copie garde l'adresse de l'original ; une adresse d'un autre site est rendue telle quelle. Le champ ne change ni de nom ni de type, etnullgarde le même sens.Ce que vous faites. Rien. Si votre intégration déduisait le format du fichier de l'extension de l'adresse, lisez l'en-tête
Content-Typede la réponse à la place. - Changement
#Aucune offre ne refuse plus une pièce pour un volume mensuel
Les quatre offres comptent maintenant les pièces par année civile. Les 6 000 premières de l'année sont comprises, chaque pièce au-delà est facturée, et au-delà d'un million de pièces dans l'année le prix se fixe sur devis. Aucune pièce n'est refusée pour une question de volume. Cela vaut sur l'offre Conformité + Identité. Seul le compte d'essai garde un volume mensuel.
Détail
La réponse que vous recevez maintenant. Sur une offre payante, un lot envoyé à
POST /v1/partner/mint/batchne reçoit plus le403dontdetail.codevautQUOTA_EXCEEDEDetdetail.resourcevautproducts. Il est accepté. Un compte d'essai reçoit toujours ce refus, avec"period": "monthly".Ce que vous faites. Rien. Si votre intégration attendait ce refus pour étaler ses envois d'un mois sur l'autre, vous pouvez retirer cette attente.
- Changement
#La clef revendeur frappe, vend et gère les webhooks de ses marques clientes
Une clef revendeur agit maintenant pour chacune de vos marques clientes sur tous les points d'entrée, sans clef par marque : la frappe (
POST /v1/partner/mint/batch, avec le suivi du lot et ses pièces), la déclaration de vente (POST /v1/partner/sellout) et les webhooks (/v1/partner/webhooks), en plus du catalogue et de l'affichage du passeport.Détail
La réponse que vous recevez maintenant. Un lot dont les lignes portent le
brand_idd'une de vos marques clientes est accepté. La vente et l'abonnement prennent un champbrand_idfacultatif, et la liste des abonnements un paramètrebrand_id. Une marque que la clef ne sert pas reçoit toujours un403, dontdetailvaut désormais"This API key cannot act for this brand."(le texte"Brand mismatch: ..."disparaît). Un lot qui mélange plusieurs marques reçoit un422dontdetail.codevautONE_BRAND_PER_BATCH.Ce que vous faites. Rien si vous ne lisiez pas le texte du refus. Si votre intégration le comparait à
"Brand mismatch", comparez le code403à la place. Avec une clef revendeur, vous pouvez retirer les clefs créées sur vos marques clientes : le détail est sur la page Remplir le catalogue par l'API. - Changement
#Le passeport d'un modèle ou d'un lot porte la photographie du produit
GET /passport/01/{gtin}etGET /passport/01/{gtin}/10/{lot}ajoutent le champimage_url, que le passeport d'une pièce portait déjà. Les passeports groupésGET /v1/partner/passports/01/{gtin}etGET /v1/partner/passports/01/{gtin}/10/{lot}le portent aussi, danspassport.Détail
La réponse que vous recevez maintenant.
image_urlest l'adresse complète de la photographie du modèle, calculée de la même façon aux trois niveaux : sa photo principale, ou à défaut la première image de sa médiathèque.nullquand le modèle n'en a pas. Sur le passeport d'une pièce, trois cas changent : une photo enregistrée comme simple chemin de stockage arrive maintenant en adresse complète, un modèle sans photo principale montre la première image de sa médiathèque au lieu denull, et un modèle d'une autre marque que celle du passeport répondnull.Ce que vous faites. Rien : c'est un champ en plus. Affichez-le si votre page montre le produit.
- Changement
#Deux offres par marque : Conformité, ou Conformité + Identité
Chaque marque est désormais sur l'offre
complianceou sur l'offrecompliance_identity. Toutes les marques existantes sont surcompliance_identity, qui est ce qu'elles avaient déjà : rien ne change pour elles. L'offrecompliancecouvre le passeport produit par modèle ou par lot, sans identité à la pièce.Détail
La réponse que vous recevez maintenant. Pour une marque sur l'offre
compliance, toute opération sur une pièce répond403, avecdetail.codeégal àOFFER_EXCLUDES_IDENTITYetdetail.featurequi dit ce qui a été refusé : création de pièces parPOST /v1/partner/mint/batch, lecture de puce parPOST /v1/partner/nfc/verify, déclaration de vente parPOST /v1/partner/sellout, et les mêmes opérations dans la console. Rien n'est écrit, mis en file ou envoyé à la blockchain.Ce que vous faites. Rien pour une marque qui ne change pas d'offre. Pour une marque sur l'offre
compliance, ne rejouez pas un appel refusé avec ce code, et imprimez le QR code de son modèle ou de son lot. Le détail est sur la page Conformité, ou Conformité + Identité. - Changement
#Le QR code d'un modèle ou d'un lot revient pour l'offre Conformité
GET /qr/01/{gtin},GET /qr/01/{gtin}/download,GET /qr/01/{gtin}/10/{lot}etGET /qr/01/{gtin}/10/{lot}/downloaddessinent de nouveau le code du modèle ou du lot, pour une marque sur l'offrecompliancedont ce passeport est publié.Détail
La réponse que vous recevez maintenant.
200et une image PNG pour une telle marque. Dans tous les autres cas, la même réponse qu'avant :410avecdetail.codeégal àITEM_QR_ONLY.Ce que vous faites. Rien si vos marques sont sur l'offre
compliance_identity: elles impriment toujours le code de chaque pièce. - Changement
#Un QR code à imprimer porte le domaine de la marque une fois ce domaine définitif
GET /qr/product/{identifier},GET /qr/product/{identifier}/download,GET /qr/verify/{identifier},GET /qr/certificate/{identifier}etGET /qr/certificate/{identifier}/download, ainsi que le QR code du PDF de certificat et la carte de portefeuille, portent le domaine de la marque seulement quand ce domaine est définitif (verrouillé). Avant, ils portent notre adresse. Un domaine seulement vérifié peut encore changer, et un code imprimé qui le portait ne mènerait plus nulle part après ce changement.Détail
La réponse que vous recevez maintenant. Le code reste
200et l'image reste un PNG. Pour une marque dont le domaine est vérifié mais pas encore définitif, l'adresse encodée commence parhttps://sealtrust.ioau lieu du domaine de la marque. Cette adresse reste valable pour toujours.Ce que vous faites. Rien. Si vous imprimez ces codes pour une marque qui veut son domaine sur ses étiquettes, la marque rend d'abord son domaine définitif depuis sa console, par l'export des QR codes d'un lot.
- Changement
#Le passeport dit les niveaux qui vous sont ouverts
GET /passport/{identifier},GET /passport/01/{gtin}etGET /passport/01/{gtin}/10/{lot}ajoutent le champavailable_tiers: les niveaux d'accès que votre appel peut demander sur ce passeport, dans l'ordrepublic,end_user,repairer,recycler,upstream,authority. Les passeports de modèle et de lot ajoutent aussiaccess_tier, le niveau servi, qui n'était jusque-là que dans l'en-têteX-DPP-Access-Tier.Détail
La réponse que vous recevez maintenant. Le code reste
200. Sans authentification,available_tiersvaut["public"]. La liste ne donne aucun droit : chaque niveau demandé reste vérifié, avec les mêmes refus qu'avant.Ce que vous faites. Rien. Si vous proposez un choix de niveau à vos utilisateurs, proposez les niveaux de cette liste, et seulement eux. Une réponse faite pour un compte connecté ne doit aller dans aucun cache partagé.
- Rupture de compatibilité
#
GET /resolve/{identifier}sert le niveaupublicGET /resolve/{identifier}ne lit aucune session. Il servait pourtant le passeport au niveauend_user, à tout appelant. Il sert désormais le niveaupublic, et lui seul : les mêmes données queGET /passport/{identifier}sans compte. Un appel fait avec une session, celle du propriétaire comprise, reçoit la même réponse.Détail
La réponse que vous recevez maintenant. Le code reste
200. Danspassport.data, l'impact environnemental, l'indice de réparabilité, la durée de vie, la durabilité, l'efficacité énergétique, l'empreinte carbone, la matière principale, l'entretien et le mouvement n'apparaissent plus. Le taux de recyclabilité et le contenu recyclé restent. Le blocevidencene change pas.Ce que vous faites. Si votre intégration affiche ces champs, lisez-les sur
GET /passport/{identifier}avec un jeton de session de compte dansAuthorization: Bearer. Si vous les affichez quand ils manquent, affichez une absence, jamais un zéro : une valeur absente n'est pas une valeur nulle. - Rupture de compatibilité
#Le niveau d'accès
end_userdemande un compte connectéLe niveau
end_userajoute au passeport l'impact environnemental, la circularité, la matière principale, la durabilité et l'efficacité énergétique. Il était servi à n'importe quel appelant qui le demandait par?access_tier=end_user, sans session. Il est désormais réservé à un compte connecté. Le propriétaire actuel de l'exemplaire le reçoit toujours par défaut.Détail
La règle vaut pour les six points d'entrée qui prennent
access_tier:GET /passport/{identifier},GET /passport/01/{gtin},GET /passport/{identifier}/vc,GET /passport/{identifier}/vc/preview,GET /passport/{identifier}/vc/verifyetGET /passport/01/{gtin}/10/{lot}.La réponse que vous recevez maintenant. Un appel sans session au niveau
end_userreçoit401, avecdetailégal àEnd-user-tier access requires authentication. Le niveaupublicne change pas.GET /resolve/{identifier}ne prend pas de paramètreaccess_tier. Il sert le niveaupublic, voir l'entrée précédente.Ce que vous faites. Si votre intégration demande
end_usersans session, présentez un jeton de session de compte dansAuthorization: Bearer, ou demandez le niveaupublic. Une clef d'API partenaire n'est pas une session et n'ouvre pas ce niveau. - Rupture de compatibilité
#Le portail partenaire répond 404 pour le produit d'une autre marque
GET /v1/partner-portal/products/{identifier}etPOST /v1/partner-portal/interventionsrépondaient 403, avec le messageCe produit appartient à une marque qui ne vous a pas accrédité, quand l'identifiant était un numéro de jeton, une empreinte ou un numéro de certificat d'une marque qui ne vous a pas accrédité. Par numéro de série, la même demande répondait déjà 404. La réponse 403 confirmait que le produit existe.Détail
La réponse exacte. Ces demandes répondent maintenant 404,
detailvautProduit introuvable, exactement comme pour un identifiant inventé. Sur le domaine propre d'une marque, le portail ne trouve que les produits de cette marque. Le 403Aucune accréditation activene change pas.Ce que vous faites. Si votre code traite ce 403 à part, traitez le 404 à la place : le produit n'est pas dans votre périmètre, ou il n'existe pas.
- Rupture de compatibilité
#Les niveaux de métier sont réservés aux administrateurs de la marque
Les niveaux
repairer,recycleretupstreamétaient ouverts à tout compte rattaché à la marque du produit, même quand ce compte n'était pas administrateur : un ancien administrateur redevenu client, ou devenu réparateur, lisait encore les trois niveaux. Ils sont ouverts maintenant aux administrateurs de la marque, aux partenaires pour le niveau de leur accréditation, et à l'autorité de surveillance du marché.Détail
La réponse exacte. Un tel compte reçoit 403 sur
GET /v1/passport/{identifier},GET /v1/passport/01/{gtin},GET /v1/passport/01/{gtin}/10/{lot}et sur les trois points d'entrée d'identité vérifiable, avec ledetailhabituel de ce refus. Un réparateur garde le niveaurepairer, et un recycleur le niveaurecycler.Ce que vous faites. Rien si vous appelez avec un compte administrateur ou partenaire. Sinon, demandez à la marque le rôle qui correspond à votre usage.
- Changement
#Afficher le passeport dans votre propre page
Six points d'entrée s'ajoutent pour le partenaire qui affiche les passeports d'une marque dans sa propre page. Trois droits nouveaux les ouvrent :
passport:read,scans:writeetnfc:verify.Détail
GET /partner/passports/{identifier},GET /partner/passports/01/{gtin}etGET /partner/passports/01/{gtin}/10/{lot}rendent le passeport, sa preuve et sa signature en un appel.POST /partner/scansetPOST /partner/nfc/verifycomptent chaque scan pour le visiteur nommé par quatre en-têtes signés, et plus pour votre serveur.GET /partner/nfc/receipts/{receipt}lit une lecture de puce que notre page a déjà vérifiée : la puce n'est vérifiée qu'une fois.POST /partner/nfc/verifyrépond503NFC_READ_IN_PROGRESS, avecRetry-After, à une relance qui arrive pendant que votre premier appel vérifie encore la même lecture, au lieu de la prendre pour une copie.- Nos pages
/claimet/transferacceptentserialetreturnet renvoient le visiteur vers votre page, avecclaim_outcomeoutransfer_outcome.GET /my-productsporte désormais le champserial.
Une clef revendeur agit aussi pour les marques clientes sur ces six points d'entrée.
Quand une marque l'active dans la console,
/p/{serial},/01/{gtin}/21/{serial},/01/{gtin}et/01/{gtin}/10/{lot}répondent302vers la page du partenaire, etGET /sdm/verify-urlporte un champpartner_redirect_url. Sans ce réglage, ces réponses ne changent pas, et le champ vautnull.Ce que vous faites. Rien pour une intégration existante. Pour afficher les passeports dans votre page, lisez Afficher le passeport dans votre page.
- Changement
#Un passeport par lot de production
Un passeport peut désormais être rattaché à un lot de production, en plus du modèle et de l'exemplaire. Trois adresses publiques nouvelles, sans clef :
Détail
GET /01/{gtin}/10/{lot}, le lien GS1 du lot, qui répond302vers la page du passeport du lot, ou vers celle du modèle quand le lot n'a pas encore de passeport publié ;GET /v1/passport/01/{gtin}/10/{lot}, le passeport du lot, avec"level": "batch",product_batch_idetbatch_code;GET /v1/passport/01/{gtin}/10/{lot}/proof, ses preuves. Son ancrage sur la chaîne vient du même balayage que les autres passeports, sans aucune frappe.
Un exemplaire sans passeport propre reçoit maintenant celui de son lot quand il en a un, avant celui de son modèle, sur
GET /v1/passport/{identifier}, sa preuve, sa vérification,GET /v1/resolve/{identifier}et le portail partenaire.Ce que vous faites. Rien : aucune réponse existante ne change tant qu'aucun passeport de lot n'est publié. Si votre intégration lit
product_id: nullcomme « passeport du modèle », lisez plutôt le champleveldes réponses de niveau partagé, qui vautmodeloubatch.Trois règles protègent les étiquettes de lot déjà imprimées :
- le GTIN d'un modèle dont un lot a un passeport publié ne change plus :
PUT /admin/product-models/{id}répond409, et l'import Excel refuse la ligne ; - un GTIN n'appartient qu'à une marque, à tous les niveaux : publier un passeport
de modèle ou de lot sous un GTIN qu'une autre marque publie déjà, par son
modèle ou par l'un de ses lots, répond
409; - publier un brouillon de lot dont le lot a été renommé depuis répond
422.
L'archive de réversibilité écrit pour chaque passeport son
level, sonproduct_batch_idet sonbatch_code. - Changement
#Remplir le catalogue par l'API, et une clef pour plusieurs marques
Sept points d'entrée s'ajoutent sous
/partner/catalog. Ils créent ou complètent des modèles, des lots et le passeport brouillon d'un modèle, et ils lisent le score de complétude. Deux droits nouveaux les ouvrent :catalog:readetcatalog:write. Chaque écriture se rejoue sans doublon, et un champ absent ou ànulln'efface rien. Rien n'est publié par cette voie. Chaque écriture est inscrite au journal d'audit, avec la clef, la marque visée et chaque champ modifié avant et après. Chaque appel, lecture comprise, est inscrit au journal d'utilisation de la clef. Un modèle créé par cette voie est au niveauunit, comme par tout autre chemin.Détail
Une clef revendeur agit aussi pour les marques clientes rattachées au contrat revendeur, sur ces sept points d'entrée seulement.
Chaque lot rendu porte
lot_passport_blocker:nullquand son code peut porter un passeport de lot, sinon la raison (plus de 20 caractères, ou un caractère que le lien GS1 refuse). Le lot est créé quand même.Quatre droits qui n'ouvraient aucun point d'entrée ne se proposent plus à la création d'une clef :
mint:single,products:read,products:statusettransfers:create. Une clef qui en porte déjà un continue de fonctionner exactement comme avant, puisque ce droit n'ouvrait rien.Ce que vous faites. Rien pour une intégration existante. Pour préremplir votre catalogue, créez une clef portant
catalog:writeet lisez Remplir le catalogue par l'API. - Rupture de compatibilité
#Seul le QR code d'un exemplaire se génère
Le code à imprimer est celui de chaque exemplaire,
/p/{serial}. Un QR code partagé par toutes les pièces d'un modèle ou d'un lot ne se génère plus.Détail
La réponse que vous recevez maintenant.
GET /qr/01/{gtin},GET /qr/01/{gtin}/download,GET /qr/01/{gtin}/10/{lot}etGET /qr/01/{gtin}/10/{lot}/downloadrépondent410, avecdetail.codeégal àITEM_QR_ONLY. La réponse est la même pour tout GTIN et tout lot, connus ou non. Les liens/01/{gtin}et/01/{gtin}/10/{lot}eux-mêmes ne changent pas : un code déjà imprimé mène toujours à son passeport.Ce que vous faites. Dessinez le code de chaque exemplaire avec
GET /qr/product/{serial}/download. La page de chaque exemplaire affiche le passeport de son lot, sinon celui de son modèle. - Changement
#Un exemplaire par pièce
Un modèle de produit porte le champ
identity_level, qui vautunit: chaque pièce reçoit son propre jeton sur la chaîne et son propre QR code, pour l'authentification, le propriétaire, la revente et la déclaration de vol. Le passeport reste porté par le modèle ou par le lot, et chaque exemplaire en hérite.Détail
POST /admin/product-modelsetPUT /partner/catalog/brands/{brand_id}/modelscréent un modèle au niveauunit, que le corps donne le champ ou non. Les connecteurs et l'import Excel créent aussi au niveauunit. Envoyer"identity_level": "model"répond422.- Un modèle encore au niveau
modelne reçoit aucun exemplaire :/mint,/mint/batch,/admin/batch/mint,/admin/batch/prepareet/admin/batch/prepare-mappedrépondent409avec le codeMODEL_LEVEL_IDENTITY, avant toute écriture, que la ligne nomme le modèle ou seulement son lot. Le détail ne donne que des identifiants. - Une ligne qui nomme le modèle ou le lot d'une autre marque que son
brand_idrépond404avec le codeUNKNOWN_PRODUCT_REFERENCE, comme un identifiant qui n'existe pas.
Ce que vous faites. N'envoyez pas
identity_level, ou envoyez"unit". Si un409MODEL_LEVEL_IDENTITYvous répond, passez le modèle au niveauunitparPUT /admin/product-models/{id}, puis renvoyez la même demande : un nouvel essai sans ce changement reçoit la même réponse.
- Changement
#Le score de conformité d'une batterie se mesure sur la liste de la Commission
La dimension « Conformité » du score de préparation ne vérifiait que trois choses : que le passeport existe, qu'il est publié, et que les champs requis de notre gabarit sont remplis. Pour une batterie, elle compare désormais aussi votre passeport aux données numérotées du guide de la Commission, et nomme celles qui manquent par leur numéro officiel.
Détail
L'exigence dépend de la catégorie : 46 données obligatoires pour un véhicule électrique, 49 pour un moyen de transport léger, 32 pour une batterie industrielle. Le score lit
product_identity.battery_categoryet note sur la colonne correspondante.Ce que vous faites. Le score d'un modèle batterie peut baisser, parce qu'il mesure maintenant ce que le règlement demande et non plus seulement ce que notre gabarit propose. Le cockpit liste les données manquantes avec leur numéro : c'est la même numérotation qu'une autorité emploiera.
⚠️ Quelques données obligatoires n'ont pas encore de champ chez nous. Elles ne sont ni comptées remplies ni comptées manquantes : le cockpit les affiche à part, comme un manque de notre côté.
- Changement
#La chronologie d'un produit ne montre ses adresses qu'à sa marque
GET /v1/timeline/{identifier}rendait les adresses e-mail et les adresses de portefeuille en clair à n'importe quel compte administrateur connecté, quelle que soit sa marque. Le clair est désormais réservé. Les adresses e-mail en clair ne vont qu'au propriétaire actuel du produit et à un administrateur de la marque qui a émis ce produit ; les adresses de portefeuillefrom_addressetto_addressne vont qu'à cet administrateur de marque. Tout autre appelant, connecté ou non, reçoit la projection anonymisée : les adresses e-mail des autres parties y sont masquées,from_addressetto_addressvalentnull. Un superadmin SealTrust reçoit le clair sur tous les produits, parce que c'est le compte d'exploitation.Détail
Ce que vous faites. Rien, si vous appeliez cette adresse pour vos propres produits. Si votre intégration lisait la chronologie de produits d'une autre marque, elle recevra désormais la projection anonymisée.
- Changement
#La résolution dit sur quelle base croire chaque section du passeport
GET /v1/resolve/{identifier}rend un champ de plus,evidence. Il dit, pour chaque section notée du passeport, si elle est vérifiée mécaniquement contre un registre public, appuyée sur un document tiers joint, ou déclarée par la marque.Détail
C'est le même bloc, calculé par la même fonction, que celui que rend déjà
GET /v1/passport/{identifier}. La fonction est la même, la version de passeport lue peut différer :/resolveest public et ne lit que les versions en visibilitépublic, tandis que/passportsert en plus les versions en visibilitéowner_onlyau propriétaire actuel qui s'authentifie. Une unité qui porte une versionowner_onlypeut donc recevoir deux niveaux de preuve différents selon le point d'entrée appelé. Pour tout autre appelant, les deux réponses portent la même version et le même niveau.La réponse exacte. Le champ s'ajoute à la fin de l'objet, à côté de
passport_anchor. Le bloc ci-dessous est celui d'un passeport qui décrit à la fois ses matières et ses substances préoccupantes.JSON { "evidence": { "sections": { "identity": "verified", "integrity": "verified", "composition": "declared", "substances_of_concern": "declared" }, "legend": { "declared": "Stated by the brand. Recorded, dated and attributable, but not independently checked.", "verified": "Rests on an on-chain reference that anyone can re-check independently. SealTrust records it and does not re-query the chain on each request." }, "derived": true, "note": "Statuses are computed by SealTrust from verifiable facts. A brand cannot set them." } }Il vaut
nullquand aucun passeport publié n'est servi, etnullsi son calcul échoue.Quatre sections peuvent être notées, et aucune autre partie du passeport ne reçoit de mention.
identityetintegritysont toujours là, parce qu'elles portent sur l'exemplaire lui-même.compositionetsubstances_of_concernn'apparaissent que si les données du passeport les portent :sectionscompte donc de deux à quatre entrées selon l'exemplaire. Lisez les clefs présentes, n'en supposez aucune.Ce que vous faites. Rien. Le champ s'ajoute, aucun champ ne change de sens et aucun appel qui passait avant ne casse. Un client qui ne lit pas
evidencereçoit la même réponse qu'avant. Si vous décidez d'afficher ces mentions, n'en affichez que pour les sections quesectionsnomme, et ne recopiez pas ces valeurs dans votre base : elles sont recalculées à chaque lecture.
Trois changements. Le premier est une rupture de compatibilité, et il concerne tout partenaire accrédité.
- Rupture de compatibilité
#Le niveau d'accès
value_chainn'existe plusLe niveau
value_chainétait accordé à tout partenaire portant n'importe quelle accréditation sur la marque, et il rendait la réunion de ce que voient le réparateur, le recycleur et le fournisseur amont. Un recycleur accrédité y lisait donc les données de fabrication et la chaîne d'approvisionnement, que le niveaurecyclerlui refuse. Cette porte est fermée.Détail
Six niveaux subsistent :
public,end_user,repairer,recycler,upstreametauthority. Les trois niveaux de métier sont des publics distincts : détenir une accréditation n'en ouvre aucune autre.La réponse exacte.
?access_tier=value_chainrépond maintenant 422, surGET /v1/passport/{identifier}, surGET /v1/passport/01/{gtin}et sur les trois points d'entrée d'identité vérifiable.detailest la liste de validation habituelle, chaque entrée portantloc,typeetmsg, etlocnommeaccess_tier.Ce que vous faites. Demandez le niveau de votre métier,
repairerourecycler. Vous recevrez moins de champs qu'avant, et ce sont précisément les champs qui ne relèvent pas de votre métier. - Changement
#Le portail partenaire annonce le métier qu'il a servi
Dans
GET /v1/partner-portal/products/{identifier}, le champpassport.access_tiervalait toujoursvalue_chain. Il porte maintenant les métiers réellement servis, joints par un+et rangés par ordre alphabétique :recycler, ourepairer+recyclerpour un compte qui porte les deux accréditations sur cette marque. Il vautpublicquand la marque ne vous en a reconnu aucune, et le passeport est alors filtré au niveau public.Détail
Ce que vous faites. Si votre code compare cette valeur à
value_chain, reprenez la comparaison. Et attendez-vous à un contenu plus étroit qu'avant : il est désormais filtré sur vos seules accréditations. - Changement
#L'image publique d'un exemplaire remonte à son modèle
Dans
GET /v1/products/{uid_hash}/public, le champimage_urlne regardait que les médias attachés directement à l'exemplaire, et valaitnulldès qu'il n'en avait aucun. Il suit maintenant la même chaîne de repli que le reste du site : une image de l'exemplaire, puis l'image principale de son modèle, puis les médias du modèle.Détail
Ce que vous faites. Rien. Un champ qui valait
nullpeut désormais porter une adresse.
Deux corrections d'API. Aucune n'est une rupture de compatibilité, mais toutes deux annulent un conseil que cette documentation donnait auparavant.
- Changement
#Le suivi d'un lot dit enfin qu'un lot a échoué
Un lot dont aucune ligne n'aboutissait répondait
status: "finished", parce que c'était la file d'exécution qui parlait. La même adresse basculait ensuite surfailedune fois la rétention de la file écoulée, environ huit minutes plus tard. Même lot, même exécution, deux réponses opposées selon l'heure du regard.Détail
Désormais, dès que votre réservation porte un état terminal, c'est elle qui décide : un lot dont aucune ligne n'a abouti répond
status: "failed". Et les quatre compteursbatch_status,items_count,success_counteterror_countsont présents dans toute réponse, dès le premier appel, alors qu'ils n'apparaissaient qu'une fois le lot oublié par la file.Ce que vous faites. Fondez votre décision sur
success_counteterror_count. Si vous aviez suivi notre ancien conseil de ne pas regarderstatus: "failed", retirez cette exception : ce statut est désormais fiable. - Changement
#Les en-têtes de débit ne sont plus émis deux fois
Trois en-têtes
x-ratelimit-*pouvaient sortir en double quand deux couches les posaient. Une seule les pose maintenant, et le filet de sécurité se retire quand une autre couche a déjà écrit la famille.Détail
Ce que vous faites. Si vous coupiez ces valeurs sur la virgule, comme cette documentation le conseillait, ce n'est plus nécessaire. Une lecture directe en nombre entier fonctionne.
Trois changements sont partis ensemble. Aucun n'est une rupture de compatibilité.
- Changement
#Le certificat public nomme la marque émettrice
Le champ
issuer_nameporte le nom de la marque qui a émis le certificat. Le serveur le calcule à la lecture, et il vautnullquand le certificat n'est rattaché à aucune marque.Détail
Trois surfaces sont concernées :
GET /v1/certificate/{identifier}, le PDF rendu parGET /v1/certificate/{identifier}/download, et le bloccertificatedeGET /v1/resolve/{identifier}.Ce que vous faites. Rien dans vos appels. Si vous avez recopié la valeur de
issuer_namedans votre propre base, remplacez-la par ce que rend l'API aujourd'hui. - Changement
#Les refus d'authentification répondent en anglais
La porte d'entrée de l'API rendait ses messages en deux langues selon le chemin appelé. Les messages qu'elle pose dans
detailsont désormais en anglais :Not authenticated,Invalid token,Invalid token: missing email,Token has been revoked,Invalid JWT token,Account disabled,User not foundetPartner account required (repairer or recycler).Détail
Deux refus de
POST /v1/originality/read-sig/verifysuivent la même règle et valent maintenantInvalid uid_hexetInvalid signature_hex.Ce que vous faites. Rien, si vous branchez votre code sur le code HTTP, comme le recommande la page des erreurs. Un client qui compare ces phrases caractère par caractère doit reprendre ses comparaisons, ou mieux, les supprimer.
- Changement
#Le portail partenaire a un plafond d'appels
Les quatre points d'entrée
/partner-portalacceptent 30 appels par fenêtre de 60 secondes, comptés par adresse d'appel. Les quatre partagent ce compteur, et la forme/v1/partner-portal/...le partage avec la forme sans préfixe.Détail
Chaque réponse acceptée porte
X-RateLimit-Limit,X-RateLimit-RemainingetX-RateLimit-Reset. Un dépassement renvoie 429, avecdetailvalantRate limit exceeded: 30 requests per 60set un en-têteRetry-Aftervalant60.Ce que vous faites. Espacez vos appels au portail et pilotez votre cadence sur
X-RateLimit-Remaining. Un parcours humain, chercher un produit puis déclarer une intervention, reste très en dessous de ce plafond.
- Changement
#L'envoi d'un lot crée maintenant des produits
POST /v1/partner/mint/batchrépondait200, son traitement allait jusqu'au bout, et aucun produit n'était créé. Il manquait à chaque ligne deux valeurs que le contrat d'envoi ne vous laisse pas fournir, et chaque ligne était rejetée pour cette raison.Détail
Le serveur pose désormais ces deux valeurs lui-même, sur chaque ligne : la méthode d'identification
qret l'identifiant technique du produit.Ce que vous faites. Rien dans vos envois. Le contrat d'une ligne ne change pas, et une ligne qui porterait la méthode d'identification ou l'identifiant technique est refusée en
400, comme tout champ que le contrat ne nomme pas.Les produits créés par cette voie sont identifiés par QR. Pour des articles NFC, passez par la console.
Sept changements sont partis ensemble. Les quatre premiers sont des ruptures de compatibilité.
- Rupture de compatibilité
#L'API refuse les champs
owner_emailetcontract_addressUne ligne de lot qui porte l'un de ces deux champs fait échouer toute la requête en
400. La réponse nomme le champ refusé.Détail
L'API acceptait ces deux champs et ne les lisait jamais. La valeur que vous y mettiez n'avait aucun effet.
Une ligne de lot accepte désormais cinq champs et rien d'autre :
product_name,brand_id,category_idetmetadata_uri, qui sont obligatoires, etexternal_ref, qui est facultatif.Ce que vous faites. Retirez ces deux colonnes de vos exports CSV et ces deux clefs de vos objets JSON. Si vous avez besoin de rattacher une ligne à une référence de votre côté, utilisez
external_ref: c'est le seul champ libre du contrat. Nous le conservons sur la ligne du lot et nous le rendons dans le résultat que litGET /v1/partner/mint/batch/status/{job_id}. Aucun champ de produit ne le reprend.Ce retrait fait passer la validation. Depuis le 21 août 2026, il fait aussi créer les produits, voir l'entrée de cette date.
- Rupture de compatibilité
#Rejouer une clef d'idempotence avec un lot différent répond 409
L'en-tête
Idempotency-Keyreste facultatif et reste mémorisé 24 heures.Détail
Rejouer la même valeur avec le même lot rend toujours la réponse du premier appel, sans rien refrapper. L'ordre des contrôles a changé le même jour. Le rejeu consomme désormais un jeton de votre plafond de débit, et l'API relit votre corps de requête avant de vous rendre la réponse mise en cache. Un rejeu au-delà du plafond reçoit donc
429. Un rejeu dont le corps est devenu illisible reçoit400.Rejouer la même valeur avec un lot différent répond maintenant
409. L'API ne met pas votre second lot en file, et la réponse vous le dit.JSON { "detail": "Idempotency-Key 'lot-2026-08-20-a' was already used with a different request body" }Le même code
409signale aussi qu'un appel portant cette clef est encore en cours de traitement. Le message est alorsA request with this Idempotency-Key is already being processed. Lisez le message avant de décider quoi faire : le premier cas vous demande de changer votre clef, le second vous demande d'attendre la fin du traitement en cours.L'égalité de deux lots porte sur leur contenu une fois lu. L'ordre des lignes, l'ordre des colonnes, le choix entre CSV et JSON et les cellules vides n'y changent rien.
Ce que vous faites. Fabriquez une valeur d'
Idempotency-Keypar lot distinct. Si votre code réutilise une valeur fixe, ou une valeur dérivée de l'heure à la minute, changez-la maintenant. - Rupture de compatibilité
#Le suivi de lot exige le droit
mint:batchGET /v1/partner/mint/batch/status/{job_id}exige le droitmint:batch, le même que l'envoi du lot. Une clef qui ne le porte pas reçoit403, et le message nomme le droit manquant.Détail
Ce que vous faites. Vérifiez que la clef qui interroge le suivi porte
mint:batch. Les droits d'une clef se fixent à sa création et aucun écran ne les modifie ensuite, donc il vous faut une nouvelle clef.Vérifiez d'abord votre plafond de clefs, qui ne compte que les clefs actives. L'offre Essentiel n'en autorise qu'une seule : révoquez l'ancienne, puis créez la nouvelle, en acceptant la coupure entre les deux. L'offre Prestige en autorise cinq : créez la nouvelle, déployez-la, puis révoquez l'ancienne. Révoquer une clef libère immédiatement une place. Une création au-delà du plafond répond
403avec le codeQUOTA_EXCEEDED. - Rupture de compatibilité
#Modifier un abonnement aux notifications exige que votre offre les comprenne
PUT /v1/partner/webhooks/{webhook_id}regarde désormais l'offre de votre marque. Un appel qui passait la veille pour une marque dont l'offre ne comprend pas les notifications est refusé en403.Détail
JSON { "detail": { "code": "FEATURE_NOT_AVAILABLE", "feature": "webhooks" } }Une extinction seule fait exception : envoyer
is_activeàfalseet rien d'autre reste possible sans l'offre. Dès qu'un autre champ accompagne cette extinction, l'API exige l'offre.La création d'un abonnement,
POST /v1/partner/webhooks, répond la même chose et l'exigeait déjà avant ce changement.Ce que vous faites. Rien si votre offre comprend les notifications. Si elle ne les comprend plus, arrêtez de modifier vos abonnements : éteignez-les avec
is_activeàfalseseul, ou supprimez-les. - Changement
#Un corps JSON illisible répond 400
Un corps mal formé envoyé à
POST /v1/partner/mint/batchrépond maintenant400, avec un message qui rappelle les deux formats acceptés.Détail
JSON { "detail": "Corps de requete illisible : le JSON envoye est mal forme. Envoyez une liste d'objets produit en application/json, ou un fichier CSV en multipart/form-data." }Ce que vous faites. Si votre code rejoue automatiquement les réponses de la famille
5xx, ce cas ne le déclenche plus. Une requête refusée en400est à corriger, et la rejouer telle quelle donnera le même refus. - Changement
#Les huit points d'entrée à clef sont plafonnés en débit
Le plafond d'appels s'applique maintenant aux huit points d'entrée de l'API partenaire, y compris le suivi de lot et les cinq points d'entrée d'abonnement aux notifications.
Détail
Deux conséquences visibles. Au-delà du plafond, vous recevez
429avec l'en-têteRetry-After, exprimé en secondes. Quand le service de plafonnement est indisponible, vous recevez503, et l'appel n'a aucun effet : une suppression refusée ainsi ne supprime rien.Les réponses qui passent portent
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-ResetetX-RateLimit-Scope.Ce que vous faites. Lisez
X-RateLimit-Remaininget ralentissez avant d'atteindre zéro. Si vous interrogez le suivi d'un lot en boucle, espacez vos appels : c'est le point d'entrée le plus exposé à ce plafond. Traitez le503comme une indisponibilité passagère et réessayez après un délai. - Changement
#Vos abonnements aux notifications restent lisibles et supprimables quelle que soit votre offre
Lire la liste de vos abonnements, lire un abonnement et supprimer un abonnement fonctionnent quelle que soit l'offre de votre marque. Ces trois appels ne regardent pas votre offre.
Détail
L'envoi des notifications suit une autre règle : une marque dont l'offre ne comprend plus les notifications ne reçoit plus de livraison, quels que soient les abonnements encore enregistrés.
Ce que vous faites. Rien. Si votre offre ne comprend plus les notifications, vous gardez la main pour inventorier vos abonnements et pour les supprimer.
- Changement
#Les adresses sans préfixe deviennent des alias permanents
Les copies sans préfixe
/v1répondaient avec deux en-têtes qui annonçaient une fin de service au 1er septembre 2026,DeprecationetSunset. L'API n'envoie plus ces deux en-têtes. Les adresses en/v1ne les ont jamais portés.Détail
Aucune date de fin de service n'est attachée à ces adresses. Si votre intégration les appelle déjà, elle continue de fonctionner.
Ce que vous faites. Rien dans l'immédiat. Utilisez la forme
/v1pour toute nouvelle intégration : c'est la forme documentée partout sur ce site.
- Changement
#Un fichier gzip abîmé répond 400
POST /v1/partner/mint/batchaccepte un CSV compressé en gzip ou en zlib.Détail
Un fichier gzip que le serveur ne parvient pas à décompresser répond maintenant
400, avec le motif dans le message. C'est une erreur de la requête, et votre code peut la traiter comme telle.Un fichier dont le contenu une fois décompressé dépasse le plafond répond
413, et le message indique ce plafond en Mio.Ce que vous faites. Rien si vos envois sont valides. Si vous compressez à la volée, vérifiez que le flux est complet avant de l'envoyer, et découpez vos lots pour rester sous le plafond. Un lot porte au plus 500 articles.
- Changement
#Le suivi de lot rend quatre champs de plus quand la file a oublié votre lot
GET /v1/partner/mint/batch/status/{job_id}répondaitunknownau propriétaire d'un lot ancien, une fois la durée de rétention de la file écoulée. Il rend maintenant le statut réel, reconstruit à partir de la réservation enregistrée à l'envoi du lot, et il ajoute quatre champs :batch_status,items_count,success_counteterror_count.Détail
Un identifiant qui ne désigne aucun lot de votre marque répond toujours
unknown, sans rien révéler de plus.Ce que vous faites. Rien, ces champs s'ajoutent.
- Changement
#Une intervention du portail partenaire porte un niveau de preuve
POST /v1/partner-portal/interventionsenregistre désormais un niveau de preuve avec chaque intervention, dans le champproof_level.Détail
Le corps de la requête accepte un champ facultatif
proof_code. Sans lui, le niveau vautdeclared. Avec un code valide, il vautcustomer_codequand le code a été lu par le client, ouwork_orderquand il vient de l'ordre de travail de la marque. Un code refusé répond422et n'enregistre rien du tout : ni l'intervention, ni la consommation du code.Les interventions enregistrées avant cette date rendent
proof_levelvide. Une valeur vide ne vaut pasdeclared: la question n'avait pas été posée.Ce que vous faites. Si vous affichez l'historique des interventions, traitez la valeur vide comme un cas à part et n'affichez pas « déclaré » à sa place.
- Rupture de compatibilité
#Supprimer un abonnement demande de retaper son adresse
DELETE /v1/partner/webhooks/{webhook_id}exige un paramètre d'URLconfirmqui contient l'adresse exacte de l'abonnement.Détail
Sans ce paramètre, un abonnement qui vous appartient répond
400avec le codeCONFIRMATION_REQUIRED. Avec une valeur qui ne correspond pas, la réponse est400avec le codeCONFIRMATION_MISMATCH, et l'API ne modifie rien. Une suppression réussie répond204.Un identifiant qui ne désigne aucun abonnement de votre marque répond
404, que vous ayez envoyéconfirmou non : l'API cherche votre abonnement avant de regarder votre confirmation.Un appel qui n'envoyait que l'identifiant est donc refusé.
Ce que vous faites. Lisez l'adresse avec
GET /v1/partner/webhooks/{webhook_id}, puis renvoyez-la dansconfirm.curl curl -X DELETE \ "https://api.sealtrust.io/v1/partner/webhooks/1?confirm=https%3A%2F%2Fexemple-sas.example%2Fwebhooks%2Fsealtrust" \ -H "Authorization: Bearer st_live_0000000000000000000000000000000000000000000000" - Changement
#Chaque livraison porte le type d'événement
Chaque livraison porte maintenant
X-Webhook-Event, qui nomme le type d'événement. La signature ne couvre pas cet en-tête.Détail
Ce que vous faites. Rien, cet en-tête s'ajoute.
- Changement
#Deux en-têtes s'ajoutent à chaque livraison
Chaque livraison porte maintenant
X-Webhook-IdetX-Webhook-Timestamp, en plus deX-Webhook-Signature.Détail
X-Webhook-Idest l'empreinte du corps de la livraison. Les réessais d'une même livraison portent la même valeur, ce qui vous permet d'écarter un réessai. Deux événements distincts dont le corps est identique portent eux aussi la même valeur.Ce que vous faites. Dédoublonnez sur le couple formé du nom de l'événement, porté par
X-Webhook-Eventdepuis le 11 août 2026, et deX-Webhook-Id. N'écartez jamais une livraison sur la valeur deX-Webhook-Timestamp: cet horodatage change à chaque réessai, donc il vous ferait traiter deux fois la même livraison. - Changement
#La signature porte les octets exacts qui vous sont envoyés
X-Webhook-Signaturea la formet=<horodatage>,v1=<empreinte>. L'empreinte est un HMAC-SHA256 calculé avec le secret de votre abonnement, sur la chaîne formée de l'horodatage, d'un point, et du corps de la requête.Détail
Le corps signé est la suite d'octets reçue sur le fil. Décoder le JSON puis le réencoder avant de vérifier casse la signature, parce que le réencodage ne rend pas les mêmes octets.
Ce que vous faites. Vérifiez la signature sur le corps brut de la requête, avant tout décodage.
- Changement
#Les points d'entrée d'abonnement exigent des droits
Lister vos abonnements et en lire un exigent le droit
webhooks:read. Créer, modifier et supprimer un abonnement exigent le droitwebhooks:write.Détail
Une clef qui ne porte pas le droit reçoit
403, et le message nomme le droit manquant.Ce que vous faites. Vérifiez les droits de la clef qui gère vos abonnements. Si elle a été créée avec le seul droit
mint:batch, créez une nouvelle clef portant aussi les droits de notification.
- Changement
#Le préfixe
/v1apparaîtChaque point d'entrée métier devient joignable à deux adresses, avec le préfixe
/v1et sans aucun préfixe.Détail
Les adresses sans préfixe répondent en plus deux en-têtes,
Deprecation: trueetSunset: 2026-09-01. Les adresses en/v1ne les portent pas. L'entrée du 16 août 2026 retire ces deux en-têtes et aucune date de fin de service n'a été appliquée.Ce que vous faites. Rien. Les deux adresses appellent le même code.
#Ce que cette page ne fait pas
Elle n'annonce pas les changements à venir. Une entrée arrive ici quand le comportement décrit est en service.
Elle ne remplace pas un essai. Nous n'ouvrons aucun environnement de test aux partenaires, et aucune adresse de bac à sable n'existe. Après avoir lu une entrée marquée rupture, rejouez votre appel réel sur un produit ou un abonnement de votre marque que vous pouvez sacrifier, et comparez le code de réponse à celui que vous attendiez.
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.