Skip to Content
APIErreurs

Erreurs

La forme

Une erreur porte toujours le champ error, et rien d’autre dans la plupart des cas :

{ "error": "description lisible" }

Ce champ est un texte, pas un code. Il est écrit pour être lu par une personne, et son libellé peut changer sans préavis. N’écrivez jamais de condition dessus : branchez sur le code HTTP, et sur le champ code lorsqu’il est présent.

Deux familles d’erreurs portent, elles, des champs supplémentaires exploitables par un programme : le refus pour module non activé et le refus pour maintenance. Les deux sont détaillés plus bas.

Les codes

CodeCe qu’il signifie iciCe qu’il faut faire
400requête mal formée, ou organisation non résoluecorriger l’appel
401identité absente, invalide, ou session terminéese réauthentifier
403identité valide, mais l’accès est refusélire la section suivante
404introuvable, ou hors de votre périmètrevérifier l’identifiant
409demande légitime que l’état en place interditlire le message
422données refusées par une règle métiercorriger les données
423maintenance en cours, écritures suspenduesréessayer plus tard
429limite de débit atteinteralentir, puis réessayer
500défaillance de notre côtéréessayer, puis signaler

Les deux refus en 403, et pourquoi ils ne se résolvent pas pareil

C’est la distinction la plus importante de cette page, et celle qui coûte le plus de temps quand on la rate. Deux situations très différentes répondent 403, et le même message « c’est refusé » mène à deux démarches opposées.

{ "error": "insufficient permissions: procurement.read required" }

Le module dont relève la route est actif pour votre organisation. C’est votre compte qui ne détient pas la permission que la route réclame — ici procurement.read. Le message la nomme explicitement.

Comment cela se résout : auprès de l’administrateur de votre organisation, qui attribue les rôles et leurs permissions. C’est une démarche interne, sans délai ni contrat, et le changement prend effet à la requête suivante — les droits sont relus à chaque appel, pas à la connexion.

Un cas particulier porte le même code mais un autre message :

{ "error": "you are not a member of this organization" }

Là, ce n’est pas une permission qui manque : l’en-tête X-Organization-Id désigne une organisation à laquelle votre compte n’appartient pas. Vérifiez l’en-tête avant de demander un droit.

L’ordre des contrôles compte. Sur une route relevant d’un module, la souscription est vérifiée avant la permission. Un compte qui n’a ni le module ni le droit reçoit donc module_disabled, et obtenir le droit ne changerait rien. Traitez la souscription d’abord.

Enfin, un rappel qui n’est pas une subtilité d’API mais une règle de construction : un droit refusé dans l’interface l’est aussi par l’API. Le grisage et les cadenas que vous voyez dans le menu sont un confort d’affichage ; l’autorité est côté serveur, et un appel direct ne contourne rien.

404 : introuvable ou hors périmètre

Le 404 est délibérément ambigu entre « cette ressource n’existe pas » et « cette ressource existe, mais appartient à une autre organisation ». Distinguer les deux permettrait de deviner l’existence d’une ressource en essayant des identifiants, et donc d’apprendre ce que contient l’espace d’une autre collectivité sans y avoir accès.

Pratiquement : si un identifiant que vous savez valide répond 404, vérifiez d’abord votre en-tête X-Organization-Id. C’est l’explication neuf fois sur dix.

422 : la donnée est refusée, pas la requête

Un 422 signifie que l’appel était bien formé et autorisé, mais que son contenu ne passe pas une règle métier — un fichier d’import sans ligne d’en-tête, une correspondance de colonnes absente, un champ de configuration manquant. Le message décrit la règle en français.

Un 422 ne liste pas les champs fautifs dans un champ structuré : il n’y a pas de tableau d’erreurs par attribut. Le message est la seule indication. Lorsqu’un appel en renvoie un, affichez le message tel quel à l’utilisateur plutôt que de le reformuler.

Un 400, lui, dit que la requête n’était pas exploitable : corps illisible, identifiant qui n’est pas un UUID, paramètre obligatoire absent, valeur hors d’une liste fermée.

409 : l’état en place s’y oppose

La demande est légitime, mais l’état actuel l’interdit : ajouter un membre qui l’est déjà, supprimer le dernier rôle par lequel une organisation peut encore être administrée, signer un document qui ne l’est pas encore. Le message dit laquelle de ces situations s’applique. Un 409 ne se résout pas en réessayant.

423 : maintenance

Pendant une opération de maintenance, l’API protège les données en refusant les écritures et continue de servir les lectures. Un POST, PUT, PATCH ou DELETE reçoit alors 423, avec un corps exploitable :

{ "error": "maintenance_read_only", "mode": "…", "message": "…", "ends_at": "2026-10-02T12:00:00Z" }

Le champ error prend la valeur maintenance_read_only lorsque toute l’application est en lecture seule, et maintenance_section lorsque seule une partie l’est — le champ section nomme alors laquelle. ends_at donne la fin annoncée, reprise dans l’en-tête Retry-After lorsqu’elle est connue.

Deux choses ne sont jamais bloquées, et c’est volontaire : la connexion, et l’ouverture des documents déjà produits.

429 : limite de débit

Deux origines possibles, deux messages distincts : le plafond des routes de connexion, compté par adresse IP, et celui des appels par clé d’API. Dans les deux cas, respectez Retry-After lorsqu’il est présent et n’enchaînez pas les tentatives. Voir Authentification, section sur les limites de débit.

Les documents répondent en HTML, pas en JSON

Les rapports et exports s’ouvrent dans un onglet de navigateur. Quand leur lien n’est plus valable, l’API ne renvoie donc pas du JSON mais une page lisible, sous le code 401, qui dit de rouvrir le document depuis l’application.

Le motif exact — lien expiré, lien déjà consommé, paramètres modifiés — n’est jamais distingué dans la réponse. Un client qui appelle ces routes doit donc traiter le 401 comme « demandez un nouveau lien », sans chercher à analyser le corps. Voir Référence, section sur les documents.

Limites connues

  • Un seul code lisible par un programme à ce jour : module_disabled. Tous les autres refus ne se distinguent que par leur code HTTP et un texte.
  • Les messages mélangent le français et l’anglais selon leur ancienneté. Les afficher tels quels à un utilisateur final n’est donc pas toujours satisfaisant, et les traduire par correspondance de texte est fragile.
  • Pas d’identifiant de requête renvoyé avec une erreur 500 : pour un signalement au support, notez l’heure, la route et l’organisation.