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

# Sahifalash (Pagination)

> Living Security Public API ro‘yxatlarini ro‘yxat envelope’i, limit parametri va noaniq page_token kursorlari yordamida ketma-ket o‘qing.

Har bir `/v1` ro‘yxat endpointi bir xil envelope qaytaradi va bir xil
usulda sahifalanadi: token asosida, faqat oldinga yo‘nalishda.

## Ro‘yxat envelope’i

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

<ResponseField name="data" type="array">
  Resurslar sahifasi, barqaror va deterministik tartibda.
</ResponseField>

<ResponseField name="next_page_token" type="string | null">
  Keyingi sahifani olish uchun buni navbatdagi so‘rovda `page_token` sifatida yuboring.
  Boshqa natijalar qolmaganda `null`.
</ResponseField>

<ResponseField name="has_more" type="boolean">
  Ushbu sahifadan tashqarida yana natijalar mavjudligini bildiradi.
</ResponseField>

## So‘rov parametrlari

<ParamField query="limit" type="integer" default="25">
  Sahifa hajmi. 1 dan 500 gacha bo‘lgan butun son. Ushbu oraliqdan tashqaridagi qiymatlar
  `400` va `invalid_request` kodini qaytaradi.
</ParamField>

<ParamField query="page_token" type="string">
  Oldingi javobdagi `next_page_token`. Birinchi sahifa uchun uni kiritmang.
</ParamField>

Offset parametrlari, oldingi sahifaga o‘tish imkoniyati va aniq umumiy
sonlar mavjud emas. To‘plamdagi elementlarni sanash uchun uni boshidan oxirigacha o‘qib chiqing.

<Note>
  **Istisno:** `GET /v1/cohorts/{id}/members` yuqoriroq `limit` so‘ralgan taqdirda ham,
  har bir sahifada ko‘pi bilan 50 ta qator qaytaradi. `has_more` va
  `next_page_token` esa Cohort’dagi haqiqiy qoldiqni aks ettirishda davom etadi.
</Note>

Basic autentifikatsiyaning istalgan ikki shaklidan biri bilan autentifikatsiyadan o‘ting — qarang:
[Quickstart](/uz/developers/v1/quickstart) (`apikey:secret` yoki `secret:`).
`BASE` qiymatini tashkilotning mintaqaviy hostiga o‘rnating — qarang:
[Regions](/uz/developers/v1/regions).

## Ro‘yxatni ketma-ket o‘qish

`LIVING_SECURITY_API_KEY` qiymatini quickstart’dagi kabi maxfiy ma’lumotlar menejeridan yuklang.
Ushbu misol `entity:read` ruxsatini talab qiladi; birinchi so‘rov qo‘llanmasida ishlatilgan kalitga
ushbu qo‘shimcha ruxsat berilishi kerak bo‘lishi mumkin. Python uchun `requests` yoki shell
misoli uchun `jq` o‘rnating. Ikkala misolda ham versiya qayd etilgan, filtrlar o‘zgarishsiz qoldiriladi va
yo‘naltirishlar (redirect) rad etiladi. Ular qisman o‘qishni to‘liq deb ko‘rsatmaslik uchun xatolarda
va 1 000 sahifadan keyin to‘xtaydi. Python’dagi o‘qish taymauti umumiy ish davomiyligini emas,
faoliyatsizlik vaqtini cheklaydi; integratsiyangizda ish uchun umumiy muddatni belgilang.

`next_page_token` qiymati `null` bo‘lguncha sahifalarni so‘rang. Ommaviy o‘qishlarda to‘plamni kamroq so‘rov bilan
qamrab olish uchun `limit=500` dan foydalaning — qarang:
[rate limits](/uz/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>

## Sahifalash davomida filtrlarni o‘zgarishsiz saqlang

Sahifa tokenlari — noaniq, imzolangan kursorlardir. Har bir token tashkilotga, autentifikatsiyadan
o‘tgan xizmat akkauntiga, kontrakt versiyasiga va uni yaratgan so‘rovning aniq filtrlar to‘plamiga
bog‘langan. O‘qish jarayonida ulardan birortasini o‘zgartirish — masalan,
ikkinchi sahifada `type` filtrini qo‘shish — `page_token` parametri bo‘yicha
`invalid_request` kodli `400` xatosini qaytaradi:

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

Filtrlarni o‘zgartirish uchun birinchi sahifadan boshlab yangi o‘qishni boshlang.

<Tip>
  `page_token` ni noaniq satr sifatida qabul qiling: uni aynan olingan ko‘rinishda qaytarib yuboring.
  Tokenlarni dekodlamang, uzoq muddat saqlamang va o‘zingiz yasamang — ularning ichki formati
  istalgan vaqtda ogohlantirishsiz o‘zgarishi mumkin.
</Tip>

<Note>
  Ro‘yxat endpointlari o‘zi qo‘llab-quvvatlamaydigan so‘rov parametrlarini parametr nomi ko‘rsatilgan
  `400` `invalid_request` bilan rad etadi. Qo‘llab-quvvatlanadigan filtrlar uchun har bir endpointning
  ma’lumotnomasini tekshiring.
</Note>

## Uzilgan yoki o‘zgarayotgan to‘plamni qayta ishlash

Ushbu misollar xatolarni avtomatik ravishda qayta urinib ko‘rmaydi. `429` uchun `Retry-After` ga
amal qiling va cheklangan [retry guidance](/uz/developers/v1/rate-limits) ko‘rsatmalariga rioya qiling.
O‘qishni qayta urinayotganda mintaqa, xizmat akkaunti, versiya, filtrlar va oxirgi muvaffaqiyatli
qayta ishlangan sahifa tokenini o‘zgarishsiz saqlang. Hisob ma’lumotlarini almashtirish ruxsat bermaydi:
har bir so‘rovda joriy ruxsatlar baribir tekshiriladi.

Ko‘p sahifali o‘qish to‘plamning oniy nusxasi (snapshot) emas. Siz uni ko‘rib chiqayotganingizda qatorlar
o‘zgarishi mumkin. Resurslarni barqaror `id` bo‘yicha qayta ishlang va keyingi yozuvlarni
idempotent qiling; qayta boshlash qatorni yana qaytarishi mumkin. Agar token rad etilsa,
birinchi sahifadan qayta boshlashdan oldin `page_token` xatosini tekshiring va so‘rovni to‘g‘irlang.
Avval qayta ishlangan ma’lumotlarni jimgina tashlab yubormang va uzilgan eksportni tugallangan deb
belgilamang. Hisobotlarning aniq umumiy sonlari uchun jonli ro‘yxat bo‘ylab o‘tishni snapshot deb hisoblamasdan,
tegishli hisobot resursidan foydalaning.


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