# Paginierung

> Wie Listen in der API blättern: signierte Cursor bei GET /monitors, page und per_page bei Vorfällen und sonst ein einziges Array, mit allen Parametern und Fehlern.

Source: https://upfour.io/de/docs/api/pagination

Nicht alle Listen blättern gleich. `GET /monitors` nutzt signierte Cursor, die Vorfall-Listen nutzen `page` und `per_page`, die meisten anderen Listen liefern alles in einem Array.

| Endpunkt | So wird geblättert | Antwort |
| --- | --- | --- |
| `GET /monitors` | `limit` und `cursor` | `data`\-Array und ein echtes `pagination`\-Objekt |
| `GET /incidents`, `GET /monitors/{id}/incidents` | `page` und `per_page` | `data`\-Objekt mit `items`, `page`, `per_page`, `total`, `counts`; kein `pagination` |
| Die meisten anderen Listen | Gar nicht. Die ganze Liste kommt zurück. | `data`\-Array und ein `pagination`\-Objekt als Platzhalter |

Manche Referenzseiten führen `limit` und `cursor` bei jeder Listen-Operation auf. Nur `GET /monitors` liest `cursor`; die anderen ignorieren ihn.

## Blättern mit Cursor: GET /monitors

```bash
curl -s -G https://app.upfour.io/v1/monitors \
  -H "Authorization: Bearer $UP4_API_KEY" \
  --data-urlencode "limit=100" \
  --data-urlencode "sort=name" \
  --data-urlencode "status=DOWN"
```

```json
{
  "data": [ { "id": "…", "name": "Lakeside Bakery site", … } ],
  "pagination": {
    "cursor": null,
    "next_cursor": "eyJ2IjoxLC…",
    "prev_cursor": null,
    "limit": 100,
    "has_more": true
  }
}
```

Wiederhole die Anfrage mit `cursor` gleich `next_cursor`, bis `has_more` false ist:

```
cursor=""
while true; do
  page=$(curl -s -G https://app.upfour.io/v1/monitors \
    -H "Authorization: Bearer $UP4_API_KEY" \
    --data-urlencode "limit=100" \
    --data-urlencode "cursor=$cursor")
  echo "$page" | jq -r '.data[].name'
  cursor=$(echo "$page" | jq -r '.pagination.next_cursor // empty')
  [ -z "$cursor" ] && break
done
```

### Parameter

| Parameter | Bedeutung |
| --- | --- |
| `limit` | Seitengröße. Standard 50, höchstens 250; ein größerer Wert wird auf 250 gesenkt, ein fehlender, null oder nicht numerischer Wert bedeutet 50. |
| `cursor` | Das next_cursor der vorherigen Seite. Für die erste Seite weglassen oder leer lassen. |
| `sort` | created_at, name oder next_check_at; ein vorangestelltes - sortiert absteigend. Standard ist -created_at. Alles andere ergibt 400. |
| `status` | UP, DOWN oder PAUSED, ohne Beachtung der Groß- und Kleinschreibung. state gilt als Alias. Alles andere ergibt 400. |
| `monitor_type` | http, tcp, ping oder dns. Alles andere ergibt 400. |
| `region` | Monitore, die in dieser Region laufen. |
| `q` | Textsuche ohne Beachtung der Groß- und Kleinschreibung in Name, URL, Typ, TCP-Host, DNS-Abfrage und Region. |
| `monitor_group_id` | Die ID einer Monitorgruppe. Ein Wert, der keine UUID ist, ergibt 400. |
| `severity, severity_group` | Monitore mit einem offenen Vorfall dieses Schweregrads oder dieser Schweregrad-Gruppe. |
| `client_id, all_clients` | Welche Kunden aufgelistet werden; siehe Kunden-Scope. Nicht Teil der Cursor-Prüfung. |

### Felder der Antwort

