> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bota.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Pagination

> Navigating large result sets with cursor-based pagination

All list endpoints (`GET /recordings`, `GET /end-users`, `GET /devices`, etc.) return paginated results. Bota uses **cursor-based pagination** — each page returns a cursor pointing to the last item, which you pass to fetch the next page.

## Query Parameters

| Parameter | Default | Max   | Description                                                                                    |
| :-------- | :------ | :---- | :--------------------------------------------------------------------------------------------- |
| `limit`   | `20`    | `100` | Maximum number of objects to return per page.                                                  |
| `cursor`  | —       | —     | Opaque cursor returned by the previous page's `next_cursor`. Omit to start from the beginning. |

## Response Structure

```json theme={null}
{
  "data": [
    { "id": "rec_1", "status": "completed", ... },
    { "id": "rec_2", "status": "completed", ... }
  ],
  "has_more": true,
  "next_cursor": "eyJpZCI6InJlY18yIiwidHMiOiIyMDI1LTAxLTE1VDEwOjAwOjAwLjAwMFoifQ",
  "total": 1247
}
```

### Response Fields

| Field         | Type    | Description                                                                                    |
| :------------ | :------ | :--------------------------------------------------------------------------------------------- |
| `data`        | array   | The list of resources for this page.                                                           |
| `has_more`    | boolean | `true` if more results exist beyond this page.                                                 |
| `next_cursor` | string  | Opaque cursor to pass as `cursor` on the next request. Present only when `has_more` is `true`. |
| `total`       | integer | Total number of matching records across all pages. Present on most list endpoints.             |

## Iterating Through All Results

Pass the previous page's `next_cursor` as the `cursor` parameter on the next request. Stop when `has_more` is `false`.

```bash theme={null}
# Page 1 — no cursor
curl "https://api.bota.dev/v1/recordings?limit=50" \
  -H "Authorization: Bearer sk_live_..."

# Page 2 — pass next_cursor from page 1
curl "https://api.bota.dev/v1/recordings?limit=50&cursor=eyJpZCI6..." \
  -H "Authorization: Bearer sk_live_..."
```

```javascript Node.js theme={null}
async function fetchAllRecordings(apiKey) {
  const recordings = [];
  let cursor;

  do {
    const params = new URLSearchParams({ limit: '100' });
    if (cursor) params.set('cursor', cursor);

    const response = await fetch(`https://api.bota.dev/v1/recordings?${params}`, {
      headers: { 'Authorization': `Bearer ${apiKey}` },
    });
    const page = await response.json();

    recordings.push(...page.data);
    cursor = page.next_cursor;
  } while (page.has_more);

  return recordings;
}
```

## Default Sorting

All list endpoints return results sorted by `created_at` descending (newest first). Cursors are tied to this sort order — changing filters requires starting from a fresh cursor.
