# Pagination

List endpoints are cursor-based.

## Parameters

| Parameter | Type | Description |
|  --- | --- | --- |
| `limit` | integer | Results per page. Default `50`, maximum `100`. |
| `cursor` | string | Opaque pointer to the next page, from `pagination.nextCursor`. |


## Response shape

Every list response wraps its results in `data`, with a `pagination` object
alongside:

```json
{
  "data": [ ... ],
  "pagination": {
    "hasMore": true,
    "nextCursor": "eyJpZCI6IjY0...",
    "limit": 50,
    "total": 214
  }
}
```

`total` is the count across all pages when known. `null` means not counted,
which is not the same as zero.

## How it works

Pass `pagination.nextCursor` back as the `cursor` parameter to get the next
page. When `pagination.hasMore` is `false`, you have everything.

Treat the cursor as opaque. Don't parse it or construct one yourself. A cursor
is minted for a specific filter set, so changing filters mid-pagination
invalidates it.

## Reading every page

```bash
cursor=""
while :; do
  response=$(curl -s "https://api.scytale.ai/v1/controls?limit=100&cursor=$cursor" \
    -H "Authorization: Bearer $ACCESS_TOKEN")

  echo "$response" | jq '.data[]'

  [ "$(echo "$response" | jq -r '.pagination.hasMore')" != "true" ] && break
  cursor=$(echo "$response" | jq -r '.pagination.nextCursor')
done
```

Use `limit=100` when reading everything: same data, half the round trips.