# Pagination

> Cursors, limits and ordering.

Every list in the API is paged the same way: at most `limit` items, and an opaque `next` cursor for the following page.

## Cursors

A list answers with its items and `next`:

```json
{
  "runs": [ ... ],
  "next": "MTAw"
}
```

Pass `next` back as `cursor` to get the following page. `next` is `null` on the last page. Treat the cursor as opaque: it is not a page number you can compute, and a cursor that is not valid is refused with `400 bad_query`, naming `cursor`.

```bash
curl -s "https://$AAL_TENANT.atlanticagenticlabs.com/api/v1/runs?limit=100&cursor=MTAw" \
  -H "Authorization: Bearer $AAL_KEY" \
  -H "CF-Access-Client-Id: $CF_ACCESS_CLIENT_ID" \
  -H "CF-Access-Client-Secret: $CF_ACCESS_CLIENT_SECRET"
```

Reading every page, in Python:

```python
import os

import httpx

client = httpx.Client(
    base_url=f"https://{os.environ['AAL_TENANT']}.atlanticagenticlabs.com/api/v1",
    headers={
        "Authorization": f"Bearer {os.environ['AAL_KEY']}",
        "CF-Access-Client-Id": os.environ["CF_ACCESS_CLIENT_ID"],
        "CF-Access-Client-Secret": os.environ["CF_ACCESS_CLIENT_SECRET"],
    },
)
params = {"limit": 500}
while True:
    page = client.get("/runs", params=params).raise_for_status().json()
    for run in page["runs"]:
        print(run["run_id_hash"], run["status"])
    if not page["next"]:
        break
    params["cursor"] = page["next"]
```

## Limits

`limit` defaults to 100 on most lists and is at most 500; a larger value is treated as 500, and one that is not a number is refused (`400 bad_query`). The [reference](/api/reference/) shows which routes take `limit` and `cursor`.

## Ordering

Each list has one fixed order, stated on its route: runs are newest first, for example. There is no sort parameter. Time windows are set with `since` and, where offered, `until` (RFC 3339, UTC); a list of runs covers the last 30 days by default.

Source: https://docs.atlanticagenticlabs.com/api/pagination/
