Blu Pantheon
مرجع API

Rate limiting

Limiti di chiamata per fascia di endpoint, header di quota, gestione del 429 e strategie di retry con backoff.

Ogni richiesta alle API di Blu Pantheon consuma quota. I limiti proteggono la piattaforma da picchi anomali e garantiscono tempi di risposta stabili per tutti i tenant. Sono espressi come numero massimo di richieste in una finestra temporale scorrevole.

Limiti per fascia

CategoriaEndpoint tipiciLimiteFinestra
AutenticazionePOST /identity/v1/auth/login, /auth/mfa/verify10 richieste1 minuto
Recupero credenziali/auth/password/forgot, /auth/password/reset5 richieste15 minuti
Scritture identitàPOST /identity/v1/users, PATCH /identity/v1/users/{userId}60 richieste1 minuto
Letture identitàGET /identity/v1/me, /identity/v1/users600 richieste1 minuto
Letture ConsoleGET /console/v1/sessions, /console/v1/clients1.200 richieste1 minuto
Scritture ConsolePOST /console/v1/clients, /console/v1/sessions/{sessionId}/close300 richieste1 minuto
Upload documentiPOST /console/v1/data-stores/{storeId}/documents30 richieste1 minuto
Statistiche e reportGET /console/v1/statistics60 richieste1 minuto
Letture BillingGET /billing/v1/subscription, /billing/v1/invoices120 richieste1 minuto
Disponibilità BookingGET /booking/v1/availability600 richieste1 minuto
Scritture BookingPOST /booking/v1/bookings120 richieste1 minuto
Servizio-a-servizio (HMAC)Tutti gli endpoint interni3.000 richieste1 minuto

Perché l'autenticazione è più restrittiva

Gli endpoint di login e recupero credenziali hanno limiti molto bassi perché sono i bersagli tipici di attacchi di forza bruta e di credential stuffing. Un'integrazione corretta autentica una volta e riutilizza il token fino alla scadenza: non chiamare /auth/login a ogni richiesta.

Header di risposta

Ogni risposta, sia in caso di successo sia in caso di errore, include gli header di quota.

Header di quota

ParametroTipoObblig.DefaultDescrizione
X-RateLimit-LimitnumberSì—Numero massimo di richieste consentite nella finestra corrente per la fascia richiesta.
X-RateLimit-RemainingnumberSì—Richieste ancora disponibili nella finestra corrente. Quando arriva a zero le chiamate successive ricevono 429.
X-RateLimit-ResetnumberSì—Timestamp Unix in secondi in cui la finestra si azzera e il contatore torna al valore di X-RateLimit-Limit.
Retry-AfternumberNo—Presente solo nelle risposte 429. Secondi da attendere prima di ritentare la richiesta.

Esempio di risposta positiva:

200 OK
HTTP/1.1 200 OK
Content-Type: application/json
X-RateLimit-Limit: 1200
X-RateLimit-Remaining: 1186
X-RateLimit-Reset: 1788515595

Esempio di superamento del limite:

429 Too Many Requests
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1788515595
Retry-After: 42

{
  "code": "RATE_LIMITED",
  "title": "Troppe richieste",
  "message": "Hai superato il limite di 10 richieste al minuto per questo endpoint. Riprova tra 42 secondi.",
  "traceId": "01J8ZQ3K5V6X7Y8Z9A0B1C2D3E",
  "details": [
    { "field": "scope", "code": "PER_KEY", "message": "Limite applicato alla chiave API bp_live_xxxx…" }
  ]
}

Come leggere Retry-After

Retry-After contiene un numero intero di secondi. Non ritentare prima che sia trascorso: le richieste anticipate consumano quota senza essere servite e prolungano il blocco.

retry-after.ts
function retryDelayMs(response: Response, fallbackMs: number): number {
  const retryAfter = response.headers.get('Retry-After');
  if (retryAfter) {
    const seconds = Number.parseInt(retryAfter, 10);
    if (Number.isFinite(seconds)) return seconds * 1000;
  }

  const reset = response.headers.get('X-RateLimit-Reset');
  if (reset) {
    const deltaMs = Number.parseInt(reset, 10) * 1000 - Date.now();
    if (deltaMs > 0) return deltaMs;
  }

  return fallbackMs;
}

