Erreurs de l'API

Lire n'importe quelle réponse d'erreur de l'API SealTrust, reconnaître le code renvoyé, décider s'il faut corriger la requête ou la rejouer, et retrouver un appel précis quand vous nous écrivez.

Sur cette page

En quittant cette page, vous saurez lire n'importe quelle réponse d'erreur de l'API SealTrust. Vous reconnaîtrez le code renvoyé, vous déciderez s'il faut corriger votre requête ou la rejouer telle quelle, et vous retrouverez un appel précis dans nos journaux quand vous nous écrivez.

Cette page se lit en entier une fois, au moment où vous écrivez votre client. Elle sert ensuite de catalogue.

#Toutes les erreurs ont la même forme

Le corps d'une réponse d'erreur contient un seul champ : detail. Sa valeur prend trois formes, et vous devez savoir gérer les trois.

Une phrase. C'est la forme la plus courante. Le texte s'adresse à un lecteur humain.

401 Unauthorized
{
  "detail": "Invalid API key"
}

Un objet qui porte un code. Certains refus liés à votre offre et certaines confirmations de suppression renvoient un objet. Le champ code est stable. Le champ message change au fil des versions.

403 Forbidden
{
  "detail": {
    "code": "QUOTA_EXCEEDED",
    "resource": "products",
    "current": 4820,
    "additional": 200,
    "max": 5000,
    "period": "monthly"
  }
}

Une liste. Quand la validation du corps ou des paramètres échoue, detail est une liste. Chaque entrée décrit une valeur refusée.

Clef de l'entréeCe qu'elle contient
locle chemin de la valeur fautive, sous forme de liste, par exemple ["body", "retailer_code"] ou ["query", "page"]
typele nom de la règle non respectée, par exemple less_than_equal
msgla phrase lisible qui explique le refus

Selon la règle non respectée, une entrée peut porter des clefs supplémentaires. Lisez loc et type. Ne comparez jamais msg caractère par caractère.

#Les en-têtes qui accompagnent une réponse

#X-Request-Id, l'identifiant de chaque appel

Chaque réponse de l'API porte un en-tête X-Request-Id. Si votre requête en envoie un, c'est le vôtre qui est repris. Sinon nous en fabriquons un.

Enregistrez cette valeur à côté de chaque appel qui échoue. Quand vous nous écrivez au sujet d'un refus, donnez-la : elle nous mène directement à l'appel concerné.

Envoyer votre propre identifiant de requête
curl -sS -D - -o /dev/null \
  -X POST https://api.sealtrust.io/v1/partner/sellout \
  -H "Authorization: Bearer st_test_0000000000000000000000000000000000000000000000" \
  -H "Content-Type: application/json" \
  -H "X-Request-Id: exemple-sas-2026-08-20-0001" \
  -d '{"identifier": "DEM000000000", "retailer_code": "BTQ-EXEMPLE-01"}'

#Les en-têtes de budget

Un appel authentifié par clef d'API porte les compteurs de débit dans sa réponse, y compris quand la route refuse ensuite. Un 400, un 403 dû à votre offre, à votre quota ou à une marque qui ne correspond pas, vous disent donc quel budget de débit il vous reste.

Trois familles de refus ne portent aucun compteur : les 401, les 403 de clef révoquée ou expirée, et les 403 de droit manquant sur la clef. Testez la présence de l'en-tête avant de lire sa valeur.

