Skip to content

Pagination

List endpoints in the User API return results one page at a time using a consistent limit/offset convention and a shared response envelope. Once you know the pattern, it applies to every collection endpoint (meetings, action items, agenda items, calendar events, and more).

Request parameters

Control paging with two query parameters:

Parameter Type Default Maximum Description
limit integer 20 100 Maximum number of items to return in one page.
offset integer 0 Number of items to skip before collecting the page.
  • limit values outside 1–100 are clamped: values above 100 become 100, and non-positive or missing values fall back to the default of 20.
  • offset is zero-based. An offset beyond the total returns an empty items array (not an error).
# Second page of 50 meetings (items 51–100)
curl "https://api.contio.ai/v1/meetings?limit=50&offset=50" \
  -H "Authorization: Bearer $CONTIO_TOKEN"

Response envelope

Every list endpoint wraps results in the same envelope:

{
  "items": [
    { "id": "123e4567-e89b-12d3-a456-426614174000", "title": "Weekly Sync" }
  ],
  "total": 100,
  "limit": 20,
  "offset": 0
}
Field Description
items The array of resources for this page.
total Total number of items available across all pages.
limit The page size actually applied (after clamping).
offset The offset actually applied for this page.

Use total together with your limit to know when you have reached the end: you have fetched everything once offset + len(items) >= total.

Iterating through all pages

def iterate_all(session, url, headers, page_size=100):
    offset = 0
    while True:
        resp = session.get(
            url, headers=headers,
            params={"limit": page_size, "offset": offset},
        )
        resp.raise_for_status()
        body = resp.json()
        yield from body["items"]
        offset += len(body["items"])
        if offset >= body["total"] or not body["items"]:
            break
async function* iterateAll(url: string, headers: HeadersInit, pageSize = 100) {
  let offset = 0;
  while (true) {
    const resp = await fetch(`${url}?limit=${pageSize}&offset=${offset}`, { headers });
    if (!resp.ok) throw new Error(`Request failed: ${resp.status}`);
    const body = await resp.json();
    yield* body.items;
    offset += body.items.length;
    if (offset >= body.total || body.items.length === 0) break;
  }
}

Use larger pages to conserve rate limit

Requesting the maximum limit of 100 minimizes the number of round trips and helps you stay within your rate limit. Prefer fewer large pages over many small ones.

Ordering and stability

New items can be created while you paginate. If exact, gap-free consistency matters, capture a snapshot of total at the start and be prepared for items shifting between pages. For always-current data, consider User Events (SSE) or Workspace Webhooks instead of repeated polling.

Next steps