# Pagination

List endpoints return results in pages using **cursor pagination**. You control
the page size with `limit` and walk forward with `starting_after`, using the id
of the last item you received as the cursor for the next page.

## The list envelope

Every list endpoint returns the same shape:

```json
{
  "object": "list",
  "data": [
    { "id": "evt_300", "...": "..." },
    { "id": "evt_299", "...": "..." }
  ],
  "has_more": true
}
```

| Field | Description |
| --- | --- |
| `object` | Always `"list"`. |
| `data` | The items on this page, newest first. |
| `has_more` | `true` if more items exist after this page. |

## Query parameters

| Parameter | Default | Description |
| --- | --- | --- |
| `limit` | `20` | Items per page. Clamped to the range **1–100**. |
| `starting_after` | — | An item `id`. Returns the page of items **after** it. |

Results are ordered newest-first. To fetch the next page, take the `id` of the
**last** item in `data` and pass it as `starting_after`. Keep going while
`has_more` is `true`.

## Which endpoints support it

Cursor pagination applies to every list endpoint, including:

* `GET /v1/events`
* `GET /v1/tickets`
* `GET /v1/marketplace/listings`
* `GET /v1/discounts`
* `GET /v1/payouts`
* `GET /v1/events/deliveries` (webhook deliveries)

Some list endpoints also accept filters (for example `event_id` on
`GET /v1/tickets`); filters compose with pagination.

## Paging through every result

**curl**

```bash
#!/usr/bin/env bash
KEY="sk_test_your_key_here"
BASE="https://api.ticketconnect.example/v1/events?limit=100"
after=""

while :; do
  url="$BASE"
  [ -n "$after" ] && url="$BASE&starting_after=$after"

  page=$(curl -s "$url" -H "Authorization: Bearer $KEY")

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

  has_more=$(echo "$page" | jq -r '.has_more')
  [ "$has_more" != "true" ] && break

  after=$(echo "$page" | jq -r '.data[-1].id')
done
```

**Node**

```js
const KEY = "sk_test_your_key_here";
const BASE = "https://api.ticketconnect.example/v1/events";

async function* listAllEvents() {
  let startingAfter;

  while (true) {
    const url = new URL(BASE);
    url.searchParams.set("limit", "100");
    if (startingAfter) url.searchParams.set("starting_after", startingAfter);

    const res = await fetch(url, {
      headers: { Authorization: `Bearer ${KEY}` },
    });
    const page = await res.json();

    for (const item of page.data) yield item;

    if (!page.has_more) break;
    startingAfter = page.data[page.data.length - 1].id;
  }
}

for await (const event of listAllEvents()) {
  console.log(event.id);
}
```

> **Note:** Use the largest `limit` (100) when bulk-syncing to minimize round trips, and a
> smaller `limit` for interactive, user-facing lists.
