# Pagination

> Every list endpoint on every Kanorio API takes limit and cursor and returns data, hasMore and nextCursor.

> Markdown version of https://kanorio.com/en/developers/basics/pagination. Append `.md` to any developer docs URL for this format. Index: https://kanorio.com/llms.txt · MCP: https://app.kanorio.com/api/mcp

All list endpoints on the Management API, the Content Delivery API and the Customer API page the same way.

## Request

| Parameter | Type | Default | Notes |
|---|---|---|---|
| `limit` | integer | 20 | From 1 to 100. Some endpoints document a lower maximum. |
| `cursor` | string | none | The `nextCursor` from the previous page. Omit it for the first page. |

## Response

```json
{
  "data": [{ "id": "post_example01" }, { "id": "post_example02" }],
  "hasMore": true,
  "nextCursor": "eyJvIjoyMCwicyI6ImFiYzEyMyJ9"
}
```

| Field | Type | Notes |
|---|---|---|
| `data` | array | The items of this page, in the endpoint's order. |
| `hasMore` | boolean | `true` when another page exists. |
| `nextCursor` | string or null | Pass it as `cursor` to get the next page. `null` on the last page. |

Some endpoints add fields next to these. For example, collection items add `assets`, a map of every image and file the page references.

## Rules

- **Cursors are opaque.** Do not parse, build or store them for long. Their format can change without notice.
- **Keep the other parameters.** A cursor belongs to the filters, sort and limit it was issued for. Sending it with different filters returns `400 INVALID_CURSOR`. Start again without a cursor when filters change.
- **No page numbers or offsets.** The APIs do not accept `page`, `pageSize` or `offset`.
- **No totals by default.** Counting every match is expensive, so lists do not return a total. Two Content Delivery API endpoints return `total` when you pass `total=true`: collection items, and search (where the total is counted in the same query as the results).
- **Short lists still use the envelope.** Lists with a small fixed cap, such as webhook endpoints or redirects, return everything in one page with `hasMore: false`. Their reference pages say so.

## Read every page

```bash
curl "https://app.kanorio.com/api/v1/sites/ws_example123/posts?limit=50" \
  -H "Authorization: Bearer $KANORIO_TOKEN"

# then, while hasMore is true
curl "https://app.kanorio.com/api/v1/sites/ws_example123/posts?limit=50&cursor=eyJvIjo1MH0" \
  -H "Authorization: Bearer $KANORIO_TOKEN"
```

The SDK's `paginate` follows `nextCursor` for you and works with any list endpoint:

```ts
import { createManagementClient, paginate } from "@kanorio/sdk";

const client = createManagementClient({ token: process.env.KANORIO_TOKEN! });

for await (const post of paginate((cursor) =>
  client.get("/sites/{id}/posts", { params: { id: "ws_example123" }, query: { limit: 50, cursor } })
)) {
  console.log(post.slug);
}
```

Use `listAll` instead of `paginate` when you want the whole list as an array.
