Ile żądań na minutę dopuszcza API LinkHarbor, jak duże może być żądanie, jak czytać nagłówki i jak poprawnie obsłużyć kod 429.
Aby API działało szybko dla wszystkich, LinkHarbor ogranicza liczbę żądań na minutę. Limity nie zależą od Twojego planu – nie ma miesięcznego limitu wywołań API. Ten artykuł wymienia wszystkie limity i pokazuje, jak Twój kod może je poprawnie obsłużyć.
Jak liczone są żądania
- Każde żądanie trafia do dokładnie jednego koszyka, na przykład user dla uwierzytelnionych żądań lub token dla wymiany tokenu
- Liczenie odbywa się w pełnych minutach (UTC); z każdą nową minutą licznik zaczyna od zera
- W zależności od koszyka API liczy na workspace, na osobę, na połączenie lub na adres IP
- Żądania, które nie przechodzą już na etapie tokenu, zakresu lub schematu (401, 403 insufficient_scope, 400, 422 validation_failed z kontroli schematu), nie są liczone; późniejsze błędy, takie jak 403 feature_not_available, są liczone
Wszystkie limity
| Koszyk (X-RateLimit-Bucket) | Limit | Liczone na | Dotyczy |
|---|---|---|---|
| user | 600 na minutę | Workspace dla tokenów z kluczy API (wszystkie klucze i narzędzia AI workspace razem); osoba dla logowań do panelu | Wszystkie uwierzytelnione żądania do /v1, które nie mają własnego koszyka |
| token | 30 na minutę | Adres IP | POST /v1/token |
| public | 120 na minutę | Adres IP | Żądania do API bez uwierzytelniania, takie jak GET /v1/plans i GET /v1/pages/available |
| callback | 120 na minutę | Adres IP | POST /v1/callbacks/sale |
| internal | 120 na minutę | Adres IP | URL ingest integracji „Custom (API)” (POST /v1/ingest/{id}) |
| mcp | 120 na minutę | Połączenie AI (token dostępu) | Serwer MCP pod /mcp |
| oauth | 300 na minutę | Adres IP | Logowanie OAuth i discovery dla asystentów AI |
| auth | 30 na minutę | Adres IP | Logowanie, rejestracja, resetowanie hasła (panel i aplikacja) |
| refresh | 120 na minutę | Adres IP | Przedłużanie sesji panelu |
| discover | 60 na minutę | Osoba, bez logowania adres IP | Sekcja „Odkrywaj” w aplikacji |
| subs_read | 120 na minutę | Osoba, bez logowania adres IP | Odczyt obserwowanych stron (aplikacja) |
| subs_write | 20 na minutę | Osoba, bez logowania adres IP | Zmiana obserwowanych stron (aplikacja) |
Jeden budżet na workspace
Wszystkie tokeny z kluczy API w tym samym workspace dzielą 600 żądań na minutę – bez względu na to, ile kluczy utworzysz. Wliczają się tu też narzędzia połączonych asystentów AI, bo wewnętrznie wywołują API. Więcej kluczy nie podnosi więc limitu. Jeśli duże obciążenie rozkłada się na kilka programów, planuj z uwzględnieniem wspólnego budżetu.
Nagłówki
- X-RateLimit-Limit
- Limit koszyka na minutę, na przykład 600.
- X-RateLimit-Remaining
- Ile żądań zostało w bieżącej minucie.
- X-RateLimit-Bucket
- Koszyk, do którego trafiło żądanie, na przykład user.
- Retry-After
- Tylko przy 429 rate_limited: liczba sekund do początku następnej minuty. Przy api_key_locked czas oczekiwania znajduje się w details.retry_after_sec.
Gdy limit zostanie osiągnięty
Po osiągnięciu limitu API odpowiada kodem HTTP 429 i taką treścią. Tekst w message jest w języku konta (zobacz Format błędów API), tutaj po angielsku. Polegaj na kodzie 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 } - Odczytaj Retry-After lub retry_after_sec
- Odczekaj co najmniej tyle sekund, plus trochę losowego czasu, aby nie wszystkie procesy ruszyły ponownie w tym samym momencie
- Ponów żądanie najwyżej kilka razy
- Jeśli nadal dostajesz 429, rozłóż pracę na dłuższy czas
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 wygasł – spróbuj jeszcze raz z nowym tokenem
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;
}
// Przykład: const { items } = await lh('GET', '/v1/pages'); Wskazówki przy dużych ilościach danych
- Przechowuj token w pamięci podręcznej i odnawiaj go dopiero tuż przed wygaśnięciem po 15 minutach
- Obserwuj X-RateLimit-Remaining i zwolnij, gdy wartość robi się niska
- Wysyłaj żądania jedno po drugim zamiast przez dziesiątki równoległych połączeń
- Wczytuj listy raz i filtruj je lokalnie, zamiast odpytywać każdą stronę osobno
- Rozkładaj duże synchronizacje na kilka minut
- Ponawiaj błędy 5xx z rosnącymi przerwami, ale nie błędy 4xx
Inne limity
| Co | Limit | Odpowiedź |
|---|---|---|
| Nieudane logowania | Blokada po 5, 10 i 20 nieudanych próbach na adres e-mail i IP: 60 sekund, 5 minut, 30 minut | 429 account_locked |
| Zgłoszenia formularzy | 10 na godzinę i adres IP, łącznie dla wszystkich formularzy | 429 form_rate_limited |
Nieudane próby wymiany tokenu tymczasowo blokują klucz i IP, zobacz Klucze API i tokeny dostępu. Powiadomienia push wysyłasz tylko w panelu; ich limity wyjaśnia artykuł Obserwujący i powiadomienia push.
Limity treści Twojego planu – strony, linki, bloki, krótkie linki itd. – nie są limitami zapytań, lecz stałymi górnymi granicami. Znajdziesz je w artykule Porównanie planów.
Rozmiar żądania
Każda treść żądania jest mierzona, zanim API ją odczyta. Jak duża może być, zależy od endpointu:
| Endpointy | Największa treść |
|---|---|
| Logowanie, rejestracja i pozostałe nieuwierzytelnione wywołania pod /v1/auth, POST /v1/token, POST /v1/oauth/exchange, endpointy OAuth dla asystentów AI pod /oauth i zgoda dla nich, POST /v1/ingest/{id}, płatność bloku „Wesprzyj”, wywołania subskrypcji w aplikacji (obserwowanie, kolekcje, urządzenia push), przełączanie workspace, POST /v1/auth/logout-all, usuwanie konta, konfiguracja uwierzytelniania dwuskładnikowego, akceptowanie zaproszenia, aktywacja programu poleceń i krok powrotu przy łączeniu integracji | 64 KB |
| Wszystkie pozostałe endpointy JSON, w tym wysyłanie formularza na stronie | 1 MB |
| POST /v1/webhooks/{id}/verify-signature i serwer MCP pod /mcp | 2 MB |
| Przesyłanie plików (POST /v1/assets i POST /v1/pages/{id}/uploads, multipart/form-data) | 11 MB dla całego żądania, sam plik najwyżej 10 MB |
Jeśli treść jest większa, API odpowiada kodem 413 request_too_large; details.max_bytes i details.max_kb podają limit. Zbyt duży plik przy przesyłaniu prowadzi do 413 payload_too_large. Endpointy bez treści, takie jak wywołania DELETE, nie przyjmują treści albo przyjmują tylko {}.
HTTP/1.1 413 Payload Too Large
{ "error": "request_too_large", "message": "…", "details": { "max_bytes": 65536, "max_kb": 64 }, "request_id": "…" } Limity obowiązują też wewnątrz treści: każdy tekst ma maksymalną długość, każda lista maksymalną liczbę wpisów, a nieznane pola są odrzucane. Wartości dla każdego endpointu znajdziesz w dokumentacji API. Naruszenie prowadzi do 422 validation_failed, a details podaje pole, regułę i limit. Ścieżka i query string żądania mogą mieć razem najwyżej 16 KB.
Może Ci się też przydać
Nic nie znaleziono?
Napisz, czego potrzebujesz, a nasz zespół pomocy technicznej pomoże Ci osobiście.