---
title: Pagination
description: Offset pagination with limit/offset and the {count, data} envelope.
---

# Pagination

List endpoints page with **offset pagination**. Pass two query parameters:

| Parameter | Type | Description |
|---|---|---|
| `limit` | integer | Page size — the maximum number of rows to return. |
| `offset` | integer | Number of rows to skip from the start of the result set. |

The response is a `{ count, data }` envelope:

```json
{
  "count": 248,
  "data": [ "…up to `limit` rows…" ]
}
```

- `count` — total rows matching the query across **all** pages, so you can
  tell how many pages remain.
- `data` — the current page of rows.

Exact default and maximum `limit` values are documented per endpoint in the
[API reference](./api/index.md) (the common bound is `limit` default 100,
max 500, `offset` from 0).

## Response shapes vary by endpoint

The `{ count, data }` envelope above is the **primary** shape — it backs the
high-traffic, deeply paged collections (parts, material grades, part
revisions). A few endpoints differ; always read the per-endpoint schema in
the [API reference](./api/index.md) rather than assuming:

| Shape | Endpoints | Notes |
|---|---|---|
| `{ count, data }` + `limit`/`offset` | `parts`, `materials/grades`, part `revisions` | The model above. |
| `{ count, items }` + `limit` | `parts/calculations` | Key is `items`, not `data`; capped by `limit` (no `offset`). |
| Bare JSON array | `environments`, `uploads`, `materials/overrides` | Small or naturally-bounded sets — no envelope, no `count`. |

The iterator below targets the `{ count, data }` endpoints; adapt the field
name (or drop the loop entirely) for the variants above.

## Iterating every page

<CodeTabs>

```python title="Python"
import requests

def all_rows(url, headers, page=100):
    offset, out = 0, []
    while True:
        r = requests.get(
            url, headers=headers, params={"limit": page, "offset": offset}
        )
        r.raise_for_status()
        body = r.json()
        out.extend(body["data"])
        offset += page
        if offset >= body["count"]:
            return out
```

```typescript title="TypeScript"
async function allRows(url: string, headers: Record<string, string>, page = 100) {
  const out: unknown[] = []
  for (let offset = 0; ; offset += page) {
    const r = await fetch(`${url}?limit=${page}&offset=${offset}`, { headers })
    const body = await r.json()
    out.push(...body.data)
    if (offset + page >= body.count) return out
  }
}
```

</CodeTabs>

> Choose a `limit` that balances round-trips against response size. Each
> request still counts toward your [rate limits](./rate-limits.md), so very
> small pages cost more requests.

## See also

- [Rate limits](./rate-limits.md) — pace your pagination loop.
- [API reference](./api/index.md) — per-endpoint `limit` bounds and filters.
