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

# Paginación

> Recorra las listas de la API pública de Living Security con el envoltorio de lista, el parámetro limit y los cursores opacos page_token.

Todos los endpoints de lista `/v1` devuelven el mismo envoltorio y paginan
de la misma manera: basada en tokens y solo hacia adelante.

## El envoltorio de lista

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

<ResponseField name="data" type="array">
  La página de recursos, en un orden estable y determinista.
</ResponseField>

<ResponseField name="next_page_token" type="string | null">
  Pase este valor como `page_token` en la siguiente solicitud para obtener la página siguiente.
  `null` cuando no haya más resultados.
</ResponseField>

<ResponseField name="has_more" type="boolean">
  Indica si existen más resultados después de esta página.
</ResponseField>

## Parámetros de la solicitud

<ParamField query="limit" type="integer" default="25">
  Tamaño de página. Un número entero entre 1 y 500. Los valores fuera de ese rango devuelven un
  `400` con el código `invalid_request`.
</ParamField>

<ParamField query="page_token" type="string">
  El `next_page_token` de la respuesta anterior. Omítalo para la primera página.
</ParamField>

No hay parámetros de desplazamiento (offset), ni recorrido hacia la página anterior, ni recuentos totales exactos. Para contar una colección, recórrala.

<Note>
  **Excepción:** `GET /v1/cohorts/{id}/members` devuelve como máximo 50 filas por
  página, incluso cuando solicita un `limit` mayor. `has_more` y
  `next_page_token` siguen reflejando el resto real de la cohorte.
</Note>

Autentíquese con cualquiera de los dos formatos de credencial Basic; consulte
[Guía de inicio rápido](/es/developers/v1/quickstart) (`apikey:secret` o `secret:`).
Establezca `BASE` con el host regional de la organización; consulte
[Regiones](/es/developers/v1/regions).

## Recorrer una lista

Cargue `LIVING_SECURITY_API_KEY` desde su gestor de secretos, como en la guía de inicio rápido.
Este ejemplo requiere `entity:read`; es posible que la clave utilizada en la guía de la primera solicitud
necesite esa concesión adicional. Instale `requests` para Python o `jq` para el ejemplo
de shell. Ambos ejemplos fijan una versión, mantienen los filtros sin cambios y rechazan
las redirecciones. Se detienen ante errores y tras 1000 páginas, en lugar de informar de un
recorrido parcial como completo. El tiempo de espera de lectura de Python limita la inactividad, no la duración
total del trabajo; establezca un plazo máximo para el trabajo en su integración.

Solicite páginas hasta que `next_page_token` sea `null`. Prefiera `limit=500` para lecturas
masivas, de modo que cubra la colección con menos solicitudes; consulte
[límites de frecuencia](/es/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>

## Mantenga estables los filtros durante la paginación

Los tokens de página son cursores firmados y opacos. Cada token está vinculado a la
organización, a la cuenta de servicio autenticada, a la versión del contrato y al
conjunto exacto de filtros de la solicitud que lo generó. Cambiar cualquiera de ellos a mitad del recorrido (por
ejemplo, añadir un filtro `type` en la segunda página) devuelve un `400` con el código
`invalid_request` en el parámetro `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
}
```

Para cambiar los filtros, inicie un nuevo recorrido desde la primera página.

<Tip>
  Trate `page_token` como una cadena opaca: devuélvala exactamente como la recibió.
  No decodifique los tokens, no los almacene a largo plazo ni los construya; su formato interno
  puede cambiar en cualquier momento sin previo aviso.
</Tip>

<Note>
  Los endpoints de lista rechazan los parámetros de consulta que no admiten con un `400`
  `invalid_request` que indica el nombre del parámetro. Consulte la referencia de cada endpoint para
  conocer los filtros que admite.
</Note>

## Gestione una colección interrumpida o cambiante

Estos ejemplos no reintentan los errores automáticamente. Para `429`, respete `Retry-After`
y siga las [pautas de reintento](/es/developers/v1/rate-limits) acotadas. Mantenga la
misma región, cuenta de servicio, versión, filtros y el último token de página procesado correctamente
al reintentar una lectura. Cambiar las credenciales no concede acceso:
cada solicitud sigue comprobando los permisos vigentes.

Una lectura de varias páginas no es una instantánea de la colección. Las filas pueden cambiar mientras
la recorre. Procese los recursos por su `id` estable y haga que las escrituras
posteriores sean idempotentes; un reinicio puede devolver de nuevo una fila. Si se rechaza un token,
revise el error `page_token` y corrija la solicitud antes de reiniciar desde
la primera página. No descarte silenciosamente los datos ya procesados ni marque como completa una
exportación interrumpida. Para obtener totales de informes exactos, utilice el recurso de informes adecuado
en lugar de tratar un recorrido de lista en vivo como una instantánea.


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