| Feld | Bedeutung |
| --- | --- |
| `data` | Die Seite mit Monitoren. |
| `pagination.limit` | Die angewendete Seitengröße, nach der Begrenzung. |
| `pagination.has_more` | True, wenn eine weitere Seite existiert. |
| `pagination.next_cursor` | Gib ihn als cursor für die nächste Seite mit. null, wenn has_more false ist. |
| `pagination.cursor` | Der Cursor, den du gesendet hast, auf der ersten Seite null. |
| `pagination.prev_cursor` | Immer null. Geblättert wird nur vorwärts. |

Eine Gesamtzahl gibt es nicht. Die Zeilen sind nach dem Sortierfeld und dann nach der ID geordnet, die Reihenfolge ist also stabil.

### Der Cursor

Ein Cursor ist eine undurchsichtige, signierte Zeichenkette. Er gilt 24 Stunden und ist an die Sortierung und die Filter der Anfrage gebunden, die ihn erzeugt hat. Gib ihn nur zurück; bau oder lies ihn nicht selbst.

| error.code | Status | Ursache |
| --- | --- | --- |
| [cursor_invalid](https://upfour.io/docs/api/errors#code-cursor_invalid) | 400 | Der Cursor stammt nicht von up4, wurde verändert oder ist fehlerhaft. |
| [cursor_expired](https://upfour.io/docs/api/errors#code-cursor_expired) | 400 | Der Cursor ist älter als 24 Stunden. |
| [cursor_parameters_changed](https://upfour.io/docs/api/errors#code-cursor_parameters_changed) | 400 | sort, status, monitor_type, region, q, monitor_group_id, severity oder severity_group weichen von der Anfrage ab, die den Cursor erzeugt hat. |

Beginne nach jedem der drei Fehler von vorn, ohne `cursor`.

## Mit Seitenzahlen: Vorfälle

`GET /incidents` und `GET /monitors/{id}/incidents` nehmen `page` (ab 1) und `per_page` (Standard 25, höchstens 100). Das Ergebnis ist ein Objekt: die Seite mit Vorfällen in `items`, die Position in `page` und `per_page`, die Zahl der Vorfälle, die deinen Filtern entsprechen, in `total` und in `counts` Kennzahlen, die Seite und Listenfilter ignorieren.

```bash
curl -s -G https://app.upfour.io/v1/incidents \
  -H "Authorization: Bearer $UP4_API_KEY" \
  --data-urlencode "per_page=50" \
  --data-urlencode "page=2"
```

## Alles auf einmal: die übrigen Listen

Die übrigen Listen liefern jede Zeile in `data`. up4 ergänzt trotzdem einen `pagination`\-Block, damit jede Liste gleich aufgebaut ist, doch er ist ein Platzhalter: `limit` ist immer 50, `has_more` ist false und die Cursor sind null, egal wie lang das Array ist. Einige Listen haben ein eigenes `limit`, etwa `GET /heartbeats/{id}/pings`, das standardmäßig 25 Pings liefert, höchstens 10.000; ihre Referenzseiten sagen es.

## Typische Fehler

- **`page` oder `per_page` an `/monitors` senden.** Das ist `400 bad_request`: Die öffentliche API nutzt dort `cursor` und `limit`.
- **Zwischen den Seiten Sortierung oder einen Filter ändern.** Die Cursor-Prüfung schlägt mit `cursor_parameters_changed` fehl. `limit` darfst du ändern.
- **Zwischen den Seiten `client_id` oder `all_clients` ändern.** Sie gehören nicht zur Cursor-Prüfung, up4 warnt dich also nicht; lass sie bei jeder Seite gleich.
- **Aufhören, wenn eine Seite kürzer als `limit` ist.** Höre auf, wenn `has_more` false oder `next_cursor` null ist.
- **Dem Platzhalter glauben.** `has_more: false` bei einer Liste außerhalb der Tabelle oben sagt nichts über ihre Größe.
- **Eine Momentaufnahme erwarten.** Jede Seite beginnt hinter der letzten Zeile der vorigen. Mit der Standardsortierung landet ein Monitor, den du während des Blätterns anlegst, vor deiner Position und fehlt in diesem Durchlauf.
- **Einen Cursor aufheben.** Er verfällt nach 24 Stunden.