En-têteCe qu'il vaut
X-RateLimit-Limitle plafond d'appels de la fenêtre en cours
X-RateLimit-Remainingle nombre d'appels encore acceptés dans cette fenêtre
X-RateLimit-Resetl'horodatage Unix, en secondes, de la fin de la fenêtre
X-RateLimit-Scopekey si le compteur le plus serré est celui de la clef, brand si c'est celui de la marque
Retry-Afterprésent sur un refus de débit, le nombre de secondes à attendre, jamais inférieur à 1
X-Quota-Limitle quota journalier de la clef. Présent uniquement sur le refus 429 du quota journalier
X-Quota-Remainingce qu'il en reste aujourd'hui. Présent uniquement sur le refus 429 du quota journalier
X-Quota-Resetla date, au format ISO 8601, de la dernière remise à zéro du compteur. Présent uniquement sur le refus 429 du quota journalier. La remise à zéro suivante a lieu au passage de minuit en temps universel
WWW-Authenticatevaut Bearer sur les refus 401 dus à un en-tête Authorization absent ou mal formé

Un appel qui réussit ne vous dit pas combien de quota journalier il vous reste. Les trois en-têtes X-Quota-* n'existent que sur le refus 429 du quota. Pour suivre ce compteur avant de le heurter, ouvrez la liste des clefs d'API dans la console : elle affiche, pour chaque clef, la consommation du jour sur son quota.

#Le catalogue, code par code

#400, votre requête est mal formée

Le serveur a compris la requête et la refuse. Corrigez la requête. La rejouer telle quelle donnera le même résultat.

Conditiondetail renvoyéCe que vous devez faire
Le fichier CSV est vide ou n'a pas de ligne d'en-tête{"error": "CSV vide ou sans en-têtes"}envoyez un fichier dont la première ligne nomme les colonnes
Une colonne obligatoire manque à l'en-tête CSV{"error": "Colonnes manquantes", "missing": ["category_id"]}ajoutez les colonnes nommées dans missing
Des lignes du CSV sont invalidesun objet dont error vaut CSV invalide et dont rows liste chaque ligne fautivecorrigez chaque ligne signalée, voir juste après ce tableau
Des objets du JSON sont invalidesun objet dont error vaut JSON invalide et dont rows liste chaque objet fautifcorrigez chaque objet signalé, voir juste après ce tableau
Le corps JSON n'est pas une liste"Le JSON doit être une liste d'objets"encadrez vos objets par des crochets
Le corps JSON est illisible"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."vérifiez que vous envoyez du JSON valide, ou passez au CSV en multipart
Le lot dépasse 500 articles"Batch trop volumineux : 640 items (max 500)"découpez en plusieurs appels de 500 articles au maximum
Le lot ne contient aucun article"Batch vide (aucun item)"n'envoyez pas de lot vide
Une catégorie citée n'existe pas"Catégories introuvables : [77, 91]"corrigez les category_id nommés
Le fichier gzip envoyé est abîméune phrase qui commence par Fichier gzip illisible : et donne le motif techniquerecompressez le fichier, ou envoyez-le sans compression
La suppression d'un abonnement n'apporte pas de confirmationun objet dont code vaut CONFIRMATION_REQUIRED, accompagné de message et de what_to_typeajoutez le paramètre confirm égal à l'adresse exacte de l'abonnement
La confirmation de suppression ne correspond pasun objet dont code vaut CONFIRMATION_MISMATCH, accompagné de message et de what_to_typerecopiez l'adresse telle que la lecture de l'abonnement la renvoie. Rien n'a été supprimé
Un GTIN mal formé est passé à une route GS1"Invalid GTIN"vérifiez que le segment ne contient que des chiffres et n'en dépasse pas quatorze
Une empreinte d'article mal formée est passée à l'historique"Invalid UID hash format (must be 0x + 64 hex characters)"envoyez 0x suivi de 64 caractères hexadécimaux

Les erreurs de lignes vous sont rendues toutes en même temps. Vous corrigez tout en un passage.

400 Bad Request, lot envoyé en CSV
{
  "detail": {
    "error": "CSV invalide",
    "rows": [
      {
        "line": 2,
        "external_ref": "EX-0001",
        "error": "brand_id: Input should be a valid integer"
      }
    ]
  }
}

Le champ line est le numéro de ligne dans le fichier. La première ligne de données porte le numéro 2, puisque la ligne 1 est l'en-tête.

