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

# 速率限制

> Living Security 公共 API 的请求配额、429 响应约定，以及如何根据 Retry-After 进行重试。

`/v1` API 实行两项相互独立的请求配额。只要其中任一配额耗尽，请求即会被拒绝。

| 配额 | 适用范围 |
| - | - |
| 每个 API 密钥 | 使用该密钥发出的所有请求，不论来自哪个地址 |
| 每个客户端 IP | 来自该地址的所有请求，无论是否经过身份验证 |

每个密钥的配额会跟随该密钥，无论其在何处使用。每个 IP 的配额是未经身份验证流量的唯一配额，同时也是经过身份验证流量的第二道上限。

<Note>
  速率限制在身份验证之前执行，因此凭据无效或缺失的请求同样会计入来源配额。具体的数值配额由运营方配置，可能会发生变化；下文所述的响应约定是可以稳定依赖的接口。
</Note>

请使用任一种 Basic 凭据形式进行身份验证，详见[快速入门](/zh-Hans/developers/v1/quickstart)（`apikey:secret` 或 `secret:`）。
请将 `BASE` 设置为组织所在区域的主机，详见[区域](/zh-Hans/developers/v1/regions)。

## 429 响应

当某项配额耗尽时，API 会返回 `429 Too Many Requests`，并附带 `Retry-After` 标头（以秒为单位）以及标准的 problem-details 响应正文：

```json 429 Too Many Requests theme={null}
{
  "type": "https://docs.livingsecurity.com/developers/v1/errors/rate_limited",
  "title": "Too Many Requests",
  "status": 429,
  "detail": "Rate limit exceeded. Retry after the Retry-After interval.",
  "code": "rate_limited",
  "request_id": "req_...",
  "doc_url": "https://docs.livingsecurity.com/developers/v1/errors/rate_limited",
  "retryable": true
}
```

该响应不会说明是哪一项配额已耗尽。请以相同方式处理每个 `429`：先等待，然后重试。

## 处理 429 响应

<Steps>
  <Step title="遵循 Retry-After">
    重试前，请至少等待 `Retry-After` 标头中指定的秒数。过早重试只会白白消耗那些注定被拒绝的请求所占用的配额。
  </Step>

  <Step title="重复失败时采用指数退避">
    如果重试再次被拒绝，请增大退避时间并加入随机抖动，以免并行的工作进程同步重试。切勿为了符合本地上限而缩短服务器给出的 `Retry-After`。如果服务器要求的等待时间超出了您的重试预算，请停止重试，并将该工作安排到稍后执行。
  </Step>

  <Step title="平滑请求速率">
    相比突发请求，请优先保持稳定的请求速率。对于批量读取，请使用最大分页大小（`limit=500`），以更少的请求覆盖整个集合，详见[分页](/zh-Hans/developers/v1/pagination)。当多个列表遍历并行运行时（例如 Power BI 表），请保持适度的并发，并遵循 `Retry-After`，以免临时出现的 429 导致整个刷新失败。
  </Step>
</Steps>

此示例仅对 **GET** 请求的 `429` 响应进行重试，最多尝试五次，每次尝试之间最多等待 60 秒。遇到其他错误时会立即停止。网络超时会向调用方传播。请根据您的工作负载配置超时和重试预算。`requests` 将读取超时解释为接收数据时的最长空闲时间，而非整体截止时间。

请从您的密钥管理器中加载 `LIVING_SECURITY_API_KEY`。运行此示例之前，请先安装 `requests`。调用 `get_with_retry("/organization")` 即可使用。

```python Python theme={null}
import os
import random
import time
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 get_with_retry(path, params=None, max_attempts=5):
    if not 1 <= max_attempts <= 5:
        raise ValueError("max_attempts must be between 1 and 5")
    for attempt in range(max_attempts):
        response = requests.get(
            f"{BASE}{path}", auth=AUTH, params=params,
            headers={"Living-Security-Version": "2026-07-01"},
            timeout=(5, 30), allow_redirects=False,
        )
        if response.status_code != 429:
            response.raise_for_status()
            if not 200 <= response.status_code < 300:
                raise RuntimeError("Unexpected redirect; check your regional API URL")
            return response

        # The API returns Retry-After as a whole number of seconds.
        raw_wait = response.headers.get("Retry-After", "")
        request_id = response.headers.get("Request-Id", "unknown")
        response.close()
        if attempt == max_attempts - 1:
            raise RuntimeError(f"Retry budget exhausted; request_id={request_id}")
        if not raw_wait.isascii() or not raw_wait.isdigit() or len(raw_wait) > 6:
            raise RuntimeError(f"Invalid Retry-After; request_id={request_id}")

        wait = max(int(raw_wait), min(2 ** attempt, 30))
        delay = wait + random.uniform(0, 1)
        if delay > 60:
            raise RuntimeError(f"Retry-After exceeds wait budget; request_id={request_id}")
        time.sleep(delay)
```

请勿将此循环复制到写入操作中使用。写入后发生超时，可能意味着服务器在连接失败之前已提交该操作。只有当该操作的参考文档明确说明其具有幂等性时，才可重复执行写入，并且必须保持相同的密钥和载荷。否则，请先核对资源状态，再重新尝试。

## 建议的刷新计划

请根据您的密钥配额和分页大小来确定刷新频率。对大型集合进行完整的历史数据加载属于一次性成本；对于常规的稳态刷新，建议使用增量时间窗口，使每次运行都远低于配额。请务必显式设置 `limit=500`，因为默认值 25 会成倍增加请求数量。


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