Bonnes pratiques5 min

Limites de débit

Comprendre le modèle de limitation par jeton OAuth, pourquoi il est conçu ainsi, et ce que votre intégration doit implémenter.

Ce guide explique comment fonctionne la limitation de débit sur l’API publique Billabex (/api/public/v1/*) et comment votre client doit se comporter pour s’intégrer de façon fiable et prévisible.

Vue d’ensemble

La limitation s’applique par jeton d’accès OAuth Bearer.

Ce modèle vise un comportement clair et déterministe pour les intégrations :

  • Un jeton = un quota partagé sur tous les endpoints publics
  • Les jetons sont isolés les uns des autres
  • Une fenêtre glissante lisse les pics courts de trafic

Si plusieurs systèmes ou plusieurs fils d’exécution utilisent le même jeton, ils partagent aussi la même limite.

Le modèle

Aspect Comportement
Portée Par jeton d’accès OAuth
Type de fenêtre Fenêtre glissante
Durée de la fenêtre 60 secondes
Limite 300 requêtes par fenêtre
S’applique à Tous les endpoints publics protégés par OAuth
En cas de dépassement 429 Too Many Requests + Retry-After

Pourquoi limiter par jeton ?

Ce choix garantit :

  • l’équité entre intégrations indépendantes ;
  • l’isolation entre jetons ;
  • un dimensionnement prévisible côté client.

Ce que cela implique pour vous

  • Traitez chaque jeton d’accès comme une ressource partagée et limitée
  • Centralisez les requêtes sortantes par jeton
  • Évitez toute concurrence non maîtrisée sur un même jeton

Où la limitation s’applique

Le modèle vaut pour tous les endpoints protégés par OAuth sous :

/api/public/v1/*

Par exemple :

  • GET /api/public/v1/accounts
  • GET /api/public/v1/invoices
  • GET /api/public/v1/organizations

Limitation de l’endpoint de jeton

En plus de la limitation par jeton sur les endpoints d’API, l’endpoint de jeton (POST /api/oauth/token) a sa propre limite, pour éviter les abus.

Aspect Comportement
Portée Par adresse IP
Limite 10 requêtes par 60 secondes
S’applique à /api/oauth/token (tous les grants)

Elle couvre :

  • l’échange du code d’autorisation ;
  • les grants de rafraîchissement.

Elle empêche un acteur malveillant de générer des jetons en masse pour contourner la limite par jeton.

Ses réponses portent les mêmes en-têtes que ci-dessous, sous le nom de politique "auth" au lieu de "public-api" : c’est un quota distinct, compté par IP et non par jeton.

En-têtes de réponse

Toute réponse soumise à limitation porte les en-têtes du draft IETF RateLimit ainsi que les en-têtes historiques X-RateLimit-*, pour compatibilité.

En-tête Description
RateLimit-Policy Nom de la politique, quota total et fenêtre en secondes
RateLimit Quota restant et fenêtre effective en secondes
X-RateLimit-Limit Historique : requêtes maximales par fenêtre
X-RateLimit-Remaining Historique : requêtes restantes dans la fenêtre courante
X-RateLimit-Reset Historique : horodatage Unix en secondes de la réinitialisation

Exemple de réponse

HTTP/1.1 200 OK
RateLimit-Policy: "public-api";q=300;w=60
RateLimit: "public-api";r=258;t=12
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 258
X-RateLimit-Reset: 1738859285

Lire la politique avant d’avoir un jeton

RateLimit-Policy est statique et publique : elle annonce le quota, pas ce qu’il vous en reste. Elle est donc renvoyée sur toute réponse de /api/public/v1/* et de /mcp, y compris le 401 reçu avant de s’authentifier. Un seul appel non authentifié suffit donc à dimensionner votre étranglement :

GET /api/public/v1/accounts HTTP/1.1

HTTP/1.1 401 Unauthorized
RateLimit-Policy: "public-api";q=300;w=60
WWW-Authenticate: Bearer resource_metadata="[baseURL]/.well-known/oauth-protected-resource"

RateLimit, qui porte votre quota restant, n’apparaît qu’une fois la requête authentifiée : il n’existe aucun compteur par appelant avant cela.

Quand la limite est dépassée (429)

Quand le quota est épuisé, l’API répond :

  • avec le statut HTTP 429 Too Many Requests ;
  • avec un en-tête Retry-After indiquant à partir de quand réessayer sans risque.

Exemple de réponse 429

HTTP/1.1 429 Too Many Requests
RateLimit-Policy: "public-api";q=300;w=60
RateLimit: "public-api";r=0;t=12
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1738859285
Retry-After: 12
Content-Type: application/json

{
  "message": "Too many requests",
  "code": "HTTP_429",
  "frontMessage": "Too many requests",
  "timestamp": "2026-08-24T18:09:55.818Z",
  "path": "/api/public/v1/invoices",
  "type": "http",
  "method": "GET",
  "resolution": "Wait for the Retry-After delay before retrying."
}

À retenir

  • Respectez toujours Retry-After
  • Ne réessayez pas immédiatement, et n’utilisez pas de délai codé en dur
  • Des dépassements répétés peuvent déclencher des protections supplémentaires

Comportement client recommandé

Pour travailler de façon fiable avec l’API, votre client devrait :

  1. centraliser toutes les requêtes sortantes par jeton d’accès ;
  2. surveiller RateLimit, avec X-RateLimit-Remaining en repli historique ;
  3. sur 429, attendre Retry-After avant de réessayer ;
  4. borner le nombre de reprises et remonter l’erreur si la limite est atteinte de façon répétée.

Exemple de reprise (JavaScript)

async function fetchWithTokenRateLimit(url, options = {}, maxRetries = 3) {
  let attempt = 0;

  while (attempt <= maxRetries) {
    const response = await fetch(url, options);

    // Succès, ou erreur sans rapport avec la limitation
    if (response.status !== 429) {
      return response;
    }

    const retryAfterSeconds = Number(
      response.headers.get('Retry-After') || '1',
    );

    // Plancher de sécurité, pour éviter une reprise immédiate
    const waitMs = Math.max(1000, retryAfterSeconds * 1000);

    if (attempt === maxRetries) {
      return response;
    }

    await new Promise((resolve) => setTimeout(resolve, waitMs));
    attempt += 1;
  }
}

Bonnes pratiques

  • Préférez la pagination et le regroupement, pour réduire le nombre de requêtes
  • Utilisez une file ou un limiteur de débit par jeton
  • Maîtrisez la concurrence, surtout sur les flux à forte écriture
  • Évitez les rafales parallèles sur un même jeton
  • Si vous faites tourner vos jetons, rappelez-vous que le quota est suivi par jeton

Pour aller plus loin

Support

Une question sur la limitation par jeton OAuth ? Écrivez-nous via le formulaire de contact.