En JSON, la forme change : la position s'appelle index et commence à 1, et external_ref n'est pas repris.

400 Bad Request, lot envoyé en JSON
{
  "detail": {
    "error": "JSON invalide",
    "rows": [
      {
        "index": 1,
        "error": "metadata_uri: Field required"
      }
    ]
  }
}

#401, l'API ne sait pas qui vous êtes

Votre requête n'a pas d'identité valide. Corrigez l'en-tête Authorization. Les deux premières lignes du tableau portent l'en-tête WWW-Authenticate: Bearer.

Conditiondetail renvoyéCe que vous devez faire
L'en-tête Authorization est absent"Missing Authorization header"ajoutez Authorization: Bearer <votre clef>
L'en-tête ne commence pas par Bearer "Invalid Authorization header format (expected 'Bearer <token>')"respectez le mot Bearer, un espace, puis la clef
La valeur envoyée n'a pas la forme d'une clef"Invalid API key format"vérifiez que la clef a été copiée en entier
La clef ne correspond à aucune clef connue"Invalid API key"la clef est fausse ou a été supprimée. Créez-en une nouvelle depuis la console de votre marque
Un niveau d'accès professionnel au passeport est demandé sans compte connecté"Professional-tier access requires authentication"connectez-vous, ou demandez le niveau public
Le niveau d'accès autorité est demandé sans compte connecté"Authority-tier access requires authentication"connectez-vous avec un compte d'autorité de surveillance

#403, l'API sait qui vous êtes et refuse

Votre identité est valide. Votre clef, votre offre ou votre périmètre ne couvrent pas cette opération. Rejouer la requête ne change rien.

Conditiondetail renvoyéCe que vous devez faire
La clef est révoquée"API key is revoked"utilisez une clef active
La clef a été marquée expirée"API key is expired"créez une nouvelle clef
La clef atteint sa date d'expiration pendant cet appel"API key has expired"créez une nouvelle clef. La clef bascule en expirée dès ce refus
Un droit exigé par la route manque à la clef"Missing required scopes: mint:batch"créez une clef qui porte les droits nommés
Un droit manque sur une route d'abonnement"Missing required scope: webhooks:write"créez une clef qui porte ce droit
Une ligne du lot porte une autre marque que celle de la clef"Brand mismatch: tous les items doivent appartenir à brand_id=12. Trouvé 3 items invalides."corrigez le brand_id des lignes fautives. Le lot entier est refusé
Votre offre ne comprend pas la fonction demandée{"code": "FEATURE_NOT_AVAILABLE", "feature": "api_access"}changez d'offre, ou n'appelez pas cette route
Le lot ferait dépasser le quota de produits de votre offreun objet dont code vaut QUOTA_EXCEEDED, détaillé juste après ce tableauattendez la période suivante, réduisez le lot, ou changez d'offre
L'identifiant de lot suivi n'est pas reconnu comme un lot de votre marque"Access denied"vérifiez que l'identifiant de lot vient bien de cette clef
Vous demandez un niveau d'accès au passeport que votre compte ne couvre pas"This tier is restricted to the product's brand, partners holding the matching accreditation, and market-surveillance authorities"demandez le niveau qui correspond à votre accréditation
Un partenaire du portail n'a aucune accréditation active"Aucune accréditation active"demandez à la marque de vous accréditer
Un partenaire du portail ouvre un produit d'une marque qui ne l'a pas accrédité"Ce produit appartient à une marque qui ne vous a pas accrédité"ce produit n'est pas dans votre périmètre
Un compte non partenaire appelle le portail partenaire"Partner account required (repairer or recycler)"utilisez un compte de type réparateur ou recycleur

L'objet QUOTA_EXCEEDED porte de quoi décider sans nous écrire :

403 Forbidden
{
  "detail": {
    "code": "QUOTA_EXCEEDED",
    "resource": "products",
    "current": 4820,
    "additional": 200,
    "max": 5000,
    "period": "monthly"
  }
}

