Aller au contenu
Sandbox

Limites de débit

Comment l'API borne les rafales par clé et par workspace, ce que disent les en-têtes de débit, ce qu'un 429 signifie et comment rejouer proprement.

Voir en Markdown

L'API Transaction Intelligence protège son moteur contre les rafales par une limite opérationnelle de débit, publiée dans le contrat sous l'extension x-noryo-rate-limit du document openapi.json, avec une version de politique (policy_version : debit_ti_v1).

Ce que c'est, et ce que ce n'est pas

Le contrat la qualifie de protection opérationnelle contre les rafales (kind : operational_burst_protection) et dit explicitement ce qu'elle n'est pas :

Ce qu'elle n'est pas, selon le contratCe que cela signifie pour vous
sandbox_lifetime_quotaElle ne compte pas vos requêtes sur la durée de vie du sandbox : le seau se recharge en continu.
production_usage_quotaElle ne dit rien d'un volume autorisé en production, qui n'est pas ouverte.
billing_entitlementRien n'est facturé.
commercial_promiseLes nombres publiés sont des réglages versionnés, pas un engagement commercial.

Deux seaux à jetons

L'algorithme est un seau à jetons (token_bucket), appliqué à deux portées en même temps :

  • la clé : chaque clé d'API a son propre seau ;
  • le workspace : un second seau borne la somme de toutes les clés du workspace : cent clés ne font pas cent fois la limite.

Les valeurs en vigueur sont celles du contrat :

debit_ti_v1operational_burst_protection · token_bucket
120 / min
par clé · capacité 120 · recharge 2/s
600 / min
par workspace · capacité 600 · recharge 10/s

« 120 requetes / minute » est traduit en seau a jetons : capacite 120 (la rafale toleree) rechargee a 2 jetons / seconde (le regime durable). Une clef au repos peut envoyer 120 requetes d'un coup, puis 2 par seconde ; sur la premiere minute apres un repos, jusqu'a 240 passent. Le workspace, lui, borne la somme de toutes ses clefs a 600 / minute (capacite 600, 10 / s) : cent clefs ne font pas cent fois la limite.

Ce n'est pas : sandbox_lifetime_quota · production_usage_quota · billing_entitlement · commercial_promise

Chaque seau a une capacité (la rafale tolérée) et un rythme de recharge (le régime durable, en jetons par seconde). « N requêtes par minute » traduit ce couple : une clé au repos peut vider son seau d'un coup, puis continue au rythme de la recharge.

Le décompte est central et atomique, une requête à la fois, sans compteur local par serveur. L'environnement fait partie de l'identité du seau (environment_scoped) : les valeurs publiées sont celles du sandbox. La production n'est pas ouverte et ses réglages ne sont pas un engagement. Voir Limites du sandbox.

Lire les en-têtes

Dès que la requête est authentifiée, la réponse porte l'état du débit, refus compris.

En-têtePrésent surSignification
noryo-ratelimit-limitsuccès, 422, 404, 409, 429La capacité de rafale de votre clé.
noryo-ratelimit-remainingsuccès, 422, 404, 409, 429Ce que votre clé peut encore envoyer maintenant : le plus petit des deux seaux, celui de la clé et celui du workspace.
Retry-After429 seulementNombre entier de secondes avant que le seau qui a refusé couvre une nouvelle requête.
noryo-request-idtoute réponse rendue après authentification (toute erreur porte request_id dans son corps)L'identifiant de la requête, à citer au support. Un 404 (chemin inconnu) ou un 405 (verbe non déclaré) vient de l'hébergeur, avant l'API, sans request_id.

noryo-ratelimit-remaining peut valoir zéro alors que votre clé a encore des jetons : c'est alors le seau du workspace qui est vide.

Quand la limite est atteinte : 429

Au-delà de la limite, l'API répond 429 avec un corps application/problem+json de type rate_limited et l'en-tête Retry-After. Rien n'a été calculé, rien n'a été enregistré, aucun événement n'a été émis. La requête peut être rejouée telle quelle après le délai.

{
  "type": "https://noryo.app/problems/transactions/rate_limited",
  "title": "Trop de requetes.",
  "status": 429,
  "detail": "La limite de debit de cette clef est atteinte. Rejouez apres le delai de Retry-After.",
  "request_id": "req_01J9…"
}
JSON

Quand c'est le workspace qui a refusé, le detail le dit. title et detail sont des textes pour une personne, rédigés en français par l'API : appuyez votre logique sur type et status, jamais sur leur formulation. Voir le catalogue des erreurs et la page Erreurs.

