频率限制:档位、响应头和退避重试
okdata 按账户限流:各档位每分钟请求数、同时进行的调用数和每日额度,X-RateLimit 响应头,rate_limited 错误和 retry_after_seconds,以及退避重试的代码。
限额按账户算,不按 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 的错误里 |
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,在被拒绝之前主动放慢速度。
被限流时的返回
{
"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。完整列表见错误码页。
退避重试
只对 rate_limited 重试。有 retry_after_seconds 就按它等;它是 null 时用指数退避;再加一点随机抖动,免得多个并发的 worker 同时重试、再撞一次限流。每次重试都用同一个 Idempotency-Key,这样重试永远不会重复扣费:
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 和账户是什么关系,见认证。
更新于