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

# Paginierung

> Durchlaufen Sie Listen der Living Security Public API mit dem List-Envelope, dem Parameter limit und opaken page_token-Cursorn.

Jeder `/v1`-Listenendpunkt liefert dasselbe Envelope zurück und paginiert auf dieselbe Weise:
tokenbasiert und nur vorwärts.

## Das List-Envelope

```json theme={null}
{
  "object": "list",
  "data": [
    {
      "id": "ent_8f3d2c1b0a9e",
      "object": "entity",
      "type": "person",
      "status": "active",
      "display_name": "Dana Rivera",
      "email": "dana.rivera@example.com",
      "created_at": "2025-11-03T09:21:44.000Z",
      "updated_at": "2026-07-28T16:02:10.000Z"
    }
  ],
  "next_page_token": "eyJvcmdhbml6YXRpb2...",
  "has_more": true
}
```

<ResponseField name="object" type="string">
  Immer `"list"`.
</ResponseField>

<ResponseField name="data" type="array">
  Die Seite mit Ressourcen in einer stabilen, deterministischen Reihenfolge.
</ResponseField>

<ResponseField name="next_page_token" type="string | null">
  Übergeben Sie diesen Wert in der nächsten Anfrage als `page_token`, um die folgende Seite abzurufen.
  `null`, wenn keine weiteren Ergebnisse vorhanden sind.
</ResponseField>

<ResponseField name="has_more" type="boolean">
  Gibt an, ob über diese Seite hinaus weitere Ergebnisse vorhanden sind.
</ResponseField>

## Anfrageparameter

<ParamField query="limit" type="integer" default="25">
  Seitengröße. Eine ganze Zahl zwischen 1 und 500. Werte außerhalb dieses Bereichs liefern einen
  `400` mit dem Code `invalid_request` zurück.
</ParamField>

<ParamField query="page_token" type="string">
  Der `next_page_token` aus der vorherigen Antwort. Lassen Sie ihn für die erste Seite weg.
</ParamField>

Es gibt keine Offset-Parameter, kein Zurückblättern zur vorherigen Seite und keine exakten
Gesamtanzahlen. Um eine Sammlung zu zählen, müssen Sie sie durchlaufen.

<Note>
  **Ausnahme:** `GET /v1/cohorts/{id}/members` liefert höchstens 50 Zeilen pro
  Seite, auch wenn Sie einen höheren `limit` anfordern. `has_more` und
  `next_page_token` geben weiterhin den tatsächlichen Rest der Kohorte wieder.
</Note>

Authentifizieren Sie sich mit einer der beiden Basic-Anmeldedatenformen – siehe
[Quickstart](/de/developers/v1/quickstart) (`apikey:secret` oder `secret:`).
Setzen Sie `BASE` auf den regionalen Host der Organisation – siehe
[Regionen](/de/developers/v1/regions).

## Eine Liste durchlaufen

Laden Sie `LIVING_SECURITY_API_KEY` wie im Quickstart aus Ihrem Secret Manager.
Dieses Beispiel benötigt `entity:read`; der Schlüssel, der für die Anleitung zur ersten Anfrage verwendet wurde,
benötigt diese zusätzliche Berechtigung möglicherweise noch. Installieren Sie `requests` für Python oder `jq` für das Shell-Beispiel.
Beide Beispiele legen eine Version fest, lassen Filter unverändert und lehnen
Weiterleitungen ab. Sie brechen bei Fehlern und nach 1.000 Seiten ab, anstatt einen
unvollständigen Durchlauf als abgeschlossen zu melden. Das Lese-Timeout von Python begrenzt die Inaktivität, nicht die gesamte
Dauer des Jobs; legen Sie in Ihrer Integration ein Zeitlimit für den Job fest.

Fordern Sie Seiten an, bis `next_page_token` den Wert `null` hat. Bevorzugen Sie `limit=500` für Massenabfragen,
damit Sie die Sammlung mit weniger Anfragen abdecken – siehe
[Ratenlimits](/de/developers/v1/rate-limits).

