Méthode POST/partner/mint/batch

Envoyer un lot de lignes de produits, en JSON ou en CSV, jusqu'à 500 lignes par appel. Droit mint:batch. Les produits créés par cette voie sont identifiés par QR.

Sur cette page

Vous envoyez un lot de lignes de produits, et vous recevez un identifiant de lot. Nous répondons dès que nous acceptons le lot, avant tout traitement. Vous suivez ensuite l'avancement avec GET /v1/partner/mint/batch/status/{job_id}. Lisez l'avertissement ci-dessous avant de lire ce suivi.

Adresse complète :

HTTP
POST https://api.sealtrust.io/v1/partner/mint/batch

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

#Autorisation

Envoyez votre clef d'API dans l'en-tête Authorization, au format Bearer. La clef doit porter le droit mint:batch. Une clef qui ne porte pas ce droit reçoit un 403 dont le message nomme le droit manquant.

Trois conditions s'ajoutent au droit de la clef.

  • L'offre de votre marque doit comprendre l'accès API. Sinon vous recevez un 403 portant le code FEATURE_NOT_AVAILABLE.
  • L'offre de votre marque doit autoriser l'identification par QR. C'est la méthode que le serveur pose sur chaque ligne de ce point d'entrée. Une offre qui ne l'autorise pas reçoit un 403 portant le code AUTH_METHOD_NOT_ALLOWED.
  • Toutes les lignes du lot doivent porter le numéro de marque de la clef. Une seule ligne portant un autre numéro fait refuser le lot entier en 403.

#Plafond d'appels

Nous mesurons le débit sur une fenêtre fixe de 60 secondes. Nous appliquons d'abord la valeur posée sur votre compte, si nous en avons posé une. Sinon celle de votre offre. En l'absence des deux, la valeur de repli est de 120 appels par fenêtre.

Deux compteurs se superposent, avec le même plafond : un par clef, un pour la somme de toutes les clefs de votre marque. Créer des clefs supplémentaires n'augmente donc pas le débit total autorisé.

Dès que nous reconnaissons votre clef, la réponse porte quatre en-têtes. Ils décrivent le compteur le plus contraignant des deux. Un refus d'authentification arrive avant le comptage et ne porte aucun de ces en-têtes.

En-têteContenu
X-RateLimit-Limitle plafond appliqué sur la fenêtre
X-RateLimit-Remainingce qu'il vous reste dans la fenêtre en cours
X-RateLimit-Resetl'horodatage de fin de la fenêtre, en secondes
X-RateLimit-Scopekey ou brand, le compteur qui a servi de référence

Un refus de débit renvoie 429. Il porte ces quatre en-têtes, décrivant cette fois le compteur qui a refusé, et il ajoute Retry-After, exprimé en secondes restantes dans la fenêtre en cours. Cette valeur n'est jamais inférieure à 1.

Deux autres plafonds peuvent refuser le même appel : le quota quotidien de votre clef, qui se consomme par article, et le quota mensuel de produits de votre offre. Vous les retrouvez dans le tableau des erreurs, plus bas.

#Paramètres de chemin et de requête

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

#En-têtes

NomTypeObligatoireDescription
AuthorizationstringouiBearer suivi de votre clef d'API.
Content-Typestringouiapplication/json pour un lot en JSON, multipart/form-data pour un fichier CSV.
Idempotency-KeystringnonVotre propre identifiant d'appel. Nous le mémorisons 24 heures. Voir la section sur le rejeu.

#Corps de la requête

Vous envoyez le lot dans l'un des deux formats. Le contenu est le même dans les deux cas.

  • JSON : envoyez une liste d'objets. Un objet seul, un nombre ou une chaîne au premier niveau fait échouer la requête en 400.
  • CSV : envoyez un fichier en multipart/form-data, sous le champ de formulaire nommé exactement file. Encodez le fichier en UTF-8. Vous pouvez laisser la marque d'ordre d'octets en tête de fichier, nous la retirons. Un fichier encodé autrement fait échouer l'appel en 500. Dans un tableur, choisissez l'export « CSV UTF-8 ». Nous retirons les espaces de bord des cellules avant de valider.

Vous pouvez compresser le fichier CSV en gzip ou en zlib, nous le décompressons. Si le contenu décompressé dépasse environ 20 Mio, vous recevez un 413.

Un lot compte au maximum 500 articles. Nous refusons un lot vide en 400.

#Champs d'une ligne

Une ligne accepte cinq champs, et cinq seulement.

NomTypeObligatoireDescription
product_namestringouiLe nom du produit.
brand_idintegerouiLe numéro de votre marque. Il doit être identique sur toutes les lignes et correspondre à la marque de la clef.
category_idintegerouiLe numéro de la catégorie du produit. La catégorie doit exister.
metadata_uristringouiL'adresse des métadonnées du produit.
external_refstringnonVotre propre référence. Nous la conservons sur la ligne du lot. Aucun point d'entrée partenaire ne vous la rend : le suivi de lot ne la contient pas, et le produit créé ne la porte pas, aucun champ de produit ne la reprend. Vous la retrouvez uniquement dans le rapport d'erreur 400 d'un envoi CSV, qui nomme la ligne refusée.

