The ChatGrid API uses cursor-based pagination for all list endpoints. This
approach is more reliable than offset pagination when data is being created or
deleted between requests.
Query parameters
| Parameter | Type | Default | Description |
|---|
limit | integer | 50 | Number of items per page (1-100) |
cursor | string | — | Opaque cursor from a previous response |
order | string | desc | Sort direction: asc or desc (by created_at) |
The Messages endpoint defaults to order=asc (chronological) instead of
desc. All other endpoints default to desc (newest first).
Every list response includes pagination metadata:
{
"object": "list",
"data": [...],
"has_more": true,
"cursor": "eyJpZCI6ImExYjJjM2Q0LWU1ZjYtNzg5MC1hYmNkLWVmMTIzNDU2Nzg5MCIsImNyZWF0ZWRfYXQiOiIyMDI2LTAzLTE1VDEwOjMwOjAwLjAwMFoifQ"
}
| Field | Type | Description |
|---|
data | array | The items for this page |
has_more | boolean | true if there are more items beyond this page |
cursor | string or null | Pass this value as the cursor query parameter to get the next page. null when there are no more pages. |
Fetching all pages
To iterate through all results, keep fetching while has_more is true:
const API_KEY = "cgk_live_your_key_here";
const boards: Board[] = [];
let cursor: string | null = null;
do {
const params = new URLSearchParams({ limit: "50" });
if (cursor) params.set("cursor", cursor);
const response = await fetch(
`https://api.chatgrid.ai/v1/boards?${params}`,
{ headers: { Authorization: `Bearer ${API_KEY}` } }
);
const json = await response.json();
boards.push(...json.data);
cursor = json.has_more ? json.cursor : null;
} while (cursor);
console.log(`Fetched ${boards.length} boards`);
import requests
api_key = "cgk_live_your_key_here"
headers = {"Authorization": f"Bearer {api_key}"}
boards = []
cursor = None
while True:
params = {"limit": 50}
if cursor:
params["cursor"] = cursor
resp = requests.get(
"https://api.chatgrid.ai/v1/boards",
headers=headers,
params=params,
)
data = resp.json()
boards.extend(data["data"])
if not data["has_more"]:
break
cursor = data["cursor"]
print(f"Fetched {len(boards)} boards")
How cursors work
Cursors are base64url-encoded JSON containing the id and created_at of the
last item on the current page. The server uses these values for a keyset query,
which is efficient even on large datasets.
Cursors are opaque — do not decode or construct them manually. They may change
format without notice. Always use the cursor value returned by the API.
Tips
- Start with a reasonable
limit. 50 is a good default. Use 100 only if
you need to minimize round trips.
- Cursors do not expire but they become invalid if the referenced row is
deleted. If you receive an
invalid_cursor error, restart pagination from
the beginning.
- Combine with filters. You can use
cursor alongside filters like
type, node_id, source_node_id, or status. The cursor is always
relative to the filtered result set.