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

# Pagination

> Cursor-based pagination for ticket, view, and message lists.

All Public API v1 list endpoints use **cursor pagination**. There is no `page` or `offset` parameter.

## Parameters

| Param    | Default                                 | Max | Description                             |
| -------- | --------------------------------------- | --- | --------------------------------------- |
| `limit`  | 40 (tickets), 50 (views), 30 (messages) | 100 | Page size                               |
| `cursor` | —                                       | —   | Opaque token from the previous response |

## Response shape

```json theme={null}
{
  "success": true,
  "data": [ ... ],
  "pagination": {
    "has_more": true,
    "next_cursor": "2026-07-20T10:00:00.000Z|019b0e3d-e88a-715c-b540-ea11ac058052"
  }
}
```

| Field         | Meaning                                                           |
| ------------- | ----------------------------------------------------------------- |
| `has_more`    | `true` if another page exists                                     |
| `next_cursor` | Pass as `cursor` on the next request; omitted or `null` when done |

<Tip>
  Ticket list responses do **not** include a total count. Use `count` on a saved view from `GET /views` when you need "how many tickets match this filter?"
</Tip>

## Walkthrough — paginate tickets

**Page 1:**

```bash theme={null}
curl -sS -H "cx-api-key: $KEY" \
  "https://api.armin.cx/public/v1/tickets?limit=40"
```

**Page 2** (use `next_cursor` from page 1):

```bash theme={null}
curl -sS -H "cx-api-key: $KEY" \
  "https://api.armin.cx/public/v1/tickets?limit=40&cursor=2026-07-20T10:00:00.000Z%7C019b..."
```

URL-encode the cursor value when it contains `|` or other special characters.

**Stop** when `has_more` is `false` or `next_cursor` is absent.

## Paginating views and messages

The same pattern applies to:

* `GET /public/v1/views` — default `limit=50`
* `GET /public/v1/tickets/:ticketNumber/messages` — default `limit=30`, use `order=asc` for chronological threads

## Anti-pattern — offset polling loops

Do **not** simulate pages with incrementing offsets or re-fetch page 1 in a tight loop:

```bash theme={null}
# ❌ Wrong — v1 has no offset/page parameter
GET /public/v1/tickets?page=2

# ❌ Wrong — wasteful and may miss or duplicate rows under concurrent writes
while true; do GET /public/v1/tickets?limit=40; sleep 1; done
```

Instead:

1. Store `next_cursor` from each response.
2. Request the next page only when `has_more` is `true`.
3. Back off on [rate limits](/api/rate-limits) (`429`).

## Cursor stability

Cursors are opaque and tied to the sort order (`created_at` desc for tickets). Do not parse or construct cursors manually — always use the value returned by the API.

If a cursor expires or becomes invalid, start a fresh list request without `cursor`.
