Berapa permintaan per menit yang diizinkan API LinkHarbor, seberapa besar permintaan boleh, cara membaca header, dan cara menangani 429 dengan benar.
Agar API tetap cepat bagi semua orang, LinkHarbor membatasi jumlah permintaan per menit. Batas ini tidak bergantung pada paket Anda – tidak ada kuota bulanan panggilan API. Artikel ini mencantumkan setiap batas dan menunjukkan cara kode Anda menanganinya dengan rapi.
Cara permintaan dihitung
- Setiap permintaan masuk ke tepat satu bucket, misalnya user untuk permintaan terautentikasi atau token untuk penukaran token
- Penghitungan per menit penuh (UTC); penghitung mulai dari nol lagi di setiap menit baru
- Tergantung bucket-nya, API menghitung per workspace, per orang, per koneksi, atau per alamat IP
- Permintaan yang sudah gagal pada token, scope, atau skema (401, 403 insufficient_scope, 400, 422 validation_failed dari pemeriksaan skema) tidak dihitung; kesalahan yang lebih belakangan seperti 403 feature_not_available dihitung
Semua batas
| Bucket (X-RateLimit-Bucket) | Batas | Dihitung per | Berlaku untuk |
|---|---|---|---|
| user | 600 per menit | Workspace untuk token dari kunci API (semua kunci dan tool AI workspace bersama-sama); orang untuk sesi masuk dasbor | Semua permintaan terautentikasi ke /v1 yang tidak punya bucket sendiri |
| token | 30 per menit | Alamat IP | POST /v1/token |
| public | 120 per menit | Alamat IP | Permintaan ke API tanpa autentikasi, seperti GET /v1/plans dan GET /v1/pages/available |
| callback | 120 per menit | Alamat IP | POST /v1/callbacks/sale |
| internal | 120 per menit | Alamat IP | URL ingest integrasi “Custom (API)” (POST /v1/ingest/{id}) |
| mcp | 120 per menit | Koneksi AI (access token) | Server MCP di /mcp |
| oauth | 300 per menit | Alamat IP | Masuk OAuth dan discovery untuk asisten AI |
| auth | 30 per menit | Alamat IP | Masuk, pendaftaran, pengaturan ulang kata sandi (dasbor dan aplikasi) |
| refresh | 120 per menit | Alamat IP | Memperpanjang sesi dasbor |
| discover | 60 per menit | Orang, alamat IP jika belum masuk | Bagian Jelajahi di aplikasi |
| subs_read | 120 per menit | Orang, alamat IP jika belum masuk | Membaca halaman yang Anda ikuti (aplikasi) |
| subs_write | 20 per menit | Orang, alamat IP jika belum masuk | Mengubah halaman yang Anda ikuti (aplikasi) |
Satu anggaran per workspace
Semua token dari kunci API di workspace yang sama berbagi 600 permintaan per menit – tidak peduli berapa banyak kunci yang Anda buat. Tool asisten AI yang terhubung juga dihitung di sini, karena tool itu memanggil API secara internal. Jadi lebih banyak kunci tidak menaikkan batasnya. Jika banyak beban tersebar di beberapa program, rencanakan dengan memperhitungkan anggaran bersama ini.
Header-headernya
- X-RateLimit-Limit
- Batas bucket per menit, misalnya 600.
- X-RateLimit-Remaining
- Berapa permintaan yang tersisa di menit saat ini.
- X-RateLimit-Bucket
- Bucket tempat permintaan itu masuk, misalnya user.
- Retry-After
- Hanya pada 429 rate_limited: detik sampai menit berikutnya dimulai. Dengan api_key_locked, waktu tunggunya ada di details.retry_after_sec.
Saat batas tercapai
Begitu batasnya tercapai, API merespons dengan HTTP 429 dan body ini. Teks di message mengikuti bahasa akun (lihat Format kesalahan API), di sini dalam bahasa Inggris. Andalkan kode 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 } - Baca Retry-After atau retry_after_sec
- Tunggu minimal selama itu, ditambah sedikit nilai acak agar tidak semua proses mulai lagi pada saat yang sama
- Ulangi permintaan paling banyak beberapa kali
- Jika Anda terus mendapat 429, sebarkan pekerjaannya ke rentang waktu yang lebih panjang
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 kedaluwarsa – coba sekali lagi dengan token baru
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;
}
// Contoh: const { items } = await lh('GET', '/v1/pages'); Tips untuk data dalam jumlah besar
- Simpan token di cache dan perbarui hanya sesaat sebelum kedaluwarsa setelah 15 menit
- Pantau X-RateLimit-Remaining dan perlambat jika nilainya menipis
- Kirim permintaan satu per satu, bukan lewat puluhan koneksi paralel
- Muat daftar sekali dan saring secara lokal, alih-alih meminta setiap halaman satu per satu
- Sebarkan sinkronisasi besar ke beberapa menit
- Ulangi kesalahan 5xx dengan jeda yang makin lama, tetapi jangan kesalahan 4xx
Batas lainnya
| Apa | Batas | Respons |
|---|---|---|
| Masuk yang gagal | Penguncian setelah 5, 10, dan 20 percobaan gagal per alamat email dan IP: 60 detik, 5 menit, 30 menit | 429 account_locked |
| Kiriman formulir | 10 per jam dan alamat IP, untuk semua formulir | 429 form_rate_limited |
Percobaan gagal pada penukaran token mengunci kunci dan IP untuk sementara, lihat Kunci API dan token. Notifikasi push hanya Anda kirim di dasbor; batasnya dijelaskan di Pengikut dan notifikasi push.
Batas konten paket Anda – halaman, tautan, blok, tautan pendek, dan sebagainya – bukan rate limit, melainkan batas tetap. Semuanya tercantum di Perbandingan paket.
Ukuran permintaan
Setiap body diukur sebelum API membacanya. Seberapa besar body boleh tergantung endpoint-nya:
| Endpoint | Body terbesar |
|---|---|
| Masuk, pendaftaran, dan panggilan lain tanpa autentikasi di bawah /v1/auth, POST /v1/token, POST /v1/oauth/exchange, endpoint OAuth untuk asisten AI di bawah /oauth dan persetujuannya, POST /v1/ingest/{id}, checkout blok Dukung, panggilan langganan aplikasi (mengikuti, koleksi, perangkat push), berpindah workspace, POST /v1/auth/logout-all, menghapus akun, penyiapan dua faktor, menerima undangan, mengaktifkan program referral, dan langkah kembali saat menghubungkan integrasi | 64 KB |
| Semua endpoint JSON lainnya, termasuk mengirim formulir di sebuah halaman | 1 MB |
| POST /v1/webhooks/{id}/verify-signature dan server MCP di /mcp | 2 MB |
| Unggahan file (POST /v1/assets dan POST /v1/pages/{id}/uploads, multipart/form-data) | 11 MB untuk seluruh permintaan, filenya sendiri paling besar 10 MB |
Jika body lebih besar, API merespons dengan 413 request_too_large; details.max_bytes dan details.max_kb menyebutkan batasnya. File yang terlalu besar dalam unggahan menghasilkan 413 payload_too_large. Endpoint tanpa body, seperti panggilan DELETE, tidak menerima body atau hanya {}.
HTTP/1.1 413 Payload Too Large
{ "error": "request_too_large", "message": "…", "details": { "max_bytes": 65536, "max_kb": 64 }, "request_id": "…" } Di dalam body juga ada batas: setiap teks punya panjang maksimum, setiap daftar jumlah entri maksimum, dan kolom yang tidak dikenal ditolak. Nilainya tercantum per endpoint di referensi API. Pelanggaran menghasilkan 422 validation_failed, dan details menyebutkan kolom, aturan, dan batasnya. Path dan query string sebuah permintaan bersama-sama paling panjang 16 KB.
Mungkin ini juga berguna
Tidak menemukan jawabannya?
Beri tahu kami apa yang Anda perlukan, dan tim dukungan kami akan membantu Anda secara langsung.