En CSV, l'en-tête doit contenir au minimum les quatre colonnes obligatoires. L'ordre des colonnes est libre.

Le serveur n'ignore aucun champ. Tout champ que ce tableau ne nomme pas fait échouer la ligne, et donc le lot, en 400.

#Rejouer un appel sans doubler son effet

Vous pouvez envoyer un en-tête Idempotency-Key. Il est facultatif. Nous le mémorisons 24 heures.

  • Rejouez la même clef d'idempotence avec le même lot, et vous recevez la réponse du premier appel, sans qu'un second traitement démarre.
  • Rejouez la même clef d'idempotence avec un lot différent, et vous recevez un
    1. Ce comportement date du 20/08/2026. Auparavant, le second lot n'était jamais traité et rien ne le signalait.
  • Rejouez une clef d'idempotence dont l'appel est encore en cours de traitement, et vous recevez aussi un 409. Ce verrou expire de lui-même au bout de 60 secondes.

Nous comparons deux lots sur leur contenu une fois lu et normalisé. L'ordre des lignes, l'ordre des colonnes, le choix entre CSV et JSON et les cellules vides n'y changent rien.

#Requête d'exemple

Un lot de deux articles, en JSON.

curl -i -X POST https://api.sealtrust.io/v1/partner/mint/batch \
  -H "Authorization: Bearer st_test_0000000000000000000000000000000000000000000000" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: lot-exemple-0001" \
  -d '[
    {
      "product_name": "Sac Exemple 001",
      "brand_id": 12,
      "category_id": 3,
      "metadata_uri": "ipfs://exemple-metadonnees-0001",
      "external_ref": "EX-0001"
    },
    {
      "product_name": "Sac Exemple 002",
      "brand_id": 12,
      "category_id": 3,
      "metadata_uri": "ipfs://exemple-metadonnees-0002",
      "external_ref": "EX-0002"
    }
  ]'

Le même lot en CSV, envoyé en multipart/form-data. Le fichier lot.csv contient :

lot.csv
product_name,brand_id,category_id,metadata_uri,external_ref
Sac Exemple 001,12,3,ipfs://exemple-metadonnees-0001,EX-0001
Sac Exemple 002,12,3,ipfs://exemple-metadonnees-0002,EX-0002

Le SDK TypeScript n'expose pas l'envoi CSV. L'onglet TypeScript ci-dessous appelle donc directement le point d'entrée.

curl -i -X POST https://api.sealtrust.io/v1/partner/mint/batch \
  -H "Authorization: Bearer st_test_0000000000000000000000000000000000000000000000" \
  -H "Idempotency-Key: lot-exemple-0001" \
  -F "file=@lot.csv;type=text/csv"

#Réponse d'exemple

Code HTTP 200OK

Code HTTP 200.

JSON
{
  "job_id": "0000a1b2c3d4e5f6",
  "status": "queued",
  "items_count": 2,
  "brand_id": 12
}

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

ChampTypeDescription
job_idstringL'identifiant du lot. Passez-le à GET /v1/partner/mint/batch/status/{job_id}.
statusstringVaut toujours queued sur cette réponse.
items_countintegerLe nombre de lignes acceptées dans le lot.
brand_idintegerLe numéro de votre marque.

status: "queued" veut dire que nous avons accepté le lot et qu'il attend son traitement. Nous n'avons encore rien traité à ce moment. Suivez la suite avec GET /v1/partner/mint/batch/status/{job_id}.

#Erreurs

Le corps d'une réponse d'erreur porte un champ detail. Selon le cas, ce champ contient une phrase ou un objet.

Un refus qui porte une phrase, ici le lot vide, code HTTP 400 :

JSON
{
  "detail": "Batch vide (aucun item)"
}

Un refus qui porte un objet, ici un en-tête CSV incomplet, code HTTP 400 :

