Quante richieste al minuto consente l’API di LinkHarbor, quanto può essere grande una richiesta, come leggere gli header e gestire bene un 429.
Per mantenere l’API veloce per tutti, LinkHarbor limita il numero di richieste al minuto. I limiti non dipendono dal tuo piano – non esiste una quota mensile di chiamate API. Questo articolo elenca tutti i limiti e mostra come il tuo codice può gestirli in modo pulito.
Come vengono contate le richieste
- Ogni richiesta finisce esattamente in un bucket, per esempio user per le richieste autenticate o token per lo scambio del token
- Il conteggio avviene per minuto intero (UTC); il contatore riparte da zero a ogni nuovo minuto
- A seconda del bucket, l’API conta per workspace, per persona, per connessione o per indirizzo IP
- Le richieste che falliscono già su token, scope o schema (401, 403 insufficient_scope, 400, 422 validation_failed dal controllo dello schema) non vengono contate; gli errori successivi come 403 feature_not_available sì
Tutti i limiti
| Bucket (X-RateLimit-Bucket) | Limite | Contato per | Vale per |
|---|---|---|---|
| user | 600 al minuto | Workspace per i token delle chiavi API (tutte le chiavi e gli strumenti AI del workspace insieme); persona per gli accessi alla dashboard | Tutte le richieste autenticate a /v1 che non hanno un bucket proprio |
| token | 30 al minuto | Indirizzo IP | POST /v1/token |
| public | 120 al minuto | Indirizzo IP | Richieste all’API senza autenticazione, come GET /v1/plans e GET /v1/pages/available |
| callback | 120 al minuto | Indirizzo IP | POST /v1/callbacks/sale |
| internal | 120 al minuto | Indirizzo IP | URL di ingest dell’integrazione «Custom (API)» (POST /v1/ingest/{id}) |
| mcp | 120 al minuto | Connessione AI (token di accesso) | Server MCP su /mcp |
| oauth | 300 al minuto | Indirizzo IP | Accesso OAuth e discovery per gli assistenti AI |
| auth | 30 al minuto | Indirizzo IP | Login, registrazione, ripristino della password (dashboard e app) |
| refresh | 120 al minuto | Indirizzo IP | Prolungamento di una sessione della dashboard |
| discover | 60 al minuto | Persona, indirizzo IP se non hai effettuato l’accesso | La sezione Scopri dell’app |
| subs_read | 120 al minuto | Persona, indirizzo IP se non hai effettuato l’accesso | Lettura delle pagine che segui (app) |
| subs_write | 20 al minuto | Persona, indirizzo IP se non hai effettuato l’accesso | Modifica delle pagine che segui (app) |
Un solo budget per workspace
Tutti i token delle chiavi API dello stesso workspace condividono le 600 richieste al minuto – indipendentemente da quante chiavi crei. Contano anche gli strumenti degli assistenti AI collegati, perché chiamano l’API internamente. Più chiavi quindi non alzano il limite. Se molto carico è distribuito su diversi programmi, pianifica tenendo conto del budget condiviso.
Gli header
- X-RateLimit-Limit
- Il limite al minuto del bucket, per esempio 600.
- X-RateLimit-Remaining
- Quante richieste restano nel minuto in corso.
- X-RateLimit-Bucket
- Il bucket in cui è finita la richiesta, per esempio user.
- Retry-After
- Solo con 429 rate_limited: secondi mancanti all’inizio del minuto successivo. Con api_key_locked, il tempo di attesa è in details.retry_after_sec.
Quando il limite è raggiunto
Una volta raggiunto il limite, l’API risponde con HTTP 429 e questo corpo. Il testo in message è nella lingua dell’account (vedi Formato degli errori API), qui in inglese. Basati sul codice rate_limited:
HTTP/1.1 429 Too Many Requests
Retry-After: 37
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 0
X-RateLimit-Bucket: user
{ "error": "rate_limited", "message": "Too many requests. Please try again in a moment.", "retry_after_sec": 37 } - Leggi Retry-After o retry_after_sec
- Attendi almeno quei secondi, più un po’ di casualità, così che non tutti i processi ripartano nello stesso momento
- Ripeti la richiesta al massimo qualche volta
- Se continui a ricevere 429, distribuisci il lavoro su un periodo più lungo
const BASE = 'https://dock.at-harbor.com';
let cached = null; // { token, expiresAt }
async function getToken() {
if (cached && Date.now() < cached.expiresAt - 60_000) return cached.token;
const res = await fetch(BASE + '/v1/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
key_id: process.env.LH_KEY_ID,
key_secret: process.env.LH_KEY_SECRET,
}),
});
if (!res.ok) throw new Error('Token exchange failed: HTTP ' + res.status);
const data = await res.json();
cached = { token: data.token, expiresAt: Date.now() + data.expires_in * 1000 };
return cached.token;
}
async function lh(method, path, body, attempt = 0) {
const headers = { Authorization: 'Bearer ' + (await getToken()) };
if (body !== undefined) headers['Content-Type'] = 'application/json';
const res = await fetch(BASE + path, {
method,
headers,
body: body === undefined ? undefined : JSON.stringify(body),
});
if (res.status === 429 && attempt < 3) {
const wait = Number(res.headers.get('Retry-After') ?? 5);
await new Promise((r) => setTimeout(r, (wait + Math.random() * 2) * 1000));
return lh(method, path, body, attempt + 1);
}
if (res.status === 401 && attempt === 0) {
cached = null; // token scaduto – riprova una volta con un nuovo token
return lh(method, path, body, attempt + 1);
}
const data = await res.json().catch(() => null);
if (!res.ok) throw new Error((data && data.error) + ' (HTTP ' + res.status + ')');
return data;
}
// Esempio: const { items } = await lh('GET', '/v1/pages'); Consigli per grandi quantità di dati
- Tieni il token in cache e rinnovalo solo poco prima che scada dopo 15 minuti
- Tieni d’occhio X-RateLimit-Remaining e rallenta quando il valore si abbassa
- Invia le richieste una dopo l’altra invece che su decine di connessioni parallele
- Carica gli elenchi una volta e filtrali in locale invece di interrogare ogni pagina singolarmente
- Distribuisci le sincronizzazioni grandi su più minuti
- Ripeti gli errori 5xx con pause crescenti, ma non gli errori 4xx
Altri limiti
| Cosa | Limite | Risposta |
|---|---|---|
| Accessi falliti | Blocco dopo 5, 10 e 20 tentativi falliti per indirizzo e-mail e IP: 60 secondi, 5 minuti, 30 minuti | 429 account_locked |
| Invii dei moduli | 10 all’ora per indirizzo IP, su tutti i moduli | 429 form_rate_limited |
I tentativi falliti nello scambio del token bloccano temporaneamente chiave e IP, vedi Chiavi API e token di accesso. Le notifiche push le invii solo dalla dashboard; i loro limiti sono spiegati in Follower e notifiche push.
I limiti di contenuto del tuo piano – pagine, link, blocchi, link brevi e così via – non sono limiti di richieste ma tetti fissi. Sono elencati in Piani a confronto.
Dimensione della richiesta
Ogni corpo viene misurato prima che l’API lo legga. Quanto può essere grande dipende dall’endpoint:
| Endpoint | Corpo massimo |
|---|---|
| Login, registrazione e le altre chiamate non autenticate sotto /v1/auth, POST /v1/token, POST /v1/oauth/exchange, gli endpoint OAuth per gli assistenti AI sotto /oauth e il relativo consenso, POST /v1/ingest/{id}, il checkout del blocco Sostieni, le chiamate di iscrizione dell’app (pagine seguite, collezioni, dispositivi push), il cambio di workspace, POST /v1/auth/logout-all, l’eliminazione di un account, la configurazione dell’autenticazione a due fattori, l’accettazione di un invito, l’attivazione del programma «Consiglia e guadagna» e il passaggio di ritorno quando colleghi un’integrazione | 64 KB |
| Tutti gli altri endpoint JSON, compreso l’invio di un modulo su una pagina | 1 MB |
| POST /v1/webhooks/{id}/verify-signature e il server MCP su /mcp | 2 MB |
| Caricamento di file (POST /v1/assets e POST /v1/pages/{id}/uploads, multipart/form-data) | 11 MB per l’intera richiesta, il file stesso al massimo 10 MB |
Se il corpo è più grande, l’API risponde con 413 request_too_large; details.max_bytes e details.max_kb indicano il limite. Un file troppo grande in un caricamento porta a 413 payload_too_large. Gli endpoint senza corpo, come le chiamate DELETE, non accettano alcun corpo oppure solo {}.
HTTP/1.1 413 Payload Too Large
{ "error": "request_too_large", "message": "…", "details": { "max_bytes": 65536, "max_kb": 64 }, "request_id": "…" } Ci sono limiti anche all’interno del corpo: ogni testo ha una lunghezza massima, ogni elenco un numero massimo di voci, e i campi sconosciuti vengono rifiutati. I valori sono elencati per endpoint nel riferimento dell’API. Una violazione porta a 422 validation_failed, e details indica campo, regola e limite. Percorso e query string di una richiesta possono essere lunghi insieme al massimo 16 KB.
Potrebbe esserti utile anche
Non hai trovato nulla?
Dicci di cosa hai bisogno e il nostro team di assistenza ti aiuterà personalmente.