Validation
Le schéma de requête est fermé : chaque refus de validation, son code, son message exact, et les règles qui surprennent le plus souvent (majuscules, null, UTC, champs inconnus).
Le corps d'une requête est validé contre un schéma fermé : un champ inconnu n'est jamais ignoré, il fait échouer la requête. Cette rigueur rend la comparaison de deux requêtes totale : un champ toléré en silence ferait différer deux requêtes identiques aux yeux du moteur, et produirait un 409 injustifié.
Toutes les erreurs de validation du corps rendent 400 avec le code invalid_request. Le champ detail dit quelle règle a échoué ; la première règle en échec arrête la validation.
{
"type": "https://developer.noryo.app/errors/invalid_request",
"title": "Invalid request",
"status": 400,
"code": "invalid_request",
"detail": "currency must be an ISO 4217 code",
"request_id": "req_…"
}JSONBâtissez votre logique sur code, pas sur detail. Le texte de detail est écrit pour un humain, en anglais, et peut être reformulé sans changement de version.
Les messages de detail
detail | Cause |
|---|---|
body must be a JSON object | Le corps est un tableau, une chaîne, un nombre ou null |
unknown field: <nom> | Un champ hors schéma est présent |
descriptor is required | descriptor absent, vide, composé seulement d'espaces, ou pas une chaîne |
descriptor is too long | Plus de 512 caractères |
amount must be a finite number | amount n'est pas un nombre JSON (une chaîne "12.40", null) |
currency must be an ISO 4217 code | Pas exactement trois lettres majuscules (eur, EURO, null) |
occurred_at must be ISO 8601 UTC | Pas une chaîne de la forme AAAA-MM-JJTHH:MM:SS suivie d'une fraction facultative et de Z, ou une date qui n'existe pas |
country must be ISO 3166-1 alpha-2 | Pas exactement deux lettres majuscules |
mcc must be four digits | Pas une chaîne d'exactement quatre chiffres (un nombre comme 5814 compris) |
external_transaction_id must be 1..255 characters | Vide, trop long, ou pas une chaîne |
Les règles qui surprennent
Les champs inconnus sont refusés. Une faute de frappe (occured_at) ou un champ de votre modèle interne envoyé par erreur rend unknown field: occured_at. Certains noms sont réservés au serveur et refusés de la même façon s'ils figurent dans le corps : status, confidence, billable, units, environment, source, customized, enrichment_id, request_id, entre autres. Le client ne peut jamais déclarer ce que le serveur calcule.
null n'est pas une absence. Pour un champ facultatif que vous n'avez pas, omettez la clé. "amount": null est refusé.
Les majuscules sont exigées. currency et country sont comparés tels quels ; le validateur refuse eur plutôt que de le corriger. Voir Formats.
occurred_at doit être en UTC, avec Z. 2026-09-06T13:42:00+02:00 est refusé : convertissez en 2026-09-06T11:42:00Z. Une date bien formée qui n'existe pas (2026-02-30T10:00:00Z, une heure à 24, une seconde à 60) est refusée de la même façon, en 400.
mcc est une chaîne. Envoyez "5814", pas 5814 : un 5814 numérique est refusé en 400 avec mcc must be four digits.
Le corps d'un rafraîchissement
Le corps de POST …/refresh accepte les six champs économiques et rien d'autre. Un external_transaction_id y est refusé (unknown field: external_transaction_id) : le rafraîchissement vise l'enrichissement nommé dans l'URL, et accepter un second identifiant laisserait une même requête désigner deux transactions. Voir Rafraîchir.
Les refus qui précèdent la validation du corps
| Code | Statut | Cause |
|---|---|---|
unsupported_media_type | 415 | Content-Type absent ou différent de application/json |
request_entity_too_large | 413 | Corps de plus de 16 Kio |
invalid_json | 400 | Corps qui n'est pas du JSON valide, ou corps vide |
invalid_idempotency_key | 400 | En-tête Idempotency-Key mal formé |
Les autres refus propres à la route
| Code | Statut | Cause |
|---|---|---|
insufficient_scope | 403 | La clé n'a pas enrich:write |
identifier_required | 400 | Création sans Idempotency-Key ni external_transaction_id, ou rafraîchissement sans Idempotency-Key |
Sur la création, l'ordre est : corps, scope, identifiant. Sur le rafraîchissement : identifiant de chemin, Idempotency-Key, scope, puis corps. L'ordre complet des contrôles est décrit dans Requêtes.
Publié le 2026-10-09 10:18 UTC (version 2).