# Pagination

> Offset paging over every collection, with the total alongside.

Collections are paged with `limit` and `offset`, and every page carries the total so you know how far there is to go.

## Parameters

| Parameter | Type | Default | Means |
| --- | --- | --- | --- |
| `limit` | integer | `25` | Rows per page, 1–100 |
| `offset` | integer | `0` | How many to skip |

Anything outside those bounds is refused with `422` rather than quietly clamped — a request for 5,000 rows is a mistake worth hearing about.

## The shape

Every collection answers with the same object inside `data`, so one reader works against all of them.

`total` is the whole collection, not the page.

```bash cURL
curl "https://api-notetaker.nabrah.ai/ext/v1/recordings?limit=2" \
  -H "Authorization: Bearer $NABRAH_API_KEY"
```
```json Response 200
{
  "data": {
    "rows": [
      { "runId": "9f8c2e10-...", "reference": "NB-3F2A-9C1D-7E5B", "title": "Weekly product sync" },
      { "runId": "7a1b4d92-...", "reference": "NB-8E4C-1B77-2D90", "title": "Design review" }
    ],
    "total": 128,
    "limit": 2,
    "offset": 0
  }
}
```

## Walking the whole collection

```ts Node
async function* allRecordings() {
  let offset = 0;
  const limit = 100;

  for (;;) {
    const response = await fetch(
      `https://api-notetaker.nabrah.ai/ext/v1/recordings?limit=${limit}&offset=${offset}`,
      { headers: { Authorization: `Bearer ${process.env.NABRAH_API_KEY}` } },
    );

    const { data } = await response.json();
    yield* data.rows;

    offset += data.rows.length;
    if (offset >= data.total || data.rows.length === 0) return;
  }
}
```
```python Python
def all_recordings():
    offset, limit = 0, 100

    while True:
        payload = requests.get(
            "https://api-notetaker.nabrah.ai/ext/v1/recordings",
            params={"limit": limit, "offset": offset},
            headers=headers,
        ).json()["data"]

        yield from payload["rows"]

        offset += len(payload["rows"])
        if offset >= payload["total"] or not payload["rows"]:
            return
```

**Warning: Offsets shift as rows are written**

Recordings arrive while you are reading. A new one at the top pushes everything down by one, so a row can repeat between pages, and a deletion can make one slip past you.

For a full sweep this rarely matters. When it does, walk **oldest first** where the endpoint allows an order, or reconcile on `runId` rather than trusting position.

## The exceptions

A few endpoints return everything they have rather than a page, because the collection is bounded by something other than your patience: `/calendar/connections`, `/organization/invites`, and `/webhooks`. They use the same envelope, with `total` equal to the number of rows, so the same reader still works.