#404, la ressource n'existe pas pour vous

Sur les points d'entrée publics et sur l'API à clef, un objet qui existe hors de votre périmètre répond 404, exactement comme un objet inexistant. Un point de vente d'une autre marque, un abonnement d'une autre marque, un produit d'une autre marque : la réponse est la même que pour un identifiant inventé.

Le portail partenaire fait exception. Quand le produit existe chez une marque qui ne vous a pas accrédité, il répond 403 et le dit, au lieu de 404.

Conditiondetail renvoyéCe que vous devez faire
Le code de point de vente est inconnu, inactif, ou d'une autre marque"Retailer 'BTQ-EXEMPLE-01' not found for this brand"créez le point de vente, ou activez-le, avant de déclarer la vente
L'identifiant de produit ne correspond à rien"Product not found for this identifier"vérifiez l'empreinte d'étiquette, l'identifiant de jeton ou le numéro de certificat
L'abonnement demandé n'existe pas ou appartient à une autre marque"Webhook subscription not found"listez vos abonnements pour retrouver le bon identifiant
Le produit demandé n'existe pas"Product not found"vérifiez l'identifiant
Le produit existe et n'a aucun passeport publié"No published passport found for this product"publiez le passeport depuis la console
Le lien GS1 ne mène à rien"Unknown GS1 Digital Link"vérifiez le GTIN et, s'il y en a un, le numéro de série
Aucun certificat n'a été émis pour ce produit"No certificate found for this product"émettez le certificat avant de le demander
Le produit n'appartient à aucun lot ancré"No Merkle anchor for this product"la preuve d'ancrage n'existe pas pour cet article
Un partenaire du portail ouvre un produit inexistant"Produit introuvable"vérifiez l'identifiant lu sur le produit

#409, l'état actuel interdit cette opération

La requête est correcte. Elle entre en conflit avec ce qui existe déjà.

Conditiondetail renvoyéCe que vous devez faire
La même clef d'idempotence a déjà servi pour un lot différent"Idempotency-Key 'exemple-lot-001' was already used with a different request body"changez de clef d'idempotence pour ce nouveau lot
Un appel portant la même clef d'idempotence est en cours de traitement"A request with this Idempotency-Key is already being processed"attendez quelques secondes, puis relisez le résultat du premier appel
Un scellé NFC est lu sur un article dont la frappe est partie et n'est pas confirmée"MINT_PENDING: mint submitted, waiting for on-chain confirmation."réessayez dans quelques minutes, la situation se résout seule
Un scellé NFC est lu sur un article jamais frappé"MINT_NOT_SUBMITTED: this product has not been minted yet."la frappe n'a pas eu lieu. Réessayer ne changera rien, reprenez la création de l'article
La preuve d'ancrage d'un lot ne peut pas être servie en l'étatune phrase qui dit que le lot doit être ancré de nouveaurejouer ne résout pas ce refus. La preuve ne pourra être servie qu'après un nouvel ancrage du lot, que nous seuls déclenchons. Relevez le X-Request-Id et signalez-le nous

Les deux messages du scellé NFC commencent par un code en majuscules suivi de deux points. Testez ce préfixe. La phrase qui suit peut être reformulée.

#413, l'envoi est trop gros

Conditiondetail renvoyéCe que vous devez faire
Un CSV compressé dépasse environ 20 Mio une fois décompressé"Fichier compresse trop volumineux une fois decompresse (plafond 20 Mio)"découpez le fichier. Un lot ne dépasse de toute façon pas 500 articles

#422, l'API refuse une valeur que vous avez envoyée

C'est le code des paramètres et des corps de requête que le serveur sait lire et refuse. Le champ detail est alors une liste, sauf mention contraire dans le tableau.

