Pagination

Overview

Most collections in the API — projects, members, resources, dependencies — come back as their full set in one response; none of those grow large enough to need paging. Task lists are the exception, since a project can hold thousands of tasks.

Supported endpoints

Only one endpoint pages today:

Everything else (list projects, list members, list resources, list dependencies) returns its full set in a single response, unpaged.

Parameters

Pass these as query parameters on a paginated request:

ParameterTypeDefaultNotes
pageinteger11-indexed — the first page is page=1, not page=0.
pageSizeintegerMaximum 500.
curl "https://api.ganttfather.com/v1/projects/{projectId}/tasks?page=1&pageSize=200" \
  -H "Authorization: Bearer glt_YOUR_TOKEN"

Response format

The response body is a plain JSON array of that page’s tasks — no envelope, no cursor object. The full-collection count comes back on the X-Total-Count response header instead.

To read every task, loop page upward while requesting the same pageSize, and stop once you’ve read X-Total-Count rows:

page = 1
fetched = 0
while fetched < X-Total-Count:
    rows = GET tasks?page={page}&pageSize=200
    fetched += rows.length
    page += 1

Note that X-Total-Count is CORS-exposed, so client-side JavaScript can read it directly without a proxy.

Torn reads

Paging is not a point-in-time snapshot: if the project is edited while you loop, the pages you stitch together may not represent one consistent state.

Don’t try to detect this by comparing ETags across pages. Each page’s ETag is computed from that page’s own rows, so different pages always carry different ETags even when the project is completely stable — a cross-page comparison would flag every normal multi-page read as torn. The ETag is only for conditional re-polling of a single page.

Instead, watch X-Total-Count. It comes back on every page and reflects the whole collection. If the count changes between the first and last page of a loop, a task was added or removed while you were paging — discard the result and re-run the loop once. (A stable count won’t catch a pure in-place edit, but it does catch the structural changes that shuffle rows across page boundaries.)

Best practices

  • Use a stable pageSize for the life of one loop — changing it mid-loop makes X-Total-Count bookkeeping unreliable.
  • Send If-None-Match with the ETag from your last read of a page; an unchanged page answers 304 Not Modified with an empty body, so re-polling is cheap.
  • Stop at X-Total-Count, not at an empty page — the count is authoritative and known up front.
  • Re-run the loop once if X-Total-Count moves mid-loop, rather than surfacing a partial result to your integration’s user.

See Rate limits & quotas → for the full caching contract.