Développeurs
Codes d'erreur
Une seule forme d'erreur sur toute l'API, et un vocabulaire de codes qui ne bouge pas. Branchez votre code sur error.code ; error.message est une phrase destinée à un humain, susceptible d'être reformulée ou traduite.
Format
{
"error": {
"code": "rate_limited",
"message": "Limite de 5000 requêtes par heure atteinte."
}
}
Les codes
| Code | HTTP | Ce que ça veut dire | Quoi faire |
|---|---|---|---|
unauthorized | 401 | Clé absente, invalide, révoquée ou expirée : un seul code pour les quatre, volontairement. | Vérifiez l'en-tête Authorization: Bearer …, puis l'état de la clé dans API & webhooks. Un cookie de session ne vaut pas clé ici. |
forbidden | 403 | La clé est valide mais n'a pas la portée requise (une clé en lecture seule sur une écriture). | Créez une clé avec la portée voulue. Ne réutilisez pas une clé d'écriture pour de la lecture. |
not_found | 404 | La ressource n'existe pas : ou n'appartient pas à votre organisation. Les deux donnent la même réponse. | Vérifiez l'identifiant. Utilisez celui renvoyé par nos listes, jamais un identifiant reconstruit. |
validation_failed | 422 | Un paramètre connu a une valeur invalide. Le message nomme le champ. | Corrigez le paramètre. Les paramètres inconnus, eux, sont ignorés sans erreur. |
rate_limited | 429 | Budget horaire épuisé : ou formule sans accès API (le message le précise). | Attendez Retry-After secondes. Surveillez X-RateLimit-Remaining, présent sur toutes les réponses, pour ralentir avant d'y arriver. |
internal_error | 500 | Une panne de notre côté. | Réessayez avec un délai croissant. Si ça persiste, écrivez-nous avec la date et l'endpoint. |
Une règle de gestion suffit. Rejouez rate_limited et internal_error avec un délai croissant ; sur unauthorized, forbidden, not_found et validation_failed, arrêtez et alertez : rejouer une requête que nous avons refusée pour sa forme ne la rendra pas valide.
Exemple de gestion
Node
async function ogerant(path, { key, tries = 4 } = {}) {
for (let attempt = 1; attempt <= tries; attempt++) {
const res = await fetch(`https://app.ogerant.com${path}`, {
headers: { authorization: `Bearer ${key}` },
});
if (res.ok) return res.json();
const { error } = await res.json().catch(() => ({ error: {} }));
// Rejouable : on attend ce qu'on nous dit d'attendre, sinon un backoff.
if (error.code === "rate_limited" || error.code === "internal_error") {
const wait = Number(res.headers.get("retry-after")) || 2 ** attempt;
await new Promise((r) => setTimeout(r, wait * 1000));
continue;
}
// Non rejouable : la requête est fautive, insister n'y changera rien.
throw new Error(`${error.code}: ${error.message}`);
}
throw new Error("épuisé après plusieurs tentatives");
}
Et si je reçois autre chose ?
Toute réponse de /api/v1/ qui ne suit pas ce format est un bug de notre côté : signalez-le. En particulier, une page HTML là où vous attendiez du JSON signifie presque toujours que l'URL appelée n'est pas une route /api/v1/ : vérifiez le préfixe.