ConditionCe que vous devez faire
Un champ obligatoire manque au corps d'une requête JSONajoutez le champ nommé dans loc
Un champ hors contrat est envoyé à la déclaration de vente ou à un abonnementretirez le champ. Ces corps refusent tout champ non prévu
L'adresse d'un abonnement ne commence pas par https://, ou sort des bornes de 10 à 2048 caractèrescorrigez l'adresse
Un type d'événement inconnu est demandé à l'abonnementreprenez un nom de la liste des événements souscriptibles
Un paramètre de pagination sort de ses bornesramenez skip à 0 ou plus, et limit entre 1 et 100
Une valeur de filtre ou de pagination sort du domaine que la route accepte. detail est alors une phraseramenez la valeur dans les bornes documentées de la route
Une empreinte de puce mal formée est envoyée à la vérification d'originalité. detail est alors une phrase, par exemple "uid_hex doit faire 7 ou 10 octets"corrigez la valeur nommée dans le message
Un partenaire du portail déclare un type d'intervention non couvert par ses accréditations. detail est alors une phrase qui liste les types autorisésdéclarez un type figurant dans la liste rendue
Un code de garde présenté par un partenaire est refusé. detail est alors une phrasel'intervention n'a pas été enregistrée et le code n'a pas été consommé. Redemandez un code valide

#429, vous appelez trop souvent

Quatre compteurs différents rendent ce code. Les en-têtes vous disent lequel a refusé.

CompteurComment le reconnaîtreCe que vous devez faire
Le débit de votre clefX-RateLimit-Scope: key et Retry-Afterattendez le nombre de secondes annoncé, puis rejouez la requête à l'identique
Le débit de votre marque, toutes clefs confonduesX-RateLimit-Scope: brand et Retry-Afterralentissez l'ensemble de vos intégrations. Créer des clefs supplémentaires n'augmente pas ce plafond
Le quota journalier de votre clefles en-têtes X-Quota-Limit, X-Quota-Remaining et X-Quota-Reset, et l'absence de Retry-Afterattendez la remise à zéro, au passage de minuit en temps universel. Le quota journalier se fixe à la création de la clef et ne se modifie plus. Si le besoin est régulier, créez une nouvelle clef avec un quota plus haut, basculez votre intégration dessus, puis révoquez l'ancienne
Le plafond par adresse sur les routes publiques de vérification"Rate limit exceeded: 30 requests per 60s". Le nombre annoncé est celui du chemin que vous avez appeléespacez vos lectures. Les chemins /passport, /certificate et /resolve acceptent 60 appels par minute et par adresse. Les chemins /qr, /verify, /timeline et /sdm en acceptent 30. Chaque famille de chemins a son propre compteur, et le préfixe /v1 ne crée pas un second budget

Un refus de plafond public porte Retry-After, en secondes. Le refus de /timeline fait exception et ne porte pas cet en-tête. Sa fenêtre est fixe et dure 60 secondes : attendez ce délai avant de rappeler.

Le refus du débit d'une clef d'API nomme le plafond qui a refusé et sa fenêtre :

429 Too Many Requests
{
  "detail": "Rate limit exceeded: 120 requests per 60 seconds"
}

Quand c'est le plafond de la marque qui refuse, la phrase le dit, elle donne le plafond de la marque, et elle précise que cette clef reste sous son propre plafond. L'en-tête X-RateLimit-Scope vaut alors brand.

Le dépassement du quota journalier prend une autre forme :

429 Too Many Requests
{
  "detail": "Quota exceeded. Remaining today: 0/1000"
}

#500, la panne est de notre côté

Votre requête n'a rien de fautif. Ne la corrigez pas. Relevez le X-Request-Id de la réponse, rejouez une fois après quelques secondes, et signalez-nous cet identifiant si le refus persiste.

Le corps d'un 500 n'a pas de forme garantie. N'écrivez aucune logique contre son contenu. Branchez-vous sur le statut 500 et sur rien d'autre.

500 Internal Server Error
{
  "detail": "Internal Server Error"
}

