> For the complete documentation index, see [llms.txt](https://docs.claret.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.claret.app/api-guide/pagination.md).

# Pagination

All list endpoints paginate their results. The API uses **two pagination styles** depending on the kind of data:

| Style                     | Used by                                                              | Why                                                                             |
| ------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| **Offset** (page numbers) | Reference and master data (items, uoms, calendars, locations, etc.)  | These sets are small and benefit from random page access and a total count.     |
| **Cursor**                | Transactional data (sales, inventory, supply plans, financial plans) | These sets are large; cursors page efficiently without an expensive `COUNT(*)`. |

Pagination details appear under `meta.pagination` in every list response.

{% hint style="warning" %}
Looking for the old `current_index` / `next_index` style? That belonged to the legacy endpoints. See [Migrating from Legacy Endpoints](/api-guide/migration.md).
{% endhint %}

## Offset pagination (reference data)

Control the page with two query parameters:

| Parameter  | Default | Description                                                                                         |
| ---------- | ------- | --------------------------------------------------------------------------------------------------- |
| `page`     | `1`     | The page number to retrieve.                                                                        |
| `per_page` | `25`    | Records per page. Each endpoint has a maximum (commonly 100, up to 1000 for larger reference sets). |

**Request:**

```bash
curl "https://plan.claret.app/{tenant}/api/v1/items?page=2&per_page=50" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
```

**Response `meta.pagination`:**

```json
{
  "meta": {
    "pagination": {
      "result_count": 50,
      "current_page": 2,
      "per_page": 50,
      "total": 1234,
      "last_page": 25
    }
  }
}
```

To walk every page, increment `page` until `current_page` equals `last_page`.

## Cursor pagination (transactional data)

Large datasets use an opaque cursor instead of page numbers:

| Parameter  | Default  | Description                                                    |
| ---------- | -------- | -------------------------------------------------------------- |
| `cursor`   | *(none)* | The cursor token for the next page. Omit on the first request. |
| `per_page` | `100`    | Records per page. Maximum `5000`.                              |

**First request** (no cursor):

```bash
curl "https://plan.claret.app/{tenant}/api/v1/inventory?per_page=500" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
```

**Response `meta.pagination`:**

```json
{
  "meta": {
    "pagination": {
      "result_count": 500,
      "per_page": 500,
      "has_more": true,
      "next_cursor": "eyJpZCI6MTUwMCwiX3BvaW50c1RvTmV4dEl0ZW1zIjp0cnVlfQ",
      "prev_cursor": null
    }
  }
}
```

**Next request** — pass `next_cursor` back as `cursor`:

```bash
curl "https://plan.claret.app/{tenant}/api/v1/inventory?per_page=500&cursor=eyJpZCI6MTUwMCwiX3BvaW50c1RvTmV4dEl0ZW1zIjp0cnVlfQ" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
```

Keep following `next_cursor` until `has_more` is `false`. At that point `next_cursor` is `null` and you have read the entire set.

{% hint style="info" %}
Cursor responses intentionally omit `total` and `last_page`. Counting every matching row on a large transactional table is expensive, so the API reports only whether more pages exist.
{% endhint %}

### Looping in pseudocode

```
cursor = null
repeat:
    response = GET /inventory?per_page=500 (+ &cursor=<cursor> if set)
    process(response.data)
    cursor = response.meta.pagination.next_cursor
until response.meta.pagination.has_more == false
```

## Choosing `per_page`

Larger pages mean fewer requests but heavier responses. Each request also spends [credits](/api-guide/credits-and-usage.md) and a [rate-limit](/api-guide/rate-limiting.md) token, so for bulk reads prefer larger pages (up to each endpoint's maximum) over many small ones.

## Related documentation

* [Filtering & Sorting](/api-guide/filtering-and-sorting.md) — narrow and order results before paging.
* [Rate Limiting](/api-guide/rate-limiting.md) — why fewer, larger pages are friendlier.
* The **API Reference** — the `per_page` maximum for each endpoint.
