EN DIRECT · AUDIT CHAÎNÉ · ÉDR UE
SYSTÈME · 99,99% DISPONIBILITÉ
v 1.0 ↗ FAIT EN UE

Erreurs + limites de débit

Une seule enveloppe d'erreur sur chaque endpoint. Codes de statut HTTP standard + une chaîne code structurée pour la correspondance programmatique. Des en-têtes de limite de débit sur chaque réponse pour vous permettre de doser votre rythme avant d'atteindre un 429.

Enveloppe d'erreur

{
  "detail": "Human-readable summary.",
  "code": "billing.subscription_past_due",
  "field_errors": {
    "scheduled_for": ["Must be a future ISO 8601 timestamp."]
  }
}
  • detail — toujours présent, sûr à afficher aux humains (il est traduit lorsque la locale est disponible).
  • code — présent pour les états d'erreur distinguables. Stable d'une version d'API à l'autre ; faites la correspondance là-dessus pour la logique de nouvelle tentative.
  • field_errors — présent uniquement sur les échecs de validation 400. Table nom-de-champ → liste de messages.

Matrice des codes de statut

StatutClasseRéessayer ?Causes courantes
400ValidationNonChamp requis manquant, mauvais format, violation de règle métier
401AuthNonIdentifiant manquant / incorrect / révoqué
402FacturationNonAbonnement en retard de paiement, limite de la formule gratuite atteinte
403PermissionNonL'identifiant n'a pas le scope, ou la ressource appartient à une autre organisation
404IntrouvableNonLa ressource n'existe pas, ou n'est pas visible pour votre identifiant
409ConflitParfoisRéutilisation incohérente de l'Idempotency-Key, violation de machine à états
422Non traitableNonCombinaison sémantiquement invalide de champs valides
429Débit limitéOui, avec backoffLimite de débit par identifiant ou par organisation atteinte
500Erreur serveurOui, avec backoffInattendu — ouvrez un ticket si cela persiste
502 / 503 / 504TransitoireOui, avec backoffAmont / déploiement / charge

Codes d'erreur notables

CodeStatutSignification
billing.subscription_past_due402L'abonnement Stripe de l'organisation est en retard de paiement. Orientez l'administrateur vers /admin/billing.
billing.free_plan_minutes_exhausted402La formule gratuite / pilote a utilisé ses 5 inspections.
billing.signature_pack_exhausted402Crédits du pack de signatures épuisés ; passez au paiement à la signature ou achetez un autre pack.
permission_denied403L'identifiant n'a pas le scope. Voir field_errors.required_scope.
idempotency.key_mismatch409Même clé, corps différent. Utilisez une nouvelle clé.
session.already_ended409Appel de end sur une session non ouverte (généralement sans danger — end est idempotent, c'est pour les cas limites).
kyb.not_verified403Signature QES demandée sur une organisation qui n'a pas passé le KYB.
rate_limited429Limite de débit par identifiant (60 rpm) ou par organisation (600 rpm) atteinte.

En-têtes de limite de débit

Chaque réponse — succès ou erreur — porte l'état de la limite de débit :

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 47
X-RateLimit-Reset: 1716461235
  • X-RateLimit-Limit — le plafond qui s'applique à cette requête.
  • X-RateLimit-Remaining — combien d'appels restent dans la fenêtre en cours.
  • X-RateLimit-Reset — timestamp Unix auquel Remaining se réinitialise.

Sur un 429, Retry-After est également défini (en secondes) conformément à la RFC 6585.

Portées de limitation de débit

PortéeLimiteFenêtre
Par identifiant601 minute
Par organisation (tous identifiants confondus)6001 minute

Autorise un pic pendant la première seconde d'une minute. Atteignez le plafond et les requêtes suivantes dans la fenêtre renvoient 429.

Stratégie de nouvelle tentative

Backoff exponentiel avec jitter pour 429 / 5xx ; ne réessayez pas les 4xx (hormis 408, 425, 429) :

async function withRetry<T>(fn: () => Promise<T>, max = 5): Promise<T> {
  let lastErr: unknown;
  for (let i = 0; i < max; i++) {
    try {
      return await fn();
    } catch (err: any) {
      const status = err?.status;
      if (status >= 400 && status < 500 && ![408, 425, 429].includes(status)) {
        throw err; // not retryable
      }
      const base = status === 429 ? (err.retryAfterMs ?? 1000) : 250 * 2 ** i;
      const jitter = Math.random() * base * 0.2;
      await new Promise((r) => setTimeout(r, base + jitter));
      lastErr = err;
    }
  }
  throw lastErr;
}

Les SDK implémentent cela en interne sur 429 + 5xx ; si vous préférez gérer les nouvelles tentatives vous-même, définissez retries: 0 dans les options du SDK.

Corrélation des erreurs

Chaque réponse porte un en-tête X-Request-Id (UUID). Citez-le dans tout ticket de support — nous pouvons extraire la trace complète de la requête à partir de ce seul id.

Et ensuite