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

# Pagination

Endpoints that support pagination use **cursor-based pagination**: there are no page numbers or offsets. You request a first page with a `limit`, and each response hands you an opaque `next_token` to fetch the following page. Each endpoint declares whether it supports pagination on its API Reference page. Like every tipee API call, the examples below are `POST` requests with a JSON body (see [First steps](/guides-and-resources/first-steps)).

## Requesting a page

Pagination is controlled by the `pagination` object of the request body:

```json theme={null}
{
  "pagination": {
    "limit": 100,
    "next_token": null
  }
}
```

| Field        | Description                                                                                                            |
| ------------ | ---------------------------------------------------------------------------------------------------------------------- |
| `limit`      | Maximum number of entries returned in this page. Set it to `null` to return the whole collection in a single response. |
| `next_token` | Opaque cursor taken from the previous response. Use `null` for the first page.                                         |

Both fields are part of the `pagination` object: send them explicitly, with `null` as the value where you have none.

<Tip>Always set an explicit `limit` — fetching an entire collection in a single call can be slow on large datasets and counts against your [rate limits](/guides-and-resources/rate-limiting).</Tip>

## Response envelope

Paginated endpoints wrap their results in an envelope:

```json theme={null}
{
  "data": [
    {
      "id": "872815618512410358"
    }
  ],
  "next_token": "eyJkYXRhIjpbIkR1cG9udCJdLCJoYXNoIjoiOWQ4ZiJ9"
}
```

`data` contains up to `limit` entries. `next_token` is the cursor for the next page, or `null` when there is no further page.

Some endpoints can also return the total size of the collection. For example, `/api/directory/resources.list` adds `total_count` and `total_count_approximate` to the envelope when the request sets `"with_total_count": true`; its `counting_mode` property (`strict` or `approximate`) trades accuracy for speed.

<Note>`.list` endpoints that do not declare pagination return a plain JSON array, without an envelope.</Note>

## Iterating through pages

<Steps>
  <Step title="Fetch the first page">
    Send your request with `"next_token": null` and an explicit `limit`, along with your `filters` and `orders`.
  </Step>

  <Step title="Follow the cursor">
    Process `data`, then resend the exact same request with `next_token` set to the value from the response.
  </Step>

  <Step title="Stop at the end">
    Stop when the response contains `"next_token": null` or an empty `data` array.
  </Step>
</Steps>

<Warning>You must resend identical `filters` and `orders` with each `next_token` — changing them invalidates the cursor and the API responds with `422 Invalid next_token`.</Warning>

A few rules to keep your iteration reliable:

* Treat `next_token` as an opaque string: never build, decode, or modify it.
* Send explicit `orders` whenever possible: the cursor is derived from the sorted values, so a deterministic order guarantees stable pages (see [Order](/guides-and-resources/order)).
* Check both stop conditions: when the collection size is an exact multiple of `limit`, the last full page still carries a non-null `next_token` and the following page comes back empty.

## Full example

First page — resources of a kind, filtered and sorted, with a total count:

```
POST https://<instance>.tipee.net/api/directory/resources.list

Accept: application/json
Content-Type: application/json
Authorization: Bearer <YOUR_API_KEY>
Tipee-Version: <version>
```

```json theme={null}
{
  "kind_id": "872815618512410358",
  "with_total_count": true,
  "filters": [
    {
      "key": "resource.text",
      "value": {
        "attribute": "last_name",
        "operator": "starts_with",
        "value": "Dup"
      }
    }
  ],
  "orders": [
    {
      "key": "resource.attribute",
      "attribute": "last_name",
      "direction": "asc"
    }
  ],
  "pagination": {
    "limit": 50,
    "next_token": null
  }
}
```

```json theme={null}
{
  "data": [
    {
      "id": "903956503593387633"
    }
  ],
  "next_token": "eyJkYXRhIjpbIkR1cG9udCJdLCJoYXNoIjoiOWQ4ZiJ9",
  "total_count": 63,
  "total_count_approximate": false
}
```

Second page — the same request, with the token swapped in:

```json theme={null}
{
  "kind_id": "872815618512410358",
  "with_total_count": true,
  "filters": [
    {
      "key": "resource.text",
      "value": {
        "attribute": "last_name",
        "operator": "starts_with",
        "value": "Dup"
      }
    }
  ],
  "orders": [
    {
      "key": "resource.attribute",
      "attribute": "last_name",
      "direction": "asc"
    }
  ],
  "pagination": {
    "limit": 50,
    "next_token": "eyJkYXRhIjpbIkR1cG9udCJdLCJoYXNoIjoiOWQ4ZiJ9"
  }
}
```

## Common errors

| Status | Cause                                                                                    |
| ------ | ---------------------------------------------------------------------------------------- |
| `422`  | `next_token` sent with different `filters` or `orders` than the request that produced it |
| `422`  | Malformed `next_token`, or token built by hand                                           |

The response body contains a message describing the problem — see [Error Handling](/guides-and-resources/error-handling) for the general error format.
