> ## 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.

# Paginering

> Gennemløb lister i Living Security Public API med liste-envelope, parameteren limit og uigennemsigtige page_token-cursorer.

Alle `/v1` liste-endpoints returnerer den samme envelope og paginerer på samme måde: tokenbaseret og kun fremad.

## Liste-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">
  Altid `"list"`.
</ResponseField>

<ResponseField name="data" type="array">
  Siden med ressourcer i en stabil, deterministisk rækkefølge.
</ResponseField>

<ResponseField name="next_page_token" type="string | null">
  Angiv denne værdi som `page_token` i den næste anmodning for at hente den følgende side.
  `null`, når der ikke er flere resultater.
</ResponseField>

<ResponseField name="has_more" type="boolean">
  Angiver, om der findes flere resultater ud over denne side.
</ResponseField>

## Anmodningsparametre

<ParamField query="limit" type="integer" default="25">
  Sidestørrelse. Et heltal mellem 1 og 500. Værdier uden for dette interval returnerer en
  `400` med koden `invalid_request`.
</ParamField>

<ParamField query="page_token" type="string">
  `next_page_token` fra det forrige svar. Udelad den ved den første side.
</ParamField>

Der er ingen offset-parametre, ingen gennemløb af forudgående sider og ingen eksakte totalantal. Hvis du vil tælle en samling, skal du gennemløbe den.

<Note>
  **Undtagelse:** `GET /v1/cohorts/{id}/members` returnerer højst 50 rækker pr. side, selv om du anmoder om en højere `limit`. `has_more` og
  `next_page_token` afspejler stadig den faktiske rest af kohorten.
</Note>

Godkend med en af de to Basic-legitimationsformer – se
[Quickstart](/da/developers/v1/quickstart) (`apikey:secret` eller `secret:`).
Angiv `BASE` som organisationens regionale vært – se
[Regioner](/da/developers/v1/regions).

## Gennemløb af en liste

Indlæs `LIVING_SECURITY_API_KEY` fra din hemmelighedsstyring som i quickstarten.
Dette eksempel kræver `entity:read`. Nøglen, der blev brugt i vejledningen til den første anmodning, kan have brug for denne ekstra tilladelse. Installer `requests` til Python eller `jq` til shell-eksemplet. Begge eksempler fastlåser en version, bevarer filtre uændrede og afviser omdirigeringer. De stopper ved fejl og efter 1.000 sider i stedet for at rapportere et delvist gennemløb som fuldført. Pythons læsetimeout begrænser inaktivitet, ikke jobbets samlede varighed. Fastsæt en tidsfrist for jobbet i din integration.

Anmod om sider, indtil `next_page_token` er `null`. Foretræk `limit=500` til massehentning, så du dækker samlingen med færre anmodninger – se
[hastighedsbegrænsninger](/da/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>

## Hold filtre stabile under paginering

Sidetokens er uigennemsigtige, signerede cursorer. Hvert token er bundet til organisationen, den godkendte servicekonto, kontraktversionen og det præcise filtersæt i den anmodning, der frembragte det. Hvis du ændrer et af disse midt i gennemløbet – for
eksempel ved at tilføje et `type`-filter på side to – returneres en `400` med koden
`invalid_request` på parameteren `page_token`:

```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
}
```

Hvis du vil ændre filtre, skal du starte et nyt gennemløb fra første side.

<Tip>
  Behandl `page_token` som en uigennemsigtig streng: send den tilbage præcis som modtaget.
  Du må ikke afkode, gemme langsigtet eller konstruere tokens – deres interne format
  kan ændres når som helst uden varsel.
</Tip>

<Note>
  Liste-endpoints afviser forespørgselsparametre, de ikke understøtter, med en `400`
  `invalid_request`, der angiver parameteren. Se hvert endpoints reference for
  dets understøttede filtre.
</Note>

## Håndtering af en afbrudt eller skiftende samling

Disse eksempler forsøger ikke automatisk fejl igen. Ved `429` skal du overholde `Retry-After`
og følge den begrænsede [vejledning til genforsøg](/da/developers/v1/rate-limits). Bevar samme
region, servicekonto, version, filtre og det sidst behandlede
sidetoken, når du forsøger en læsning igen. Skift af legitimationsoplysninger giver ikke adgang:
hver anmodning kontrollerer stadig de aktuelle tilladelser.

En læsning over flere sider er ikke et øjebliksbillede af samlingen. Rækker kan ændre sig, mens
du gennemløber den. Behandl ressourcer ud fra deres stabile `id`, og gør efterfølgende
skrivninger idempotente; en genstart kan returnere en række igen. Hvis et token afvises,
skal du undersøge `page_token`-fejlen og rette anmodningen, før du starter forfra fra
side ét. Kassér ikke stiltiende tidligere behandlede data, og markér ikke en
afbrudt eksport som fuldført. Brug den relevante rapporteringsressource til eksakte rapporteringstotaler
i stedet for at behandle et levende listegennemløb som et øjebliksbillede.


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