> ## Documentation Index
> Fetch the complete documentation index at: https://docs.illumichat.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Pagination

> Learn how to paginate through API results using offset-based and cursor-based patterns.

The IllumiChat API provides two pagination patterns depending on the endpoint and the nature of the data being returned. Offset-based pagination is used for static collections such as workspaces, assistants, and members. Cursor-based pagination is used for streaming or append-heavy data such as messages and webhook deliveries.

## Offset-Based Pagination

Offset-based pagination uses `limit` and `offset` query parameters to control which slice of results is returned.

| Parameter | Type    | Default | Description                                                |
| --------- | ------- | ------- | ---------------------------------------------------------- |
| `limit`   | integer | `25`    | Number of items to return. Minimum `1`, maximum `100`.     |
| `offset`  | integer | `0`     | Number of items to skip before starting to return results. |

### Response Shape

Every offset-paginated response includes the following top-level fields:

```json theme={null}
{
  "data": [
    { "id": "ws_abc123", "name": "Acme Corp" },
    { "id": "ws_def456", "name": "Globex" }
  ],
  "total": 48,
  "limit": 25,
  "offset": 0
}
```

| Field    | Type    | Description                                                |
| -------- | ------- | ---------------------------------------------------------- |
| `data`   | array   | The requested items for the current page.                  |
| `total`  | integer | Total number of items matching the query across all pages. |
| `limit`  | integer | The limit that was applied.                                |
| `offset` | integer | The offset that was applied.                               |

### Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://app.illumichat.com/api/workspaces?limit=10&offset=20" \
    -H "Authorization: Bearer <your-api-key>"
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch(
    "https://app.illumichat.com/api/workspaces?limit=10&offset=20",
    {
      headers: { Authorization: "Bearer <your-api-key>" },
    }
  );

  const { data, total, limit, offset } = await res.json();
  console.log(`Showing ${data.length} of ${total} workspaces`);
  ```

  ```python Python theme={null}
  import requests

  res = requests.get(
      "https://app.illumichat.com/api/workspaces",
      params={"limit": 10, "offset": 20},
      headers={"Authorization": "Bearer <your-api-key>"},
  )

  result = res.json()
  print(f"Showing {len(result['data'])} of {result['total']} workspaces")
  ```
</CodeGroup>

<Tip>
  To iterate through all pages, increment `offset` by `limit` on each request until `offset >= total`.
</Tip>

### Iterating Through All Pages

<CodeGroup>
  ```javascript JavaScript theme={null}
  async function fetchAll(baseUrl, token) {
    const items = [];
    let offset = 0;
    const limit = 100;

    while (true) {
      const res = await fetch(`${baseUrl}?limit=${limit}&offset=${offset}`, {
        headers: { Authorization: `Bearer ${token}` },
      });
      const { data, total } = await res.json();
      items.push(...data);
      offset += limit;
      if (offset >= total) break;
    }

    return items;
  }
  ```

  ```python Python theme={null}
  def fetch_all(base_url: str, token: str) -> list:
      items = []
      offset = 0
      limit = 100

      while True:
          res = requests.get(
              base_url,
              params={"limit": limit, "offset": offset},
              headers={"Authorization": f"Bearer {token}"},
          )
          result = res.json()
          items.extend(result["data"])
          offset += limit
          if offset >= result["total"]:
              break

      return items
  ```
</CodeGroup>

***

## Cursor-Based Pagination

Cursor-based pagination uses an opaque `cursor` parameter and returns a `nextCursor` value. This pattern is more efficient for large, frequently changing datasets because it avoids the consistency issues inherent in offset-based pagination.

| Parameter | Type    | Default | Description                                                               |
| --------- | ------- | ------- | ------------------------------------------------------------------------- |
| `limit`   | integer | `25`    | Number of items to return. Minimum `1`, maximum `100`.                    |
| `cursor`  | string  | `null`  | Opaque cursor from a previous response. Omit to start from the beginning. |

### Response Shape

```json theme={null}
{
  "data": [
    { "id": "msg_aaa111", "content": "Hello" },
    { "id": "msg_bbb222", "content": "Hi there" }
  ],
  "nextCursor": "eyJpZCI6Im1zZ19iYmIyMjIifQ==",
  "hasMore": true
}
```

| Field        | Type           | Description                                                                                              |
| ------------ | -------------- | -------------------------------------------------------------------------------------------------------- |
| `data`       | array          | The requested items for the current page.                                                                |
| `nextCursor` | string or null | Pass this value as the `cursor` parameter to fetch the next page. `null` when there are no more results. |
| `hasMore`    | boolean        | `true` if additional pages exist beyond the current result set.                                          |

### Examples

<CodeGroup>
  ```bash cURL theme={null}
  # First page
  curl -X GET "https://app.illumichat.com/api/conversations/conv_abc/messages?limit=50" \
    -H "Authorization: Bearer <your-api-key>"

  # Next page
  curl -X GET "https://app.illumichat.com/api/conversations/conv_abc/messages?limit=50&cursor=eyJpZCI6Im1zZ19iYmIyMjIifQ==" \
    -H "Authorization: Bearer <your-api-key>"
  ```

  ```javascript JavaScript theme={null}
  async function fetchMessages(conversationId, token) {
    const messages = [];
    let cursor = null;

    do {
      const params = new URLSearchParams({ limit: "50" });
      if (cursor) params.set("cursor", cursor);

      const res = await fetch(
        `https://app.illumichat.com/api/conversations/${conversationId}/messages?${params}`,
        { headers: { Authorization: `Bearer ${token}` } }
      );

      const result = await res.json();
      messages.push(...result.data);
      cursor = result.nextCursor;
    } while (cursor);

    return messages;
  }
  ```

  ```python Python theme={null}
  def fetch_messages(conversation_id: str, token: str) -> list:
      messages = []
      cursor = None

      while True:
          params = {"limit": 50}
          if cursor:
              params["cursor"] = cursor

          res = requests.get(
              f"https://app.illumichat.com/api/conversations/{conversation_id}/messages",
              params=params,
              headers={"Authorization": f"Bearer {token}"},
          )

          result = res.json()
          messages.extend(result["data"])
          cursor = result.get("nextCursor")
          if not cursor:
              break

      return messages
  ```
</CodeGroup>

<Warning>
  Cursor values are opaque and may change between API versions. Do not parse, construct, or store cursors for long-term use. Always obtain a fresh cursor from the most recent API response.
</Warning>

***

## Choosing a Pattern

| Use Case                                | Pattern      | Reason                                                |
| --------------------------------------- | ------------ | ----------------------------------------------------- |
| Listing workspaces, assistants, members | Offset-based | Stable datasets; total count is useful for UI         |
| Browsing messages in a conversation     | Cursor-based | Append-heavy data; avoids skipped or duplicated items |
| Webhook delivery logs                   | Cursor-based | High-volume, time-ordered data                        |
| Search results                          | Offset-based | Users expect page numbers and total counts            |

<Note>
  If an endpoint supports pagination, the documentation for that endpoint specifies which pattern is used. When in doubt, check the response shape: the presence of `nextCursor` indicates cursor-based pagination, while `total` and `offset` indicate offset-based pagination.
</Note>
