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

# Paginazione

> Scorrere gli elenchi della Living Security Public API con l'envelope di elenco, il parametro limit e i cursori opachi page_token.

Ogni endpoint di elenco `/v1` restituisce lo stesso envelope ed esegue la paginazione
nello stesso modo: basata su token e solo in avanti.

## L'envelope di elenco

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

<ResponseField name="data" type="array">
  La pagina di risorse, in un ordine stabile e deterministico.
</ResponseField>

<ResponseField name="next_page_token" type="string | null">
  Passare questo valore come `page_token` nella richiesta successiva per ottenere la pagina seguente.
  `null` quando non ci sono altri risultati.
</ResponseField>

<ResponseField name="has_more" type="boolean">
  Indica se esistono ulteriori risultati oltre questa pagina.
</ResponseField>

## Parametri della richiesta

<ParamField query="limit" type="integer" default="25">
  Dimensione della pagina. Un numero intero compreso tra 1 e 500. I valori al di fuori di tale intervallo restituiscono un
  `400` con codice `invalid_request`.
</ParamField>

<ParamField query="page_token" type="string">
  Il valore `next_page_token` della risposta precedente. Omettere per la prima pagina.
</ParamField>

Non sono presenti parametri di offset, né la possibilità di tornare alla pagina precedente, né conteggi totali esatti. Per contare una raccolta, è necessario scorrerla.

<Note>
  **Eccezione:** `GET /v1/cohorts/{id}/members` restituisce al massimo 50 righe per
  pagina, anche se si richiede un valore `limit` più alto. `has_more` e
  `next_page_token` riflettono comunque il resto effettivo della Coorte.
</Note>

Eseguire l'autenticazione con una qualsiasi delle due forme di credenziali Basic: vedere
[Guida introduttiva](/it/developers/v1/quickstart) (`apikey:secret` o `secret:`).
Impostare `BASE` sull'host regionale dell'organizzazione: vedere
[Regioni](/it/developers/v1/regions).

## Scorrere un elenco

Caricare `LIVING_SECURITY_API_KEY` dal proprio secret manager come nella guida introduttiva.
Questo esempio richiede `entity:read`; la chiave utilizzata per la guida alla prima richiesta
potrebbe richiedere questa autorizzazione aggiuntiva. Installare `requests` per Python o `jq` per l'esempio
shell. Entrambi gli esempi fissano una versione, mantengono invariati i filtri e rifiutano i
reindirizzamenti. Si interrompono in caso di errori e dopo 1.000 pagine, anziché segnalare come completo un
scorrimento parziale. Il timeout di lettura di Python limita l'inattività, non la durata
totale del processo; impostare una scadenza del processo nella propria integrazione.

Richiedere le pagine finché `next_page_token` non è `null`. Preferire `limit=500` per le
letture in blocco, in modo da coprire la raccolta con meno richieste: vedere
[limiti di frequenza](/it/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>

## Mantenere stabili i filtri durante la paginazione

I token di pagina sono cursori opachi e firmati. Ogni token è associato all'organizzazione,
all'account di servizio autenticato, alla versione del contratto e all'esatto insieme di filtri della
richiesta che lo ha generato. La modifica di uno di questi elementi durante lo scorrimento, ad
esempio l'aggiunta di un filtro `type` alla seconda pagina, restituisce un `400` con codice
`invalid_request` sul parametro `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
}
```

Per modificare i filtri, avviare un nuovo scorrimento dalla prima pagina.

<Tip>
  Trattare `page_token` come una stringa opaca: restituirla esattamente come ricevuta.
  Non decodificare i token, non conservarli a lungo termine e non costruirli: il loro formato interno
  può cambiare in qualsiasi momento senza preavviso.
</Tip>

<Note>
  Gli endpoint di elenco rifiutano i parametri di query che non supportano con un `400`
  `invalid_request` che indica il nome del parametro. Consultare il riferimento di ciascun endpoint per
  i filtri supportati.
</Note>

## Gestire una raccolta interrotta o soggetta a modifiche

Questi esempi non ripetono automaticamente gli errori. Per `429`, rispettare `Retry-After`
e seguire le [indicazioni sui tentativi ripetuti](/it/developers/v1/rate-limits) con limiti definiti. Mantenere
la stessa regione, lo stesso account di servizio, la stessa versione, gli stessi filtri e l'ultimo token di
pagina elaborato con successo quando si ripete una lettura. Cambiare le credenziali non concede l'accesso:
ogni richiesta verifica comunque le autorizzazioni correnti.

Una lettura su più pagine non è un'istantanea della raccolta. Le righe possono cambiare mentre
le si scorre. Elaborare le risorse in base al loro `id` stabile e rendere idempotenti le scritture
a valle; un riavvio può restituire nuovamente una riga. Se un token viene rifiutato,
esaminare l'errore `page_token` e correggere la richiesta prima di ricominciare dalla
prima pagina. Non scartare silenziosamente i dati già elaborati e non contrassegnare come completa
un'esportazione interrotta. Per totali di reportistica esatti, utilizzare la risorsa di reportistica appropriata
anziché considerare uno scorrimento di un elenco in tempo reale come un'istantanea.


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