Version

Pagination

How list endpoints wrap data in a meta and links envelope, the 100-row page cap, and how to iterate a large result set.

Every paginated list endpoint returns a data array wrapped in a meta + links envelope. Pagination is page-based, capped at 100 rows per request.

Response shape

{
  "data": [
    { "id": "7d1f...", "key": "CRM", "name": "CRM Replacement" },
    { "id": "9a3c...", "key": "PAY", "name": "Payments" }
  ],
  "links": {
    "first": "https://api.example.test/v1/projects?page=1",
    "last": "https://api.example.test/v1/projects?page=4",
    "prev": null,
    "next": "https://api.example.test/v1/projects?page=2"
  },
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 4,
    "per_page": 25,
    "to": 25,
    "total": 92
  }
}

The per_page and page parameters

Every paginated endpoint accepts:

  • per_page, the number of rows in the response (default 25, maximum 100). limit is accepted as an alias.
  • page, the 1-based page index (default 1).
  • sort_by and sort_direction (asc or desc), where the endpoint documents sortable columns; an unknown column falls back to the default order.
curl "https://api.example.test/v1/projects?per_page=50&page=2" \
  -H "Authorization: Bearer zg_live_..."
EndpointDefault per_pageOrder
GET /v1/projects25Newest first; sort_by takes name, key, status, created_at
GET /v1/tokens25Newest first
GET /v1/webhook-endpoints15Newest first
GET /v1/webhook-deliveries15Newest first
GET /v1/me/notifications15Newest first
GET /v1/webhook-events3 (max 10)Newest first, no envelope

Short lists are not paginated: GET /v1/teams, GET /v1/teams/{team}/members, GET /v1/roles, GET /v1/groups, GET /v1/me/alert-destinations and GET /v1/activity return every row in data with no meta.

Requesting per_page above the cap (100) clamps to the maximum silently. Requesting a page past the last page returns an empty data array with meta.total still populated, so a polling loop can detect the end without guessing.

Iterating across pages

async function fetchAllProjects(apiUrl: string, token: string) {
  const all = [];
  let page = 1;

  while (true) {
    const res = await fetch(`${apiUrl}/v1/projects?per_page=100&page=${page}`, {
      headers: { Authorization: `Bearer ${token}` },
    });
    const body = await res.json();

    all.push(...body.data);

    if (body.meta.current_page >= body.meta.last_page) break;
    page += 1;
  }

  return all;
}

Filtering before paginating

Combine per_page with the resource-specific filters to avoid long loops:

curl "https://api.example.test/v1/projects?status=in_development&per_page=100" \
  -H "Authorization: Bearer zg_live_..."

How is this guide?

Last updated on

Version

On this page

What changed recentlyEvery release of Zuse Bifrost, with the pages it touched.

For AI agents: llms.txt ยท llms-full.txt