Skip to main content
https://.thoughtindustries.com

Pagination

List endpoints return paginated results to keep response sizes manageable. The REST API uses cursor-based pagination, which provides stable results even when the underlying data changes between requests.

How it works

Every list response includes a meta object with pagination details:

Response: 200 Paginated response

{
  "data": [
    { "id": "usr_abc123", "email": "[email protected]" },
    { "id": "usr_def456", "email": "[email protected]" }
  ],
  "meta": {
    "page": 1,
    "perPage": 25,
    "totalCount": 142,
    "totalPages": 6,
    "nextCursor": "eyJpZCI6InVzcl9kZWY0NTYiLCJjcmVhdGVkQXQiOiIyMDI1LTAxLTE1VDA4OjMwOjAwWiJ9"
  }
}

Events endpoint pagination

Resource endpoints (Users, Courses, etc.) use the meta object described above. Event endpoints use the pageInfo model described below. The two are not interchangeable.

Events & Notifications endpoints use a cursor-only pagination model. Responses include a pageInfo object instead of the meta object:

Response: 200 Events pagination

{
  "pageInfo": {
    "cursor": "MTUxODM2NTg1Mzk5OQ",
    "hasMore": true
  },
  "events": [ ... ]
}
FieldTypeDescription
pageInfo.cursorstringOpaque cursor to pass as the cursor query parameter for the next page
pageInfo.hasMorebooleanWhether additional pages of results are available

Pass the cursor value as a query parameter to fetch the next page. Continue until hasMore is false.

Pagination parameters

Query parameters

ParameterTypeRequiredDefaultDescription
pageintegerNo1Page number to retrieve (1-indexed).
perPageintegerNo25Number of records per page. Maximum 100.
cursorstringNoOpaque cursor for stable forward pagination. Use the nextCursor value from the previous response.

Pagination meta fields

FieldTypeDescription
pageintegerCurrent page number
perPageintegerRecords returned per page
totalCountintegerTotal records matching the query
totalPagesintegerTotal number of pages
nextCursorstring | nullCursor for the next page. null on the last page.

Iterating through pages

Use the nextCursor value from each response to request the next page:

# First page
curl -s -H "Authorization: Bearer ti_live_a1b2c3d4e5f6g7h8i9j0" \
  "https://api.thoughtindustries.com/incoming/v2/users?perPage=50"

# Subsequent pages using the cursor from the previous response
curl -s -H "Authorization: Bearer ti_live_a1b2c3d4e5f6g7h8i9j0" \
  "https://api.thoughtindustries.com/incoming/v2/users?perPage=50&cursor=eyJpZCI6InVzcl9kZWY0NTYifQ"
async function fetchAllUsers(apiKey) {
  const users = [];
  let cursor = null;

  do {
    const url = new URL("https://api.thoughtindustries.com/incoming/v2/users");
    url.searchParams.set("perPage", "50");
    if (cursor) url.searchParams.set("cursor", cursor);

    const response = await fetch(url, {
      headers: { "Authorization": `Bearer ${apiKey}` }
    });
    const { data, meta } = await response.json();

    users.push(...data);
    cursor = meta.nextCursor;
  } while (cursor);

  return users;
}
import requests

def fetch_all_users(api_key):
    users = []
    cursor = None
    base_url = "https://api.thoughtindustries.com/incoming/v2/users"

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

        response = requests.get(
            base_url,
            headers={"Authorization": f"Bearer {api_key}"},
            params=params
        )
        body = response.json()
        users.extend(body["data"])

        cursor = body["meta"].get("nextCursor")
        if not cursor:
            break

    return users
function fetchAllUsers(string $apiKey): array {
    $users = [];
    $cursor = null;
    $baseUrl = "https://api.thoughtindustries.com/incoming/v2/users";

    do {
        $params = ["perPage" => 50];
        if ($cursor) $params["cursor"] = $cursor;

        $url = $baseUrl . "?" . http_build_query($params);
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            "Authorization: Bearer $apiKey"
        ]);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        $body = json_decode(curl_exec($ch), true);
        $users = array_merge($users, $body["data"]);
        $cursor = $body["meta"]["nextCursor"] ?? null;
    } while ($cursor);

    return $users;
}

Best practices

  • Use perPage=50 or perPage=100 for bulk data exports to minimize round-trips
  • Prefer cursor-based pagination over page numbers for large datasets — cursors remain stable as records are added or removed
  • Store the totalCount from the first response if you need progress indicators
  • Avoid requesting pages beyond totalPages — the API returns an empty data array

If you only need to check whether records exist, set perPage=1 and inspect totalCount in the meta object.