# Pagination & Rate Limit

## Pagination

OmniStream memakai dua gaya pagination.

### Page-based (daftar relasional)

Endpoint daftar seperti `/api/conversations`, `/api/contacts`, dan
`/api/campaigns` menerima query `page` (mulai 1) dan `per_page` (maks 100).

```bash
curl "https://api.omnistream.example/api/contacts?search=acme&page=2&per_page=50" \
  -H "X-API-Key: os_..."
```

Bentuk responsnya ada dua, dan ini mudah keliru:

- **Array polos** — `/api/conversations`, `/api/wa-templates`, dan sejenisnya
  mengembalikan array JSON langsung. Halaman terakhir tercapai saat jumlah item
  yang dikembalikan kurang dari `per_page`.
- **Envelope pagination** — `/api/contacts` dan `/api/messages/search`
  membungkus barisnya: `{ data | results, total, page, per_page, total_pages }`.
  Jangan perlakukan responsnya sebagai array; pakai `total_pages` untuk tahu
  batas halaman. `per_page` untuk `/api/messages/search` di-clamp 1..50 (bukan
  100), dan endpoint itu tidak mengenal `limit`.

### Cursor-based (pesan)

Daftar pesan `/api/conversations/{id}/messages` memakai cursor (hex ObjectId
MongoDB), diurutkan dari yang terbaru:

```bash
curl "https://api.omnistream.example/api/conversations/ID/messages?limit=50&cursor=CURSOR" \
  -H "X-API-Key: os_..."
```

:::tip
[TypeScript SDK](/developer/typescript-sdk) menyediakan `client.paginate()` yang
otomatis menelusuri seluruh halaman sebagai async iterator — hanya untuk
endpoint yang mengembalikan array polos. Untuk endpoint ber-envelope pakai
`client.contacts.listPage()` / `client.messages.search()`.
:::

## Rate limiting

API menerapkan rate limit per klien. Saat terlampaui, server membalas
**HTTP 429** dengan header **`Retry-After`** (detik).

Perilaku klien yang disarankan:

- Hormati `Retry-After` sebelum mencoba lagi.
- Gunakan **exponential backoff + jitter** untuk retry.
- Hanya retry otomatis untuk request **idempoten** (GET). Untuk POST, retry
  hanya pada 429 (belum diproses) — atau kirim **`Idempotency-Key`** agar aman
  di-retry pada kegagalan jaringan.

SDK resmi sudah menerapkan semua ini secara default.
