错误与限制

Anysite API 可能返回的每一种响应、每种状态的含义、计费规则、超时、分页和速率限制。

目标:正确处理 API 可能返回的每一种响应,并清楚哪些调用会消耗积分。

成功的响应

成功的数据调用响应体始终是 JSON 数组,即使端点返回的是单个实体 —— linkedin/user 返回的是包含 一个元素的列表。没有匹配结果的搜索是正常的 200,响应体为 []

应从 x-result-count 响应头读取结果数量,而不是数组长度:如果 x-result-count 较大而响应体为空, 说明响应被截断了,而不是没有结果。

一次调用是如何被处理的

检查按以下顺序执行;第一个未通过的检查会返回其错误,且不计费:

  1. 身份验证请求头存在且只有一个 → 否则返回 422
  2. 密钥有效、套餐未到期、密钥允许用于 REST API → 否则返回 401 / 403
  3. 端点在你的套餐中可用,且参数不超过套餐允许的最大值 → 否则返回 404 / 529 / 403 / 400
  4. 余额中有足够的积分 → 否则返回 401
  5. 速率限制和用量窗口 → 否则返回 429
  6. 请求在端点上执行;其响应会返回给你,并按 What is charged 中的规则计费。

调用执行前返回的状态

以下状态来自 Anysite 的计费层,在到达端点之前返回。这些响应均不计费,响应体的结构是 {"detail": ...}

{"detail": "Token expired"}

422 返回的是字段错误列表,429 返回一个对象,并附带一个值相同(单位:秒)的 X-Retry-After 响应头:

{"detail": {"message": "Rate limit exceeded: ...", "retry_after": 12}}
状态码 detail 该怎么做
422 缺少必需的请求头 发送 access-token 请求头。
422 Body should be a valid dict object 请求体应为 JSON 对象,而不是数组或标量值。
401 Invalid token 从「订阅与 API」页面重新复制密钥。参见身份验证
401 Token does not exist 密钥已被删除;请使用另一个密钥。
401 Token expired 套餐已到期;请在「订阅与 API」页面续订。
401 Points limit exhausted, required at least N points 购买更多积分或升级套餐。参见套餐与积分
403 This token is restricted to MCP usage only and cannot be used for direct API access 改用 MCP 服务器,或选择一个包含 REST API 的套餐。
403 This endpoint is disabled for your plan 选择一个包含此端点的套餐。
400 Parameter 'count' exceeds the maximum allowed for your plan: N count 降到 N 或更低,或分页获取结果。
404 Endpoint was removed 该端点已不存在;请在 API 参考中查找替代端点。
529 This endpoint is temporarily unavailable while we work on a fix. ... 该端点已被我们临时关闭。重试无济于事;如果你依赖它,请从「支持」页面提交工单。
429 object, Rate limit exceeded: scope=..., limit=N requests <window>. ... 等待 retry_after 秒。参见 Rate limits
429 object, You've reached your <window> usage limit. ... 等待窗口释放额度,或升级套餐。参见 Usage windows

429 一定来自 Anysite 的速率限制器 —— 端点背后的数据源本身永远不会产生这个状态码。

Statuses from the endpoint

通过检查之后,端点自身的状态码和响应体会原样返回给你。端点的错误响应体仍然是空的 JSON 数组 [];原因在 x-error 响应头中,该响应头只有在状态码为 400 或更高时才会出现:

HTTP/1.1 412
x-error: Failed to fetch URL. Website is not accessible
x-result-count: 0

[]

验证错误是例外:格式错误的请求体会被 422 拒绝,并返回一个指明具体字段的 detail 对象。

