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:
- List tasks → —
GET /v1/projects/{projectId}/tasks
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:
| Parameter | Type | Default | Notes |
|---|---|---|---|
page | integer | 1 | 1-indexed — the first page is page=1, not page=0. |
pageSize | integer | — | Maximum 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-Countis 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
pageSizefor the life of one loop — changing it mid-loop makesX-Total-Countbookkeeping unreliable. - Send
If-None-Matchwith theETagfrom your last read of a page; an unchanged page answers304 Not Modifiedwith 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-Countmoves mid-loop, rather than surfacing a partial result to your integration’s user.
See Rate limits & quotas → for the full caching contract.