Aller au contenu principal

Format des erreurs de l'API

Quand l'API refuse une requête, elle répond avec un corps qui identifie le motif du refus par une URI stable. Cette page décrit ce format, l'engagement de stabilité qui l'accompagne, et la façon de le traiter dans une intégration.

Ce format est servi à partir de la révision 2026-08-26. Les révisions antérieures continuent de servir le format historique, décrit en fin de page.


Principe

Le corps d'erreur suit la RFC 9457 — Problem Details for HTTP APIs, et est servi avec le type de média application/problem+json.

HTTP/1.1 400 Bad Request
Content-Type: application/problem+json
{
"type": "https://enkore.io/problems/referral-already-pending",
"title": "This email address has already been invited and its referral is pending.",
"status": 400,
"detail": "referral already exists for this email",
"instance": "/point/referral",
"property": "email"
}
MembreRôle
typeURI identifiant le motif du refus. C'est la valeur sur laquelle brancher votre traitement.
titleRésumé court du motif, en anglais. Ne dépend que de type.
statusCode HTTP de la réponse.
detailCe qui a échoué sur cette requête précise, quand l'API a mieux à dire que title.
instanceChemin appelé, pour retrouver l'occurrence dans vos journaux.

Un motif peut ajouter ses propres membres à la racine du corps — ici property. Ils sont documentés avec le motif dans la référence d'API.

:::warning Ne branchez pas sur le texte title et detail sont en anglais et destinés au développeur qui intègre. Ils peuvent être reformulés à tout moment sans que cela constitue un changement incompatible. Le texte montré à un utilisateur final se choisit chez vous, à partir de type. :::


L'engagement sur type

Une URI publiée dans type ne change jamais — ni sa forme, ni son sens. C'est ce qui vous permet d'écrire un switch dessus et de ne plus y revenir.

Concrètement :

  • Un motif dont le sens change reçoit une nouvelle URI ; l'ancienne n'est pas réutilisée.
  • Une formulation corrigée se fait sur title, jamais sur type.
  • De nouveaux motifs peuvent apparaître à tout moment, y compris sans changement de révision : c'est un ajout, pas une rupture.

Ce dernier point a une conséquence directe sur votre code : prévoyez toujours un traitement par défaut pour une URI que vous ne connaissez pas. Un motif inconnu ne doit jamais produire un écran vide ni un fragment de JSON à l'écran.

const messages = {
'https://enkore.io/problems/referral-already-pending':
'Cette adresse a déjà été invitée.',
// …
};

const problem = await response.json();
const message = messages[problem.type] ?? 'Une erreur est survenue. Réessayez.';

Les URI ne sont pas déréférençables : elles servent d'identifiant, pas d'adresse. La RFC 9457 §3.1.1 le prévoit explicitement. La description de chaque motif se trouve sur cette page et dans la référence d'API.


Erreurs de validation

Lorsque le corps envoyé ne respecte pas le contrat, l'API répond 400 avec le motif validation-failed et une entrée par champ refusé dans errors :

{
"type": "https://enkore.io/problems/validation-failed",
"title": "The request payload is invalid.",
"status": 400,
"instance": "/api/order/register",
"errors": [
{
"type": "https://enkore.io/problems/validation/malformed",
"pointer": "/customer/email",
"detail": "email must be an email",
"format": "email"
},
{
"type": "https://enkore.io/problems/validation/out-of-range",
"pointer": "/order/storeAmount",
"detail": "storeAmount must be a positive number",
"exclusiveMinimum": 0
}
]
}
Membre de l'entréeRôle
typeNature de la règle violée (voir le tableau ci-dessous).
pointerJSON Pointer (RFC 6901) désignant le champ fautif dans le corps que vous avez envoyé, par exemple /order/products/0/amount.
detailPhrase anglaise du validateur, pour le développeur.

Les autres membres sont les paramètres du motif. Ils empruntent le vocabulaire de JSON Schema et vous donnent de quoi composer votre propre phrase :

MotifSensParamètres
validation/requiredLe champ est absent ou vide.
validation/wrong-typeLe champ n'est pas du type attendu.expectedType
validation/out-of-rangeValeur numérique hors bornes.minimum, maximum, exclusiveMinimum
validation/wrong-lengthLongueur ou taille hors bornes.minLength, maxLength, minItems, maxItems
validation/not-allowedValeur hors de l'ensemble autorisé.allowedValues
validation/malformedValeur mal formée.format
validation/invalidValeur refusée par une règle qui n'entre dans aucune des catégories ci-dessus.

:::tip Sept motifs, pas un par règle Ces sept motifs décrivent la nature de la règle violée, et non la contrainte technique qui l'a détectée. C'est délibéré : le moteur de validation de l'API peut changer, et vos switch n'ont pas à en dépendre. :::

Un champ peut aussi porter un motif métier à la place de ces sept : type décrit alors le refus lui-même — par exemple « cette plateforme e-commerce n'est pas prise en charge » plutôt que « valeur hors liste ».


Motifs d'échec d'une boutique

Certaines opérations font appel à la boutique du marchand (PrestaShop, WooCommerce). Quand cet appel échoue, l'API ne relaie jamais le statut de la boutique : elle sert son propre motif, avec un statut qui dit ce qu'il y a à faire.

StatutSens
422 Unprocessable EntityLa configuration de la boutique est en cause : le marchand a un geste à faire.
502 Bad GatewayLa boutique n'a rien répondu d'exploitable : il n'y a qu'à réessayer.

Le membre platform indique la plateforme concernée, ce qui vous permet d'orienter le marchand vers le bon écran de configuration.

{
"type": "https://enkore.io/problems/platform-credentials-rejected",
"title": "The store platform rejected the credentials registered for this store.",
"status": 422,
"instance": "/reward/claim/1042",
"platform": "prestashop"
}

Liste des motifs

Chaque endpoint publie, dans la référence d'API, la liste exacte des type qu'il peut renvoyer pour chaque code HTTP. C'est la source à consulter pour une intégration : elle est générée depuis le code de l'API, et non rédigée à part.


Révisions antérieures

Les révisions antérieures à 2026-08-26 servent le format historique, en application/json, sous deux formes selon la nature du refus :

{
"statusCode": 400,
"error": "Bad request",
"messages": [
{
"property": "email",
"constraint": "isEmail",
"defaultMessage": "email must be an email",
"message": "L'adresse e-mail est invalide"
}
]
}
{
"statusCode": 400,
"error": "Bad Request",
"message": "The store could not be reached."
}

Ce format n'identifie pas le motif autrement que par son texte, et ce texte n'est pas stable. Pour toute nouvelle intégration, demandez la révision 2026-08-26 ou ultérieure — voir Versionnage de l'API.