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

# Pagination

> Use the `cursor` query parameter to walk through results, with `limit` controlling page size and `include_total` opting into a total count.

List endpoints support **two pagination styles**, pickable per request:

* **Cursor (keyset) pagination** — round-trip `page.next_cursor` / `page.prev_cursor` via `?cursor=`. O(page size) regardless of depth. Recommended for browsing UIs and forward/backward walking.
* **Offset pagination** — classic `?limit=&offset=`. Supports random-access deep jumps ("go to page 47"). Cost grows with `offset` value.

Both produce the same response envelope; only the request shape differs. Cursor wins when both are sent (`?cursor=X&offset=N` ignores the offset).

<Note>
  Need the older `offset`-based shape? Send `API-Version: 2026-05-22` (or any earlier date) and the response will use the legacy `{ limit, offset, total }` envelope. Old clients keep working unchanged.
</Note>

## Parameters

| Parameter       | Type    | Default | Description                                                                                                                                                                                                |
| --------------- | ------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cursor`        | string  | —       | Opaque token from a previous response's `page.next_cursor` or `page.prev_cursor`. **When present, the cursor carries its own `limit` and `offset` — `?limit=` and `?offset=` on the request are ignored.** |
| `limit`         | integer | `25`    | Page size. Used when no `cursor` is sent. Max varies by endpoint.                                                                                                                                          |
| `offset`        | integer | `0`     | Number of rows to skip. Used when no `cursor` is sent (offset pagination). Echoed in `page.offset` when a cursor is used (the cursor carries it).                                                          |
| `include_total` | boolean | —       | Pass `true` to include `page.total` (runs a separate COUNT query).                                                                                                                                         |

**Limits by endpoint:**

| Endpoint                                                          | Max `limit` |
| ----------------------------------------------------------------- | ----------- |
| `/api/data/entities`, `/api/data/investors`, `/api/data/founders` | 500         |
| `/api/data/transactions`, `/api/data/valuations`                  | 2000        |

## Response shape

```json theme={null}
{
  "data": [ ... ],
  "page": {
    "limit": 25,
    "offset": 0,
    "next_cursor": "eyJ2IjoxLCJkIjoibmV4dCJ9...",
    "prev_cursor": null,
    "total": 5634
  }
}
```

* `page.limit` — applied page size (carried by the cursor on subsequent pages)
* `page.offset` — the server's view of where this page sits in the result set (`0` for the first page, `limit` for the second, etc.). Use it for "showing rows X–Y of Z" display
* `page.next_cursor` — token to fetch the next page, or `null` when this is the last page
* `page.prev_cursor` — token to fetch the previous page, or `null` when this is the first page
* `page.total` — total matching records; present only when `include_total=true`

## Walking forward (cursor)

```bash theme={null}
# Page 1: no cursor — set sort + filter + limit
curl "https://api-next.dealroom.co/api/data/entities?sort=-launch_date&filter=organization_subtype%5Beq%5D%3Acompany&limit=25" \
  -H "Authorization: Bearer $TOKEN"

# Page 2 onward: round-trip the cursor AND echo the same sort + filter back.
# The cursor carries limit/offset for you; sort and filter must match the
# request that minted the cursor or the server returns 400.
curl "https://api-next.dealroom.co/api/data/entities?cursor=$NEXT&sort=-launch_date&filter=organization_subtype%5Beq%5D%3Acompany" \
  -H "Authorization: Bearer $TOKEN"

# Keep going until page.next_cursor is null
```

## Random access (offset)

```bash theme={null}
# Jump straight to page 11 (offset=250 with limit=25):
curl "https://api-next.dealroom.co/api/data/entities?sort=-launch_date&limit=25&offset=250" \
  -H "Authorization: Bearer $TOKEN"
```

Offset cost grows with the offset value — for deep pages, prefer cursor walking. Offset is fine for small jumps (a few hundred rows) and for one-shot fetches.

## Walking back

```bash theme={null}
# From any page, replay page.prev_cursor to step back one page. Echo the
# same sort + filter as the request that minted the cursor.
curl "https://api-next.dealroom.co/api/data/entities?cursor=$PREV&sort=-launch_date&filter=organization_subtype%5Beq%5D%3Acompany" \
  -H "Authorization: Bearer $TOKEN"
```

`prev_cursor` is `null` exactly when you're on the first page.

For a "Page N of M" UI, read `page.offset` and `page.limit` straight from the response — the cursor token already carries the current offset, so the server reports it back without the client doing any arithmetic.

## Cursor rules

* **Opaque** — treat the cursor as a black box. Do not decode, modify, or construct it manually.
* **Carries limit/offset only** — the cursor token embeds page size and offset, so `?limit=` and `?offset=` are ignored when `?cursor=` is sent. To change page size, restart from the first page with the new `?limit=`.
* **Echo `sort` and `filter` on every request** — the cursor does NOT contain the sort or filter expression. The server compares the cursor's fingerprints against the *resolved* sort and filter of the current request, so the rule is "the request's resolved sort/filter must match what minted the cursor." In practice that means resending the same `?sort=` and `?filter=` you used on page 1. Technically, if a cursor was minted under default sort and empty filter, omitting both is fine because the defaults still match — but the safe pattern is to always echo them so client code doesn't break the moment a non-default sort or filter is in play. Mismatch returns a 400.
* **Bound to sort** — changing `?sort=` mid-paging returns `400 Invalid cursor for this sort order; restart from the first page`.
* **Bound to filter** — changing `?filter=` mid-paging returns `400 Cursor is bound to a different filter; restart from the first page`. Currency (`?currency=`) is **not** bound — switching currencies mid-paging is safe.
* **No deep jumps** — there's no way to jump to a specific deep page (e.g. "page 47"). Walk pages sequentially, or restart from the first page.

## Including the total count

By default `page.total` is omitted — cursor pages stay cheap. Pass `include_total=true` to include it:

```bash theme={null}
curl "https://api-next.dealroom.co/api/data/entities?sort=-launch_date&limit=25&include_total=true" \
  -H "Authorization: Bearer $TOKEN"
```

For large datasets, skip the total count when you don't need it — omitting it avoids a full-table count query.

<Note>
  In-memory list endpoints (`/api/platform/ecosystems`, `/api/platform/teams`, `/api/platform/api-keys`) keep the legacy `{ limit, offset, total }` shape even on the new version — their datasets are small and bounded, so cursor pagination offers no benefit.
</Note>
