<!-- tempo-docs-context -->
> Source: [/docs/api/pagination](https://tempo.xyz/developers/docs/api/pagination.md)
> Section: [API reference](https://tempo.xyz/developers/docs/api.md). Tempo API reference: authentication, conventions, endpoints grouped by product, Console management endpoints, JSON-RPC, and the indexer. An API key authenticates API requests; an account signing key authorizes transactions.
> [Documentation index](https://tempo.xyz/developers/llms.txt) · [Docs skill](https://tempo.xyz/developers/SKILL.md)

> Tempo MCP: Use `search`, `find_pages`, `read_page`, and `code` at `https://mcp.tempo.xyz` for Tempo and related documentation.
> If an indexed page is missing or reflects an older site, read this site’s [documentation index](https://tempo.xyz/developers/llms.txt) and Markdown pages directly.

# Tempo API pagination: two modes explained

Many Tempo list endpoints use the pagination contract below. Check each endpoint for supported parameters and limits; Routes and Indexer endpoints can differ. Use **cursor** pagination for stable traversal and deep reads. Use **page** pagination only when an endpoint supports it and you need a shallow, page-numbered UI.

## Tempo API pagination modes

| Mode | Parameters | Use for | Notes |
| --- | --- | --- | --- |
| Cursor | `limit`, `cursor` | Deep traversal, bulk reads, live feeds | Canonical. Omit `cursor` on the first request, then pass each `nextCursor` back verbatim. |
| Page | `limit`, `page` | Shallow, page-numbered UIs | Optional. `page` is 1-indexed and `page × limit` must be at most `500`. |

Cursor pagination anchors traversal to a row position, so the next cursor continues from exactly where the previous page ended, even when new rows arrive at the head of a feed between requests.

Page pagination is positional. If new rows arrive at the head of a feed, items can shift across page boundaries, which can duplicate or skip results. Some endpoints support cursor pagination only.

:::warning
Do not send `cursor` and `page` together. The request fails with a `400 query_invalid` error.
:::

## Pagination request parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `limit` | integer | `10` | Items per page. Minimum `5`; values above `50` are clamped to `50`. |
| `cursor` | string | none | Opaque cursor from the previous response's `nextCursor`. Omit on the first request. Mutually exclusive with `page`. |
| `page` | integer | none | 1-indexed positional page number. `page=1` is the head page. Mutually exclusive with `cursor`. `page × limit` must be at most `500`. |
| `include` | string | none | Comma-separated include flags. On endpoints that support it, send `include=totalCount` to add `meta.totalCount` and `meta.totalCountCapped` to the response. |

## Pagination response envelope

Endpoints that support `include=totalCount` add counts to the list envelope when requested:

```json
{
  "data": [],
  "nextCursor": "WzIzNDU2Nzg5LDBd",
  "meta": {
    "totalCount": 42,
    "totalCountCapped": false
  }
}
```

| Field | Type | Description |
| --- | --- | --- |
| `data` | array | Items for this page. |
| `nextCursor` | string or `null` | Cursor for the next page. Pass it back as the `cursor` query parameter. `null` means you have reached the end of the list. |
| `meta.totalCount` | integer | Present only when you request `include=totalCount`. Exact when `meta.totalCountCapped` is `false`; a lower bound when `true`. |
| `meta.totalCountCapped` | boolean | Present only when you request `include=totalCount`. `true` means the count hit the `10,000` cap. |

:::warning
`nextCursor === null` is the only end-of-list signal. Do not stop because `data` is shorter than `limit`, because `data` is empty, or because of `totalCount`.
:::

## Cursor pagination for Tempo API lists

Fetch the first page without a cursor:

```bash
curl 'https://api.tempo.xyz/v1/tokens?limit=50' \
  --header 'Authorization: Bearer tempo:sk:...'
```

The response includes `nextCursor` when another page is available:

```json
{
  "data": [],
  "nextCursor": "WzIzNDU2Nzg5LDBd",
  "meta": {}
}
```

Fetch the next page by passing that value back as `cursor`:

```bash
curl --get 'https://api.tempo.xyz/v1/tokens' \
  --data-urlencode 'limit=50' \
  --data-urlencode 'cursor=WzIzNDU2Nzg5LDBd' \
  --header 'Authorization: Bearer tempo:sk:...'
```

Keep going until `nextCursor` is `null`:

```json
{
  "data": [],
  "nextCursor": null,
  "meta": {}
}
```

:::info
Cursors are opaque. Store and pass them back exactly as received; do not decode, parse, shorten, or construct them. Their format and length may change without notice.

If a cursor is malformed or forged, the request starts again from the head instead of returning an error.
:::

## Page pagination for shallow Tempo API lists

Use `page` only for shallow, page-numbered interfaces:

```bash
curl 'https://api.tempo.xyz/v1/tokens?limit=25&page=2' \
  --header 'Authorization: Bearer tempo:sk:...'
```

`page` is 1-indexed:

* `page=1` returns the head page.
* `page=2` returns the next positional page.
* `page × limit` must be at most `500`.

For anything deeper than `500` rows, use cursor pagination. Some endpoints support cursor pagination only — this is common when each returned item is derived from a variable number of underlying rows, which makes positional page boundaries unstable.

## Count results in paginated responses

Counts are optional. Request them with `include=totalCount`:

```bash
curl 'https://api.tempo.xyz/v1/transactions?limit=50&include=totalCount' \
  --header 'Authorization: Bearer tempo:sk:...'
```

The count is computed by a capped subquery up to `10,000` matched rows:

```json
{
  "data": [],
  "nextCursor": "WzIzNDU2Nzg5LDBd",
  "meta": {
    "totalCount": 10000,
    "totalCountCapped": true
  }
}
```

* When `meta.totalCountCapped` is `false`, `meta.totalCount` is exact.
* When `meta.totalCountCapped` is `true`, `meta.totalCount` is a lower bound: there are at least that many matches.
* Counts are independent of pagination. Use `nextCursor`, not `totalCount`, to decide whether to request another page.

## Pagination best practices for Tempo API clients

* Prefer cursor pagination for integrations, sync jobs, exports, and live feeds.
* Use the largest `limit` your workload can handle, up to the endpoint's maximum (`50` for the contract above), to reduce round trips.
* Persist `nextCursor` if you need to resume traversal later.
* Pass cursors back verbatim, and URL-encode them when placing them in a query string.
* Stop only when `nextCursor` is `null`.
* Use page pagination only for shallow UI navigation where duplicate or skipped rows on a live feed are acceptable.
