> ## Documentation Index
> Fetch the complete documentation index at: https://docs.clipstake.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Pagination

> Page through list endpoints with an opaque keyset cursor.

List endpoints take `limit` and `cursor`, and return `data` with a
`next_cursor`.

```bash theme={null}
curl --get "https://api.clipstake.com/v1/submissions" \
  --header "Authorization: Bearer $CLIPSTAKE_API_KEY" \
  --data-urlencode "project_id=$PROJECT_ID" \
  --data-urlencode "limit=50"
```

```json theme={null}
{
  "data": [{ "shortcode": "DAbc123XyZ" }],
  "next_cursor": "MTcyNjg0NzIwMDAwMC4yYzEuYjkx"
}
```

`limit` is 1 to 100 and defaults to 25. A `next_cursor` of `null` means you
have reached the end.

```js theme={null}
let cursor;
const all = [];

do {
  const params = new URLSearchParams({ project_id: projectId, limit: "100" });
  if (cursor) params.set("cursor", cursor);

  const res = await fetch(`https://api.clipstake.com/v1/submissions?${params}`, {
    headers: { Authorization: `Bearer ${process.env.CLIPSTAKE_API_KEY}` },
  });
  const page = await res.json();

  all.push(...page.data);
  cursor = page.next_cursor;
} while (cursor);
```

## The cursor is keyset, not an offset

Pages are ordered by creation time and cut at a stable key. A row inserted
between two of your requests does not shift the rows behind it, so page two
never repeats an item or silently skips one.

## Keep the filters the same

A cursor is bound to the filters it was issued for. Sending it with different
filters returns `400 invalid_request`.

Repeat the same query parameters on every page, and change filters only by
starting again without a cursor.

## Treat it as opaque

The cursor is an encoded string, and what it encodes is an implementation
detail that can change. Store it and send it back. Do not decode it, parse it,
or build one yourself.

## There is no total

List responses carry no total count. Counting an entire result set on every
page is a cost that is invisible until it is slow.

Page until `next_cursor` is `null` when you need a total of your own.