JSON
{
  "detail": {
    "error": "Colonnes manquantes",
    "missing": ["category_id", "metadata_uri"]
  }
}
CodeConditionQue faire
400Le corps JSON envoyé est mal formé.Vérifiez que vous envoyez du JSON valide, ou un fichier CSV en multipart/form-data.
400Le corps JSON n'est pas une liste au premier niveau.Enveloppez votre objet dans une liste, même pour un article seul.
400Une ou plusieurs lignes JSON sont invalides. detail vaut {"error": "JSON invalide", "rows": [...]}, chaque entrée portant l'index de la ligne fautive et la raison.Corrigez les lignes signalées. Le premier objet de la liste porte l'index 1. Aucune ligne du lot n'a été traitée.
400Le fichier CSV est vide ou n'a pas de ligne d'en-tête. detail vaut {"error": "CSV vide ou sans en-têtes"}.Ajoutez la ligne d'en-tête.
400Une colonne obligatoire manque dans l'en-tête CSV. detail vaut {"error": "Colonnes manquantes", "missing": [...]}.Ajoutez les colonnes nommées dans missing. Le fichier n'a pas été lu au-delà de son en-tête.
400Une ou plusieurs lignes CSV sont invalides. detail vaut {"error": "CSV invalide", "rows": [...]}, chaque entrée portant la line du fichier, son external_ref et la raison.Corrigez les lignes signalées. La première ligne de données porte le numéro 2.
400Le fichier gzip envoyé est illisible.Renvoyez le fichier, ou envoyez-le sans compression.
400Le lot est vide.Envoyez au moins une ligne.
400Le lot dépasse 500 lignes. Le message donne le nombre reçu et le plafond.Découpez votre envoi en plusieurs appels de 500 lignes au maximum.
400Un ou plusieurs category_id ne correspondent à aucune catégorie. Le message liste les numéros introuvables.Corrigez les numéros de catégorie. La liste des catégories est visible dans la console.
401L'en-tête Authorization est absent. La réponse porte aussi WWW-Authenticate: Bearer.Ajoutez l'en-tête.
401L'en-tête Authorization ne commence pas par Bearer suivi d'un espace. La réponse porte aussi WWW-Authenticate: Bearer.Corrigez la forme de l'en-tête.
401La valeur envoyée après Bearer est vide ou fait moins de 40 caractères.Envoyez le secret complet, sans espace ni retour à la ligne.
401La clef envoyée est inconnue.Vérifiez que vous utilisez une clef de cet environnement, et qu'elle n'a pas été recréée.
403La clef n'est plus active, parce qu'elle a été révoquée. Le message donne son état.Créez une nouvelle clef dans la console.
403La clef a atteint sa date d'expiration.Créez une nouvelle clef. L'ancienne ne redeviendra jamais valide.
403La clef ne porte pas le droit mint:batch. Le message nomme le droit manquant.Créez une clef portant ce droit. Les droits d'une clef existante ne se modifient pas.
403L'offre de votre marque ne comprend pas l'accès API. detail vaut {"code": "FEATURE_NOT_AVAILABLE", "feature": "api_access"}.Contactez-nous pour ouvrir ce droit sur votre offre. Réessayer ne changera rien.
403L'offre de votre marque n'autorise pas l'identification par QR, qui est la méthode posée par ce point d'entrée. detail porte le code AUTH_METHOD_NOT_ALLOWED.Contactez-nous pour ouvrir le QR sur votre offre. Réessayer ne changera rien.
403Au moins une ligne porte un brand_id différent de celui de la clef. Le message donne le numéro attendu et le nombre de lignes fautives.Corrigez les lignes. Aucune ligne du lot n'a été traitée.
403Le lot ferait dépasser le quota mensuel de produits de votre offre. detail vaut {"code": "QUOTA_EXCEEDED", "resource": "products", "current": ..., "additional": ..., "max": ..., "period": "monthly"}.Attendez la période suivante, réduisez la taille du lot, ou contactez-nous pour changer d'offre. Ce refus ne consomme pas le quota quotidien de votre clef.
409La clef d'idempotence a déjà servi pour un lot différent dans les 24 dernières heures.Utilisez une nouvelle clef d'idempotence pour ce lot. Ce lot n'a pas été traité.
409Un appel portant la même clef d'idempotence est en cours de traitement.Attendez la réponse du premier appel, puis relisez son résultat. Le verrou expire au bout de 60 secondes.
413Le fichier compressé dépasse environ 20 Mio une fois décompressé.Découpez votre fichier. Un lot de 500 lignes reste très en dessous de ce plafond.
429Le plafond de débit de la clef est atteint. Retry-After et la famille X-RateLimit-* accompagnent la réponse, avec X-RateLimit-Scope: key.Attendez le nombre de secondes indiqué par Retry-After, puis réessayez.
429Le plafond de débit de la marque est atteint, toutes clefs confondues. X-RateLimit-Scope vaut brand.Attendez le nombre de secondes indiqué par Retry-After. Créer une clef supplémentaire ne relève pas ce plafond.
429Le quota quotidien de la clef est atteint. Les en-têtes X-Quota-Limit, X-Quota-Remaining et X-Quota-Reset accompagnent la réponse.Attendez le passage de minuit en temps universel, ou faites relever le quota de la clef. Le quota se consomme par article : un lot de 100 lignes en consomme 100.
500Le fichier CSV envoyé n'est pas encodé en UTF-8.Réenregistrez le fichier en UTF-8. Dans un tableur, choisissez l'export « CSV UTF-8 ».
500Votre liste JSON contient un élément qui n'est pas un objet, par exemple une chaîne ou un nombre.Envoyez une liste dont chaque élément est un objet portant les champs décrits plus haut.
500Un category_id hors des bornes que la base accepte.Envoyez des numéros de catégorie visibles dans la console.
500La marque rattachée à votre clef est introuvable.Contactez-nous en indiquant l'heure de l'appel.
500Une erreur inattendue s'est produite pendant le traitement de votre appel.Réessayez. Si l'erreur persiste, contactez le support en indiquant l'heure de l'appel.
503Le service de plafonnement des appels est momentanément indisponible. Nous refusons alors l'appel.Réessayez dans quelques instants. Aucune ligne n'a été traitée.

#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