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

# Paginare

> Parcurgeți listele din Living Security Public API folosind învelișul listei, parametrul limit și cursoarele opace page_token.

Fiecare endpoint de tip listă `/v1` returnează același înveliș și realizează
paginarea în același mod: bazată pe token, doar înainte.

## Învelișul listei

```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">
  Întotdeauna `"list"`.
</ResponseField>

<ResponseField name="data" type="array">
  Pagina de resurse, într-o ordine stabilă și deterministă.
</ResponseField>

<ResponseField name="next_page_token" type="string | null">
  Transmiteți această valoare ca `page_token` în cererea următoare pentru a obține pagina următoare.
  `null` când nu mai există rezultate.
</ResponseField>

<ResponseField name="has_more" type="boolean">
  Indică dacă există rezultate suplimentare după această pagină.
</ResponseField>

## Parametrii cererii

<ParamField query="limit" type="integer" default="25">
  Dimensiunea paginii. Un număr întreg între 1 și 500. Valorile din afara acestui interval returnează un
  `400` cu codul `invalid_request`.
</ParamField>

<ParamField query="page_token" type="string">
  Valoarea `next_page_token` din răspunsul anterior. Omiteți-o pentru prima pagină.
</ParamField>

Nu există parametri de tip offset, nici parcurgere spre pagina anterioară, nici
totaluri exacte. Pentru a număra elementele unei colecții, parcurgeți-o integral.

<Note>
  **Excepție:** `GET /v1/cohorts/{id}/members` returnează cel mult 50 de rânduri pe
  pagină, chiar dacă solicitați un `limit` mai mare. `has_more` și
  `next_page_token` reflectă în continuare restul real al cohortei.
</Note>

Autentificați-vă cu oricare dintre cele două forme de credențiale Basic — consultați
[Ghid de pornire rapidă](/ro/developers/v1/quickstart) (`apikey:secret` sau `secret:`).
Setați `BASE` la gazda regională a organizației — consultați
[Regiuni](/ro/developers/v1/regions).

## Parcurgerea unei liste

Încărcați `LIVING_SECURITY_API_KEY` din managerul dvs. de secrete, ca în ghidul de pornire rapidă.
Acest exemplu necesită `entity:read`; este posibil ca cheia utilizată în ghidul primei cereri
să necesite această permisiune suplimentară. Instalați `requests` pentru Python sau `jq` pentru exemplul
de shell. Ambele exemple fixează o versiune, păstrează filtrele neschimbate și resping
redirecționările. Se opresc la erori și după 1.000 de pagini, în loc să raporteze o
parcurgere parțială drept completă. Timpul de citire (read timeout) din Python limitează inactivitatea, nu durata totală
a sarcinii; stabiliți un termen limită pentru sarcină în integrarea dvs.

Solicitați pagini până când `next_page_token` este `null`. Preferați `limit=500` pentru citiri
în volum mare, astfel încât să acoperiți colecția cu mai puține cereri — consultați
[limitele de rată](/ro/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>

## Mențineți filtrele neschimbate pe durata paginării

Tokenurile de pagină sunt cursoare opace, semnate. Fiecare token este asociat
organizației, contului de serviciu autentificat, versiunii contractului și
setului exact de filtre din cererea care l-a generat. Modificarea oricăruia dintre acestea în timpul parcurgerii — de
exemplu, adăugarea unui filtru `type` la pagina a doua — returnează un `400` cu codul
`invalid_request` pentru parametrul `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
}
```

Pentru a schimba filtrele, începeți o parcurgere nouă de la prima pagină.

<Tip>
  Tratați `page_token` ca pe un șir opac: transmiteți-l înapoi exact așa cum l-ați primit.
  Nu decodați, nu stocați pe termen lung și nu construiți tokenuri — formatul lor intern
  se poate modifica în orice moment, fără notificare prealabilă.
</Tip>

<Note>
  Endpointurile de tip listă resping parametrii de interogare pe care nu îi acceptă cu un `400`
  `invalid_request` care indică parametrul respectiv. Consultați referința fiecărui endpoint pentru
  filtrele acceptate.
</Note>

## Gestionarea unei colecții întrerupte sau aflate în schimbare

Aceste exemple nu reîncearcă automat cererile care returnează erori. Pentru `429`, respectați `Retry-After`
și urmați [recomandările privind reîncercările](/ro/developers/v1/rate-limits), care sunt limitate. Păstrați
aceeași regiune, același cont de serviciu, aceeași versiune, aceleași filtre și ultimul token de pagină
procesat cu succes atunci când reîncercați o citire. Schimbarea credențialelor nu acordă acces:
fiecare cerere verifică în continuare permisiunile curente.

O citire pe mai multe pagini nu reprezintă un instantaneu al colecției. Rândurile se pot modifica în timp ce
o parcurgeți. Procesați resursele după `id` lor stabil și faceți scrierile din aval
idempotente; o repornire poate returna din nou un rând. Dacă un token este respins,
analizați eroarea `page_token` și corectați cererea înainte de a relua de la
prima pagină. Nu eliminați în mod tacit datele procesate anterior și nu marcați o
exportare întreruptă drept finalizată. Pentru totaluri exacte în rapoarte, utilizați resursa de raportare
adecvată, în loc să tratați o parcurgere a unei liste în timp real drept instantaneu.


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