Note

Le limiteur ne fabrique jamais de 429 quand il est lui-même en panne : il répond 500 (internal_error) plutôt que de laisser passer sans limite.

Ce qui consomme un jeton, ce qui n'en consomme pas

Le contrat fixe l'ordre de traitement : hôte, type de contenu, taille du corps, credential, puis authentification, préfixe, usage et débit dans une seule transaction, puis JSON, Idempotency-Key, schéma et métier. Le jeton est consommé dès que l'authentification réussit, avant toute lecture du corps : toute requête authentifiée en consomme un, quelle que soit sa réponse.

RéponseJeton consomméPourquoi
201 créé ; 200 lecture ou couverture enregistréeouiRequête authentifiée et traitée.
200 rejeu idempotentouiAuthentifiée et traitée, même si rien n'a été créé.
422 schéma ; 404 introuvable ; 409 conflit d'idempotenceouiLa credential était valide ; le refus vient après le débit.
400 JSON illisible ou Idempotency-Key hors alphabetouiMême raison.
401 clé absente, mal formée, d'une autre famille, inconnue, révoquée, ou sous un préfixe divergentnonAucun seau touché, aucun usage marqué ; une credential inconnue n'apprend pas qu'un seau existe.
403 workspace ou organisation inactifnonMême règle que le 401.
400 hôte non déclaré ; 413 ; 415nonRefusés avant toute lecture de la credential.
GET /openapi.jsonnonPublic, sans credential.

Les trois opérations comptées sont POST /transactions/v1/enrichments, GET /transactions/v1/enrichments/{enrichment_id} et POST /transactions/v1/coverage-windows, un jeton chacune : une lecture coûte autant qu'un enrichissement.

Rejouer proprement

  1. Respectez Retry-After. Attendez au moins le délai indiqué : c'est le nombre de secondes avant que le seau qui a refusé couvre une nouvelle requête.
  2. Rejouez la même requête, avec la même Idempotency-Key. Un 429 est décidé avant la lecture du corps : la requête rejouée est traitée comme une première fois. Si une tentative antérieure avait abouti sans que la réponse vous parvienne, la même clé rend un 200 de rejeu plutôt qu'un doublon. Voir Enrichir une transaction.
  3. Bornez les tentatives et lissez l'envoi. Quand les 429 se répètent, envoyez au rythme de la recharge plutôt que d'ajouter des tentatives : la capacité absorbe un pic occasionnel, elle n'est pas un débit tenable.
  4. Surveillez noryo-ratelimit-remaining et ralentissez quand il approche de zéro.
  5. Coordonnez vos clés. Répartir la charge sur plusieurs clés n'ajoute pas de capacité au-delà du seau du workspace.

Un exemple fetch qui honore Retry-After et conserve l'Idempotency-Key d'une tentative à l'autre :

async function enrichir(transaction: unknown, idempotencyKey: string, tentativesMax = 3) {
  for (let tentative = 1; ; tentative++) {
    const reponse = await fetch("https://api.noryo.app/transactions/v1/enrichments", {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${process.env.NORYO_API_KEY}`,
        "Content-Type": "application/json",
        "Idempotency-Key": idempotencyKey,
      },
      body: JSON.stringify(transaction),
    });

    if (reponse.status !== 429 || tentative >= tentativesMax) return reponse;

    // Retry-After est en secondes entières.
    const secondes = Number(reponse.headers.get("retry-after") ?? "1");
    await new Promise((resoudre) => setTimeout(resoudre, secondes * 1000));
  }
}

const reponse = await enrichir(
  {
    descriptor: "PRLV SEPA NETFLIX INTERNATIONAL",
    direction: "outgoing",
    occurred_at: "2026-09-05T03:10:00+02:00",
    amount: { value: "13.49", currency: "EUR" },
    payment: { rail: "sepa_direct_debit" },
  },
  crypto.randomUUID(),
);
console.log(reponse.status, reponse.headers.get("noryo-ratelimit-remaining"));
TypeScript

Où observer les 429

Les 429 apparaissent sur Platform, page Usage, section Transaction Intelligence, dans la catégorie des requêtes limitées, par clé et par workspace. Les 401 n'y figurent jamais : une clé révoquée ou inconnue ne compte pas. Voir Usage et clés d'API.

Publié le 2026-09-17 11:19 UTC (version 1).

Cette page vous a-t-elle aidé ?