# Pagination

> Page through contacts and conversations with opaque cursors; which endpoints paginate and their page-size limits.

Source: https://dev.ody.co/api/pagination

List endpoints that can grow without bound use **cursor pagination**: you ask for a page, and the response tells you where the next one starts. Cursors are stable — new rows arriving while you page don't make you skip or repeat items, unlike offset pagination.

## How it works

1. Call the list endpoint with an optional `limit`.
2. The response includes `nextCursor`.
3. Pass it back as `cursor` on the next request.
4. Stop when `nextCursor` is `null`. (When the last page happens to be exactly full, you get one more request that returns an empty list and `nextCursor: null`.)

cURL:

```bash
curl "https://api.ody.co/v1/api/contacts?limit=100" \
  -H "Authorization: Bearer $ODY_API_KEY"

# next page
curl "https://api.ody.co/v1/api/contacts?limit=100&cursor=eyJjIjoiMjAyNi0x…" \
  -H "Authorization: Bearer $ODY_API_KEY"
```
TypeScript:

```ts
// The SDK follows nextCursor for you.
for await (const contact of ody.contacts.listAll({ limit: 200 })) {
  console.log(contact.id);
}
```
Python:

```python
# The SDK follows nextCursor for you.
for contact in client.contacts.list_all(limit=200):
    print(contact["id"])
```

Response:

```json
{
  "contacts": [{ "id": "8b1d…", "firstName": "Ada" }],
  "nextCursor": "eyJjIjoiMjAyNi0xMC0xNFQxODowMjoxMS4wMDBaIiwiaSI6IjhiMWQ…"
}
```

- `limit` *integer* — Page size. Defaults and maximums per endpoint below.
- `cursor` *string* — The previous response's `nextCursor`, passed back **verbatim**. A modified or stale cursor returns `400 invalid_argument`.

## Limits per endpoint

| Endpoint | Paginates | Default `limit` | Max `limit` | Order |
|---|---|---|---|---|
| `GET /contacts` | cursor | 50 | 200 | Newest created first |
| `GET /conversations` | cursor | 50 | 100 | Most recent activity first |
| `GET /calls` | `limit` only | 50 | 200 | Newest first |
| `GET /messages/search` | `limit` only | 25 | 100 | Best match |
| `GET /numbers/available` | `limit` only | 20 | 50 | Carrier order |
| `GET /webhooks/:id/deliveries` | `limit` only | 50 | 200 | Newest first |

> **Syncing a large workspace:**
Use the maximum `limit`, and switch to [webhooks](https://dev.ody.co/webhooks/overview) (`contact.updated`, `message.received`) for incremental changes once the initial backfill is done — it's faster and stays well under the [rate limit](https://dev.ody.co/api/rate-limits).
