# 频率限制：档位、响应头和退避重试

> okdata 按账户限流：各档位每分钟请求数、同时进行的调用数和每日额度，X-RateLimit 响应头，rate_limited 错误和 retry_after_seconds，以及退避重试的代码。

网页版：https://okdata.online/zh/docs/rate-limits/

限额按账户算，不按 Key 算：一个账户下的所有 API Key，以及用这些 Key 发起的 MCP `call`，共用同一套计数。新账户每分钟可以发 60 个请求，第一次充值之后提高到每分钟 600 个。超出限额会收到 `429 rate_limited` 和 `retry_after_seconds`，不扣费。

## 档位

| 档位 | 什么时候 | 每分钟请求数 | 同时进行的调用 | 每日消费额度 | 每天的 not_found 次数 |
| --- | --- | --- | --- | --- | --- |
| trial（试用） | 第一次充值之前 | 60 | 5 | $5 | 200 |
| standard（标准） | 第一次充值起 | 600 | 20 | $1,000 | 5,000 |
| pro | 申请后由我们设置 | 3,000 | 50 | $10,000 | 20,000 |

表里“每天的 not_found 次数”指的是查无此项、没有扣费的调用；到了上限，当天再调接口就会被拒绝，UTC 时间 00:00 之后恢复。

`GET https://api.okdata.online/v1/account` 返回的 `rate` 里写着你当前的档位，以及 `per_minute`、`concurrent` 和 `free_per_minute`。查这个接口不收费。

## 每分钟请求数：先突发，再匀速补充

每分钟的计数是一个令牌桶。桶一开始是满的，所以一分钟的额度可以一次性用完；之后匀速补充：试用档每秒补 1 个，标准档每秒 10 个，pro 每秒 50 个。在标准档一口气发 600 个请求的脚本，接下来就得等令牌补回来；而一直保持每秒 10 个的脚本永远不会触发限流。

每个带 Key 的请求都会消耗一次计数，参数错误被拒绝的也算。免费路由 `/v1/account`、`/v1/calls` 和 `/v1/usage` 有自己单独的计数，不分档位，都是每分钟 120 次，所以查余额、查调用记录不会占用你调接口的额度。目录和服务状态路由不需要 Key。

## 响应头

每个带有效 Key 的请求，返回里都有这些响应头：

| 响应头 | 含义 |
| --- | --- |
| `X-RateLimit-Limit` | 这个路由每分钟的请求上限 |
| `X-RateLimit-Remaining` | 现在还能发多少个请求（整数） |
| `X-RateLimit-Reset` | 计数什么时候补满，Unix 时间戳（秒） |
| `Retry-After` | 要等几秒；出现在 `rate_limited` 和其他带 `retry_after_seconds` 的错误里 |

```bash
curl -s -D - -o /dev/null "https://api.okdata.online/v1/douyin/trends/list" -H "Authorization: Bearer $OKDATA_API_KEY"
```

```
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 599
X-RateLimit-Reset: 1794470460
```

这条命令是一次真实调用，花费 $0.002。留意 `X-RateLimit-Remaining`，在被拒绝之前主动放慢速度。

## 被限流时的返回

```json
{
  "code": "rate_limited",
  "request_id": "0f6c2a8e-4b1d-4e0a-9a51-3c7d2b9e1f20",
  "message": "Too many requests, or too many calls in progress",
  "message_zh": "请求太多，或同时进行的调用太多",
  "charged": false,
  "retry": "yes",
  "retry_after_seconds": 1,
  "param": null,
  "problems": ["Too many requests for this account (600 a minute); retry in 1 s."],
  "reason": "rate",
  "docs_url": "https://okdata.online/docs/errors/#rate_limited"
}
```

- `reason: rate`：超过了每分钟的请求数。等 `retry_after_seconds` 秒再试，`Retry-After` 响应头里是同一个数。
- `reason: concurrency`：账户同时在跑的调用已经到了档位上限。这时 `retry_after_seconds` 是 null，等你自己的某个调用结束后再试。
- `cost_cap_exceeded`：账户今天已经扣的钱，加上这次调用最多可能花的钱，会超过每日消费额度。
- `uncharged_cost_limit`：账户今天收到的 `not_found` 次数已经到了档位上限。

这两项每日额度都在 UTC 时间 00:00 重置，它们的 `retry_after_seconds` 是到那一刻的倒计时，可能长达好几个小时，所以不要在循环里干等。以上几种都是 `429`，并且都是 `charged: false`。完整列表见[错误码页](/zh/docs/errors/)。

## 退避重试

只对 `rate_limited` 重试。有 `retry_after_seconds` 就按它等；它是 null 时用指数退避；再加一点随机抖动，免得多个并发的 worker 同时重试、再撞一次限流。每次重试都用同一个 `Idempotency-Key`，这样重试永远不会重复扣费：

```python
import os
import random
import time
import uuid
import requests

URL = "https://api.okdata.online/v1/xiaohongshu/notes/search"
HEADERS = {"Authorization": f"Bearer {os.environ['OKDATA_API_KEY']}"}

def search(query, attempts=5):
    headers = {**HEADERS, "Idempotency-Key": str(uuid.uuid4())}
    for attempt in range(attempts):
        body = requests.get(URL, headers=headers, params={"query": query}, timeout=60).json()
        if body["code"] != "rate_limited":
            return body
        wait = body["retry_after_seconds"] or min(2 ** attempt, 30)
        time.sleep(wait + random.uniform(0, 0.5))
    raise RuntimeError("重试多次仍被限流：请放慢速度，或申请更高档位")

print(search("防晒")["meta"]["billing"])
```

如果调用量长期稳定，主动控速比被拒后重试更省事：在标准档，每秒 10 个请求、同时最多 20 个在跑，就不会碰到每分钟上限和并发上限。

## MCP 和 HTTP 共用额度

`https://api.okdata.online/mcp` 上的 MCP 服务用的是同一把 Key，所以它的 `call` 工具和你的 HTTP 调用共用每分钟的计数和同时进行的调用数；带 Key 调 `account` 时也会消耗计数。`find` 和 `describe` 不需要 Key，不计入。也就是说，同一个账户下的智能体和脚本共用一份额度：智能体调用多了，脚本就可能被限流，反过来也一样。

## 申请更高的限额

pro 档位，或者按你的业务量调整的限额，都由我们手动设置。请写信到 hello@okdata.online，附上账户 ID（在 `GET https://api.okdata.online/v1/account` 的返回里）、你要调用的接口，以及预计的峰值速率。Key 和账户是什么关系，见[认证](/zh/docs/authentication/)。

更新于 2026-11-12
