Skip to main content
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

ParameterTypeDefaultDescription
limitinteger50Number of items per page (1-100)
cursorstringOpaque cursor from a previous response
orderstringdescSort 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).

Response format

Every list response includes pagination metadata:
{
  "object": "list",
  "data": [...],
  "has_more": true,
  "cursor": "eyJpZCI6ImExYjJjM2Q0LWU1ZjYtNzg5MC1hYmNkLWVmMTIzNDU2Nzg5MCIsImNyZWF0ZWRfYXQiOiIyMDI2LTAzLTE1VDEwOjMwOjAwLjAwMFoifQ"
}
FieldTypeDescription
dataarrayThe items for this page
has_morebooleantrue if there are more items beyond this page
cursorstring or nullPass 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.