Un'integrazione ben scritta non aspetta il 429: quando X-RateLimit-Remaining scende sotto il dieci per cento del limite, rallenta autonomamente il ritmo delle chiamate.

Strategia di retry consigliata

Applica un backoff esponenziale con jitter per evitare che tutti i client ritentino nello stesso istante (effetto "thundering herd"). Ritenta solo su 429, 502, 503 e 504, e solo per richieste idempotenti o accompagnate da un header Idempotency-Key.

fetch-with-retry.ts
const RETRYABLE_STATUS = new Set([429, 502, 503, 504]);

interface RetryOptions {
  maxAttempts?: number;
  baseDelayMs?: number;
  maxDelayMs?: number;
}

const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

export async function fetchWithRetry(
  url: string,
  init: RequestInit = {},
  options: RetryOptions = {},
): Promise<Response> {
  const maxAttempts = options.maxAttempts ?? 5;
  const baseDelayMs = options.baseDelayMs ?? 500;
  const maxDelayMs = options.maxDelayMs ?? 30_000;

  let lastError: unknown;

  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      const response = await fetch(url, init);

      if (!RETRYABLE_STATUS.has(response.status)) return response;
      if (attempt === maxAttempts) return response;

      // Rispetta Retry-After se presente, altrimenti backoff esponenziale con full jitter.
      const header = response.headers.get('Retry-After');
      const serverDelay = header ? Number.parseInt(header, 10) * 1000 : 0;
      const backoff = Math.min(baseDelayMs * 2 ** (attempt - 1), maxDelayMs);
      const jittered = Math.random() * backoff;

      await sleep(Math.max(serverDelay, jittered));
    } catch (error) {
      lastError = error;
      if (attempt === maxAttempts) break;

      const backoff = Math.min(baseDelayMs * 2 ** (attempt - 1), maxDelayMs);
      await sleep(Math.random() * backoff);
    }
  }

  throw lastError ?? new Error('Numero massimo di tentativi superato');
}

Non ritentare le scritture senza chiave di idempotenza

Un POST che va in timeout potrebbe essere stato eseguito comunque dal server. Ritentarlo senza Idempotency-Key può creare risorse duplicate. Genera la chiave una volta prima del primo tentativo e riusala identica in tutti i ritentativi.

Limiti per chiave, per tenant e per IP

I tre livelli sono applicati contemporaneamente: viene rifiutata la richiesta che supera il primo limite raggiunto.

LivelloChiave di conteggioScopoCome identificarlo
Per credenzialeChiave API o jti del tokenIsola le integrazioni tra loro: un job impazzito non blocca la Consoledetails[0].code vale PER_KEY
Per tenantIdentificativo del tenant (tid)Somma di tutte le credenziali del tenant, allineata al piano sottoscrittodetails[0].code vale PER_TENANT
Per IPIndirizzo sorgenteProtegge gli endpoint non autenticati come /auth/logindetails[0].code vale PER_IP

Il limite per tenant dipende dal piano: il piano Business ha un tetto complessivo pari a cinque volte il limite per singola credenziale, il piano Enterprise è configurabile contrattualmente.

Traffico attraverso proxy

Se le tue chiamate passano da un gateway NAT condiviso, tutte le richieste risultano provenire dallo stesso IP e possono saturare il limite per IP sugli endpoint pubblici. In questo caso richiedi l'inserimento dei tuoi IP di uscita nella allowlist: vedi Ambienti.

Buone pratiche

Richiedere un aumento dei limiti

Gli aumenti sono valutati caso per caso per i piani Business ed Enterprise.

Raccogli i dati

Prepara: endpoint interessati, volume di picco misurato (richieste al minuto), volume medio giornaliero, finestra oraria in cui si concentra il traffico e motivazione funzionale.

Verifica le alternative

Il supporto chiederà se hai già adottato webhook al posto del polling, limit più alti e caching lato tuo. Un aumento non viene concesso per compensare un'integrazione inefficiente.

Apri la richiesta

Invia la richiesta dalla Console.

ConsoleSupportoRichiesteAumento limiti API

La valutazione richiede alcuni giorni lavorativi. Per eventi pianificati (migrazioni, campagne) segnala la finestra con almeno due settimane di anticipo.

في هذه الصفحة