# Pagination

> **Section:** [Introduction](https://docs.editsquare.com/api.md)
> **Related:** [Authentication](https://docs.editsquare.com/api/authentication.md) · [Errors](https://docs.editsquare.com/api/errors.md) · [Renders](https://docs.editsquare.com/api/renders.md) · [Webhooks](https://docs.editsquare.com/api/webhooks.md)
> **Also:** [HTML version](https://docs.editsquare.com/api/pagination) · [Docs index](https://docs.editsquare.com/llms.txt)

---

List endpoints that can grow without bound, such as
[projects](/api/reference/operations/listprojects/) and
[renders](/api/reference/operations/listrenders/), use cursor-based pagination through the `cursor`
parameter. Each page of results includes a `next_cursor` value. Pass it as
`cursor` on your next request to fetch the following page.

Endpoints whose results stay small (a project's templates, a team's members,
the teams a key can access) return everything in a single response and carry
only `data`.

## The list response

Every list endpoint returns an object, never a bare array:

```json
{
  "data": [ /* … */ ],
  "has_more": true,
  "next_cursor": "kBIAAAAAeyJ2IjoxLCJjIjoxNzQ4ODc1OTg2fQ"
}
```

| Field | Description |
| --- | --- |
| `data` | An array containing the elements of the current page. |
| `has_more` | Whether more elements are available after this set. If `false`, this set comprises the end of the list. |
| `next_cursor` | A cursor for fetching the next page. `null` on the last page. |

## Parameters

| Parameter | Description |
| --- | --- |
| `limit` | Optional, default is 20. The number of objects to return, ranging between 1 and 60. Values above 60 are clamped to 60, not rejected. |
| `cursor` | Optional. A cursor for use in pagination. Pass the `next_cursor` value from the previous response to fetch the next page. Omit it to fetch the first page. |

Cursors are opaque: they encode a position in the result set, not an object
ID. Don't construct or parse them, and don't store them for long.

A cursor is only valid for the endpoint and filters that produced it. If you
change `search`, `status` or `order`, start again from the first page.

## Fetching every page

`GET /v1/renders`

**Shell (cURL)**

```sh
url='https://api.editsquare.com/v1/renders?project_id=proj_j123456789&limit=60'

while :; do
  page=$(curl --silent --request GET \
    --url "$url" \
    --header 'Authorization: Bearer sk_your_key_here')

  echo "$page" | jq '.data[]'

  cursor=$(echo "$page" | jq --raw-output '.next_cursor // empty')
  [ -z "$cursor" ] && break
  url='https://api.editsquare.com/v1/renders?project_id=proj_j123456789&limit=60&cursor='$cursor
done
```

**JavaScript (Fetch)**

```js
const renders = [];
let cursor;

do {
  const url = new URL('https://api.editsquare.com/v1/renders');
  url.searchParams.set('project_id', 'proj_j123456789');
  url.searchParams.set('limit', '60');
  if (cursor) url.searchParams.set('cursor', cursor);

  const response = await fetch(url, {
    headers: { Authorization: 'Bearer sk_your_key_here' },
  });
  if (!response.ok) throw new Error(response.status + ' ' + (await response.text()));

  const page = await response.json();
  renders.push(...page.data);
  cursor = page.next_cursor;
} while (cursor);

console.log(renders);
```

Stop when `next_cursor` is `null`, not when a page comes back short. A page
can contain fewer than `limit` results and still be followed by more.

## Ordering

Objects are returned in reverse chronological order by creation time, newest
first. Pass `order=asc` to return oldest first.

`search` orders results by relevance and ignores `order`.