ClientSphereDocs
Guides

Pagination

How list endpoints page their results, and how to walk a collection larger than one page.

Most list endpoints return a page of results rather than the whole collection. A handful return everything in one response instead — see the unpaginated endpoints.

The response shape

A paginated response is an object with a data array and a meta object. It is never a bare array — code that assumes an array will break on the first response it sees:

{
  "data": [ /* ... */ ],
  "meta": {
    "pagination": {
      "page": 1,
      "limit": 20,
      "totalCount": 137,
      "totalPages": 7
    }
  }
}

totalCount is the number of records matching your filters across all pages, not the number in data.

Parameters

ParameterDefaultNotes
page1Page number, starting at 1
limit20Items per page, maximum 100
searchFree-text search across the resource, where supported
curl "https://clientsphere.io/api/v1/contacts?page=2&limit=50" \
  -H "Authorization: Bearer sk_live_your_key_here"

Walking every page

Loop until you have reached totalPages, rather than until you get an empty page — that costs one request fewer and does not depend on how the last page happens to fall:

async function everyContact(apiKey) {
  const all = [];
  let page = 1;
  let totalPages = 1;
 
  do {
    const res = await fetch(
      `https://clientsphere.io/api/v1/contacts?page=${page}&limit=100`,
      { headers: { Authorization: `Bearer ${apiKey}` } },
    );
    if (!res.ok) throw new Error(`Request failed: ${res.status}`);
 
    const body = await res.json();
    all.push(...body.data);
    totalPages = body.meta.pagination.totalPages;
    page += 1;
  } while (page <= totalPages);
 
  return all;
}

Use limit=100 when you are walking a whole collection — it is the maximum, and it makes the loop do a fifth of the requests the default would.

Bear in mind the default rate limit of 60 requests a minute per key when paging through something large. See Rate limits.

The unpaginated endpoints

Five endpoints return every matching record in a single response. They still wrap the results in data, but there is no meta object at all, and page, limit and search are ignored if you send them:

EndpointReturns
GET /widgetsEvery widget in the workspace
GET /activitiesThe whole activity feed
GET /tasks/overdueEvery overdue task
GET /knowledge-base/categoriesEvery category
GET /knowledge-base/articles/searchSearch matches, up to limit
{
  "data": [ /* every record */ ]
}

So body.meta.pagination.totalPages throws on these. A generic client that assumes meta is always present needs to tolerate its absence.

Most of them are small by nature — a workspace has a handful of widgets and categories, not thousands. GET /activities is the one to watch: the activity feed grows without bound and has no filters, so it gets slower as a workspace ages.

Search has its own shape again

GET /knowledge-base/articles/search nests its results one level deeper, with the total beside them rather than in meta:

{
  "data": {
    "articles": [ /* ... */ ],
    "totalCount": 42
  }
}

totalCount is the number of matches, which can exceed the number returned — limit defaults to 10 on this endpoint rather than the usual 20, and there is no way to ask for the next page.

A note on ordering

Records created or deleted while you are paging can shift results between pages, so a long walk is not a consistent snapshot. For large exports, prefer filtering to a narrow window over paging the entire collection.

On this page