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

# Pagination

> Cursor format, limit bounds, and which endpoints paginate

Collection endpoints use **cursor-based pagination** in `created_at DESC, id DESC` order — newest first. Pass the `next_cursor` from one response as `?cursor=` on the next request. There are no page numbers and no offsets.

## Paginated endpoints

The following endpoints include `next_cursor` and `has_more` in `meta`:

* `GET /v1/videos`
* `GET /v1/videos/{id}/analyses`
* `GET /v1/deals`
* `GET /v1/deals/{id}/activities`
* `GET /v1/deals/{id}/scorings`

## Non-paginated collections

These endpoints return the full collection in a single response — no `cursor` or `limit` parameters are accepted:

* `GET /v1/members`
* `GET /v1/webhooks`
* `GET /v1/videos/{id}/transcript`
* `GET /v1/videos/{id}/events`

<Warning>
  `?cursor=...` and `?limit=...` on these endpoints are silently ignored — the request will not error. If you're expecting a limit to apply and it isn't, you're probably on a non-paginated endpoint.
</Warning>

## Query parameters

| Param    | Default | Range   | Notes                                                         |
| -------- | ------- | ------- | ------------------------------------------------------------- |
| `limit`  | `25`    | `1–100` | Out-of-range values return `422 validation_failed`            |
| `cursor` | —       | —       | Opaque base64url string. Pass verbatim; do not parse or edit. |

## Response shape

```json theme={null}
{
  "data": [ ... ],
  "meta": {
    "request_id": "req_xxxxx",
    "next_cursor": "eyJpZCI6IjdkZmE...", 
    "has_more": true
  }
}
```

When there are no more pages, `has_more` is `false` and `next_cursor` is `null`.

## Drill-through example

Loop on `has_more` rather than on the stringified cursor — it's unambiguous even if a future response shape changes:

```bash theme={null}
CURSOR=""
while true; do
  URL="$LYMO_BASE/v1/videos?limit=10"
  [ -n "$CURSOR" ] && URL="$URL&cursor=$CURSOR"

  RESP=$(curl -s "$URL" -H "Authorization: Bearer $LYMO_KEY")
  echo "$RESP" | jq .data

  HAS_MORE=$(echo "$RESP" | jq -r .meta.has_more)
  [ "$HAS_MORE" != "true" ] && break
  CURSOR=$(echo "$RESP" | jq -r .meta.next_cursor)
done
```

## Invalid cursors

A malformed or unparseable `cursor` **silently falls back to page 1**. This is intentional — cursor encoding may evolve between API versions, and a stale cursor from a previous client build shouldn't break the consumer.

If you need to detect stale cursors, compare the first item's ID to what you were expecting — or, more robustly, store the last successful cursor with a timestamp and re-fetch from scratch periodically.

## Stability under concurrent writes

Cursors use keyset pagination on `(created_at, id)`, so:

* **Items created after you start paging** appear on the first page of a fresh query, never in the middle of your drill-through.
* **Items deleted during paging** may skip pages — you'll see the next item after the gap, not a duplicate of an earlier ID.
* **No overlapping IDs between pages.**

This is safer than offset pagination for long-running drill-throughs, but the total count isn't available mid-iteration.