Sur une opération qui écrit, comme la frappe d'un lot, considérez le résultat comme inconnu. Rejouez avec la même valeur d'Idempotency-Key que le premier appel : soit le premier appel avait abouti et vous recevez sa réponse, soit il n'avait rien créé et le lot part.

#503, l'API refuse l'appel sans rien modifier

Conditiondetail renvoyéCe que vous devez faire
Le comptage des appels est momentanément indisponible"Rate limiting temporarily unavailable, please retry shortly"attendez quelques secondes et rejouez. Rien n'a été lu ni modifié
La lecture en chaîne a échoué pendant une vérification"Error during blockchain verification"réessayez plus tard. Le produit n'est pas déclaré faux pour autant

#Une réponse 200 peut vouloir dire non

Six points d'entrée répondent 200 sur un cas que vous devez traiter comme un refus. Un client qui ne regarde que le code HTTP les manque tous les six. Pour chacun, le champ à lire est nommé ci-dessous.

La vérification publique d'un QR. GET /qr/verify répond 200 avec "valid": false dans cinq situations. Le champ message dit laquelle s'applique. Lisez toujours valid.

Valeur de messageCe que cela veut dire
Invalid product: blockchain verification failed.la vérification en chaîne a échoué. C'est le seul des cinq cas qui déclare le produit non authentique
Invalid QR code signature. This QR code may be tampered with.la signature du code est fausse. Le code a été modifié, ou il ne vient pas de nous
QR code has expired. Please request a new QR code.le code a plus de 30 jours. Faites produire un nouveau QR
Mint submitted, waiting for on-chain confirmation.la frappe de l'article est partie et n'est pas encore confirmée. Réessayez dans quelques minutes
This product has not been minted yet.l'article n'a jamais été frappé. Réessayer ne changera rien
200 OK, et pourtant refusé
{
  "valid": false,
  "message": "Invalid QR code signature. This QR code may be tampered with.",
  "uid_hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "token_id": null,
  "product_name": null,
  "brand_name": null,
  "image_url": null,
  "contract_address": null,
  "scan_area": null
}

La vérification d'une signature d'originalité. POST /originality/read-sig/verify répond 200 avec "valid": false quand la signature lue sur la puce ne se vérifie pas contre la clef publique utilisée. Le champ error vaut alors signature invalide. Lisez valid.

La vérification d'intégrité d'un passeport. GET /passport/{identifier}/verify répond 200 même quand une comparaison échoue. Trois champs portent le résultat.

db_hash_match et ipfs_match valent true, false ou null. false veut dire que la comparaison a échoué. null veut dire qu'elle n'a pas pu être faite, ce qui est différent d'un échec.

seal.chain_link_match vaut true ou false, et il est absent du bloc seal quand la version du passeport n'a pas été scellée, ou quand elle a été scellée avant l'existence du chaînage. Lisez d'abord seal.sealed et seal.linked : quand les deux valent true, seal.chain_link_match est présent. C'est le champ qui dit si une version scellée a été modifiée après publication.

La vérification du justificatif vérifiable. GET /passport/{identifier}/vc/verify répond 200 avec "verified": false quand la signature du justificatif ne se vérifie pas contre la clef de la marque. Le champ error vaut alors verification_failed et credential_subject vaut null. Lisez verified.

Le suivi d'un lot. GET /v1/partner/mint/batch/status/{job_id} répond 200 avec "status": "unknown" quand le lot est introuvable, et 200 avec "status": "failed" quand il a échoué. Les valeurs que vous verrez sont queued, started, finished, failed et unknown. Bouclez sur status, et arrêtez-vous dès qu'il quitte queued et started. Ne bouclez pas sur is_finished : la réponse unknown ne porte que job_id et status, et une boucle qui attend is_finished ne s'arrêterait jamais.

La déclaration de vente. POST /v1/partner/sellout répond 200 avec "status": "already_activated" quand cet article avait déjà été déclaré vendu. Rien n'a été créé une seconde fois.