状态码 含义
200 成功。响应体是一个数组,可能为空。
209 查找了但没有结果,且本次查找没有产生费用 —— 一次免费的未命中。仅出现在 What is charged 中列出的端点上。
400 客户端在结果准备好之前断开了连接,或者 LinkedIn URN 格式有误,且验证未能捕获这种错误。
408 调用超时。参见 Timeouts。响应体中仍可能包含截止前已收集到的数据行。
412 API 的「未找到」:实体不存在、资料是私密的或被限制访问,或者(在 webparser/* 上)目标主机不可达。
415 webparser/* 指向的是 PDF、Office 文档、图片、压缩包或其他非页面文件。
422 模式验证失败(detail 中指明字段)、请求体无效,或响应过大而无法返回。
500 数据源无法访问,或对它的重试已耗尽。
529 该数据源目前的抓取能力全部繁忙。

API 参考中每个端点只列出它不那么显而易见的状态码 —— 例如 linkedin/user 会返回 412,而不是你可能预期的 404。列表中没出现的状态码并非不可能出现;上面的含义始终适用。

被限制访问的 LinkedIn 资料,只要仍处于限制状态就会一直返回 412 —— 用同一个别名重试不会改变结果。

What is charged

简而言之:

Endpoint response Charged
低于 400 的任意状态码(209 除外) 计费
209 不计费
408412 计费
其他任意 4xx / 5xx 仅当响应报告了至少一条结果时计费
上述检查产生的任何错误,或端点不可达时返回的 500「Internal server error」 不计费

调用的价格取决于端点和你的套餐,并且在许多端点上会随结果数量增长:每开始一个结果区块就按基础价格 计费一次,因此按每 10 条结果计价的端点,返回 11 条时收费两次,返回 21 条时收费三次。这两个数字都 按端点发布在 API 参考中:x-price 是基础价格,x-increase-every 是区块大小(没有该 字段表示每次调用一口价)。只请求你真正需要的 count —— count 越大,可能越贵。每次调用的精确 金额在 x-credits-charged 响应头中 —— 0 表示本次调用免费 —— 以及「订阅与 API」页面的请求日志里。

积分优先从套餐积分中扣除,然后才扣除已购买积分。只要余额能覆盖基础价格,调用就会被允许;如果 最终价格更高(例如返回结果更多),余额可能变为负数,负的部分会从你之后追加的积分中扣除。

值得关注的响应头

响应头 含义
x-credits-charged 本次调用花费的积分。0 表示免费。
x-token-points 余额中剩余的积分。
x-result-count 响应中的结果行数。如果比你收到的数组长度大 → 说明响应被截断了。
x-error 调用失败的原因。仅当状态码为 400 或更高时出现。
x-warning 请求虽然成功,但存在一些问题 —— 参见 Ignored parameters
x-execution-time 端点处理耗时,单位为秒。
x-request-id 本次调用的 id。在支持工单中引用它。你也可以自己指定它,但必须是合法的 UUID,否则请求会被 422 拒绝。
X-Total-Available-Results 在数据源提供可用总数的端点上,总共可获取的结果数量。

Timeouts

请求体中的 timeout 字段默认值为 300 秒,可接受 20-1500 之间的值。

它是停滞预算,而不是总时长:衡量的是调用在多长时间内没有产生新结果。每收到一条新数据, 截止时间就会向后推移,直到 1500 秒的硬上限为止。因此,一次持续有进展的调用完全可能比它的 timeout 运行得更久,而一旦停滞的调用在 timeout 时间内没有进展,就会被 408 中断。

由于这个上限的存在,对于可能长时间运行的端点,请把你的 HTTP 客户端自身的超时设置为约 1600 秒。如果客户端在 30 秒或 60 秒就放弃,会中断那些其实仍在正常工作的调用。

curl --max-time 1600 -X POST "https://api.anysite.io/api/linkedin/search/users" \
  -H "access-token: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"keywords": "cto", "count": 100, "timeout": 600}'

ACTION FOR THE HUMAN: copy your API key at https://app.anysite.io/billing — an agent cannot obtain it.

Ignored parameters

请求体中无法识别的字段会被忽略,而不是拒绝。 因此拼错的过滤条件的表现和没有过滤条件完全一样: 你会得到 200 和未过滤的结果,并为此付费。每个被忽略的字段都会列在 x-warning 响应头中(在 MCP 结果中则是 warnings 字段),所以当某个过滤条件看起来没有生效时,检查一下这个响应头。

在每个可能返回多条结果的端点上,count 都是必填的,而且它是上限而不是承诺:请求的数量超过实际 存在的数量时,会返回 200 和更少的结果行。

分页

REST API 上没有游标可以跟随。每次调用时把 offset 增加 count(或者对接受 page 参数的端点, 递增 page)。不推进就重复同样的调用会返回相同的结果 —— 这通常就是「API 一直给我重复数据」的原因。

重试

Anysite 与数据源之间的传输失败已经替你自动重试过了 —— 最多重试三次,退避间隔分别为 1 秒、5 秒 和 10 秒 —— 你看到错误之前这些重试已经发生。这里没有幂等键:如果状态属于计费状态,你自己发起的重试 会再次计费。

端点可能被关闭

某个端点即使已经被关闭,仍可能出现在 API 参考中。列出的端点返回 404 Endpoint was removed529,就是这种情况,而不是你这边的问题。如果你依赖它,请从「支持」页面 提交工单。

Rate limits

套餐以及部分端点会在滚动窗口(10 秒、1 分钟、1 小时、1 天或 30 天)内限制请求数量。任何通过了之前 检查的请求都会计入这些限制,无论最终是否计费 —— 包括免费的 209。达到限制后,API 会返回 429retry_after 等于窗口中最早那次请求过期所需的秒数。

Usage windows

部分套餐(包括 MCP 套餐)还会在两个滚动窗口内限制消耗的积分:5 小时每周。部分套餐还会 加上单独的 LinkedIn 5 小时和每周窗口,只统计 LinkedIn 端点。用量是窗口内被计费积分的总和,所以随着 较早的调用移出窗口,额度会逐渐释放。

窗口用满后,API 会返回 429retry_after 等于整个窗口的长度 —— 这是最长的等待时间,实际释放 可能更早。

对于 MCP 套餐,每个窗口当前的用量百分比会显示在「MCP 集成」页面上。

ACTION FOR THE HUMAN: open https://app.anysite.io/mcp (查看 MCP 用量).