---
title: rate_limited — Terlalu banyak request
source: https://se-hari.com/docs/error/rate-limited
updated: 2026-08-15T22:09:55.127895+00:00
---

> HTTP 429. Anda melewati batas jumlah request dalam satu jendela waktu. Batas dihitung **per API key**, bukan per alamat IP — di Indonesia banyak pengguna…

`rate_limited` adalah kode error HTTP 429 pada Se-Hari API. Anda melewati batas jumlah request dalam satu jendela waktu. Batas dihitung **per API key**, bukan per alamat IP — di Indonesia banyak pengguna berbagi IP lewat CGNAT operator, sehingga batas per-IP akan menghukum orang yang tidak melakukan apa-apa.

## Bentuk responsnya

Semua error Se-Hari memakai amplop yang sama. Yang perlu dicabang di kode Anda adalah `code`, bukan `message` — teks pesan bisa kami perbaiki sewaktu-waktu, sedangkan `code` adalah kontrak publik yang hanya berubah lewat versi API baru.

```json
{
  "error": {
    "code": "rate_limited",
    "message": "Contoh pesan untuk rate_limited.",
    "docs_url": "https://se-hari.com/docs/error/rate-limited",
    "request_id": "req_a1b2c3d4e5f6",
    "details": {
      "limit": 120,
      "window_seconds": 60
    }
  }
}
```

## Kapan ini muncul

Batas dihitung per API key, bukan per alamat IP. Keputusan itu penting di Indonesia: operator seluler besar menempatkan ribuan pelanggan di balik satu alamat IP lewat CGNAT, sehingga batas per-IP akan menghukum orang yang tidak melakukan apa-apa dan sekaligus gagal membatasi penyalahguna yang berganti IP.

## Kenapa ini terjadi

- Polling status terlalu sering, alih-alih memakai webhook
- Perulangan tanpa jeda atas ratusan item
- Beberapa proses berbagi satu key dan saling menghabiskan kuota

## Cara memperbaikinya

Baca header `Retry-After` dan tunggu selama itu — mencoba lebih cepat hanya memperpanjang masa tunggu. Header `X-RateLimit-Remaining` pada setiap respons memberi tahu sisa kuota Anda sebelum menyentuh batas, jadi Anda bisa melambat sebelum ditolak, bukan sesudahnya.

### Yang memicu error

```bash
# Polling tiap detik
while true; do
  curl -s "https://se-hari.com/api/v1/notes/<id>" -H "Authorization: Bearer $SEHARI_API_KEY"
done
```

### Yang seharusnya

```bash
# Hormati Retry-After
res=$(curl -s -D /tmp/h -o /tmp/b -w '%{http_code}' \
  "https://se-hari.com/api/v1/notes" -H "Authorization: Bearer $SEHARI_API_KEY")

if [ "$res" = "429" ]; then
  tunggu=$(grep -i '^retry-after:' /tmp/h | tr -d 'A-Za-z-: \r')
  echo "menunggu $tunggu detik"
  sleep "$tunggu"
fi
```

## Aman diulang?

**Ya, setelah menunggu.** Tunggu selama yang disebutkan `Retry-After`, tidak kurang. Mengulang lebih cepat memperpanjang masa tunggu pada sebagian besar implementasi jendela tetap, termasuk yang kami pakai.

## Jangan tertukar dengan

Kode ini soal frekuensi, bukan soal kuota kredit. `insufficient_credits` dan `credit_cap_exceeded` membatasi berapa banyak pekerjaan yang boleh Anda bayar; kode ini membatasi seberapa cepat Anda boleh bertanya. Sebuah key bisa menyentuh 429 tanpa memakai satu kredit pun, misalnya karena polling terus-menerus ke endpoint baca.

## Mencegahnya terulang

Sebagian besar kasus 429 pada integrasi Se-Hari berasal dari polling. Notulen butuh beberapa menit untuk diproses, dan menanyakan statusnya setiap detik menghasilkan ratusan request yang semuanya menjawab hal yang sama. Daftarkan webhook `note.completed` sekali, lalu berhenti bertanya. Kalau polling memang tidak terhindarkan, pakai jeda yang membesar dan baca `X-RateLimit-Remaining` untuk melambat sebelum ditolak.

## Menangani ini di kode

Cabangkan pada `error.code`, dan bedakan kegagalan yang layak diulang dari yang tidak. Mengulang kegagalan yang tidak akan pernah berhasil hanya menghabiskan kuota rate limit — dan menyembunyikan kegagalan yang sebenarnya butuh perhatian Anda.

```javascript
const res = await fetch('https://se-hari.com/api/v1/me', {
	headers: { Authorization: `Bearer ${process.env.SEHARI_API_KEY}` }
});

if (!res.ok) {
	const { error } = await res.json();

	if (error.code === 'rate_limited') {
		// Baca header `Retry-After` dan tunggu selama itu — mencoba lebih cepat hanya…
		console.error(error.message, error.details);
	}

	// request_id adalah satu-satunya cara kami menemukan request ini di log.
	console.error(`request_id: ${error.request_id}`);
}
```

## Selanjutnya

- [Semua kode error](/docs/error) — daftar lengkap
- [Autentikasi](/docs/autentikasi) — scope dan siklus hidup API key
- [Referensi API](/docs/api) — error apa saja yang mungkin muncul di tiap endpoint