#Que rejouer, que ne pas rejouer

CodeRejouer à l'identique ?Pourquoi
400nonla requête est fautive, elle le restera
401nonil faut d'abord réparer l'en-tête d'autorisation
403nonil faut d'abord changer la clef, le droit ou l'offre
404nonl'objet n'existe pas dans votre périmètre
409 sur une clef d'idempotencenonchangez de clef, ou lisez le résultat du premier appel
409 MINT_PENDINGoui, après quelques minutesla confirmation en chaîne arrive
409 MINT_NOT_SUBMITTEDnonla frappe n'a jamais eu lieu
409 sur la preuve d'ancrage d'un lotnonil faut d'abord que le lot soit ancré de nouveau, et cela ne dépend pas de vous
413nonil faut réduire l'envoi
422nonl'API refuse une valeur que vous avez envoyée
429 de débitoui, après Retry-Afterla fenêtre de débit se libère
429 de quota journaliernon avant la remise à zéro de minuit en temps universelce refus ne porte pas de Retry-After. Le compteur ne se libère qu'au changement de jour
500une fois, avec la même clef d'idempotencele résultat de l'appel est inconnu
503oui, après quelques secondesrien n'a été modifié

Un rejeu automatique se fait avec un délai qui croît, et un nombre d'essais borné. Rejouez sur 503, sur 500, et sur les 429 qui portent un Retry-After. Sur un 429 de quota journalier, arrêtez d'appeler jusqu'au changement de jour. Sur les autres codes 4xx, corrigez la requête avant tout nouvel appel.

#Une gestion d'erreur complète, en trois langages

Ces trois programmes font la même chose : ils déclarent une vente, ils distinguent les familles d'erreur, et ils gardent l'identifiant de requête.

Exécutez ces trois programmes sur votre serveur. L'API partenaire n'accepte pas d'appel venant d'un navigateur, et une clef d'API n'a rien à faire dans du code envoyé au navigateur. Depuis un navigateur, la lecture de X-Request-Id et celle de Retry-After rendraient null : ces deux en-têtes ne sont pas exposés au code de page.

#!/usr/bin/env bash
set -u

entetes=$(mktemp)
trap 'rm -f "$entetes"' EXIT

reponse=$(curl -sS -w '\n%{http_code}' -D "$entetes" \
  -X POST https://api.sealtrust.io/v1/partner/sellout \
  -H "Authorization: Bearer st_test_0000000000000000000000000000000000000000000000" \
  -H "Content-Type: application/json" \
  -d '{"identifier": "DEM000000000", "retailer_code": "BTQ-EXEMPLE-01"}')

code=$(printf '%s' "$reponse" | tail -n 1)
corps=$(printf '%s' "$reponse" | sed '$d')
requete=$(grep -i '^x-request-id:' "$entetes" | tr -d '\r' | cut -d' ' -f2)

echo "code=$code request_id=$requete"
echo "$corps"

case "$code" in
  200) echo "vente enregistrée" ;;
  429|503) echo "réessayez plus tard" ;;
  5*) echo "panne serveur, signalez $requete" ;;
  *) echo "requête à corriger" ;;
esac

#Ce qu'il faut retenir

  • Le corps d'erreur porte toujours detail, sous trois formes : une phrase, un objet à code, ou une liste de valeurs refusées.
  • Branchez votre code sur le statut HTTP et sur detail.code. Ne comparez jamais les phrases.
  • Gardez le X-Request-Id de chaque échec. C'est ce que nous vous demanderons.
  • Rejouez sur 503, sur 500, et sur les 429 qui portent un Retry-After. Corrigez sur tout le reste.
  • Sur une écriture, rejouez avec la même valeur d'Idempotency-Key que l'appel dont vous ignorez le sort.
  • Lisez valid, verified, status et les champs de correspondance : six points d'entrée décrivent un refus dans une réponse 200.

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