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

# Pagination

> Cursors, and why there is no offset.

Every list endpoint returns the same envelope:

```json theme={null}
{
  "object": "list",
  "data": [ … ],
  "has_more": true,
  "next_cursor": "eyJ0IjoiMjAyNi0wOS0wMlQxNTozMDowMFoiLCJpIjoiNDIifQ"
}
```

## Walking pages

```bash theme={null}
curl "https://api.voice.wixzel.com/v1/calls?limit=50" \
  -H "Authorization: Bearer $WIXZEL_API_KEY"

curl "https://api.voice.wixzel.com/v1/calls?limit=50&starting_after=$NEXT_CURSOR" \
  -H "Authorization: Bearer $WIXZEL_API_KEY"
```

Stop when `has_more` is `false`. At that point `next_cursor` is `null`.

| Parameter        |                                        |
| ---------------- | -------------------------------------- |
| `limit`          | 1–100, default 20                      |
| `starting_after` | A cursor from a previous `next_cursor` |
| `ending_before`  | The same, in the other direction       |

Passing both returns `400 conflicting_cursors`.

## Cursors are opaque

A cursor is base64url and encodes an ordering position. Do not parse, construct
or modify one — a cursor we did not issue returns `400 invalid_cursor` rather
than an empty page, so a mangled cursor fails loudly instead of looking like the
end of the list.

## Why no offset

`?page=47` degrades as the offset grows — the database counts past every skipped
row — and it is wrong in a way that is hard to see: records arrive while you are
reading. Calls complete, usage rows land. With an offset, an insertion shifts
every later page and you silently re-read or skip records. A cursor names a
position in the ordering, so it stays correct regardless of what arrives.

Once an offset parameter is documented it cannot be withdrawn without breaking
clients, which is why there has never been one here.
