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

# 分頁

> 透過清單封包、limit 參數及不透明的 page_token 游標，逐頁瀏覽 Living Security Public API 的清單。

每個 `/v1` 清單端點都會傳回相同的封包，並以相同方式進行分頁：採用權杖機制，且僅能向前翻頁。

## 清單封包

```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">
  一律為 `"list"`。
</ResponseField>

<ResponseField name="data" type="array">
  該頁的資源，依穩定且具確定性的順序排列。
</ResponseField>

<ResponseField name="next_page_token" type="string | null">
  在下一次請求中將此值作為 `page_token` 傳入，即可取得下一頁。
  若已無更多結果，則為 `null`。
</ResponseField>

<ResponseField name="has_more" type="boolean">
  此頁之後是否還有更多結果。
</ResponseField>

## 請求參數

<ParamField query="limit" type="integer" default="25">
  每頁筆數。須為介於 1 至 500 之間的整數。超出此範圍的值會傳回 `400`，錯誤代碼為 `invalid_request`。
</ParamField>

<ParamField query="page_token" type="string">
  上一個回應中的 `next_page_token`。取得第一頁時請省略此參數。
</ParamField>

本 API 不提供位移（offset）參數、不支援回溯至上一頁，也不提供精確的總筆數。若要計算某個集合的筆數，請逐頁走訪該集合。

<Note>
  \*\*例外：\*\*即使您要求更高的 `limit`，`GET /v1/cohorts/{id}/members` 每頁最多仍只會傳回 50 列。`has_more` 與 `next_page_token` 仍會反映該群組實際的剩餘筆數。
</Note>

請使用任一種 Basic 憑證形式進行驗證，詳見[快速入門](/zh-Hant/developers/v1/quickstart)（`apikey:secret` 或 `secret:`）。
請將 `BASE` 設定為貴組織所在區域的主機，詳見[區域](/zh-Hant/developers/v1/regions)。

## 走訪清單

如同快速入門所示，請從您的密鑰管理工具載入 `LIVING_SECURITY_API_KEY`。
此範例需要 `entity:read`；用於首次請求指南的金鑰可能需要額外授予該權限。Python 範例請安裝 `requests`，Shell 範例請安裝 `jq`。兩個範例皆固定版本、保持篩選條件不變，並拒絕重新導向。遇到錯誤時，或已達 1,000 頁時，範例會停止，而不會將不完整的走訪結果回報為已完成。Python 的讀取逾時僅限制閒置時間，而非整體工作時間；請在您的整合中設定工作期限。

持續請求各頁，直到 `next_page_token` 為 `null`。進行大量讀取時，建議使用 `limit=500`，以便用較少的請求涵蓋整個集合，詳見[速率限制](/zh-Hant/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>

## 分頁時請保持篩選條件不變

分頁權杖是不透明且經過簽署的游標。每個權杖都會綁定至產生它的請求所屬的組織、經驗證的服務帳戶、合約版本，以及完全相同的篩選條件組合。若在走訪途中變更其中任何一項（例如在第二頁加入 `type` 篩選條件），將傳回 `400`，錯誤代碼為 `invalid_request`，且指向 `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
}
```

若要變更篩選條件，請從第一頁重新開始走訪。

<Tip>
  請將 `page_token` 視為不透明字串：以收到的原樣傳回即可。
  請勿解碼、長期儲存或自行建構權杖，其內部格式可能隨時變更，恕不另行通知。
</Tip>

<Note>
  清單端點會拒絕其不支援的查詢參數，並傳回指出該參數名稱的 `400` `invalid_request`。請查閱各端點的參考文件，了解其支援的篩選條件。
</Note>

## 處理中斷或變動中的集合

這些範例不會自動重試錯誤。遇到 `429` 時，請遵守 `Retry-After`，並依照有限度的[重試指引](/zh-Hant/developers/v1/rate-limits)操作。重試讀取時，請保持相同的區域、服務帳戶、版本、篩選條件，以及最後一個成功處理的分頁權杖。更換憑證並不會授予存取權：每次請求仍會檢查目前的權限。

多頁讀取並非集合的快照。走訪期間，資料列可能發生變動。請依穩定的 `id` 處理資源，並確保下游寫入具冪等性；重新啟動後可能會再次傳回同一列。若權杖遭拒絕，請先檢查 `page_token` 錯誤並修正請求，再從第一頁重新開始。請勿默默捨棄先前已處理的資料，也不要將中斷的匯出標示為已完成。若需要精確的報表總數，請使用適當的報表資源，而非將即時的清單走訪視為快照。


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