<CodeGroup>
  ```bash cURL + jq theme={null}
  set -euo pipefail
  # US: BASE="https://api.us-east-1.livingsecurity.ai/v1"
  BASE="https://api.eu-west-1.livingsecurity.ai/v1"
  : "${LIVING_SECURITY_API_KEY:?Set LIVING_SECURITY_API_KEY}"
  TOKEN=""

  # Bound each run. Increase this page budget deliberately for larger collections.
  for ((page_number=1; page_number<=1000; page_number++)); do
    PARAMS=(--data-urlencode "limit=500" --data-urlencode "type=person")
    if [ -n "$TOKEN" ]; then
      PARAMS+=(--data-urlencode "page_token=$TOKEN")
    fi
    RESULT=$(curl --silent --show-error --fail-with-body \
      --connect-timeout 5 --max-time 30 --get \
      -u "apikey:$LIVING_SECURITY_API_KEY" \
      -H "Living-Security-Version: 2026-07-01" \
      --write-out '\n%{http_code}' "${PARAMS[@]}" "$BASE/entities")
    STATUS="${RESULT##*$'\n'}"
    PAGE="${RESULT%$'\n'*}"
    [ "$STATUS" = "200" ] || { echo "Unexpected HTTP status: $STATUS" >&2; exit 1; }
    jq -e 'has("next_page_token") and .object == "list" and (.data | type == "array") and
      ((.has_more == false and .next_page_token == null) or
       (.has_more == true and (.next_page_token | type == "string" and length > 0)))' \
      <<< "$PAGE" > /dev/null
    NEXT=$(jq -r '.next_page_token // empty' <<< "$PAGE")
    [ -z "$NEXT" ] || [ "$NEXT" != "$TOKEN" ] || { echo "Repeated page token" >&2; exit 1; }
    jq -r '.data[].id' <<< "$PAGE"
    [ -n "$NEXT" ] || exit 0
    TOKEN="$NEXT"
  done
  echo "Page budget exhausted; the collection is incomplete" >&2
  exit 1
  ```

  ```python Python theme={null}
  import os
  import requests

  # US: BASE = "https://api.us-east-1.livingsecurity.ai/v1"
  BASE = "https://api.eu-west-1.livingsecurity.ai/v1"
  AUTH = ("apikey", os.environ["LIVING_SECURITY_API_KEY"])

  def iter_entities(*, entity_type="person", max_pages=1000):
      if type(max_pages) is not int or max_pages < 1:
          raise ValueError("max_pages must be a positive integer")
      params = {"limit": 500, "type": entity_type}
      for _ in range(max_pages):
          response = requests.get(
              f"{BASE}/entities",
              auth=AUTH,
              params=params,
              headers={"Living-Security-Version": "2026-07-01"},
              timeout=(5, 30),
              allow_redirects=False,
          )
          try:
              response.raise_for_status()
              if response.status_code != 200:
                  raise RuntimeError("Unexpected response; check your regional API URL")
              page = response.json()
          finally:
              response.close()
          if (not isinstance(page, dict) or page.get("object") != "list"
                  or not isinstance(page.get("data"), list)
                  or type(page.get("has_more")) is not bool
                  or "next_page_token" not in page):
              raise RuntimeError("Invalid list response")
          token = page["next_page_token"]
          if ((page["has_more"] and (not isinstance(token, str) or not token))
                  or (not page["has_more"] and token is not None)):
              raise RuntimeError("Inconsistent list response")
          if token is not None and token == params.get("page_token"):
              raise RuntimeError("Repeated page token")
          yield from page["data"]
          if token is None:
              return
          params = {**params, "page_token": token}
      raise RuntimeError("Page budget exhausted; the collection is incomplete")

  if __name__ == "__main__":
      for entity in iter_entities():
          print(entity["id"])
  ```
</CodeGroup>

## Filter während der Paginierung stabil halten

Page-Tokens sind opake, signierte Cursor. Jedes Token ist an die Organisation, das authentifizierte Servicekonto, die Vertragsversion und den
exakten Filtersatz der Anfrage gebunden, die es erzeugt hat. Wenn Sie eines davon mitten im Durchlauf ändern – zum
Beispiel durch Hinzufügen eines `type`-Filters auf Seite zwei –, wird ein `400` mit dem Code
`invalid_request` für den Parameter `page_token` zurückgegeben:

```json 400 Invalid request theme={null}
{
  "type": "https://docs.livingsecurity.com/developers/v1/errors/invalid_request",
  "title": "Invalid request",
  "status": 400,
  "detail": "page_token does not match this request's organization, credential, contract version, or filters.",
  "code": "invalid_request",
  "param": "page_token",
  "request_id": "req_...",
  "doc_url": "https://docs.livingsecurity.com/developers/v1/errors/invalid_request",
  "retryable": false
}
```

Um Filter zu ändern, beginnen Sie einen neuen Durchlauf ab der ersten Seite.

<Tip>
  Behandeln Sie `page_token` als opaken String: Geben Sie ihn exakt so zurück, wie Sie ihn erhalten haben.
  Decodieren Sie Tokens nicht, speichern Sie sie nicht langfristig und erzeugen Sie sie nicht selbst – ihr internes Format
  kann sich jederzeit ohne Vorankündigung ändern.
</Tip>

<Note>
  Listenendpunkte weisen Abfrageparameter, die sie nicht unterstützen, mit einem `400`
  `invalid_request` zurück, der den Parameter benennt. Prüfen Sie in der Referenz des jeweiligen Endpunkts, welche
  Filter unterstützt werden.
</Note>

## Unterbrochene oder sich ändernde Sammlungen behandeln

Diese Beispiele wiederholen Fehler nicht automatisch. Beachten Sie bei `429` den Wert `Retry-After`
und befolgen Sie die begrenzten [Wiederholungsempfehlungen](/de/developers/v1/rate-limits). Behalten Sie bei der Wiederholung einer Leseanfrage
dieselbe Region, dasselbe Servicekonto, dieselbe Version, dieselben Filter und das zuletzt erfolgreich verarbeitete
Page-Token bei. Ein Wechsel der Anmeldedaten gewährt keinen Zugriff:
Jede Anfrage prüft weiterhin die aktuellen Berechtigungen.

Ein mehrseitiger Lesevorgang ist kein Snapshot der Sammlung. Zeilen können sich ändern, während
Sie die Sammlung durchlaufen. Verarbeiten Sie Ressourcen anhand ihrer stabilen `id` und gestalten Sie nachgelagerte
Schreibvorgänge idempotent; nach einem Neustart kann eine Zeile erneut zurückgegeben werden. Wird ein Token abgelehnt,
prüfen Sie den Fehler `page_token` und korrigieren Sie die Anfrage, bevor Sie
mit Seite eins neu beginnen. Verwerfen Sie bereits verarbeitete Daten nicht stillschweigend und markieren Sie einen
unterbrochenen Export nicht als abgeschlossen. Verwenden Sie für exakte Berichtssummen die entsprechende
Berichtsressource, anstatt einen Live-Listendurchlauf als Snapshot zu behandeln.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.