Gestion des erreurs et codes d'état HTTP
Gestion des erreurs
L'API utilise des codes d'état HTTP standard et des messages d'erreur structurés au format JSON pour assurer une gestion cohérente des erreurs.
Codes d'état HTTP
| Code | Statut | Description |
|---|---|---|
| 200 | OK | Requête réussie (GET, POST, DELETE) |
| 201 | Créé | Nouvelle ressource créée (POST) |
| 400 | Requête incorrecte | Corps de requête non valide, paramètres manquants ou paramètre de requête invalide (depuis la version v2.122.10 sur chaque point de terminaison JSON, voir ci-dessous) |
| 401 | Non autorisé | Joker manquant ou non valide |
| 403 | Accès interdit | Le jeton ne dispose pas des périmètres d'accès requis |
| 404 | Introuvable | Ressource introuvable |
| 409 | Conflit | Impossible de supprimer la ressource (contrôle de sécurité) |
| 429 | Trop de requêtes | Limite de requêtes dépassée ; Retry-After indique le temps d'attente en secondes |
| 500 | Erreur interne du serveur | Erreur de serveur |
Format de réponse d'erreur
HTTP/1.1 401 Unauthorized
X-XoPort-Deny-Reason: deny_token_required
Content-Type: application/json; charset=utf-8
{
"success": false,
"api_version": "2.122.13",
"error": {
"code": "UNAUTHORIZED",
"reason": "deny_token_required",
"message": "Authentication required. JSON/REST routes always require an OAuth2 token and check its scopes; the XML_PORT_IP_FILTER whitelist does not authorize them (changed in API 2.119.0). Obtain a token via POST /oauth/token (client_credentials grant)."
}
}Les erreurs liées aux paramètres de requête comportent en outre les champs details[], param et message pour chaque erreur (exemple sur la page API d'exportation). Utilisez error.code comme valeur, et non le texte du message.
Depuis la version v2.119.0, en cas d'appel rejeté, l'API indique le motif dans le champ reason; pour le code 401, elle l'indique également dans l'en-tête X-XoPort-Deny-Reason: par exemple deny_token_required (401, appel sans jeton) ou deny_ip_not_listed (403, adresse non présente dans XOPORT_REST_IP_LIST; uniquement dans le corps).
Codes d'erreur courants
| Code | HTTP | Description |
|---|---|---|
INVALID_FILTER_VALUE | 400 | Un paramètre de requête contient une valeur invalide ou une valeur de liste (?status[]=1) ; details[] répertorie les erreurs respectives sur param et message. Depuis la version v2.122.10, cela s'applique à tous les points de terminaison JSON, y compris les opérations d'importation et de suppression ; dans ce cas, aucune donnée n'est lue, écrite ou supprimée |
INVALID_PAGINATION | 400 | limit, offset, page, sort ou order deviennent inutilisables (details[] comme ci-dessus) |
INVALID_RANGE | 400 | Forme de chemin ou segment de chemin invalide : new:{datum} à un point d’extrémité autre que « clients » et « commandes » (depuis la v2.122.10) ; dans l’export JSON depuis la v2.122.12, également un segment qui n’est ni un nombre entier, ni une plage, ni un sous-itinéraire (/product/42x, /order/42.0, /contracts/10/20). Le message mentionne le segment |
FILTER_NOT_APPLICABLE | 400 | filtre appliqué à une requête unique ou à une plage d’identifiants sur laquelle il n’a aucun effet ; depuis la v2.122.13, également ?categories_id= associé à un identifiant ou à une plage dans le chemin d’accès de la liste des produits par catégorie (/categories/5/productlist?categories_id=7, /categories/5:10/productlist?categories_id=5). Seule la valeur identique à l’identifiant du chemin d’accès unique reste autorisée |
INVALID_STATUS | 400 | status_id au point de terminaison de statut PUT /Import/JSON/contracts/{id}/status n’est pas un statut de contrat de la boutique ou n’est pas un nombre entier. Depuis la v2.122.13, error.valid_status_ids indique les ID valides ; jusqu’à la v2.122.12, le point de terminaison vérifiait par rapport aux statuts de commande |
UNKNOWN_FILTER | 200 ou 400 | Nom de paramètre inconnu lors de l’exportation : avertissement sur warnings[], avec ?_strict=true HTTP 400 |
MISSING_ID | 400 | Suppression sans ID dans le chemin d'accès ; l'ID doit figurer dans le chemin d'accès, par exemple DELETE /…/categories/99 |
UNAUTHORIZED | 401 | Joint d'accès manquant, invalide ou expiré, ou le client est désactivé ; error.reason et l'en-tête X-XoPort-Deny-Reason indiquent la raison |
IP_NOT_ALLOWED | 403 | Appel provenant d'une adresse qui ne figure pas dans XOPORT_REST_IP_LIST (depuis la v2.119.0) |
INSUFFICIENT_PERMISSIONS | 403 | Le jeton ne dispose pas de la portée requise pour le point de terminaison (message: « Required scope: … ») |
NOT_FOUND | 404 | Ressource introuvable : requête individuelle sans résultat vers /product/{id}, /products/{id} et /order_status/{id} (depuis la v2.122.10), ainsi que vers les médias, les pièces jointes aux tickets, les documents justificatifs et DELETE pour un identifiant inconnu. Les autres requêtes individuelles renvoient un code HTTP 200 et un corps de réponse vide ( data). Une URL de base erronée renvoie également un code 404 NOT_FOUND |
HAS_SUBCATEGORIES | 409 | La catégorie comporte des sous-catégories |
HAS_PRODUCTS | 409 | La catégorie contient des produits |
HAS_NEWS | 409 | La catégorie « Actualités » contient des articles |
HAS_ORDERS | 409 | Le client a passé des commandes |
RATE_LIMIT_EXCEEDED | 429 | Limite de requêtes du client dépassée ; depuis la version v2.122.11 avec error.retry_after |
Le point de terminaison des jetons POST /oauth/token répond au format OAuth2 (error, error_description), et non avec ces codes : voir « Erreur au niveau du point de terminaison des jetons » ci-dessous.
Une modification de la portée sur le client ne prend effet qu’avec le prochain jeton : un jeton déjà émis conserve les portées qui lui étaient attribuées lors de son émission jusqu’à son expiration, c’est-à-dire pendant une heure maximum. Pour révoquer immédiatement l’accès dans le backend, utilisez « Révoquer les jetons » dans le menu d’actions du client (à partir de la version 4.9.168 de la boutique) ; dans les versions antérieures, désactivez puis réactivez le client ; le secret reste inchangé. En revanche, une modification de la limite de requêtes prend effet immédiatement.
Le journal d’utilisation du client ne mentionne pas les interruptions de l’exportation avec un code HTTP 400 avant le début d’une requête (erreurs de filtrage, de navigation et de chemin d’accès), ni la réponse 429. Si vous recherchez une erreur à cet endroit, vous ne trouverez donc pas ces cas ; les codes 400 sont néanmoins pris en compte dans la limite de requêtes.
- Les valeurs invalides et les valeurs de liste des paramètres de requête génèrent un code HTTP 400 «
INVALID_FILTER_VALUE» sur chaque point de terminaison JSON (lors des opérations d’importation et de suppression, respectivement « … Nothing was written » et « … Nothing was deleted »). Jusqu’à la v2.122.9, un tel filtre était généralement ignoré, et la réponse était renvoyée sans filtrage avec un code HTTP 200. Règles et exemples : API d’exportation. GET /product/{id}et les valeurs «/products/{id}» pour un article supprimé ou jamais attribué génèrent un code HTTP 404NOT_FOUND(message « Product with id=… not found ») au lieu d’un code HTTP 200 avec un corps de réponse videdata. Si vous interrompez l’opération en cas de réponse autre qu’un code 2xx, ce cas est désormais traité comme une erreur.new:{datum}Sur un autre point de terminaison que « Clients » et « Commandes », cela renvoie un code HTTP 400INVALID_RANGE.
- Un segment de chemin invalide dans l’exportation JSON génère un code HTTP 400 «
INVALID_RANGE». Jusqu’à la version v2.122.11, le code HTTP 200 renvoyait la liste paginée, et des formats tels que1e3,4.2ou+5étaient considérés comme des identifiants. Règles et exemples : API d’exportation, section « Segment de chemin ». - Les espaces à la fin d’une valeur de requête ou d’un identifiant dans le chemin ne sont plus pris en compte. Certaines requêtes qui, jusqu’à présent, contournaient la validation des valeurs tout en fonctionnant différemment, renvoient désormais une erreur ou un résultat différent ; par exemple,
?_strict=true%0Aavec un filtre inconnu renvoie désormais un code HTTP 400.
- Statut du contrat : le point de terminaison de statut
PUT /Import/JSON/contracts/{id}/statusvérifiestatus_idpar rapport aux statuts de contrat de la boutique plutôt que par rapport aux statuts de commande. Un identifiant qui n’existe qu’en tant que statut de commande renvoie désormais un code HTTP 400INVALID_STATUS; un statut de contrat qui n’existe pas également en tant que statut de commande est enregistré. Récupérez les identifiants à partir decontracts_statuses[], deGET /Export/JSON/contractsou deerror.valid_status_ids, jamais à partir de/order_statuses. L’importation des contrats signale un identifiant non valide (par exemple, un identifiant correspondant uniquement à un statut de commande) avec l’avertissementCONTRACT_STATUS_UNKNOWN: l’enregistrement est écrit, mais pas le statut. - Liste des produits par catégorie :
?categories_id=, associé à un ID ou à une plage dans le chemin d'accès, renvoie une erreur HTTP 400FILTER_NOT_APPLICABLE, sauf si la valeur est identique à celle de l'ID du chemin d'accès unique. Jusqu'à la version v2.122.12, la catégorie était renvoyée sous forme de paramètre avec un code HTTP 200. Envoyez la catégorie soit dans le chemin d'accès, soit en tant que paramètre.
Limite de requêtes dépassée (429)
Depuis la v2.122.11, Retry-After indique le nombre de secondes avant qu’une nouvelle requête ne soit acceptée (de 1 à 3 600), et le corps de la requête contient le même nombre que error.retry_after. À cela s’ajoutent les en-têtes X-RateLimit-Limit, X-RateLimit-Remaining et X-RateLimit-Reset, que chaque réponse envoyée à un client soumis à une limite de requêtes contient (voir Clients OAuth2).
HTTP/1.1 429 Too Many Requests
Retry-After: 1260
X-RateLimit-Limit: 5000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1792327500
Content-Type: application/json; charset=utf-8
{
"success": false,
"api_version": "2.122.13",
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit of 5000 requests per 3600 s (sliding window) exceeded.",
"retry_after": 1260
}
}- La valeur déterminante pour la prochaine tentative est
Retry-After. La plupart du temps, « maintenant +Retry-After» correspond exactement àX-RateLimit-Reset; si la limite d’un client vient d’être réduite, c’estRetry-Afterqui s’applique. - Jusqu’à la version v2.122.10 (boutique jusqu’à la version 4.9.170),
Retry-Afterétait toujours égal à 3600, il n’y avait pas de champretry_afteret le message indiquait « Rate limit of 5000 requests/hour exceeded. ». Tenez compte de la valeur deerror.code, jamais du texte du message. - Une requête rejetée (429) ne compte pas. Il faut répartir un grand nombre de requêtes de manière uniforme sur l’heure et ralentir dès que
X-RateLimit-Remainingatteint 0, au lieu d’attendre le 429.
Erreur au niveau du point de terminaison du jeton
POST /oauth/token répond, dans le format OAuth2, par error et error_description. Depuis la version v2.122.11, une portée demandée illisible (UTF-8 non valide ou une liste telle que scope[]=…) génère un code HTTP 400 invalid_scope; aucun jeton n’est émis. client_id ou client_secret sous forme de liste génèrent un code HTTP 400 invalid_request. Retry-After indique le délai d'attente (de 1 à 300 secondes) propre au point de terminaison du jeton. Toutes les erreurs liées au point de terminaison du jeton sont répertoriées sous « Clients OAuth2 ».
Bonnes pratiques
Vérifiez toujours le champ « success » dans la réponse et implémentez une logique de réessai pour les erreurs 429 et 5xx.