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"
}
| Membre | Rôle |
|---|---|
type | URI identifiant le motif du refus. C'est la valeur sur laquelle brancher votre traitement. |
title | Résumé court du motif, en anglais. Ne dépend que de type. |
status | Code HTTP de la réponse. |
detail | Ce qui a échoué sur cette requête précise, quand l'API a mieux à dire que title. |
instance | Chemin 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 surtype. - 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ée | Rôle |
|---|---|
type | Nature de la règle violée (voir le tableau ci-dessous). |
pointer | JSON Pointer (RFC 6901) désignant le champ fautif dans le corps que vous avez envoyé, par exemple /order/products/0/amount. |
detail | Phrase 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 :
| Motif | Sens | Paramètres |
|---|---|---|
validation/required | Le champ est absent ou vide. | — |
validation/wrong-type | Le champ n'est pas du type attendu. | expectedType |
validation/out-of-range | Valeur numérique hors bornes. | minimum, maximum, exclusiveMinimum |
validation/wrong-length | Longueur ou taille hors bornes. | minLength, maxLength, minItems, maxItems |
validation/not-allowed | Valeur hors de l'ensemble autorisé. | allowedValues |
validation/malformed | Valeur mal formée. | format |
validation/invalid | Valeur 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.
| Statut | Sens |
|---|---|
422 Unprocessable Entity | La configuration de la boutique est en cause : le marchand a un geste à faire. |
502 Bad Gateway | La 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.