Developer Platform: MaxAEO 开发者平台:用 API Key 调用开放 API 与 MCP,抓取各 AI 平台的回答与引用来源
# 开发者平台概览
> MaxAEO 开发者平台提供开放 API 与 MCP 服务器:用一个 API Key 向豆包、DeepSeek、Kimi 等主流 AI 平台提问,拿到回答原文、引用来源与分享链接,按成功次数计费。
MaxAEO 开发者平台把 MaxAEO 抓取 AI 平台回答的能力开放给你的程序:你提交一个问题和一个目标平台,我们去该平台真实提问,把 AI 的**回答原文、引用来源、分享链接**以及平台提供的执行过程、视频/图片卡片原样交还给你。 它适合这些场景: * **自建 AI 搜索监控**:把品牌相关问题定期发给各 AI 平台,在自己的数据仓库里统计品牌是否被提及、被哪些网页引用。 * **内容与 GEO 效果验证**:发布内容后,直接看 AI 回答里有没有引用你的页面(`cited` 字段)。 * **研究与分析**:批量收集不同平台对同一问题的回答,比较观点、信源和回答结构。 * **给 AI Agent 加一个「问问别的 AI」的工具**:通过 MCP,让 Claude Code、Cursor 等客户端直接调用。 ## 两种接入方式 [Section titled “两种接入方式”](#两种接入方式) | | 开放 API | MCP 服务器 | | ----- | --------------------------------- | ------------------------ | | 适合谁 | 你的后端服务、脚本、数据管道 | 支持 MCP 的 AI 客户端与 Agent | | 协议 | HTTPS + JSON,统一 `POST` | MCP Streamable HTTP(无状态) | | 能力 | 查询平台、提交任务、查询任务、任务列表 | 同样四项,包装成 4 个工具 | | 鉴权 | `Authorization: Bearer ` | 相同 | | 计费与限流 | 按成功任务扣点数 | 与开放 API 完全一致 | 两种方式共用同一个 API Key、同一份点数余额和同一套限流。 ## 用 AI 编码助手接入 [Section titled “用 AI 编码助手接入”](#用-ai-编码助手接入) 用 Claude Code、Cursor 等 AI 编码助手写接入代码时,把 `maxaeo-api.md` 交给它。这是一份写给 AI 看的接入指南:基础信息、4 个接口与任务对象的字段、错误码、最容易写错的规则,以及能直接运行的 Python / Node.js 参考实现。文件里不含、也不需要你的 API Key。 文件开头是 Agent Skill 格式的 `name` / `description` 元数据,正文是普通 Markdown,所以既能作为 Skill 安装,也能当普通文档使用。 [下载 maxaeo-api.md](maxaeo-api.md) * Claude Code 作为 Skill 安装,二选一:
```bash
# 只在当前项目使用(可以随仓库共享给团队)
mkdir -p .claude/skills/maxaeo-api && curl -fsSL https://maxaeo.cn/docs/developers/maxaeo-api.md -o .claude/skills/maxaeo-api/SKILL.md
# 在所有项目中使用
mkdir -p ~/.claude/skills/maxaeo-api && curl -fsSL https://maxaeo.cn/docs/developers/maxaeo-api.md -o ~/.claude/skills/maxaeo-api/SKILL.md
```
之后让 Claude Code 调用 MaxAEO 开放 API 或配置 MCP 时,它会按 `description` 自动加载这份 Skill。 * 其他 AI 编码工具 保存到项目里:
```bash
mkdir -p docs && curl -fsSL https://maxaeo.cn/docs/developers/maxaeo-api.md -o docs/maxaeo-api.md
```
再在 `AGENTS.md`(或所用工具的规则文件)里加一句:
```markdown
- 调用 MaxAEO 开放 API 或 MCP 前,先阅读 docs/maxaeo-api.md,并遵守其中「必须遵守的规则」。
```
支持 Agent Skills 的工具,也可以把它放到该工具 skills 目录下的 `maxaeo-api/SKILL.md`。 * 网页版 AI 能联网读取网页的 AI,直接把链接写进提问: > 阅读 ,然后帮我用 Python 写一个脚本:把 10 个问题分别发给豆包和 DeepSeek,记录回答是否引用了 example.com。 不能联网的,下载文件后作为附件上传。 需要更多细节时,开发者平台的全部页面也合并成了一个文本文件 [developer-platform.txt](../_llms-txt/developer-platform.txt),可以整份交给 AI。 ## 工作方式:异步任务 [Section titled “工作方式:异步任务”](#工作方式异步任务) AI 平台生成一条回答通常要几十秒到两分钟,排队时间另算,所以接口是**异步**的: 1. **提交任务**:调用[提交任务](api/submit-task/),传入平台和问题,立即拿到 `task_id`,状态为 `queued`。提交时会按该平台单价**预占**点数。 2. **轮询结果**:每隔 15 秒左右调用[查询任务](api/get-task/),直到状态变为 `succeeded`、`failed` 或 `canceled`。 3. **读取结果**:成功时从 `answer` 和 `raw_result` 读取回答正文与引用来源,按提交时的单价**扣除**点数;失败或取消**不扣费**,预占的点数会退回。 完整的状态流转见[任务生命周期](guides/task-lifecycle/)。 ## 基础信息 [Section titled “基础信息”](#基础信息) | 项目 | 值 | | ------------ | ----------------------------------------------------------------------------- | | API Base URL | `https://maxaeo.cn/geoapi/geodata/developer` | | MCP 地址 | `https://maxaeo.cn/geoapi/geodata/developer/mcp` | | 鉴权 | 请求头 `Authorization: Bearer gdev_…`,详见[认证与 API Key](authentication/) | | 请求格式 | 所有接口均为 `POST`,请求体为 JSON 对象 | | 响应格式 | `{"ret": 1, "data": {"ent": …}}`,`ret` 不为 1 即失败,详见 [API 概述](api/) | | 开发者控制台 | [maxaeo.cn/developers](https://maxaeo.cn/developers/):创建 API Key、在线调试、查看日志与用量 | 开发者平台与 MaxAEO 产品使用**同一个账号**,用你登录 MaxAEO 的方式登录控制台即可。 ## 开发者控制台页面一览 [Section titled “开发者控制台页面一览”](#开发者控制台页面一览) | 控制台页面 | 用途 | 文档 | | ------- | ------------------------- | ------------------------------- | | 概览 | 快速开始进度、点数余额、近 7 天请求、平台状态 | 本页 | | 接口与平台 | 支持的平台、各平台状态、近 24 小时成功率与耗时 | [平台、优先级与国家](guides/platforms/) | | 在线调试 | 不写代码直接发请求,查看返回结构并复制调用代码 | [在线调试](console/playground/) | | API Key | 创建、停用、重置、删除 API Key | [管理 API Key](console/api-keys/) | | 调用日志 | 每次请求的明细、状态、错误与响应 | [调用日志与用量](console/logs-usage/) | | 用量统计 | 点数余额、消耗、成功率、额度与限制 | [调用日志与用量](console/logs-usage/) | | 计费说明 | 各平台两档单价与计费规则 | [计费与点数](guides/billing/) | API Key 只在服务端使用 API Key 代表你的账户并直接消耗点数。不要把它写进网页前端、小程序、App 安装包或公开的代码仓库,应在服务端从环境变量读取。 ## 从这里开始 [Section titled “从这里开始”](#从这里开始) [快速开始](quickstart/)5 分钟内创建 API Key,发出第一个请求并拿到 AI 的回答。 [认证与 API Key](authentication/)请求头格式、Key 的权限范围与安全建议。 [API 参考](api/)四个开放接口的参数、响应与错误码。 [接入 MCP](mcp/)在 Claude Code、Cursor、VS Code 等客户端中直接调用。 [解析回答结果](guides/results/)读懂回答正文、引用来源、执行过程和多媒体卡片。 [计费与点数](guides/billing/)预占、扣点与退回规则,以及如何估算成本。
# API 概述
> MaxAEO 开放 API 的通用约定:Base URL、接口列表、请求格式与请求头、统一的 ret/data.ent 响应结构、msg 双语错误提示、字段命名与数据类型、未知字段与请求体大小限制。
开放 API 是一组基于 HTTPS 的 JSON 接口,用 API Key 认证。本页是所有接口共用的约定;各接口的参数与返回见下方的接口页。 ## Base URL [Section titled “Base URL”](#base-url)
```text
https://maxaeo.cn/geoapi/geodata/developer
```
所有端点都在这个地址下。代码里通常把它存成 `BASE_URL`,再拼上各接口的路径(如 `/task/submit`)。 ## 接口列表 [Section titled “接口列表”](#接口列表) | 接口 | 完整端点 | 说明 | | ------------------------- | --------------------------------------------------------------- | ----------------------------------- | | [查询平台列表](list-platforms/) | `POST https://maxaeo.cn/geoapi/geodata/developer/platforms/get` | 已开放的平台、单价、状态与近 24 小时统计 | | [提交任务](submit-task/) | `POST https://maxaeo.cn/geoapi/geodata/developer/task/submit` | 向指定平台提问,返回 `task_id` | | [查询任务](get-task/) | `POST https://maxaeo.cn/geoapi/geodata/developer/task/get` | 按 `task_id` 读取任务状态与结果 | | [任务列表](list-tasks/) | `POST https://maxaeo.cn/geoapi/geodata/developer/task/key/list` | 列出当前 Key 提交的任务,用于找回 `task_id` | | [MCP 服务器](../mcp/) | `POST https://maxaeo.cn/geoapi/geodata/developer/mcp` | MCP Streamable HTTP 入口,把上面四个接口包装成工具 | 所有接口返回或操作的任务结构见[任务对象](task-object/)。同样的四项能力也以 MCP 工具的形式提供,见[接入 MCP](../mcp/)。 ## 对接流程 [Section titled “对接流程”](#对接流程) 一次完整的对接只用到这四个接口,按下面的顺序串起来: | 步骤 | 调用 | 要做的事 | | ------- | --------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | | 1. 选平台 | `POST https://maxaeo.cn/geoapi/geodata/developer/platforms/get` | 取 `platform` 标识与单价,跳过 `platform_status` 为 `maintenance` 的平台;可以缓存几分钟,不要写死在代码里 | | 2. 提交 | `POST https://maxaeo.cn/geoapi/geodata/developer/task/submit` | 传 `platform`、`query`(可选 `priority`、`thinking`、`country`);**拿到 `task_id` 立即保存** | | 3. 轮询 | `POST https://maxaeo.cn/geoapi/geodata/developer/task/get` | 每 15 秒左右查一次未结束的任务,直到 `status` 为 `succeeded`、`failed` 或 `canceled` | | 4. 取结果 | 同上 | `succeeded`:读 `answer` 和 `raw_result.references`;`failed` / `canceled`:按 `error_code` 处理,不扣费 | | 5. 异常兜底 | `POST https://maxaeo.cn/geoapi/geodata/developer/task/key/list` | 提交超时、断连或返回 `-1` 时,按问题文本和时间找回 `task_id`,确认没有创建再重新提交 | 判断成败分两层:响应体的 `ret` 不为 `1` 表示这次调用没有被受理(不会创建任务);任务是否成功看 `status`,失败原因看 `error_code`。见[错误处理](../guides/errors/)。可运行的完整代码见[快速开始](../quickstart/#%E5%AE%8C%E6%95%B4%E7%A4%BA%E4%BE%8B)。 ## 请求 [Section titled “请求”](#请求) * **方法**:所有接口都用 `POST`。 * **请求头**: * `Authorization: Bearer `(必填,见[认证与 API Key](../authentication/)) * `Content-Type: application/json`(建议) * **请求体**:一个 JSON 对象,不超过 64 KiB。没有参数的接口也要传 `{}`,空请求体会返回 `1001`。 * **只接受已定义的字段**:请求体中出现接口未定义的字段(包括拼写错误,如把 `task_id` 写成 `taskId`),整个请求返回 `1001`「请求包含不支持的字段」,不会被静默忽略。 * **编码**:UTF-8。
```bash
curl -X POST "https://maxaeo.cn/geoapi/geodata/developer/task/get" \
-H "Authorization: Bearer $MAXAEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"task_id": "task_3f6c1d2e-8a4b-4c1f-9e2d-7b5a0c9d1e23"}'
```
## 响应 [Section titled “响应”](#响应) 所有接口的响应体结构相同。**成功**时 `ret` 为 `1`,业务数据在 `data.ent`:
```json
{
"ret": 1,
"data": {
"ent": { "task_id": "task_3f6c1d2e-8a4b-4c1f-9e2d-7b5a0c9d1e23", "status": "queued" }
}
}
```
**失败**时 `ret` 为错误码,`msg` 是一个 JSON **字符串**,包含中英文两种提示:
```json
{
"ret": 1001,
"msg": "{\"zh\":\"参数错误:task_id 不能为空且不超过 64 个字符\",\"en\":\"Invalid parameters: task_id is required and must be at most 64 characters\"}"
}
```
要点: * **用 `ret` 判断成败。** 业务成功和业务失败的 HTTP 状态码都是 `200`。非 200 只在两种情况出现:请求本身写错(方法不是 `POST` 返回 `405`,路径写错返回 `404`),或请求在网络链路上出错(如代理超时)。处理方式见[错误处理](../guides/errors/#http-%E7%8A%B6%E6%80%81%E7%A0%81%E4%B8%8D%E6%98%AF-200)。 * **响应体始终是 JSON**,但响应头的 `Content-Type` 目前可能是 `text/plain`。请直接把响应体按 JSON 解析,不要依赖 `Content-Type` 判断。 * 所有响应都带 `Cache-Control: no-store`,请不要在客户端或代理层缓存。 * 全部错误码见[错误处理](../guides/errors/)。 ## 字段与数据类型 [Section titled “字段与数据类型”](#字段与数据类型) | 约定 | 说明 | | ---- | ------------------------------------------------------------------------------------------------ | | 字段命名 | 请求与响应字段使用下划线风格,如 `task_id`、`created_at`。例外:`raw_result` 内部使用小驼峰,见[任务对象](task-object/#raw_result) | | 时间戳 | Unix 时间戳,单位**秒**,`0` 表示尚未发生(如未结束任务的 `finished_at`) | | 日期 | `monitor_date` 为 `YYYY-MM-DD`,按北京时间(UTC+8) | | 零值 | 外层字段即使为空也会返回(`""`、`0`、`false`);`raw_result` 内部的零值字段会被省略 | | 空数组 | 列表为空时可能返回 `[]` 或 `null`,请统一按空数组处理 | | 新字段 | 我们可能在响应中新增字段,请让解析代码忽略不认识的字段 | ## 认证与安全 [Section titled “认证与安全”](#认证与安全) * API Key 只放在 `Authorization` 请求头中,不接受放在 URL 或请求体里。 * 每个请求都会重新校验 Key 的状态;Key 无效统一返回 `1030`。 * 只从你的服务端调用。不要在浏览器、小程序或 App 中直接调用开放 API,否则 Key 会暴露给最终用户。 ## 接口页 [Section titled “接口页”](#接口页) [查询平台列表](list-platforms/)POST https\://maxaeo.cn/geoapi/geodata/developer/platforms/get [提交任务](submit-task/)POST https\://maxaeo.cn/geoapi/geodata/developer/task/submit [查询任务](get-task/)POST https\://maxaeo.cn/geoapi/geodata/developer/task/get [任务列表](list-tasks/)POST https\://maxaeo.cn/geoapi/geodata/developer/task/key/list [任务对象](task-object/)任务与 raw\_result 的完整字段定义
# 查询任务
> POST https://maxaeo.cn/geoapi/geodata/developer/task/get —— 按 task_id 读取任务的最新状态与结果,成功时返回回答正文、引用来源、分享链接和扣除的点数。用于轮询异步任务,不消耗点数。
```text
POST https://maxaeo.cn/geoapi/geodata/developer/task/get
```
按 `task_id` 读取任务的最新状态;任务成功后,响应里包含完整结果。**不消耗点数。** ## 请求参数 [Section titled “请求参数”](#请求参数) | 参数 | 类型 | 必填 | 说明 | | --------- | ------ | -- | ---------------------------------------------------------------- | | `task_id` | string | 是 | [提交任务](../submit-task/)或[任务列表](../list-tasks/)返回的任务 ID,最长 64 个字符 | **能查询哪些任务**:同一用户在个人账户下提交的所有任务,不论用的是哪个 API Key,还是在控制台在线调试提交的。提交它的 Key 被停用或删除后,可以用其他有效 Key 查询。 ## 请求示例 [Section titled “请求示例”](#请求示例) * cURL
```bash
curl -X POST "https://maxaeo.cn/geoapi/geodata/developer/task/get" \
-H "Authorization: Bearer $MAXAEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"task_id": "task_3f6c1d2e-8a4b-4c1f-9e2d-7b5a0c9d1e23"}'
```
* Python
```python
import os
import time
import requests
URL = "https://maxaeo.cn/geoapi/geodata/developer/task/get"
HEADERS = {"Authorization": f"Bearer {os.environ['MAXAEO_API_KEY']}"}
def wait_task(task_id, interval=15):
while True:
data = requests.post(URL, headers=HEADERS, json={"task_id": task_id}, timeout=30).json()
if data["ret"] != 1:
raise RuntimeError(f"ret={data['ret']}: {data['msg']}")
task = data["data"]["ent"]
if task["status"] in ("succeeded", "failed", "canceled"):
return task
time.sleep(interval)
task = wait_task("task_3f6c1d2e-8a4b-4c1f-9e2d-7b5a0c9d1e23")
print(task["status"], task["answer"][:200])
```
* Node.js
```js
const TASK_GET_URL = "https://maxaeo.cn/geoapi/geodata/developer/task/get";
const headers = {
Authorization: `Bearer ${process.env.MAXAEO_API_KEY}`,
"Content-Type": "application/json",
};
async function waitTask(taskId, intervalMs = 15_000) {
for (;;) {
const resp = await fetch(TASK_GET_URL, { method: "POST", headers, body: JSON.stringify({ task_id: taskId }) });
const data = await resp.json();
if (data.ret !== 1) throw new Error(`ret=${data.ret}: ${data.msg}`);
const task = data.data.ent;
if (["succeeded", "failed", "canceled"].includes(task.status)) return task;
await new Promise((resolve) => setTimeout(resolve, intervalMs));
}
}
const task = await waitTask("task_3f6c1d2e-8a4b-4c1f-9e2d-7b5a0c9d1e23");
console.log(task.status, task.answer.slice(0, 200));
```
## 响应 [Section titled “响应”](#响应) `data.ent` 是[任务对象](../task-object/)。按 `status` 读取: * **未结束**(`queued` / `dispatching` / `pending` / `running`):结果字段为空,`credits` 为预占点数,继续轮询。 * **`succeeded`**:`answer` 是回答正文,`raw_result` 是结构化结果(引用来源、执行过程、卡片等),`credits` 为扣除的点数。 * **`failed` / `canceled`**:原因在 `error_code` 与 `error_message`,`credits` 为 `0`。 成功任务的响应示例(`answer`、`result_json` 等长文本已截断):
```json
{
"ret": 1,
"data": {
"ent": {
"thinking": false,
"task_id": "task_3f6c1d2e-8a4b-4c1f-9e2d-7b5a0c9d1e23",
"platform": "doubao",
"query": "适合程序员的机械键盘推荐",
"status": "succeeded",
"answer": "给程序员选机械键盘,可以重点看手感、配列和长时间打字的舒适度……",
"result_json": "{\"taskId\":\"task_3f6c1d2e-8a4b-4c1f-9e2d-7b5a0c9d1e23\",\"platform\":\"doubao\",…}",
"share_link": "https://www.doubao.com/thread/…",
"error_code": "",
"error_message": "",
"started_at": 1793018431,
"finished_at": 1793018497,
"created_at": 1793018425,
"updated_at": 1793018503,
"monitor_date": "2026-10-26",
"priority": 2,
"country": "",
"credits": 3,
"raw_result": {
"taskId": "task_3f6c1d2e-8a4b-4c1f-9e2d-7b5a0c9d1e23",
"platform": "doubao",
"monitorDate": "2026-10-26",
"query": "适合程序员的机械键盘推荐",
"success": true,
"rawContent": "给程序员选机械键盘,可以重点看手感、配列和长时间打字的舒适度……",
"references": [
{
"rank": 1,
"title": "2026 年机械键盘选购指南",
"url": "https://www.example.com/keyboard-guide",
"snippet": "从轴体、配列到键帽材质,一文讲清机械键盘怎么选……",
"source": "示例科技",
"domain": "www.example.com",
"cited": true
},
{
"rank": 2,
"title": "程序员常用键盘配列对比",
"url": "https://blog.example.org/layouts",
"domain": "blog.example.org",
"cited": false
}
],
"shareLink": "https://www.doubao.com/thread/…",
"elapsedMs": "48213",
"completedAt": "2026-10-26T12:41:37.512Z",
"priority": 2,
"agentSteps": [
{ "type": "search", "queries": ["程序员 机械键盘 推荐 2026"] }
],
"conversationId": "…",
"messageId": "…"
}
}
}
}
```
平台执行失败的任务示例:
```json
{
"ret": 1,
"data": {
"ent": {
"thinking": false,
"task_id": "task_9b2e4f60-1c3d-4e8a-b7f5-2d6c8a0e4b19",
"platform": "deepseek",
"query": "跑步新手应该怎么选第一双跑鞋?",
"status": "failed",
"answer": "",
"result_json": "{\"taskId\":\"task_9b2e4f60-1c3d-4e8a-b7f5-2d6c8a0e4b19\",\"error\":\"{\\\"zh\\\":\\\"平台抓取失败,本次不扣费,请稍后重试或更换平台\\\",\\\"en\\\":\\\"The platform crawl failed. No credits were charged. Please try again later or choose another platform.\\\"}\",…}",
"share_link": "",
"error_code": "crawl_failed",
"error_message": "{\"zh\":\"平台抓取失败,本次不扣费,请稍后重试或更换平台\",\"en\":\"The platform crawl failed. No credits were charged. Please try again later or choose another platform.\"}",
"started_at": 0,
"finished_at": 1793007356,
"created_at": 1793006882,
"updated_at": 1793007363,
"monitor_date": "2026-10-26",
"priority": 2,
"country": "",
"credits": 0,
"raw_result": {
"taskId": "task_9b2e4f60-1c3d-4e8a-b7f5-2d6c8a0e4b19",
"platform": "deepseek",
"monitorDate": "2026-10-26",
"query": "跑步新手应该怎么选第一双跑鞋?",
"error": "{\"zh\":\"平台抓取失败,本次不扣费,请稍后重试或更换平台\",\"en\":\"The platform crawl failed. No credits were charged. Please try again later or choose another platform.\"}",
"elapsedMs": "2",
"completedAt": "2026-10-26T09:35:56.853Z",
"priority": 2
}
}
}
}
```
`error_message` 和 `raw_result.error` 是 `{"zh","en"}` JSON 字符串,解析后按语言展示;程序判断请用 `error_code`,不要按文案。 外层的 `thinking` 是提交时请求的思考模式。上面两个任务都没有开启思考,所以 `raw_result` 里没有 `thinking`;请求开启且实际生效时,`raw_result` 里会有 `"thinking": true`,见[思考模式](../../guides/platforms/#%E6%80%9D%E8%80%83%E6%A8%A1%E5%BC%8Fthinking)。 注意 `started_at` 可能为 `0`:如果任务直接拿到最终结果、没有观察到执行中的状态,就不会记录开始时间。计算耗时请用 `finished_at - created_at`(含排队)或 `raw_result.elapsedMs`(仅执行)。 ## 轮询建议 [Section titled “轮询建议”](#轮询建议) * 每 15 秒左右查询一次即可,查得更勤通常拿到的是同一个状态。见[任务生命周期](../../guides/task-lifecycle/#%E8%BD%AE%E8%AF%A2%E5%A4%9A%E4%B9%85%E6%9F%A5%E4%B8%80%E6%AC%A1)。 * 任务没有服务端截止时间,排队可能较久;超过你自己的业务超时后可以先放下,之后再用 `task_id` 取结果。 * 判断是否结束只看 `status`,不要因为 `error_code` 非空就停止轮询。 ## 错误 [Section titled “错误”](#错误) | `ret` | 原因 | | ------ | ---------------------------------- | | `1001` | `task_id` 为空或超过 64 个字符,或请求体含未定义的字段 | | `1030` | API Key 无效 | | `1031` | 任务不存在,或不属于当前用户 | | `1003` | 账户权限异常(少见),请联系我们 | | `-1` | 服务暂时不可用,可以直接重试 |
# 查询平台列表
> POST https://maxaeo.cn/geoapi/geodata/developer/platforms/get —— 返回已开放的 AI 平台标识(含维护中的平台),以及每个平台的区域、状态、P1/P2 两档单价和近 24 小时成功率、耗时统计。不消耗点数。
```text
POST https://maxaeo.cn/geoapi/geodata/developer/platforms/get
```
返回已开放的 AI 平台(含维护中的平台,见 `platform_status`)。提交任务前用它获取平台标识和单价,也可以用它做 API Key 的连通性检查。**不消耗点数。** ## 请求 [Section titled “请求”](#请求) 无参数,请求体传空对象 `{}`。 * cURL
```bash
curl -X POST "https://maxaeo.cn/geoapi/geodata/developer/platforms/get" \
-H "Authorization: Bearer $MAXAEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
```
* Python
```python
import os
import requests
resp = requests.post(
"https://maxaeo.cn/geoapi/geodata/developer/platforms/get",
headers={"Authorization": f"Bearer {os.environ['MAXAEO_API_KEY']}"},
json={},
timeout=30,
)
data = resp.json()
if data["ret"] != 1:
raise RuntimeError(data["msg"])
for item in data["data"]["ent"]["items"] or []:
print(item["platform"], item["platform_status"], item["p1_credits"], item["p2_credits"])
```
* Node.js
```js
const resp = await fetch("https://maxaeo.cn/geoapi/geodata/developer/platforms/get", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MAXAEO_API_KEY}`,
"Content-Type": "application/json",
},
body: "{}",
});
const data = await resp.json();
if (data.ret !== 1) throw new Error(data.msg);
for (const item of data.data.ent.items ?? []) {
console.log(item.platform, item.platform_status, item.p1_credits, item.p2_credits);
}
```
## 响应 [Section titled “响应”](#响应) `data.ent` 的字段: | 字段 | 类型 | 说明 | | ----------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------- | | `platforms` | string\[] | 已配置单价的平台标识,与 `items` 顺序一致,即[提交任务](../submit-task/)的 `platform` 可选值;**包含维护中的平台**(提交返回 `1029`),提交前请看 `items[].platform_status` | | `items` | PlatformItem\[] | 每个平台的详细信息,与 `platforms` 顺序一致 | `PlatformItem`: | 字段 | 类型 | 说明 | | ---------------------- | ------- | --------------------------------------------------------------------------------- | | `platform` | string | 平台标识,如 `doubao` | | `region` | string | `domestic`(国内)或 `overseas`(海外) | | `platform_status` | string | `normal` 正常、`degraded` 波动、`maintenance` 维护中(暂停接单,提交返回 `1029`) | | `p1_credits` | integer | P1 优先档每次成功调用的点数 | | `p2_credits` | integer | P2 标准档每次成功调用的点数 | | `has_stats` | boolean | 近 24 小时样本数是否达到统计门槛;为 `false` 时 `success_rate` 与 `p50_duration_seconds` 为 `0`,不应展示 | | `success_rate` | number | 近 24 小时成功率,0–1 | | `p50_duration_seconds` | integer | 近 24 小时成功任务从提交到完成的中位耗时(秒,含排队) | | `sample_count` | integer | 近 24 小时到达终态的任务数(所有调用方,不含 Key 失效、参数被拒、取消等非平台原因) | | `stats_updated_at` | integer | 统计计算时间(Unix 秒),`0` 表示尚未计算 | 状态与统计字段的解读见[平台、优先级与国家](../../guides/platforms/#%E5%B9%B3%E5%8F%B0%E7%8A%B6%E6%80%81)。 ### 响应示例 [Section titled “响应示例”](#响应示例)
```json
{
"ret": 1,
"data": {
"ent": {
"platforms": ["kimi", "doubao", "deepseek"],
"items": [
{
"platform": "kimi",
"region": "domestic",
"platform_status": "normal",
"p1_credits": 40,
"p2_credits": 20,
"has_stats": false,
"success_rate": 0,
"p50_duration_seconds": 0,
"sample_count": 0,
"stats_updated_at": 1793018400
},
{
"platform": "doubao",
"region": "domestic",
"platform_status": "normal",
"p1_credits": 6,
"p2_credits": 3,
"has_stats": true,
"success_rate": 0.9612,
"p50_duration_seconds": 52,
"sample_count": 129,
"stats_updated_at": 1793018400
},
{
"platform": "deepseek",
"region": "domestic",
"platform_status": "degraded",
"p1_credits": 6,
"p2_credits": 3,
"has_stats": true,
"success_rate": 0.8235,
"p50_duration_seconds": 75,
"sample_count": 34,
"stats_updated_at": 1793018400
}
]
}
}
}
```
示例中的单价与统计仅为演示,以实际返回为准。 ## 错误 [Section titled “错误”](#错误) | `ret` | 原因 | | ------ | ------------------------------ | | `1001` | 请求体不是 JSON 对象(例如空请求体)或包含未定义的字段 | | `1030` | API Key 缺失、无效、已停用或已过期 | | `1003` | 账户权限异常(少见),请联系我们 | | `-1` | 服务暂时不可用,稍后重试 | 完整说明见[错误处理](../../guides/errors/)。
# 任务列表
> POST https://maxaeo.cn/geoapi/geodata/developer/task/key/list —— 分页列出当前 API Key 提交的任务(按提交时间倒序),可按时间、平台、状态和关键词筛选。主要用于提交响应丢失时找回 task_id,以及对账。不含回答正文,不消耗点数。
```text
POST https://maxaeo.cn/geoapi/geodata/developer/task/key/list
```
分页列出**当前 API Key** 提交的任务,按提交时间从新到旧排列。列表项不含回答正文,需要结果时再用[查询任务](../get-task/)。**不消耗点数。** 主要用途: * **找回 `task_id`**:提交请求超时或进程崩溃,不确定任务是否已创建时,按问题文本和时间查找,避免重复提交。 * **对账与巡检**:按时间段、状态翻页,统计成功任务的点数,找出失败的任务。 ## 请求参数 [Section titled “请求参数”](#请求参数) 全部可选。 | 参数 | 类型 | 说明 | | ------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `page` | integer | 页码,从 1 开始,默认 `1` | | `page_size` | integer | 每页条数,默认 `20`,最大 `100` | | `start_time` | integer | 提交时间下限(Unix 秒,**含**) | | `end_time` | integer | 提交时间上限(Unix 秒,**不含**),须大于 `start_time` | | `platform` | string | 只看这个平台的任务 | | `status` | string | 只看这个状态的任务:`queued`、`dispatching`、`pending`、`running`、`succeeded`、`failed`、`canceled`。传 `pending` 时同时返回 `queued`、`dispatching`、`pending` 三种排队中的任务(列表项的 `status` 仍是各自的实际状态);其他取值精确匹配 | | `keyword` | string | 以 `task_` 开头时按任务 ID **精确匹配**;否则按「问题包含该文本」匹配。最长 256 个字符 | ## 请求示例 [Section titled “请求示例”](#请求示例) 查找最近一小时内、问题包含「机械键盘」的任务: * cURL
```bash
curl -X POST "https://maxaeo.cn/geoapi/geodata/developer/task/key/list" \
-H "Authorization: Bearer $MAXAEO_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"keyword\": \"机械键盘\", \"start_time\": $(($(date +%s) - 3600)), \"page_size\": 10}"
```
* Python
```python
import os
import time
import requests
resp = requests.post(
"https://maxaeo.cn/geoapi/geodata/developer/task/key/list",
headers={"Authorization": f"Bearer {os.environ['MAXAEO_API_KEY']}"},
json={"keyword": "机械键盘", "start_time": int(time.time()) - 3600, "page_size": 10},
timeout=30,
)
data = resp.json()
if data["ret"] != 1:
raise RuntimeError(f"ret={data['ret']}: {data['msg']}")
for item in data["data"]["ent"]["items"]:
print(item["task_id"], item["status"], item["query"])
```
* Node.js
```js
const resp = await fetch("https://maxaeo.cn/geoapi/geodata/developer/task/key/list", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MAXAEO_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
keyword: "机械键盘",
start_time: Math.floor(Date.now() / 1000) - 3600,
page_size: 10,
}),
});
const data = await resp.json();
if (data.ret !== 1) throw new Error(`ret=${data.ret}: ${data.msg}`);
for (const item of data.data.ent.items) {
console.log(item.task_id, item.status, item.query);
}
```
## 响应 [Section titled “响应”](#响应) `data.ent` 的字段: | 字段 | 类型 | 说明 | | ----------- | ----------- | -------------- | | `total` | integer | 符合条件的任务总数 | | `page` | integer | 当前页码 | | `page_size` | integer | 每页条数 | | `items` | TaskItem\[] | 当前页的任务,按提交时间倒序 | `TaskItem` 是任务对象的精简版,**不含** `answer`、`result_json`、`share_link`、`raw_result` 和 `updated_at`: | 字段 | 类型 | 说明 | | --------------- | ------- | ----------------------------------------------------------------------------------- | | `task_id` | string | 任务 ID | | `status` | string | 任务状态 | | `platform` | string | 平台标识 | | `query` | string | 问题 | | `priority` | integer | 提交时的优先级,`1` 或 `2` | | `country` | string | 请求的出口国家(大写),未指定为空 | | `thinking` | boolean | 提交时请求的思考模式;实际是否开启要用[查询任务](../get-task/)读取 `raw_result.thinking` | | `monitor_date` | string | 业务日期 `YYYY-MM-DD` | | `credits` | integer | 成功为扣除点数,未结束为预占点数,失败或取消为 `0` | | `error_code` | string | 任务级错误码,见[错误处理](../../guides/errors/#%E4%BB%BB%E5%8A%A1%E5%A4%B1%E8%B4%A5error_code) | | `error_message` | string | 错误说明,`{"zh","en"}` JSON 字符串 | | `created_at` | integer | 提交时间(Unix 秒) | | `started_at` | integer | 开始执行时间,`0` 表示未记录 | | `finished_at` | integer | 结束时间,`0` 表示未结束 |
```json
{
"ret": 1,
"data": {
"ent": {
"total": 2,
"page": 1,
"page_size": 10,
"items": [
{
"thinking": false,
"task_id": "task_3f6c1d2e-8a4b-4c1f-9e2d-7b5a0c9d1e23",
"status": "succeeded",
"platform": "doubao",
"query": "适合程序员的机械键盘推荐",
"priority": 2,
"country": "",
"monitor_date": "2026-10-26",
"credits": 3,
"error_code": "",
"error_message": "",
"created_at": 1793018425,
"started_at": 1793018431,
"finished_at": 1793018497
},
{
"thinking": true,
"task_id": "task_5a7d9c1b-3e2f-4d6a-8b0c-9e1f2a3b4c5d",
"status": "pending",
"platform": "kimi",
"query": "机械键盘和薄膜键盘哪个更适合写代码",
"priority": 2,
"country": "",
"monitor_date": "2026-10-26",
"credits": 20,
"error_code": "",
"error_message": "",
"created_at": 1793018390,
"started_at": 0,
"finished_at": 0
}
]
}
}
}
```
## 翻页与对账 [Section titled “翻页与对账”](#翻页与对账) * 列表按提交时间倒序,翻页期间有新任务提交时,后面的页可能出现与前一页重复的条目。对账时建议固定 `end_time`(如对账开始的时间),在一个固定的时间窗口内翻页。 * 统计某段时间的消耗:筛选 `status` 为 `succeeded`,对 `credits` 求和。 ## 错误 [Section titled “错误”](#错误) | `ret` | 原因 | | ------ | --------------------------------------------------------------------------------------------------------- | | `1001` | 参数不合法:`page` 或 `page_size` 越界、`end_time` 不大于 `start_time`、时间为负数、`status` 取值不在列表中、`keyword` 过长,或请求体含未定义的字段 | | `1003` | 账户权限异常(少见),请联系我们 | | `1030` | API Key 无效 | | `-1` | 服务暂时不可用,可以直接重试 |
# 提交任务
> POST https://maxaeo.cn/geoapi/geodata/developer/task/submit —— 向指定 AI 平台提交一个问题,立即返回 task_id 与 queued 状态的任务;支持 priority 优先级、thinking 思考模式、country 出口国家、monitor_date 业务日期和 wait_seconds 同步等待。成功后按提交时单价扣点数。
```text
POST https://maxaeo.cn/geoapi/geodata/developer/task/submit
```
向一个 AI 平台提交一个问题。接口立即返回新建的任务(状态 `queued`)和 `task_id`,之后用[查询任务](../get-task/)获取结果。 **每次调用都会创建一个新任务。** 成功后按提交时的单价扣点数;提交时先预占这部分点数,失败或取消会退回。 ## 请求参数 [Section titled “请求参数”](#请求参数) | 参数 | 类型 | 必填 | 说明 | | -------------- | ------- | -- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `platform` | string | 是 | 平台标识,如 `doubao`、`deepseek`,取值见[查询平台列表](../list-platforms/),`platform_status` 为 `maintenance` 的不可提交。不区分大小写,最长 64 个字符 | | `query` | string | 是 | 要问平台的问题。去掉首尾空白后最长 4096 个字符;必须包含可见文字,除换行、回车、制表符外不能有控制字符 | | `priority` | integer | 否 | `1` = P1 优先,`2` = P2 标准。不传或传 `0` 按 P2。两档排队方式和单价不同,见[优先级](../../guides/platforms/#%E4%BC%98%E5%85%88%E7%BA%A7p1-%E4%B8%8E-p2) | | `thinking` | boolean | 否 | 是否请求平台的思考模式,默认 `false`。必须是 JSON 布尔值。见下文 | | `country` | string | 否 | 两位字母国家代码(ISO 3166-1 alpha-2),如 `US`、`JP`,不区分大小写。只影响海外平台的抓取出口,见[出口国家](../../guides/platforms/#%E5%87%BA%E5%8F%A3%E5%9B%BD%E5%AE%B6country) | | `monitor_date` | string | 否 | 任务的业务日期,`YYYY-MM-DD`,默认北京时间当天。也接受带时区的 RFC 3339 时间(如 `2026-10-26T09:30:00-07:00`),会换算为北京时间的日期。不影响执行时间,见[monitor\_date 是什么](../../guides/task-lifecycle/#monitor_date-%E6%98%AF%E4%BB%80%E4%B9%88) | | `wait_seconds` | integer | 否 | 同步等待秒数,`0`–`120`,默认 `0`(立即返回)。见下文 | 不接受其他字段,出现未定义的字段返回 `1001`。 ## 同步等待 `wait_seconds` [Section titled “同步等待 wait\_seconds”](#同步等待-wait_seconds) * `0`(默认):立即返回,任务状态为 `queued`。 * `1`–`120`:服务端在这段时间内每 2 秒检查一次任务,任务到达终态(`succeeded` / `failed` / `canceled`)就立刻返回;时间用完仍未结束,返回当时的任务状态。 使用同步等待时: * 客户端 HTTP 超时要大于 `wait_seconds`,建议多留 15 秒以上。 * 返回的任务**可能仍未结束**,代码必须能继续按 `task_id` 轮询。 * 连接在等待期间被断开不会影响任务本身,按[避免重复提交](../../guides/task-lifecycle/#%E9%81%BF%E5%85%8D%E9%87%8D%E5%A4%8D%E6%8F%90%E4%BA%A4)找回 `task_id` 即可。 ## 思考模式 `thinking` [Section titled “思考模式 thinking”](#思考模式-thinking) 传 `"thinking": true` 时,请求平台以思考模式回答,例如 DeepSeek 的深度思考、豆包的专家模式:
```bash
curl -X POST "https://maxaeo.cn/geoapi/geodata/developer/task/submit" \
-H "Authorization: Bearer $MAXAEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"platform": "deepseek", "query": "适合程序员的机械键盘推荐", "thinking": true}'
```
* 没有思考开关的平台会按关闭执行,不报错。实际是否开启看结果里的 `raw_result.thinking`;响应外层的 `thinking` 只是你请求的值。 * 开启后明显更慢,不加价。 各平台的支持情况见[思考模式](../../guides/platforms/#%E6%80%9D%E8%80%83%E6%A8%A1%E5%BC%8Fthinking)。 ## 请求示例 [Section titled “请求示例”](#请求示例) * cURL
```bash
curl -X POST "https://maxaeo.cn/geoapi/geodata/developer/task/submit" \
-H "Authorization: Bearer $MAXAEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"platform": "doubao",
"query": "适合程序员的机械键盘推荐",
"priority": 2
}'
```
* Python
```python
import os
import requests
resp = requests.post(
"https://maxaeo.cn/geoapi/geodata/developer/task/submit",
headers={"Authorization": f"Bearer {os.environ['MAXAEO_API_KEY']}"},
json={"platform": "doubao", "query": "适合程序员的机械键盘推荐", "priority": 2},
timeout=30,
)
data = resp.json()
if data["ret"] != 1:
raise RuntimeError(f"ret={data['ret']}: {data['msg']}")
task = data["data"]["ent"]
print(task["task_id"], task["status"], task["credits"])
```
* Node.js
```js
const resp = await fetch("https://maxaeo.cn/geoapi/geodata/developer/task/submit", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MAXAEO_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ platform: "doubao", query: "适合程序员的机械键盘推荐", priority: 2 }),
});
const data = await resp.json();
if (data.ret !== 1) throw new Error(`ret=${data.ret}: ${data.msg}`);
const task = data.data.ent;
console.log(task.task_id, task.status, task.credits);
```
## 响应 [Section titled “响应”](#响应) `data.ent` 是[任务对象](../task-object/)。不使用同步等待时,刚提交的任务: * `status` 为 `queued`; * `task_id` 形如 `task_` 加一个 UUID,后续查询都用它; * `credits` 为预占的点数,即该平台、该档位当前的单价; * `thinking` 为你请求的思考模式,没传时为 `false`; * `answer`、`result_json` 等结果字段为空,`raw_result` 不出现。
```json
{
"ret": 1,
"data": {
"ent": {
"thinking": false,
"task_id": "task_3f6c1d2e-8a4b-4c1f-9e2d-7b5a0c9d1e23",
"platform": "doubao",
"query": "适合程序员的机械键盘推荐",
"status": "queued",
"answer": "",
"result_json": "",
"share_link": "",
"error_code": "",
"error_message": "",
"started_at": 0,
"finished_at": 0,
"created_at": 1793018425,
"updated_at": 1793018425,
"monitor_date": "2026-10-26",
"priority": 2,
"country": "",
"credits": 3
}
}
}
```
## 错误 [Section titled “错误”](#错误) 以下错误发生在创建任务之前:**不会创建任务,也不扣点数**。 | `ret` | 原因 | 处理 | | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | | `1001` | 参数不合法,`msg` 会写明字段,例如 `query` 为空或过长、`priority` 不是 1 或 2、`country` 不是两位字母、`monitor_date` 格式不对、`wait_seconds` 超出 0–120;请求体含未定义字段,或字段类型不对(如 `thinking` 传了字符串 `"true"`)时也返回 `1001` | 修正参数 | | `1022` | 开发者 API 计费未开通 | 联系商务 | | `1023` | 可用点数不足以支付这次的单价 | 充值或改用更便宜的平台 / 档位 | | `1024` | 同时进行的任务数已达上限 | 等部分任务结束后重试 | | `1025` | 提交过于频繁 | 降低速率,退避后重试 | | `1029` | 平台未开放(未配置单价或已下线),或正在维护 | 重新获取平台列表,换平台 | | `1030` | API Key 无效 | 检查 Key | | `1003` | 账户权限异常(少见) | 请联系我们 | | `-1` | 服务暂时不可用 | **任务可能已创建**,先用[任务列表](../list-tasks/)确认,再决定是否重新提交 | 还有一类情况:请求通过了校验、任务也创建了,但之后派发或执行失败。这时提交接口返回成功,任务最终 `status` 为 `failed`,原因在 `error_code`(例如平台已下线时为 `crawler_rejected`),同样不扣点数。见[错误处理](../../guides/errors/#%E4%BB%BB%E5%8A%A1%E5%A4%B1%E8%B4%A5error_code)。 不要盲目重试提交 提交接口不是幂等的:重复调用会创建多个任务,各自成功后各自扣费。请求超时、断连或返回 `-1` 时,先用任务列表按问题文本和时间确认是否已创建。完整做法见[提交结果未知时](../../guides/errors/#%E6%8F%90%E4%BA%A4%E7%BB%93%E6%9E%9C%E6%9C%AA%E7%9F%A5%E6%97%B6)。
# 任务对象
> 开放 API 任务对象的完整字段定义:外层任务字段(状态、时间、点数、错误码)以及 raw_result 结构化结果中的 references、agentSteps、mediaCards 等全部子结构与编码规则。
[提交任务](../submit-task/)和[查询任务](../get-task/)都返回任务对象;[任务列表](../list-tasks/)返回它的精简版。 ## 任务字段 [Section titled “任务字段”](#任务字段) | 字段 | 类型 | 说明 | | --------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `task_id` | string | 任务 ID,形如 `task_` 加 UUID | | `platform` | string | 平台标识(已转为小写) | | `query` | string | 问题(已去掉首尾空白) | | `status` | string | `queued`、`dispatching`、`pending`、`running`、`succeeded`、`failed`、`canceled`,见[任务生命周期](../../guides/task-lifecycle/) | | `answer` | string | 回答正文(Markdown),等于 `raw_result.rawContent`;没有结果时为空字符串 | | `result_json` | string | 原始结果的 JSON 字符串,结构与 `raw_result` 相同,可能包含 `raw_result` 尚未收录的新字段;没有结果时为空字符串 | | `share_link` | string | 平台分享链接,没有为空字符串 | | `error_code` | string | 任务级错误码,见[错误处理](../../guides/errors/#%E4%BB%BB%E5%8A%A1%E5%A4%B1%E8%B4%A5error_code)。**不为空不代表失败**,以 `status` 为准 | | `error_message` | string | 错误说明,`{"zh","en"}` JSON 字符串,解析后按语言展示;不要按文案做程序判断 | | `created_at` | integer | 提交时间(Unix 秒) | | `updated_at` | integer | 最近更新时间(Unix 秒) | | `started_at` | integer | 开始执行时间(Unix 秒),`0` 表示未开始或未记录 | | `finished_at` | integer | 结束时间(Unix 秒),`0` 表示未结束 | | `monitor_date` | string | 业务日期 `YYYY-MM-DD`(北京时间),提交时确定 | | `priority` | integer | 提交时的优先级:`1` = P1、`2` = P2。实际执行档位以 `raw_result.priority` 为准 | | `country` | string | 请求的出口国家(大写),未指定为空字符串;不代表已验证的实际出口 | | `thinking` | boolean | 提交时请求的思考模式,未请求为 `false`。实际是否开启以 `raw_result.thinking` 为准,见[思考模式](../../guides/platforms/#%E6%80%9D%E8%80%83%E6%A8%A1%E5%BC%8Fthinking) | | `credits` | integer | `succeeded`:扣除的点数;未结束:预占的点数;`failed` / `canceled`:`0` | | `raw_result` | object | 结构化结果,见下文。**只在拿到结果后出现**(成功,或平台执行失败);排队中、被取消、派发失败的任务没有这个字段 | 外层字段即使为空也会返回(`""`、`0` 或 `false`)。 ## `raw_result` [Section titled “raw\_result”](#raw_result) 结构化结果沿用 protobuf 的 JSON 编码,与外层的约定不同: * 字段名为**小驼峰**(`rawContent`、`shareLink`)。 * **零值字段省略**:`false`、`0`、空字符串、空数组都不出现,读取时自行补默认值。 * `elapsedMs` 是 64 位整数,编码为**字符串**(如 `"48213"`)。 | 字段 | 类型 | 说明 | | ---------------- | ------------ | ---------------------------------------------------------------------------- | | `taskId` | string | 任务 ID | | `platform` | string | 平台标识 | | `monitorDate` | string | 业务日期 `YYYY-MM-DD` | | `query` | string | 实际执行的问题 | | `success` | boolean | 是否拿到回答;为 `false` 时字段不出现 | | `rawContent` | string | 回答原文(Markdown),平台的引用标记与卡片占位符原样保留 | | `references` | Reference\[] | 引用来源,见下文 | | `shareLink` | string | 平台分享链接 | | `error` | string | 失败说明,与 `error_message` 相同的 `{"zh","en"}` JSON 字符串;不要按文案做程序判断 | | `elapsedMs` | string | 执行耗时(毫秒),**不含排队** | | `completedAt` | string | 完成时间,ISO 8601 UTC,如 `2026-10-26T12:41:37.512Z` | | `priority` | integer | 实际执行的档位:`1` = P1、`2` = P2,对账以此为准 | | `thinking` | boolean | 实际是否开启了思考:`true` 为开启;没有开启、平台没有思考开关或任务失败时不出现。判断思考模式是否生效以此为准,而不是外层的 `thinking` | | `agentSteps` | AgentStep\[] | 执行过程(思考、搜索、工具调用),按发生顺序 | | `mediaCards` | MediaCard\[] | 回答中的多媒体卡片,按出现顺序 | | `conversationId` | string | 平台侧会话 ID,仅供对照 | | `messageId` | string | 平台侧消息 ID,仅供对照 | ### Reference [Section titled “Reference”](#reference) | 字段 | 类型 | 说明 | | ----------------- | ------- | --------------------------------------------------------- | | `rank` | integer | 平台展示顺序,从 1 开始 | | `title` | string | 标题 | | `url` | string | 链接;少数来源没有链接或为平台内部 ID,使用前请校验 | | `snippet` | string | 摘要 | | `source` | string | 来源名称(站点名) | | `domain` | string | 域名 | | `contentPlatform` | string | 识别出的内容平台,识别不出时不出现 | | `cited` | boolean | `true` 被正文引用,`false` 搜到但未引用;**字段不存在表示平台不区分**,不能当作 `false` | | `publishTime` | string | 发布时间:ISO 8601、`YYYY-MM-DD` 或平台给出的相对时间原文(如「1天前」) | | `author` | string | 作者(笔记作者、视频 UP 主等) | 引用来源包含平台搜到或读过的全部来源,被正文引用的排在前面。各平台对 `cited` 的支持情况见[解析回答结果](../../guides/results/#cited-%E7%9A%84%E4%B8%89%E7%A7%8D%E5%8F%96%E5%80%BC)。 ### AgentStep [Section titled “AgentStep”](#agentstep) 按 `type` 读取对应字段: | 字段 | 类型 | 适用 `type` | 说明 | | --------- | -------------------- | --------------- | ----------------------------------------- | | `type` | string | — | `thinking` 思考、`search` 联网搜索、`tool` 其他工具调用 | | `content` | string | `thinking` | 思考正文 | | `summary` | string | `thinking` | 思考摘要或平台的过程说明 | | `name` | string | `search`、`tool` | 平台工具名 | | `queries` | string\[] | `search` | 本次搜索使用的检索词 | | `results` | AgentSearchResult\[] | `search` | 搜索返回的结果,未必被正文引用 | | `args` | string | `tool` | 调用参数原文 | `AgentSearchResult`:`title`、`url`、`siteName`(站点展示名)、`snippet`。 ### MediaCard [Section titled “MediaCard”](#mediacard) | 字段 | 类型 | 说明 | | -------------- | ---------------- | ------------------------------------------- | | `type` | string | `image`、`video`、`product`、`ranking`、`other` | | `platformType` | string | 平台原始卡片类型名,仅供对照,取值随平台变化 | | `anchor` | string | 卡片在 `rawContent` 中的占位符原文;平台不在正文放占位符时不出现 | | `items` | MediaCardItem\[] | 卡片中的各项 | `MediaCardItem`: | 字段 | 类型 | 说明 | | ------------- | ------ | --------------------- | | `title` | string | 标题或品名 | | `url` | string | 点击跳转的页面(视频页、商品页、笔记页) | | `imageUrl` | string | 封面或图片链接,**通常带签名、会过期** | | `source` | string | 来源站点、店铺或商城名 | | `author` | string | 作者 | | `duration` | string | 视频时长,平台原文(如 `05:03`) | | `price` | string | 价格,平台原文 | | `rating` | string | 评分或推荐度,平台原文 | | `publishTime` | string | 发布时间,口径同 Reference | | `description` | string | 平台给出的说明或点评 | ## 完整示例 [Section titled “完整示例”](#完整示例) 成功任务的完整示例见[查询任务](../get-task/#%E5%93%8D%E5%BA%94)。
# 认证与 API Key
> MaxAEO 开放 API 与 MCP 统一使用 Bearer API Key 认证。本页说明请求头格式、Key 的权限范围、鉴权失败的表现,以及保管与轮换 Key 的安全建议。
开放 API 和 MCP 服务器只接受一种认证方式:在 HTTP 请求头里携带 API Key。没有 OAuth,也没有基于 Cookie 的登录态。 ## 请求头格式 [Section titled “请求头格式”](#请求头格式)
```http
Authorization: Bearer gdev_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```
* 每个请求带**且只带一个** `Authorization` 头,scheme 写 `Bearer`(大小写不敏感),后跟一个空格和完整 Key。 * API Key 以 `gdev_` 开头,共 48 个字符。控制台列表里展示的是前 12 个字符(如 `gdev_Ab3dEfG`),用来区分不同的 Key。 * Key **只能放在请求头里**。放在 URL 查询参数或请求体里都不会被识别;请求体里出现 `api_key` 这类接口未定义的字段,会直接返回参数错误 `1001`。 ## 获取 API Key [Section titled “获取 API Key”](#获取-api-key) 在[开发者控制台](https://maxaeo.cn/developers/) → **API Key** 页创建。完整 Key 只在创建或重置成功时显示一次,服务端只保存它的摘要,事后无法再查看。遗失只能重置或新建。 创建、停用、重置、删除等操作见[管理 API Key](../console/api-keys/)。 ## Key 的权限范围 [Section titled “Key 的权限范围”](#key-的权限范围) API Key 代表**创建它的用户**在其**个人账户**下调用接口: * **计费**:所有 Key 和控制台的在线调试共用账户的点数余额与限流额度。 * **查询任务**:用任意一个有效 Key 都能按 `task_id` 查询这个用户提交过的任务,包括用其他 Key 提交的、在控制台在线调试提交的。 * **任务列表**:[任务列表](../api/list-tasks/)接口只列出**当前这个 Key** 提交的任务。 * **团队账户**:目前未开放,Key 只能创建在个人账户下。 一个 Key 能做的事与开放 API 一一对应:查询平台、提交任务、查询任务、列出任务。Key 不能用来管理 Key 本身,也不能访问 MaxAEO 产品里的品牌监控数据。 ## 鉴权失败 [Section titled “鉴权失败”](#鉴权失败) 服务端在**每个请求**上重新校验 Key:Key 存在、处于启用状态、未过期,且所属用户和账户仍然有效。任一条件不满足,开放 API 都返回:
```json
{
"ret": 1030,
"msg": "{\"zh\":\"API Key 无效、已停用或已过期\",\"en\":\"The API key is invalid, disabled or expired.\"}"
}
```
缺少 `Authorization` 头、格式不对、出现多个 `Authorization` 头时也返回 `1030`。出于安全考虑,`1030` 不区分具体原因,请按下面的顺序排查: 1. 环境变量是否读到了完整的 Key(常见问题:只复制了前缀、末尾多了换行或空格)。 2. 请求头是否写成了 `Authorization: Bearer `,而不是 `Bearer: ` 或 `Token `。 3. 在控制台 API Key 页确认这个 Key 的状态:已停用、已过期、已删除的 Key 都会被拒绝;重置后旧 Key 会在宽限期结束时失效。 ## Key 失效对进行中任务的影响 [Section titled “Key 失效对进行中任务的影响”](#key-失效对进行中任务的影响) 停用、删除 Key,或 Key 到期后: * 用这个 Key 发起的**新请求**立即被拒绝(`1030`)。 * 已经提交、但还在本地排队(`queued`)没有派发出去的任务,派发时会失败,`error_code` 为 `credential_invalid`,不扣点数。 * 已经派发给平台执行的任务照常完成,结果仍可以用其他有效 Key 或在控制台查询。 ## 安全建议 [Section titled “安全建议”](#安全建议) * **只在服务端使用。** 不要把 Key 写进网页前端、小程序、App 安装包、浏览器插件或公开的代码仓库;在服务端通过环境变量或密钥管理服务读取。 * **按环境、按项目分开创建。** 例如「生产」「测试」「数据看板」各一个。单个 Key 泄露时,停用或重置它即可,不影响其他调用;控制台也能按 Key 查看用量。 * **为非长期用途设置有效期。** 临时脚本、外包协作用的 Key 选 30 天或 90 天有效期,到期自动失效。 * **定期轮换,平滑替换。** 用「重置 Key」生成新 Key,并给旧 Key 留出宽限期(1 小时、24 小时或 7 天),先把新 Key 部署上线,再让旧 Key 自然失效。 * **怀疑泄露时立即处理。** 在控制台重置并选择「立即失效」,或直接停用;然后在调用日志里检查是否有异常调用。 * **不要在日志里打印完整 Key。** 需要标识 Key 时,记录前 12 个字符即可。 ## 相关页面 [Section titled “相关页面”](#相关页面) [管理 API Key](../console/api-keys/)在控制台创建、停用、重置和删除 Key。 [错误处理](../guides/errors/)1030 之外的请求级错误码与处理建议。
# 管理 API Key
> 在 MaxAEO 开发者控制台创建、编辑、停用、启用、重置和删除 API Key:有效期选项、只显示一次的完整 Key、重置时的旧 Key 宽限期、Key 数量上限,以及各操作对正在进行的请求和任务的影响。
API Key 在[开发者控制台](https://maxaeo.cn/developers/)的 **API Key** 页统一管理。页面列出你账户下所有未删除的 Key,以及每个 Key 的状态、本月消耗和最近使用时间。 ## 创建 API Key [Section titled “创建 API Key”](#创建-api-key) 1. 点击右上角「**创建 API Key**」。 2. 填写: * **名称**:用来区分用途,建议按环境或项目命名,如「生产环境」「数据看板」。最长 128 个字符。 * **有效期**:永不过期、30 天、90 天、180 天、1 年,或自定义到期日期。**有效期创建后不能修改**,需要更换只能重置或新建。 3. 点「**创建**」。弹窗显示完整的 Key。**完整 Key 只显示这一次**:立即复制并保存到你的密钥管理处,关闭弹窗后无法再次查看。 4. 可以在弹窗里点「**试一下**」,用这个 Key 查询支持的平台,确认 Key 可用(不消耗点数)。 每个账户最多保留 10 个未删除的 Key(含已停用、已过期的),达到上限后需要先删除不用的 Key。当前上限以页面顶部的提示为准。 ## Key 列表 [Section titled “Key 列表”](#key-列表) | 列 | 说明 | | ------- | ------------------------------------- | | 名称 | 创建或编辑时填写的名称 | | API Key | Key 的前 12 个字符,用来区分不同的 Key;完整 Key 不再显示 | | 状态 | **启用**、**已停用**、**已过期**;即将过期时会提示剩余天数 | | 本月消耗(点) | 本自然月(北京时间)用这个 Key 成功调用扣除的点数 | | 最近使用 | 最近一次用这个 Key 成功通过鉴权的时间;从未使用显示「从未使用」 | 从操作菜单的「**查看调用日志**」可以直接跳到这个 Key 的调用记录。 ## 编辑 [Section titled “编辑”](#编辑) 只能修改**名称**。Key 本身和有效期都不能修改。 ## 停用与启用 [Section titled “停用与启用”](#停用与启用) * **停用**:使用这个 Key 的请求会立即被拒绝(`ret 1030`)。可以随时重新启用。适合暂时不用、或怀疑有异常调用时先止损。 * **启用**:恢复已停用的 Key。**已过期的 Key 不能启用**,请新建。 ## 重置 Key [Section titled “重置 Key”](#重置-key) 重置会生成一个**新 Key**,用于定期轮换或在怀疑泄露时更换: 1. 在操作菜单点「**重置 Key**」。 2. 选择**旧 Key 失效时间**:立即失效、1 小时后、24 小时后(默认)或 7 天后。宽限期内新旧 Key 都能用,你可以先把新 Key 部署上线,再让旧 Key 自然失效。 3. 确认后弹窗显示新 Key 的完整内容,同样**只显示这一次**。 重置的规则: * 新 Key 沿用旧 Key 的名称和到期时间,在列表中是一条新记录;旧 Key 保留在列表中,宽限期结束后变为已过期(选择「立即失效」时直接变为已停用)。 * 旧 Key 的失效时间取「现在 + 宽限期」与它原本到期时间中较早的一个。 * 只能重置**启用中且未过期**的 Key;已停用的请先启用,已过期的请新建。 * Key 数量已达上限时仍可重置一次;超过上限后需要先删除不用的旧 Key 才能再次重置。 * 重置前用旧 Key 提交的任务,不会出现在新 Key 的[任务列表](../../api/list-tasks/)里,但仍可以凭 `task_id` 查询。 选择「立即失效」前确认影响 立即失效后,所有还在使用旧 Key 的请求会马上被拒绝(`ret 1030`)。只有在确认 Key 已泄露、需要立即止损时才建议这样做。 ## 删除 [Section titled “删除”](#删除) 删除后**无法恢复**,使用这个 Key 的请求会立即被拒绝(`ret 1030`)。只是暂时不用的话,建议停用。 删除后,这个 Key 提交过的任务仍然保留:调用日志和用量统计里照常显示 Key 的名称和前缀,任务也可以用其他有效 Key 按 `task_id` 查询。 ## 对进行中任务的影响 [Section titled “对进行中任务的影响”](#对进行中任务的影响) 停用、删除 Key,或 Key 到期、重置宽限期结束后: * 用这个 Key 提交、但还在排队(`queued`)未派发的任务,派发时会失败(`error_code` 为 `credential_invalid`),不扣点数。 * 已经派发给平台执行的任务照常完成。 ## 安全建议 [Section titled “安全建议”](#安全建议) * 不要把 Key 写进网页前端、小程序、App 安装包或公开的代码仓库,在服务端通过环境变量读取。 * 按环境、项目分别创建 Key,单个 Key 泄露时停用或重置它即可,不影响其他调用。 * 怀疑泄露时立即重置;需要平滑替换时给旧 Key 留出宽限期。 更多说明见[认证与 API Key](../../authentication/#%E5%AE%89%E5%85%A8%E5%BB%BA%E8%AE%AE)。 ## 相关页面 [Section titled “相关页面”](#相关页面) [认证与 API Key](../../authentication/)请求头格式、Key 的权限范围与鉴权失败排查。 [调用日志与用量](../logs-usage/)按 Key 查看调用明细与点数消耗。
# 调用日志与用量
> 在 MaxAEO 开发者控制台查看每一次请求的明细(状态、耗时、点数、错误与完整响应),以及点数余额、冻结点数、消耗趋势、按平台和按来源的用量拆分、账户的额度与限制。
开发者控制台提供两个页面帮你掌握调用情况:**调用日志**看每一次请求,**用量统计**看汇总与余额。 ## 调用日志 [Section titled “调用日志”](#调用日志) 「**调用日志**」列出账户下的每一次任务请求,包括 API Key 调用和在线调试发出的请求。 ### 筛选 [Section titled “筛选”](#筛选) * **时间**:今天、近 7 天、近 30 天,或自定义日期。日期按北京时间(UTC+8)划分;列表里的时间按你电脑的本地时区显示。控制台可查询近 30 天的记录。 * **平台**、**状态**、**来源**(各个 API Key / 在线调试)。 * **搜索**:输入任务 ID 精确查找,或输入问题中的文字。 ### 列表字段 [Section titled “列表字段”](#列表字段) | 列 | 说明 | | ----- | ------------------------------------------ | | 时间 | 提交时间 | | 任务 ID | 即开放 API 的 `task_id` | | 请求 | 平台与问题 | | 状态 | 排队中、进行中、成功、失败、已取消 | | 耗时 | 从提交到结束的时间(含排队) | | 点数 | 成功为扣除的点数,进行中为预占的点数,失败为 0 | | 来源 | 使用的 API Key(名称与前缀),或「在线调试」;已删除的 Key 也会显示名称 | ### 请求详情 [Section titled “请求详情”](#请求详情) 点击任意一行打开详情,可以看到: * 请求时间、平台、出口国家、来源、耗时、档位(P1 / P2)、消耗点数; * **请求参数**; * **响应**:「预览」以可读形式展示回答与引用来源,「JSON」是与开放 API 一致的完整响应; * 失败时的**错误码**与**说明**,含义见[错误处理](../../guides/errors/#%E4%BB%BB%E5%8A%A1%E5%A4%B1%E8%B4%A5error_code)。 请求还在进行中时,详情会提示完成后刷新查看。点「**在调试中重放**」可以把这次请求的参数带到[在线调试](../playground/)再次发送。 ## 用量统计 [Section titled “用量统计”](#用量统计) 「**用量统计**」汇总点数余额与消耗。可以选择近 7 天、近 30 天或本月,日期按北京时间划分,**只有成功的请求计费**。 ### 关键指标 [Section titled “关键指标”](#关键指标) | 指标 | 说明 | | ---- | --------------------------- | | 点数余额 | 当前可用的点数;有即将到期的点数时,显示到期数量与日期 | | 冻结 | 进行中任务预占的点数,任务结束后扣除或退回 | | 消耗点数 | 所选时间段内成功任务扣除的点数,附日均值 | | 请求数 | 所选时间段内提交的任务数,附成功率 | | 平均耗时 | 已结束任务从提交到结束的平均时间(含排队) | ### 趋势与拆分 [Section titled “趋势与拆分”](#趋势与拆分) * **每日用量**:按天展示点数消耗、请求数与失败数。 * **按平台**:各平台的请求数、成功率、点数与平均耗时,帮你判断哪些平台性价比更高。 * **按来源**:各个 API Key 与在线调试分别消耗了多少点数、占比多少,适合按项目或环境核算成本。 ### 额度与限制 [Section titled “额度与限制”](#额度与限制) 页面底部显示账户当前生效的限制:AI 回答并发数、每分钟请求数、API Key 数量上限。含义见[限流与配额](../../guides/rate-limits/)。需要更高的并发或额度,请联系商务。 开发者 API 的计费尚未开通时,页面顶部会提示暂时不能提交任务。 ## 概览页 [Section titled “概览页”](#概览页) 控制台首页「**概览**」把关键信息集中在一屏:快速开始的完成进度(创建 Key → 在线调试 → 接入代码)、点数余额、今日请求、近 7 天消耗、启用中的 Key 数量、近 7 天请求趋势、平台状态和最近的请求。适合作为每天巡检的入口。 ## 相关页面 [Section titled “相关页面”](#相关页面) [计费与点数](../../guides/billing/)预占、扣点、退回与点数有效期。 [管理 API Key](../api-keys/)按环境或项目拆分 Key,方便按来源核算。
# 在线调试
> 在 MaxAEO 开发者控制台的在线调试页,不写代码直接向 AI 平台提问,查看回答预览、完整 JSON 响应,并一键复制当前参数的 cURL、Python、Node.js 调用代码。在线调试固定按 P1 执行和计费。
**在线调试**让你不写代码就能调用开放 API:选平台、输入问题、发送,就能看到 AI 的回答、引用来源和完整的响应结构。确认效果后,可以直接复制当前参数的调用代码到你的项目里。 ## 发送一次请求 [Section titled “发送一次请求”](#发送一次请求) 1. 打开[开发者控制台](https://maxaeo.cn/developers/),进入「**在线调试**」。 2. 填写请求参数: * **平台**:选择要提问的 AI 平台。平台处于「波动」时会提示可能较慢或偶发失败;「维护中」的平台暂停接单,提交会被直接拒绝且不计费。 * **问题**:输入要问 AI 平台的问题,也可以点「试试」使用示例问题。 * **出口国家 / 地区**:仅对海外平台有效,用该国家的网络出口访问平台,回答可能随地区变化;国内平台固定从中国大陆访问。默认「自动」。 3. 确认页面显示的**预计消耗**,点「**发送请求**」(或按 ⌘ / Ctrl + Enter)。 4. 等待结果。页面会依次显示「已提交」「排队中」「抓取中」「完成」等阶段和已等待的时间。抓取通常需要几十秒到两分钟,排队时间另算。 ## 查看结果 [Section titled “查看结果”](#查看结果) 响应面板有三个标签页: * **预览**:以接近平台原貌的方式展示回答正文、引用来源列表,以及「在平台中查看」的分享链接。任务失败时显示错误码与说明。 * **JSON**:完整的响应 JSON,字段与开放 API 的[查询任务](../../api/get-task/)返回一致,可以用来对照解析代码。 * **代码**:当前参数的调用示例,支持 cURL、Python、Node.js。API Key 从环境变量 `MAXAEO_API_KEY` 读取;示例包含提交和每 15 秒轮询一次直到结束的完整流程。 响应面板顶部还会显示**任务 ID**、**耗时**和**消耗**的点数。 ## 计费与限流 [Section titled “计费与限流”](#计费与限流) * 在线调试**固定按 P1 优先档执行,按 P1 单价计费**,失败不计费。 * 与 API 调用共用账户的点数余额,以及并发、每分钟提交次数的限制。余额不足、超过限制时会直接提示,不会创建任务。 * 在线调试的请求会记录在调用日志里,来源显示为「在线调试」。 ## 从调用日志重放 [Section titled “从调用日志重放”](#从调用日志重放) 在[调用日志](../logs-usage/#%E8%B0%83%E7%94%A8%E6%97%A5%E5%BF%97)的请求详情里点「**在调试中重放**」,会把那次请求的参数带到在线调试页,修改后可以再次发送。重放会创建新任务,同样按 P1 计费。 ## 相关页面 [Section titled “相关页面”](#相关页面) [快速开始](../../quickstart/)从在线调试走向代码调用。 [计费与点数](../../guides/billing/)P1 与 P2 的单价与扣点规则。
# 常见问题
> MaxAEO 开发者平台接入中的高频问题:任务一直排队、提交超时会不会重复扣费、有没有 Webhook、能否在前端调用、HTTP 200 却失败、引用为空、回答里的引用标记、思考模式、平台波动、免费额度、多轮对话与模型选择等。
## 任务 [Section titled “任务”](#任务) ### 任务一直是 `pending` 或 `queued`,正常吗? [Section titled “任务一直是 pending 或 queued,正常吗?”](#任务一直是-pending-或-queued正常吗) 正常。接口是异步的,排队时间没有上限:平台繁忙或平台账号暂时不可用时,P2 任务会留在队列里等待恢复。服务端不会因为等太久把任务判为失败。你可以: * 继续按 15 秒左右的间隔轮询; * 对时效敏感的任务改用 P1; * 参考[平台列表](../api/list-platforms/)里各平台的 `p50_duration_seconds` 和状态,避开正在波动的平台。 见[任务生命周期](../guides/task-lifecycle/)。 ### 提交接口超时了,重新提交会不会扣两次费? [Section titled “提交接口超时了,重新提交会不会扣两次费?”](#提交接口超时了重新提交会不会扣两次费) 可能会。每次调用提交接口都会创建一个新任务,两个任务都成功就会扣两次点数。超时后请先用[任务列表](../api/list-tasks/)按问题文本和时间查找刚才的任务,确认没有创建再重新提交。见[提交结果未知时](../guides/errors/#%E6%8F%90%E4%BA%A4%E7%BB%93%E6%9E%9C%E6%9C%AA%E7%9F%A5%E6%97%B6)。 ### 有 Webhook 回调吗? [Section titled “有 Webhook 回调吗?”](#有-webhook-回调吗) 目前没有,任务结果需要轮询获取。建议每 15 秒左右查询一次未结束的任务。 ### 可以取消已经提交的任务吗? [Section titled “可以取消已经提交的任务吗?”](#可以取消已经提交的任务吗) 开放 API 目前不提供取消接口。不需要的任务可以不再查询;任务成功仍会扣点数。 ### 同一个问题问两次,结果不一样? [Section titled “同一个问题问两次,结果不一样?”](#同一个问题问两次结果不一样) 正常。AI 的回答天然有随机性,每次提问得到的措辞、推荐和引用都可能不同。每次提交都是一次独立的真实提问,结果会分别保存。 ### `started_at` 为什么是 0? [Section titled “started\_at 为什么是 0?”](#started_at-为什么是-0) 如果任务直接拿到了最终结果、中间没有观察到「执行中」状态,就不会记录开始时间。计算耗时请用 `finished_at - created_at`(含排队)或 `raw_result.elapsedMs`(仅执行)。 ### 任务结果保存多久? [Section titled “任务结果保存多久?”](#任务结果保存多久) 控制台的调用日志可以查询近 30 天的记录。建议拿到结果后及时保存到你自己的系统。 ## 请求与错误 [Section titled “请求与错误”](#请求与错误) ### 为什么 HTTP 状态码是 200,请求却失败了? [Section titled “为什么 HTTP 状态码是 200,请求却失败了?”](#为什么-http-状态码是-200请求却失败了) 开放 API 的业务结果看响应体里的 `ret`:`1` 为成功,其他值为失败,HTTP 状态码都是 200。见 [API 概述](../api/#%E5%93%8D%E5%BA%94)。 ### 一直返回 1030 怎么办? [Section titled “一直返回 1030 怎么办?”](#一直返回-1030-怎么办) `1030` 表示 API Key 缺失、无效、已停用或已过期。检查环境变量是否读到了完整的 Key、请求头是否为 `Authorization: Bearer `,并在控制台确认 Key 的状态。见[认证与 API Key](../authentication/#%E9%89%B4%E6%9D%83%E5%A4%B1%E8%B4%A5)。 ### 返回「请求包含不支持的字段」? [Section titled “返回「请求包含不支持的字段」?”](#返回请求包含不支持的字段) 请求体里出现了接口未定义的字段,最常见的是把 `task_id`、`wait_seconds` 写成了小驼峰 `taskId`、`waitSeconds`。开放 API 的请求字段都是下划线风格。 ### 可以在网页前端、小程序或 App 里直接调用吗? [Section titled “可以在网页前端、小程序或 App 里直接调用吗?”](#可以在网页前端小程序或-app-里直接调用吗) 不要这样做。API Key 会随前端代码暴露给所有用户,任何人都可以用它消耗你的点数。请在你的服务端调用开放 API,再把结果返回给前端。 ### 有官方 SDK 吗? [Section titled “有官方 SDK 吗?”](#有官方-sdk-吗) 目前没有。接口只有四个,都是「POST + JSON」,用任何 HTTP 客户端几行代码即可封装,参考[快速开始](../quickstart/#%E5%AE%8C%E6%95%B4%E7%A4%BA%E4%BE%8B)。 ### 有测试环境或沙箱吗? [Section titled “有测试环境或沙箱吗?”](#有测试环境或沙箱吗) 目前没有独立的沙箱。调试可以用控制台的[在线调试](../console/playground/),或用少量真实请求验证——查询类接口不消耗点数,失败的任务也不扣费,首次使用赠送的 1000 点也可以用来测试。 ## 结果 [Section titled “结果”](#结果) ### 任务成功了,但 `references` 是空的? [Section titled “任务成功了,但 references 是空的?”](#任务成功了但-references-是空的) 正常。有的问题平台没有联网搜索,回答就不带引用来源。`succeeded` 只表示拿到了回答。 ### 回答里的 `[citation:1]`、`【turn0search2】` 是什么? [Section titled “回答里的 \[citation:1\]、【turn0search2】 是什么?”](#回答里的-citation1turn0search2-是什么) 是平台自己的引用标记,我们原样保留在 `answer` 和 `rawContent` 中,不做转换。展示前可以按需清洗,判断引用关系请用 `references` 和 `cited`。见[解析回答结果](../guides/results/#%E5%9B%9E%E7%AD%94%E6%AD%A3%E6%96%87)。 ### `cited` 字段有时候没有? [Section titled “cited 字段有时候没有?”](#cited-字段有时候没有) `cited` 是三态:`true` 被正文引用,`false` 搜到但没引用,**字段不存在**表示这个平台不区分是否引用,不能当作 `false`。 ### `references` 里的 `url` 不是一个链接? [Section titled “references 里的 url 不是一个链接?”](#references-里的-url-不是一个链接) 少数平台的来源没有链接,或给出的是平台内部 ID。使用 `url` 前请校验是否以 `http://` 或 `https://` 开头。 ### 能指定模型、开启深度思考或联网搜索吗? [Section titled “能指定模型、开启深度思考或联网搜索吗?”](#能指定模型开启深度思考或联网搜索吗) 可以开启思考:提交时传 `"thinking": true`,平台会以思考模式回答(如 DeepSeek 的深度思考、豆包的专家模式),默认关闭,不加价。部分平台没有思考开关,会按关闭执行;实际是否开启看结果里的 `raw_result.thinking`。见[思考模式](../guides/platforms/#%E6%80%9D%E8%80%83%E6%A8%A1%E5%BC%8Fthinking)。 不能指定模型,也不能开关联网搜索,这些由各平台的抓取方式决定。平台是否进行了搜索,可以从结果的 `agentSteps` 和 `references` 看出来。 ### 能基于上一次回答继续追问(多轮对话)吗? [Section titled “能基于上一次回答继续追问(多轮对话)吗?”](#能基于上一次回答继续追问多轮对话吗) 不能。每个任务都是一次独立的单轮提问。`raw_result` 里的 `conversationId` 仅供对照,不能用于继续对话。 ## 平台与计费 [Section titled “平台与计费”](#平台与计费) ### 平台显示「波动」,还能用吗? [Section titled “平台显示「波动」,还能用吗?”](#平台显示波动还能用吗) 可以提交。「波动」表示近期观察到失败,可能更慢或偶发失败,失败不扣费。「维护中」的平台暂停接单,提交会直接返回 `1029`。见[平台状态](../guides/platforms/#%E5%B9%B3%E5%8F%B0%E7%8A%B6%E6%80%81)。 ### 有免费额度吗? [Section titled “有免费额度吗?”](#有免费额度吗) 有。第一次使用开发者平台时会自动向你的个人账户赠送 1000 点,永久有效,每个账号一次。见[获取点数](../guides/billing/#%E8%8E%B7%E5%8F%96%E7%82%B9%E6%95%B0)。 ### 失败的任务扣费吗? [Section titled “失败的任务扣费吗?”](#失败的任务扣费吗) 不扣。只有 `succeeded` 的任务扣点数;`failed`、`canceled` 以及被拒绝的提交都不扣,提交时预占的点数会退回。见[计费与点数](../guides/billing/)。 ### MCP 调用和 API 调用计费一样吗? [Section titled “MCP 调用和 API 调用计费一样吗?”](#mcp-调用和-api-调用计费一样吗) 一样。MCP 工具底层就是开放 API,共用同一个账户的点数余额、单价和限流额度。 ### 团队里多个人能共用一个账户的点数吗? [Section titled “团队里多个人能共用一个账户的点数吗?”](#团队里多个人能共用一个账户的点数吗) 团队账户暂未开放,API Key 和点数都属于个人账户。团队内部可以按项目在同一个账号下创建多个 Key,在用量统计里按来源拆分消耗。 ## 相关页面 [Section titled “相关页面”](#相关页面) [错误处理](../guides/errors/)全部错误码与重试策略。 [上线检查清单](../guides/production-checklist/)接入生产环境前的逐项核对。
# 计费与点数
> MaxAEO 开发者平台按成功任务扣点数:提交时按平台与优先级单价预占,成功后扣除,失败与取消退回。本页说明首次使用赠送的 1000 点、单价查询、任务 credits 字段的含义、余额不足时的表现、对账方法与成本估算。
开发者平台以**点数**计费:只有成功拿到回答的任务扣点数,失败、取消、被拒绝的请求都不扣。 ## 计费规则 [Section titled “计费规则”](#计费规则) * **按成功任务计费。** 每个 `succeeded` 的任务扣一次点数;`failed`、`canceled` 不扣。 * **按平台和档位定价。** 每个平台有 P1 优先、P2 标准两档单价;不传 `priority` 按 P2 计价。 * **单价在提交时锁定。** 任务按**提交那一刻**的单价计费,之后调价不影响已提交的任务。 * **指定出口国家、开启[思考模式](../platforms/#%E6%80%9D%E8%80%83%E6%A8%A1%E5%BC%8Fthinking)都不加价。** * **查询不收费。** 查询平台列表、查询任务、任务列表都不消耗点数。 * **账户内共用。** 同一账户下所有 API Key、MCP 调用和控制台的在线调试共用一份点数余额。在线调试固定按 P1 单价计费。 ## 获取点数 [Section titled “获取点数”](#获取点数) * **首次使用赠送 1000 点。** 第一次使用开发者平台时(进入[开发者控制台](https://maxaeo.cn/developers/),或用 API Key 调用任一接口),系统会自动向你的个人账户发放 1000 点,**永久有效**,不需要先创建 Key 或提交任务。每个账号只赠送一次,点数用完、更换或删除 Key 都不会再次发放。 * **充值**:需要更多点数请联系商务。 赠送的点数计入点数余额,可以在控制台「概览」和「用量统计」查看。 ## 查询单价 [Section titled “查询单价”](#查询单价) 两种方式: * 调用[查询平台列表](../../api/list-platforms/),每个平台的 `p1_credits`、`p2_credits` 即两档每次成功调用的点数。 * 在[开发者控制台](https://maxaeo.cn/developers/)的「计费说明」页查看各平台单价表。 单价按各平台的抓取成本制定,不同平台差别较大。程序里请以接口返回为准,不要写死。 ## 点数怎么变化 [Section titled “点数怎么变化”](#点数怎么变化) 提交时先**预占**,到终态再结算。任务对象的 `credits` 字段反映这个过程: | 任务状态 | `credits` 的值 | 余额的变化 | | ------------------------------------------ | ------------ | ---------------- | | `queued`、`dispatching`、`pending`、`running` | 提交时的单价(预占) | 预占这部分点数,可用余额相应减少 | | `succeeded` | 提交时的单价 | 正式扣除 | | `failed`、`canceled` | `0` | 预占的点数退回 | **可用余额 = 有效点数余额 − 进行中任务的预占点数。** 提交时如果可用余额小于这次的单价,请求直接返回 `1023`,不会创建任务,也不会透支。 当前余额与冻结(预占)点数可以在控制台「用量统计」查看。计费尚未开通时,[查询平台列表](../../api/list-platforms/)返回空列表,提交任务返回 `1022`。 ## 对账 [Section titled “对账”](#对账) * **单个任务**:任务对象的 `credits` 是这个任务计费的点数(成功)或预占的点数(进行中);实际执行档位以 `raw_result.priority` 为准。 * **按 Key、平台、日期汇总**:控制台「用量统计」按天、按平台、按来源(各个 API Key / 在线调试)拆分点数消耗与请求数,日期按北京时间划分;「API Key」页显示每个 Key 本月的消耗。 * **自己汇总**:用[任务列表](../../api/list-tasks/)按时间翻页,对 `status` 为 `succeeded` 的任务累加 `credits`。注意任务列表只列出当前 Key 提交的任务。 ## 估算成本 [Section titled “估算成本”](#估算成本) 预计消耗 = 问题数 × 每个问题投放的平台单价之和(仅成功的任务计费)。 例如:每天 50 个问题,分别发往豆包、DeepSeek、Kimi,都用 P2。假设三个平台的 P2 单价分别为 3、3、20 点(以接口返回为准),则每天最多消耗 50 ×(3 + 3 + 20)= 1300 点,失败的任务不计入。 降低成本的常见做法: * 批量、定时类任务用 P2。 * 先在少量问题上比较各平台的回答价值,只投放到真正需要的平台。 * 避免重复提交同一问题(见[避免重复提交](../task-lifecycle/#%E9%81%BF%E5%85%8D%E9%87%8D%E5%A4%8D%E6%8F%90%E4%BA%A4))。 ## 相关页面 [Section titled “相关页面”](#相关页面) [限流与配额](../rate-limits/)并发、速率与 Key 数量限制。 [调用日志与用量](../../console/logs-usage/)在控制台查看余额、消耗与每次请求的明细。
# 错误处理
> 开放 API 的两层错误:请求级的 ret 错误码(1001、1022–1031、-1)与任务级的 error_code(crawl_failed、credential_invalid 等)。逐一说明含义、是否可重试与处理建议,并给出安全重试与提交结果未知时的处理代码。
开放 API 的错误分两层,处理方式完全不同: | 层级 | 在哪里看 | 含义 | 例子 | | ------- | ----------------------------------------------------- | ------------------------------ | ----------------- | | **请求级** | 响应体的 `ret` 不为 `1` | 这次 HTTP 请求没有被受理,**没有创建任务、不扣费** | 参数错误、余额不足、Key 无效 | | **任务级** | 任务的 `status` 为 `failed` 或 `canceled`,原因在 `error_code` | 任务已创建,但没有成功拿到回答,**不扣费** | 平台抓取失败、派发前 Key 失效 | ## 请求级错误 [Section titled “请求级错误”](#请求级错误) ### 响应格式 [Section titled “响应格式”](#响应格式) 请求失败时 HTTP 状态码仍是 `200`,响应体为:
```json
{
"ret": 1023,
"msg": "{\"zh\":\"点数余额不足,请充值后重试\",\"en\":\"Insufficient credits. Please top up and try again.\"}"
}
```
* **程序判断一律用 `ret`。** 文案可能调整,不要按文案做逻辑。 * `msg` 是一个 **JSON 字符串**,解析后得到 `{"zh": "…", "en": "…"}` 两种语言的提示,可以直接展示给你的用户。为稳妥起见,解析失败时把 `msg` 原文当作提示即可。 * 参数错误 `1001` 的提示会写明具体字段,例如「参数错误:query 不能超过 4096 个字符」。 ### 错误码一览 [Section titled “错误码一览”](#错误码一览) | `ret` | 含义 | 可能出现在 | 可以重试吗 | 处理建议 | | ------ | ----------------------------------------------- | ----- | ----- | --------------------------------------------------------------------------------- | | `1` | 成功 | 全部 | — | — | | `1001` | 参数错误:请求体不是单个 JSON 对象、超过 64 KiB、包含未定义的字段,或字段值不合法 | 全部 | 否 | 按提示修正请求。注意字段名要用下划线风格,如 `task_id`、`wait_seconds` | | `1022` | 开发者 API 计费未开通 | 提交任务 | 否 | 联系商务开通 | | `1023` | 点数余额不足 | 提交任务 | 充值后 | 充值,或改用单价更低的平台 / P2 档 | | `1024` | 待派发或执行中的任务数已达上限 | 提交任务 | 是,稍后 | 等部分任务结束后再提交,见[限流与配额](../rate-limits/) | | `1025` | 提交过于频繁 | 提交任务 | 是,稍后 | 降低提交速率,退避后重试 | | `1029` | 平台暂不支持或正在维护 | 提交任务 | 换平台 | 重新获取平台列表,换一个可用平台 | | `1030` | API Key 缺失、无效、已停用或已过期 | 全部 | 否 | 检查 Key,见[认证与 API Key](../../authentication/#%E9%89%B4%E6%9D%83%E5%A4%B1%E8%B4%A5) | | `1031` | 任务不存在 | 查询任务 | 否 | 检查 `task_id`;只能查询自己账号下的任务 | | `1003` | 无权限(账户权限异常,例如 Key 所属账户的所有权已转移) | 全部 | 否 | 少见,请联系我们 | | `-1` | 服务暂时不可用 | 全部 | 是,退避 | 指数退避重试;**提交任务时遇到要先确认是否已创建**,见下文 | 请求级错误(`-1` 除外)都发生在创建任务之前:**被拒绝的提交不会创建任务,也不会扣点数**。 ### HTTP 状态码不是 200 [Section titled “HTTP 状态码不是 200”](#http-状态码不是-200) `405`(请求方法不是 `POST`)和 `404`(路径写错)说明请求没有进入业务处理,**确定没有创建任务**,修正代码后重新请求即可。 除此之外,如果收到 `502`、`504` 等非 200 状态码,或者连接超时、中断,说明请求在网络链路上出了问题,你**无法确定服务端是否已经处理**: * 查询类接口(查询平台、查询任务、任务列表):直接重试即可。 * 提交任务:先按下文「提交结果未知时」的流程确认,再决定是否重新提交。 ## 任务失败:`error_code` [Section titled “任务失败:error\_code”](#任务失败error_code) 任务的 `status` 为 `failed` 或 `canceled` 时,`error_code` 说明原因。**失败和取消的任务都不扣点数**,预占的点数会退回。 | `error_code` | `status` | 含义 | 处理建议 | | ---------------------------- | ---------- | ---------------------------- | ------------------------------------- | | `crawl_failed` | `failed` | 平台没有返回有效回答(超时、平台异常等) | 稍后重试,或换平台;时效要求不高时可改用 P2,平台不可用时会排队等待恢复 | | `credential_invalid` | `failed` | 任务派发前,提交它的 API Key 已停用、删除或过期 | 换一个有效 Key 重新提交 | | `crawler_rejected` | `failed` | 平台暂不支持或已下线 | 重新获取平台列表,换平台 | | `crawler_internal_error` | `failed` | 抓取服务内部错误,任务没有被受理 | 稍后重试 | | `crawler_submit_failed` | `failed` | 抓取服务没有受理这个任务 | 稍后重试 | | `crawler_invalid_request` | `failed` | 抓取服务拒绝了这次的请求参数 | 检查问题内容和 `country` 后重新提交 | | `crawler_method_unavailable` | `failed` | 抓取服务未开通原始结果抓取(服务端配置问题) | 请联系我们 | | `crawler_auth_failed` | `failed` | 服务端配置问题 | 请联系我们 | | `crawl_canceled` | `canceled` | 任务被取消 | 需要的话重新提交 | 下面两个值出现在**未结束**的任务上,不代表失败: | `error_code` | `status` | 含义 | | --------------------------- | ------------- | ------------------------------- | | `dispatch_uncertain` | `dispatching` | 正在确认派发结果,服务端会自行确认、不会重复派发,继续轮询即可 | | `crawler_query_unavailable` | 未结束 | 暂时无法同步执行进度,继续轮询;长时间不变化请联系我们 | 判断成败只看 status `error_code` 不为空不等于失败(见上表的 `dispatching`)。请用 `status` 判断任务是否结束、是否成功;`error_code` 只用于失败后的分支处理。遇到表里没有的 `error_code`,按「任务失败、不扣费」处理,并记录 `error_message`。 `error_message` 与请求级错误的 `msg` 格式相同,是一个 JSON **字符串**,解析后得到 `{"zh": "…", "en": "…"}` 两种语言的提示,可以写进日志或按语言展示给用户;解析失败时按原文处理。不要按文案做程序判断,分支请用 `error_code`。`raw_result.error`(以及 `result_json` 里的 `error`)格式相同。 ## 重试策略 [Section titled “重试策略”](#重试策略) | 情况 | 做法 | | ------------------------------------------------ | --------------------------------------------- | | `-1`、网络错误、非 200 状态码(查询类接口) | 指数退避重试,例如 2、4、8 秒…,最多几次 | | `1024`、`1025` | 不会创建任务,等待后重试是安全的;同时降低并发和提交速率 | | `-1`、超时、连接中断(提交任务) | **不要直接重试**,先确认是否已创建,见下节 | | `1001`、`1003`、`1022`、`1023`、`1029`、`1030`、`1031` | 不要自动重试,修正问题后再请求 | | 任务 `failed` / `canceled` | 重新提交会创建新任务,成功后才扣费;`crawl_failed` 建议间隔一段时间或换平台 | ### 提交结果未知时 [Section titled “提交结果未知时”](#提交结果未知时) 提交请求超时、连接中断或返回 `-1` 时,任务可能已经创建。直接重试会产生第二个任务,两个都成功就会扣两次点数。正确做法: 1. 调用[任务列表](../../api/list-tasks/),用 `keyword` 传入刚才的问题文本(`keyword` 最多 256 个字符,按「包含」匹配,长问题取前 256 个字符即可),`start_time` 设为提交前的时间。 2. 找到了:继续轮询那个 `task_id`。 3. 没找到:重新提交。 * Python
```python
# BASE_URL、HEADERS 的定义同快速开始
import json
import time
import requests
RETRYABLE = {-1, 1024, 1025}
class MaxAEOError(Exception):
def __init__(self, ret, msg):
self.ret = ret
try:
self.message = json.loads(msg).get("zh") or msg
except (TypeError, ValueError, AttributeError):
self.message = msg
super().__init__(f"ret={ret}: {self.message}")
def post(path, body):
resp = requests.post(BASE_URL + path, headers=HEADERS, json=body, timeout=30)
resp.raise_for_status()
data = resp.json()
if data["ret"] != 1:
raise MaxAEOError(data["ret"], data.get("msg", ""))
return data["data"]["ent"]
def get_with_retry(path, body, retries=4):
"""查询类接口:可以安全重试。"""
for attempt in range(retries + 1):
try:
return post(path, body)
except (requests.RequestException, MaxAEOError) as e:
retryable = not isinstance(e, MaxAEOError) or e.ret in RETRYABLE
if not retryable or attempt == retries:
raise
time.sleep(2 ** (attempt + 1))
def submit_safely(platform, query):
"""提交任务:只有确认没有创建过,才重新提交。"""
started = int(time.time()) - 60 # 留出时钟误差
for attempt in range(4):
try:
return post("/task/submit", {"platform": platform, "query": query})
except MaxAEOError as e:
if e.ret in (1024, 1025): # 没有创建任务,等一会儿再试
time.sleep(15 * (attempt + 1))
continue
if e.ret != -1:
raise
except requests.RequestException:
pass
# 结果未知:先找有没有刚才那次提交
found = get_with_retry("/task/key/list", {
"keyword": query.strip()[:256], "platform": platform, "start_time": started, "page_size": 5,
})
if found["items"]:
return get_with_retry("/task/get", {"task_id": found["items"][0]["task_id"]})
raise RuntimeError("提交多次未成功,请稍后再试")
```
* Node.js
```js
// BASE_URL、headers 的定义同快速开始
const RETRYABLE = new Set([-1, 1024, 1025]);
class MaxAEOError extends Error {
constructor(ret, msg) {
let message = msg;
try {
message = JSON.parse(msg).zh || msg;
} catch {}
super(`ret=${ret}: ${message}`);
this.ret = ret;
}
}
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function post(path, body) {
const resp = await fetch(BASE_URL + path, {
method: "POST",
headers,
body: JSON.stringify(body),
signal: AbortSignal.timeout(30_000),
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
const data = await resp.json();
if (data.ret !== 1) throw new MaxAEOError(data.ret, data.msg ?? "");
return data.data.ent;
}
// 查询类接口:可以安全重试
async function getWithRetry(path, body, retries = 4) {
for (let attempt = 0; ; attempt++) {
try {
return await post(path, body);
} catch (e) {
const retryable = !(e instanceof MaxAEOError) || RETRYABLE.has(e.ret);
if (!retryable || attempt === retries) throw e;
await sleep(2 ** (attempt + 1) * 1000);
}
}
}
// 提交任务:只有确认没有创建过,才重新提交
async function submitSafely(platform, query) {
const started = Math.floor(Date.now() / 1000) - 60; // 留出时钟误差
for (let attempt = 0; attempt < 4; attempt++) {
try {
return await post("/task/submit", { platform, query });
} catch (e) {
if (e instanceof MaxAEOError && (e.ret === 1024 || e.ret === 1025)) {
await sleep(15_000 * (attempt + 1)); // 没有创建任务,等一会儿再试
continue;
}
if (e instanceof MaxAEOError && e.ret !== -1) throw e;
}
// 结果未知:先找有没有刚才那次提交
const found = await getWithRetry("/task/key/list", {
keyword: Array.from(query.trim()).slice(0, 256).join(""), platform, start_time: started, page_size: 5,
});
if (found.items.length > 0) {
return getWithRetry("/task/get", { task_id: found.items[0].task_id });
}
}
throw new Error("提交多次未成功,请稍后再试");
}
```
## 联系我们排查问题 [Section titled “联系我们排查问题”](#联系我们排查问题) 需要我们协助排查时,请提供: * `task_id`(任务相关问题); * 请求时间(精确到分钟)与调用的接口; * 响应头里的请求追踪 ID `ipalfish-trace-id`(如有); * 完整的 `ret`、`msg` 或 `error_code`、`error_message`。 **不要**把完整的 API Key 发给任何人,包括我们的工作人员。 ## 相关页面 [Section titled “相关页面”](#相关页面) [任务生命周期](../task-lifecycle/)状态流转、轮询频率与避免重复提交。 [限流与配额](../rate-limits/)1024、1025 背后的并发与速率限制。
# 平台、优先级与国家
> 开放 API 支持的 AI 平台标识与区域、平台状态(正常/波动/维护)的含义、P1 优先与 P2 标准两档优先级的区别和选择方法、country 参数如何影响抓取出口,以及 thinking 思考模式在各平台的支持情况。
提交任务时,`platform` 决定向哪个 AI 平台提问,`priority` 决定排队档位和单价,`country` 决定海外平台的抓取出口,`thinking` 决定是否请求平台的思考模式。本页逐一说明。 ## 支持的平台 [Section titled “支持的平台”](#支持的平台) `platform` 参数使用下表中的**平台标识**(不区分大小写)。 | 平台标识 | 平台 | 区域 | | -------------------- | -------------- | -- | | `doubao` | 豆包 | 国内 | | `deepseek` | DeepSeek | 国内 | | `kimi` | Kimi | 国内 | | `yuanbao` | 腾讯元宝 | 国内 | | `qianwen` | 千问 | 国内 | | `wenxin` | 文心一言 | 国内 | | `zhipu` | 智谱清言 | 国内 | | `xunfei` | 讯飞星火 | 国内 | | `metaso` | 秘塔 AI 搜索 | 国内 | | `xiaohongshu` | 小红书点点 | 国内 | | `chatgpt` | ChatGPT | 海外 | | `gemini` | Gemini | 海外 | | `claude` | Claude | 海外 | | `perplexity` | Perplexity | 海外 | | `copilot` | Copilot | 海外 | | `grok` | Grok | 海外 | | `google-ai-mode` | Google AI Mode | 海外 | | `google-ai-overview` | Google AI 概览 | 海外 | 以接口实时返回为准 平台会随上下线调整,上表只是写作时的快照。程序里请调用[查询平台列表](../../api/list-platforms/)获取当前开放的平台,不要把列表写死在代码里。没有配置单价或已下线的平台不会出现在接口返回里;维护中的平台会出现,但 `platform_status` 为 `maintenance`。向这两类平台提交都返回 `1029`。 ## 平台状态 [Section titled “平台状态”](#平台状态) [查询平台列表](../../api/list-platforms/)的每一项都带 `platform_status` 和近 24 小时的统计: | `platform_status` | 控制台显示 | 含义 | 能否提交 | | ----------------- | ----- | ------------------------------------------- | ----------------------- | | `normal` | 正常 | 没有被标记为波动或维护,且近 24 小时内最近一次到达终态的任务不是失败 | 可以 | | `degraded` | 波动 | 近期出现失败(最近一次失败不早于最近一次成功),或被人工标记为波动;可能更慢或偶发失败 | 可以,失败不扣费 | | `maintenance` | 维护中 | 暂停接单 | 不可以,提交直接返回 `1029`,不创建任务 | 统计字段这样读: * `sample_count`:近 24 小时所有调用中,该平台到达终态的任务数(不含 API Key 失效、参数被拒、取消这类非平台原因)。 * `has_stats`:样本数达到统计门槛时为 `true`,此时 `success_rate`(0–1)和 `p50_duration_seconds` 才有意义;为 `false` 时这两项为 `0`,不要展示成「成功率 0%」。 * **`normal` 且 `sample_count` 为 0**,表示近 24 小时没人调用过这个平台,只能说明「没有观察到失败」,不等于已验证运行正常。控制台对这种情况显示「暂无样本」。 * 统计每隔几分钟重新计算一次,`stats_updated_at` 是计算时间。统计不区分是否开启了思考模式。 ## 优先级:P1 与 P2 [Section titled “优先级:P1 与 P2”](#优先级p1-与-p2) `priority` 有两档,单价不同(见[计费与点数](../billing/)): | | P1 优先(`priority: 1`) | P2 标准(`priority: 2`,默认) | | ---------- | --------------------- | -------------------------------------- | | 出队顺序 | 先于 P2 | P1 取完后再取 | | 可用产能 | 可以用满 | 最多用一半,其余留给 P1 | | 平台账号暂时不可用时 | 不长时间等待,可能较快以失败结束(不扣费) | 留在队列里等恢复,期间保持 `pending` | | 失败重试 | 在同一次执行内重试 | 可重试的失败回到队列再执行一次(`running` → `pending`) | | 适合 | 对时效敏感:用户在等结果、实时看板 | 对时效不敏感:每日批量监控、离线分析 | | 单价 | 较高 | 较低 | * 不传或传 `0` 按 **P2** 执行和计价;传 `1`、`2` 以外的值返回 `1001`。 * 控制台的[在线调试](../../console/playground/)固定按 P1 执行和计价。 * 实际执行的档位以结果里的 `raw_result.priority` 为准,对账时请用它。 * 两档都**不承诺排队时长**。P1 只是排在前面,平台整体繁忙时同样需要等待。 **怎么选**:每天定时跑的批量监控用 P2,成本更低,晚一点出结果不影响;有人在界面上等结果、或下游流程卡在这一步时用 P1。 ## 出口国家:`country` [Section titled “出口国家:country”](#出口国家country) `country` 是可选的两位字母国家代码(ISO 3166-1 alpha-2,如 `US`、`JP`、`DE`,不区分大小写)。 * **海外平台**:决定访问平台时使用哪个国家的网络出口,AI 的回答(语言、推荐的品牌和信源)可能随地区变化。不传时由服务端决定,目前为美国出口;海外平台不支持中国大陆出口,传 `CN` 也会使用美国出口。 * **国内平台**:一律从中国大陆访问,`country` 不改变出口。 * 不保证每个国家都有专属出口,没有配置该国家出口时会使用默认出口。响应里的 `country` 是你请求的值(转为大写),不代表已验证的实际出口。 * 指定国家**不额外收费**。 一般情况下不需要传 `country`。只有在研究「某个国家的用户问 ChatGPT 会得到什么回答」这类场景时才需要指定。 ## 思考模式:`thinking` [Section titled “思考模式:thinking”](#思考模式thinking) `thinking` 是可选的布尔值,默认 `false`(关闭),平台按快速档回答。传 `true` 时请求平台的思考模式,即平台网页上「深度思考」「专家」这类模式的默认强度,不包括深度研究等更高的档位。 * **只是请求,不保证生效。** 没有思考开关的平台传 `true` 也会按关闭执行,不报错,照常计费。实际是否开启以结果里的 `raw_result.thinking` 为准:为 `true` 表示开启;没有开启、平台没有开关或任务失败时,这个字段不出现。任务对象外层的 `thinking` 只是你提交时请求的值。 * **明显更慢。** 开启后平台要先推理再作答,耗时通常明显长于关闭时,可能超过两分钟;使用 `wait_seconds` 时也更容易在任务结束前就返回,需要继续轮询。 * **不加价。** 按同一平台、同一档位(P1 / P2)的单价计费,见[计费与点数](../billing/)。 * 必须传 JSON 布尔值:传字符串 `"true"` 会返回 `1001`。 各平台的情况(2026 年 10 月): | 平台 | 关闭(默认) | 开启(`"thinking": true`) | | -------- | ----------- | ---------------------- | | DeepSeek | 深度思考关闭,联网搜索 | 深度思考开启,联网搜索 | | 豆包 | 快速 | 专家 | | Kimi | 思考强度「标准」 | 思考强度「进阶」 | | 腾讯元宝 | 快速回答 | 专家模式(网页默认) | | 千问 | 快速 | 思考研究 | | 智谱清言 | 快速 | 深度 | | 秘塔 AI 搜索 | 极速 | 快思考(网页默认) | | 讯飞星火 | 快速 | 推理 | | ChatGPT | 思考关闭 | 思考开启 | 文心一言、小红书点点、Google AI 概览、Copilot、Grok、Perplexity、Gemini、Google AI Mode、Claude 没有思考开关,传 `true` 也按关闭执行。 以结果里的 raw\_result.thinking 为准 上表是 2026 年 10 月的情况,平台改版可能随时变化,[查询平台列表](../../api/list-platforms/)也不返回平台是否支持思考。程序里请读取每个任务的 `raw_result.thinking`,不要按上表写死。腾讯元宝、秘塔 AI 搜索在网页上默认使用的是开启思考的档位;腾讯元宝的两档使用不同的模型。 开启思考且实际生效的任务,结果里是这样(节选):
```json
{
"thinking": true,
"task_id": "task_…",
"platform": "deepseek",
"status": "succeeded",
"…": "…",
"raw_result": {
"…": "…",
"agentSteps": [
{ "type": "thinking", "content": "……" },
{ "type": "search", "queries": ["……"] }
],
"thinking": true
}
}
```
关闭思考时,`raw_result` 里不出现 `thinking`;思考步骤怎么读见[解析回答结果](../results/#%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B-agentsteps)。 ## 平台之间的结果差异 [Section titled “平台之间的结果差异”](#平台之间的结果差异) 不同平台返回的内容丰富度不同:有的平台提供思考与搜索过程,有的会在回答里插入视频、商品卡片,有的不区分来源是否被正文引用。具体差异和解析方法见[解析回答结果](../results/)。 ## 相关页面 [Section titled “相关页面”](#相关页面) [查询平台列表](../../api/list-platforms/)接口参数、返回字段与示例。 [计费与点数](../billing/)两档单价、预占与扣点规则。
# 上线检查清单
> 把 MaxAEO 开放 API 接入生产环境前的逐项核对清单,覆盖 API Key 安全、异步任务与重试、限流、成本控制、结果解析与监控告警。
从脚本走向生产前,按下面的清单逐项核对。每一项都链接到详细说明。 ## 安全 [Section titled “安全”](#安全) * [ ] API Key 只存放在服务端的环境变量或密钥管理服务中,没有出现在前端代码、App、代码仓库和日志里。见[认证与 API Key](../../authentication/#%E5%AE%89%E5%85%A8%E5%BB%BA%E8%AE%AE)。 * [ ] 生产、测试使用不同的 Key,并为非长期用途的 Key 设置了有效期。 * [ ] 团队知道 Key 泄露时怎么处理:在控制台重置并选择「立即失效」,或停用。见[管理 API Key](../../console/api-keys/)。 * [ ] 有 Key 轮换流程:重置时给旧 Key 留出宽限期,新 Key 部署完成后再让旧 Key 失效。 ## 异步任务与可靠性 [Section titled “异步任务与可靠性”](#异步任务与可靠性) * [ ] 提交后立即持久化 `task_id`,并在自己的系统里记录提交时间和参数。 * [ ] 轮询间隔约 15 秒;未结束的任务由定时循环批量查询,不为每个任务单独阻塞等待。见[任务生命周期](../task-lifecycle/#%E8%BD%AE%E8%AF%A2%E5%A4%9A%E4%B9%85%E6%9F%A5%E4%B8%80%E6%AC%A1)。 * [ ] 业务超时不等于失败:超时后保留 `task_id`,之后仍能取回结果。 * [ ] 判断任务成败只看 `status`,不因 `error_code` 非空就判失败。 * [ ] 提交请求超时、断连或返回 `-1` 时,先用任务列表确认是否已创建,**不盲目重复提交**。见[错误处理](../errors/#%E6%8F%90%E4%BA%A4%E7%BB%93%E6%9E%9C%E6%9C%AA%E7%9F%A5%E6%97%B6)。 * [ ] 使用 `wait_seconds` 时,客户端 HTTP 超时大于 `wait_seconds`,并能处理返回非终态的情况。 ## 请求与错误处理 [Section titled “请求与错误处理”](#请求与错误处理) * [ ] 用响应体的 `ret` 判断请求成败,而不是 HTTP 状态码;同时处理非 200 状态码和网络错误。 * [ ] 解析 `msg`(JSON 字符串)得到可展示的提示,解析失败时回退为原文。 * [ ] 请求体只包含接口定义的字段,字段名使用下划线风格(`task_id`、`wait_seconds`)。 * [ ] 解析响应时忽略不认识的字段,以兼容今后新增的字段。 * [ ] `-1`、`1024`、`1025` 做了退避重试;`1001`、`1003`、`1022`、`1023`、`1029`、`1030`、`1031` 不自动重试,而是告警或提示。 * [ ] 遇到未知的 `error_code` 按「任务失败、不扣费」处理,并记录 `error_message`。 ## 限流与成本 [Section titled “限流与成本”](#限流与成本) * [ ] 批量提交时在客户端节流,低于每分钟提交上限;遇到 `1024` / `1025` 会退避。见[限流与配额](../rate-limits/)。 * [ ] 平台列表从接口动态获取,不写死;`maintenance` 状态的平台不提交。 * [ ] 按场景选择优先级:批量、定时任务用 P2,时效敏感的用 P1。见[平台、优先级与国家](../platforms/#%E4%BC%98%E5%85%88%E7%BA%A7p1-%E4%B8%8E-p2)。 * [ ] 余额低于预警线时有告警(控制台「用量统计」可查看余额与到期时间),避免任务因 `1023` 中断。见[计费与点数](../billing/)。 ## 结果解析 [Section titled “结果解析”](#结果解析) * [ ] 读取 `raw_result` 前判断它是否存在;对省略的零值字段补默认值。 * [ ] `elapsedMs` 按字符串解析为数字。 * [ ] `cited` 按三态处理,字段不存在不当作 `false`。见[解析回答结果](../results/#cited-%E7%9A%84%E4%B8%89%E7%A7%8D%E5%8F%96%E5%80%BC)。 * [ ] 使用思考模式时,以 `raw_result.thinking` 判断实际是否开启,不以提交的 `thinking` 为准。见[思考模式](../platforms/#%E6%80%9D%E8%80%83%E6%A8%A1%E5%BC%8Fthinking)。 * [ ] 使用 `url` 前校验是否为 `http(s)` 链接。 * [ ] 需要长期保存的图片已自行转存(`imageUrl` 会过期)。 * [ ] 展示给用户前按需清洗正文里的平台引用标记。 ## 可观测性 [Section titled “可观测性”](#可观测性) * [ ] 记录每次请求的接口、`ret`、耗时、`task_id`,以及响应头 `ipalfish-trace-id`(如有),便于排查。 * [ ] 监控任务失败率与 `error_code` 分布,按平台拆分;某个平台持续 `crawl_failed` 时考虑暂时换平台。 * [ ] 定期与控制台「调用日志」「用量统计」对账。 ## 相关页面 [Section titled “相关页面”](#相关页面) [API 概述](../../api/)请求与响应的通用约定。 [常见问题](../../faq/)接入过程中的高频疑问。
# 限流与配额
> MaxAEO 开放 API 的并发任务上限、每分钟提交次数、API Key 数量、请求体与参数长度等限制,各自的计算口径、触发后的错误码,以及在客户端控制并发与速率的做法。
为保证各账户之间公平使用平台产能,开放 API 对**提交任务**设有并发和速率限制,对请求本身设有大小限制。 ## 限制一览 [Section titled “限制一览”](#限制一览) | 限制 | 默认值 | 计算范围 | 超出时 | | ---------------- | -------- | ------------------------------------------- | ------------ | | 同时进行的任务数 | 5 | 账户内状态为 `queued`、`dispatching`、`running` 的任务 | 提交返回 `1024` | | 每分钟提交次数 | 120 | 账户内最近 60 秒提交的任务(滚动窗口) | 提交返回 `1025` | | API Key 数量 | 10 | 账户内未删除的 Key(含停用、过期的) | 控制台无法创建新 Key | | 请求体大小 | 64 KiB | 单个请求 | 返回 `1001` | | `query` 长度 | 4096 个字符 | 单个任务 | 返回 `1001` | | `wait_seconds` | 0–120 秒 | 单个请求 | 返回 `1001` | | 任务列表 `page_size` | 最大 100 | 单个请求 | 返回 `1001` | * 你账户当前生效的并发、每分钟请求数和 Key 数量上限,以控制台「用量统计 → 额度与限制」显示为准。需要更高的额度请联系商务。 * 限制按**账户**计算:同一账户下所有 API Key、MCP 调用和控制台的在线调试共享这些额度。 * **只有提交任务计入并发和速率。** 查询平台列表、查询任务、任务列表不占用这两项额度,但请保持合理的轮询频率(建议每个任务 15 秒查一次)。 * 被限流拒绝的提交**不会创建任务**,也不扣点数,等待后重试是安全的。 ## 并发上限的口径 [Section titled “并发上限的口径”](#并发上限的口径) 并发只统计 `queued`、`dispatching`、`running` 三种状态,**不包括 `pending`**(已派发、在平台队列中排队)。也就是说: * 提交后,任务一旦被派发进入 `pending`,就不再占用并发额度。 * 大量 P2 任务在平台繁忙时长时间 `pending`,不会把你的并发额度占满。 * 真正占用额度的是「刚提交还没派发」和「正在执行」的任务。 ## 在客户端控制速率 [Section titled “在客户端控制速率”](#在客户端控制速率) 批量提交时,与其等服务端拒绝,不如在客户端主动控制: * **节流**:两次提交之间留出间隔,让每分钟提交数低于上限(例如每 0.6 秒最多提交一个)。 * **遇到 `1024` / `1025` 时退避**:暂停一段时间(如 15 秒起,逐次加倍)后再提交同一个任务。 * **提交和轮询分开**:用一个队列负责提交,另一个定时循环批量查询未结束的任务。 - Python
```python
# 依次提交一批问题:主动节流,遇到限流时退避重试
import time
SUBMIT_INTERVAL = 0.6 # 秒,约每分钟 100 次
def submit_batch(platform, queries):
task_ids = []
for query in queries:
delay = 15
while True:
try:
task = post("/task/submit", {"platform": platform, "query": query})
task_ids.append(task["task_id"])
break
except MaxAEOError as e:
if e.ret not in (1024, 1025):
raise
time.sleep(delay) # 没有创建任务,等待后重试同一个问题
delay = min(delay * 2, 120)
time.sleep(SUBMIT_INTERVAL)
return task_ids
```
- Node.js
```js
// 依次提交一批问题:主动节流,遇到限流时退避重试
const SUBMIT_INTERVAL = 600; // 毫秒,约每分钟 100 次
async function submitBatch(platform, queries) {
const taskIds = [];
for (const query of queries) {
let delay = 15_000;
for (;;) {
try {
const task = await post("/task/submit", { platform, query });
taskIds.push(task.task_id);
break;
} catch (e) {
if (!(e instanceof MaxAEOError) || (e.ret !== 1024 && e.ret !== 1025)) throw e;
await sleep(delay); // 没有创建任务,等待后重试同一个问题
delay = Math.min(delay * 2, 120_000);
}
}
await sleep(SUBMIT_INTERVAL);
}
return taskIds;
}
```
示例中的 `post`、`MaxAEOError`、`sleep` 见[错误处理](../errors/#%E6%8F%90%E4%BA%A4%E7%BB%93%E6%9E%9C%E6%9C%AA%E7%9F%A5%E6%97%B6)。生产环境里,提交遇到超时或 `-1` 时还要按该页的方法先确认任务是否已创建。 ## 相关页面 [Section titled “相关页面”](#相关页面) [错误处理](../errors/)1024、1025 等错误码的处理与重试策略。 [计费与点数](../billing/)限流之外,余额不足会返回 1023。
# 解析回答结果
> 任务成功后如何读取 AI 回答:answer、result_json 与 raw_result 的关系,引用来源与 cited 三态,正文里的平台引用标记,执行过程 agentSteps、多媒体卡片 mediaCards 与分享链接,以及判断品牌是否被引用的示例代码。
任务到达 `succeeded` 后,回答和引用来源都在任务对象里。本页讲怎么读、哪些地方容易踩坑。字段的完整定义见[任务对象](../../api/task-object/)。 ## 同一份结果的三种形态 [Section titled “同一份结果的三种形态”](#同一份结果的三种形态) | 字段 | 内容 | 什么时候用 | | ------------- | ----------------------------------------- | ---------------------------------- | | `answer` | 回答正文(Markdown),等于 `raw_result.rawContent` | 只需要正文时 | | `raw_result` | 结构化结果:正文、引用来源、执行过程、卡片、耗时等 | **推荐**,大多数场景用它 | | `result_json` | 原始结果的 JSON **字符串** | 需要完整留档,或要读取 `raw_result` 尚未收录的新字段时 | 三者内容重复,单个字段最大可达 8 MiB,查询响应可能比较大。只有任务拿到了结果(成功,或平台执行失败)时才有 `raw_result`;排队中、被取消或派发失败的任务**没有这个字段**,读取前先判断是否存在。 ### `raw_result` 的编码规则 [Section titled “raw\_result 的编码规则”](#raw_result-的编码规则) `raw_result` 沿用 protobuf 的 JSON 编码,和外层字段的风格不同: * 字段名是**小驼峰**:`rawContent`、`shareLink`、`agentSteps`,而外层是 `share_link` 这样的下划线风格。 * **零值字段会被省略**:`success`、`thinking` 为 `false`,空字符串、空数组、`rank` 为 0 时都不出现。读取时请自行补默认值,例如 Python 用 `raw.get("references", [])`。 * `elapsedMs`(执行耗时,毫秒,不含排队)是**字符串**,如 `"48213"`,需要自己转成数字。 * `completedAt` 是 ISO 8601 格式的 UTC 时间,如 `2026-10-26T12:41:37.512Z`。 ## 回答正文 [Section titled “回答正文”](#回答正文) `rawContent`(以及 `answer`)是平台返回的 Markdown 原文,**平台自己的引用标记和卡片占位符原样保留,不做转换**。常见写法: | 平台 | 正文里的标记(示例) | | -------- | ----------------------------------------------------------------------------------------------------- | | DeepSeek | `[citation:3]`;开启[思考模式](../platforms/#%E6%80%9D%E8%80%83%E6%A8%A1%E5%BC%8Fthinking)时为 `[reference:3]` | | 腾讯元宝 | `[citation:2]`;卡片占位符 `[](@replace=media_…)` | | Kimi | `[…]` 包裹的引用 | | 智谱清言 | `【turn0search2】` | | 秘塔 AI 搜索 | `[[2]]`;图片以 Markdown 图片语法留在正文 | | 文心一言 | `^2^`(不常见),也可能直接写成 Markdown 链接 | | 千问 | 卡片占位符,如 `[(video_note_list_1)]` | | 豆包、讯飞星火 | 正文中不标注引用位置 | | 小红书点点 | `` 下划线标签、零宽空格等平台原文 | 标记格式由平台决定 上表是 2026 年 10 月的观测结果,平台改版可能随时改变写法。展示给用户前可以按需清洗这些标记;但不要把标记格式当作强校验条件,判断引用关系请使用 `references` 和 `cited`。 ## 引用来源 `references` [Section titled “引用来源 references”](#引用来源-references) `references` 是平台在这次回答中**搜到或读过的全部来源**,按链接去重。被正文引用的排在前面,之后是搜到但没引用的。每一项: | 字段 | 说明 | | ----------------- | --------------------------------------------- | | `rank` | 平台展示顺序,从 1 开始 | | `title` | 标题 | | `url` | 链接;平台的跳转链接会尽量还原成原始地址 | | `snippet` | 摘要,可能为空 | | `source` | 来源名称(站点名),可能为空 | | `domain` | 域名,可能为空 | | `contentPlatform` | 识别出的内容平台(如某个内容社区),识别不出为空 | | `cited` | 是否被正文引用,**三态**,见下 | | `publishTime` | 发布时间:ISO 8601、`YYYY-MM-DD` 或「1天前」这样的平台原文,可能为空 | | `author` | 作者(笔记作者、视频 UP 主等),可能为空 | ### `cited` 的三种取值 [Section titled “cited 的三种取值”](#cited-的三种取值) | 取值 | 含义 | | --------- | -------------------------- | | `true` | 回答正文引用了这个来源 | | `false` | 平台搜到或读过,但正文没引用 | | **字段不存在** | 平台不区分是否引用,**不能当作 `false`** | 各平台的情况(2026 年 10 月观测): * 豆包、Kimi、腾讯元宝、智谱清言、秘塔 AI 搜索、文心一言:区分 `true` / `false`。 * DeepSeek:能对应到具体网页的标 `true`,只能对应到一批搜索结果的不设。 * 讯飞星火:当前平台不返回搜索来源,`references` 取自模型写在回答里的链接,`cited` 恒为 `true`,除标题外没有其他信息。 * 千问、小红书点点和海外平台:不设 `cited`。 ### 读取时的注意事项 [Section titled “读取时的注意事项”](#读取时的注意事项) * **`url` 不一定是合法链接。** 少数平台的来源没有链接(如地图类插件),`url` 为空;个别平台会给出平台内部 ID。使用前请校验是否以 `http://` 或 `https://` 开头。 * **`domain` 可能为空。** 需要按域名统计时,`domain` 为空可以从 `url` 解析。 * **`references` 为空是正常结果。** 有的问题平台没有联网搜索,回答就不带来源。 ## 示例:判断你的网站是否被引用 [Section titled “示例:判断你的网站是否被引用”](#示例判断你的网站是否被引用) 下面的代码找出回答中引用了指定域名的来源,并区分「被正文引用」「搜到未引用」「平台不区分」三种情况: * Python
```python
from urllib.parse import urlparse
def match_domain(ref, domain):
host = ref.get("domain") or urlparse(ref.get("url", "")).hostname or ""
return host == domain or host.endswith("." + domain)
def citation_report(task, domain):
refs = (task.get("raw_result") or {}).get("references", [])
hits = [r for r in refs if match_domain(r, domain)]
return {
"cited": [r for r in hits if r.get("cited") is True],
"not_cited": [r for r in hits if r.get("cited") is False],
"unknown": [r for r in hits if "cited" not in r],
}
report = citation_report(task, "example.com")
print({k: len(v) for k, v in report.items()})
```
* Node.js
```js
function matchDomain(ref, domain) {
let host = ref.domain ?? "";
if (!host) {
try {
host = new URL(ref.url ?? "").hostname;
} catch {
host = "";
}
}
return host === domain || host.endsWith("." + domain);
}
function citationReport(task, domain) {
const hits = (task.raw_result?.references ?? []).filter((r) => matchDomain(r, domain));
return {
cited: hits.filter((r) => r.cited === true),
notCited: hits.filter((r) => r.cited === false),
unknown: hits.filter((r) => r.cited === undefined),
};
}
const report = citationReport(task, "example.com");
console.log(Object.fromEntries(Object.entries(report).map(([k, v]) => [k, v.length])));
```
## 执行过程 `agentSteps` [Section titled “执行过程 agentSteps”](#执行过程-agentsteps) 部分平台会提供回答的执行过程,按发生顺序排列。按 `type` 读取对应字段: | `type` | 读取字段 | 内容 | | ---------- | -------------------------- | ------------------------------------------------------------------------ | | `thinking` | `content`、`summary` | 思考正文与平台给出的思考摘要 | | `search` | `name`、`queries`、`results` | AI 实际使用的**检索词**,以及每次搜索返回的结果(`title`、`url`、`siteName`、`snippet`),结果未必都被引用 | | `tool` | `name`、`args` | 其他工具调用及其参数原文 | `search` 步骤的 `queries` 很有价值:它告诉你 AI 为了回答这个问题实际去搜了什么词,可以据此调整内容的关键词布局。平台在该档位不提供执行过程时,`agentSteps` 不出现。 `thinking` 步骤多数只在开启[思考模式](../platforms/#%E6%80%9D%E8%80%83%E6%A8%A1%E5%BC%8Fthinking)时出现;关闭时,千问、智谱清言、秘塔 AI 搜索等平台也可能给出简短的思考或进度文字。要判断这次回答是否开启了思考,请看 `raw_result.thinking`,不要看有没有 `thinking` 步骤。 ## 多媒体卡片 `mediaCards` [Section titled “多媒体卡片 mediaCards”](#多媒体卡片-mediacards) 回答中的视频、图片、商品、推荐榜单等卡片,按在回答中出现的先后排列: * `type`:`image`、`video`、`product`、`ranking`、`other`。 * `anchor`:卡片在 `rawContent` 里的占位符原文,可据此定位卡片位置;平台不在正文放占位符时为空,只能按先后顺序排列。 * `items[]`:卡片里的每一项,含 `title`、`url`、`imageUrl`、`source`、`author`、`duration`、`price`、`rating`、`publishTime`、`description`,未取到的字段不出现。 图片链接会过期 `imageUrl` 通常是平台带签名的临时链接,过一段时间会失效。需要长期留存时请保存 `url`(视频、笔记、商品页面地址),或在拿到结果后尽快自行转存图片。 ## 分享链接 [Section titled “分享链接”](#分享链接) `share_link`(`raw_result.shareLink`)是平台上这次会话的分享页,可以让人在平台上复查原始回答。平台不提供或创建分享失败时为空字符串。注意:小红书点点的分享链接只能在小红书 App 内打开,网页打开是空白页。 `raw_result.conversationId`、`messageId` 是平台侧的会话与消息 ID,仅供对照,开放 API 不支持基于它们继续对话。 ## 失败任务的结果 [Section titled “失败任务的结果”](#失败任务的结果) 平台执行失败(`error_code` 为 `crawl_failed`)的任务也会带 `raw_result`,其中 `success` 字段不出现(即 `false`),`rawContent` 为空,`error` 是失败说明(与 `error_message` 相同的 `{"zh","en"}` JSON 字符串)。判断失败请看外层的 `status` 与 `error_code`,见[错误处理](../errors/#%E4%BB%BB%E5%8A%A1%E5%A4%B1%E8%B4%A5error_code)。 ## 相关页面 [Section titled “相关页面”](#相关页面) [任务对象](../../api/task-object/)外层字段与 raw\_result 全部子结构的定义。 [平台、优先级与国家](../platforms/)各平台的区域与状态。
# 任务生命周期
> 开放 API 的任务是异步执行的。本页说明 queued、dispatching、pending、running、succeeded、failed、canceled 七种状态的含义与流转、轮询频率、同步等待 wait_seconds,以及结果未知时如何避免重复提交。
每次[提交任务](../../api/submit-task/)都会创建一个新任务,并立即返回 `task_id`。之后任务在服务端依次经历派发、排队、执行,最终停在一个**终态**。你通过[查询任务](../../api/get-task/)读取它的最新状态。 ## 状态一览 [Section titled “状态一览”](#状态一览) | `status` | 含义 | 终态 | `credits` | | ------------- | ------------------- | -- | --------- | | `queued` | 已受理并保存,等待派发 | | 预占 | | `dispatching` | 正在派发,或正在确认派发结果 | | 预占 | | `pending` | 已派发,在平台队列中排队 | | 预占 | | `running` | 正在向 AI 平台提问并抓取回答 | | 预占 | | `succeeded` | 拿到了回答 | ✓ | 扣除 | | `failed` | 失败,原因见 `error_code` | ✓ | 0(退回) | | `canceled` | 任务被取消 | ✓ | 0(退回) | 只有 `succeeded`、`failed`、`canceled` 是终态,正常情况下到达后不再变化(极少数情况下,运维人工重跑会用更新的结果覆盖终态,对账以最新一次查询为准)。点数规则见[计费与点数](../billing/)。
```text
提交 ──▶ queued ──▶ dispatching ──▶ pending ⇄ running ──▶ succeeded
──▶ failed
──▶ canceled
```
几点需要注意: * **任务可能在多个阶段失败。** 派发前 API Key 已失效(`queued` → `failed`)、派发被拒绝(`dispatching` → `failed`)、平台抓取失败(`running` → `failed`);排队或执行中的任务也可能被取消(→ `canceled`)。 * **`pending` 与 `running` 可能往返。** P2 任务遇到可重试的失败(网络、平台临时异常)会回到队列再执行一次,此时 `started_at` 会清零,重新开始执行时再记录。 * **`dispatching` 不是失败。** 派发结果需要确认时,任务会停留在 `dispatching`,`error_code` 显示 `dispatch_uncertain`。服务端会自行确认,不会重复派发。**判断成败只看 `status`,不要因为 `error_code` 非空就当作失败。** * **成功也可能内容很少。** `succeeded` 只表示拿到了平台的回答;引用来源为空、回答很短都可能是正常结果(有的问题平台不联网搜索)。 ## 时间预期 [Section titled “时间预期”](#时间预期) * **抓取本身**通常需要几十秒到两分钟,视平台和回答长度而定;开启[思考模式](../platforms/#%E6%80%9D%E8%80%83%E6%A8%A1%E5%BC%8Fthinking)后通常明显更慢。不同平台差异较大,可参考[平台列表](../../api/list-platforms/)返回的 `p50_duration_seconds`(近 24 小时成功任务从提交到完成的中位耗时,含排队)。 * **排队时间没有上限,也不承诺 SLA。** 平台繁忙或平台账号暂时不可用时,P2 任务会留在队列里等待恢复,可能等待较久;P1 先出队,但也不保证几秒内开始。两档的区别见[平台、优先级与国家](../platforms/#%E4%BC%98%E5%85%88%E7%BA%A7p1-%E4%B8%8E-p2)。 * **服务端不设执行截止时间。** 任务不会因为等太久被自动判失败,也不会因为过了 `monitor_date` 当天而失效。 ## 轮询:多久查一次 [Section titled “轮询:多久查一次”](#轮询多久查一次) 服务端每 15 秒左右与执行方同步一次未完成任务的进度,[查询任务](../../api/get-task/)读取的是同步后保存的状态。所以: * **建议每 15 秒查询一次。** 查得更勤通常只会拿到同一个状态。 * 大量任务时,用一个定时循环批量查询各个未完成的 `task_id`,不必为每个任务单独起一个等待线程。 * 你可以设置自己的业务超时(例如 30 分钟后先不等了),但**不要把超时当作失败**:任务仍会继续执行,之后随时可以用 `task_id` 取回结果。 * 查询本身不消耗点数。 ## 同步等待 `wait_seconds` [Section titled “同步等待 wait\_seconds”](#同步等待-wait_seconds) 不想自己写轮询时,提交时可以传 `wait_seconds`(0–120 秒)。服务端会在这段时间内每 2 秒检查一次任务,任务到达终态或时间用完就返回当时的任务。 * `0`(默认):不等待,立即返回 `queued`。 * 等待到时间仍未结束,会返回非终态的任务,你仍需要按 `task_id` 继续轮询。 * 把客户端的 HTTP 超时设得比 `wait_seconds` 更长(例如再多留 15 秒)。实际能等多久还受网络链路上代理超时的限制;如果连接被中途断开,任务不受影响,按下一节的方法找回 `task_id` 继续查询即可。 * 同步等待只影响**这次 HTTP 请求何时返回**,不会延长或缩短任务的执行时间,也不影响计费。 ## 避免重复提交 [Section titled “避免重复提交”](#避免重复提交) **每次调用提交接口都会创建一个新任务**,成功后各自计费;服务端不会按问题内容去重。所以当你不确定上一次提交是否成功时(例如请求超时、连接中断、进程崩溃),**不要直接重试提交**,而是: 1. 调用[任务列表](../../api/list-tasks/),用 `keyword` 传入问题文本(最多 256 个字符,长问题取前 256 个字符),或用 `start_time` / `end_time` 限定提交时间,找出刚才那次提交的 `task_id`。 2. 找到了就继续轮询它;确认没有,再重新提交。 在你自己的系统里,建议先落库「待提交」记录,拿到 `task_id` 后立刻回写,这样任何时候都能对上账。 ## `monitor_date` 是什么 [Section titled “monitor\_date 是什么”](#monitor_date-是什么) `monitor_date` 是任务的业务日期(`YYYY-MM-DD`,北京时间),默认是提交当天。它用于给任务打上「属于哪一天的监控」的标签,便于你按天归档和对账: * 它**不是**计划执行时间:任务提交后就会进入队列,不会等到那一天才执行。 * 它**不是**截止时间:过了那一天任务照常执行。 * 跨时区系统可以传带时区的 RFC 3339 时间(如 `2026-10-26T09:30:00-07:00`),服务端会换算成北京时间的日期。 ## 没有回调 [Section titled “没有回调”](#没有回调) 目前不提供 Webhook 回调,任务结果只能通过轮询获取。 ## 相关页面 [Section titled “相关页面”](#相关页面) [查询任务](../../api/get-task/)按 task\_id 读取任务状态与结果。 [错误处理](../errors/)failed 状态下各个 error\_code 的含义与处理。
# 接入 MCP
> MaxAEO 开发者平台的 MCP 服务器把开放 API 包装成 4 个工具,用 API Key 即可在 Claude Code、Cursor、VS Code、Cherry Studio 等支持 Streamable HTTP 的客户端中直接让 AI 向豆包、DeepSeek 等平台提问。
MCP(Model Context Protocol)是 AI 客户端调用外部工具的开放协议。MaxAEO 的 MCP 服务器把四个开放接口包装成工具,接入后你可以直接对 AI 助手说「帮我问问豆包和 DeepSeek 怎么回答这个问题,看看有没有引用我们官网」,由它完成提交、等待和读取结果。 | 项目 | 值 | | ----- | --------------------------------------------------------------------------- | | 地址 | `https://maxaeo.cn/geoapi/geodata/developer/mcp` | | 传输方式 | Streamable HTTP(无状态,仅返回 JSON) | | 鉴权 | 请求头 `Authorization: Bearer ` | | 工具 | `list_platforms`、`submit_task`、`get_task`、`list_tasks`,见 [MCP 工具参考](tools/) | | 计费与限流 | 与开放 API 完全一致:成功的任务扣点数,共用账户的余额与限流额度 | 客户端需要支持自定义请求头 服务器用 API Key 鉴权,不支持 OAuth。客户端必须能为远程 MCP 服务器配置 `Authorization` 请求头;只支持 stdio 的客户端可以通过 `mcp-remote` 桥接,见下文。 ## 准备 API Key [Section titled “准备 API Key”](#准备-api-key) 在[开发者控制台](https://maxaeo.cn/developers/) → **API Key** 页创建一个 Key,建议单独为 MCP 创建(如命名为「MCP - 我的电脑」),方便在用量统计里区分,也便于单独停用。见[管理 API Key](../console/api-keys/)。 ## 配置客户端 [Section titled “配置客户端”](#配置客户端) * Claude Code 在终端执行:
```bash
claude mcp add --transport http maxaeo https://maxaeo.cn/geoapi/geodata/developer/mcp \
--header "Authorization: Bearer $MAXAEO_API_KEY"
```
执行前先 `export MAXAEO_API_KEY="gdev_…"`。添加后运行 `claude mcp list`,看到 `maxaeo` 为已连接状态即可。 * Cursor 编辑 `~/.cursor/mcp.json`(全局)或项目下的 `.cursor/mcp.json`:
```json
{
"mcpServers": {
"maxaeo": {
"url": "https://maxaeo.cn/geoapi/geodata/developer/mcp",
"headers": {
"Authorization": "Bearer gdev_你的完整Key"
}
}
}
}
```
保存后在 Cursor 设置的 MCP 页面确认 `maxaeo` 已启用并列出 4 个工具。 * VS Code 在项目下创建 `.vscode/mcp.json`。用 `inputs` 在首次启动时输入 Key,避免把 Key 写进文件:
```json
{
"inputs": [
{
"type": "promptString",
"id": "maxaeo-api-key",
"description": "MaxAEO API Key",
"password": true
}
],
"servers": {
"maxaeo": {
"type": "http",
"url": "https://maxaeo.cn/geoapi/geodata/developer/mcp",
"headers": {
"Authorization": "Bearer ${input:maxaeo-api-key}"
}
}
}
}
```
然后在 Copilot Chat 的 Agent 模式中启用 `maxaeo` 的工具。 * 仅支持 stdio 的客户端 对只能启动本地命令的客户端(如 Claude Desktop 的配置文件方式),用 [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) 把远程服务器桥接为本地进程(需要安装 Node.js):
```json
{
"mcpServers": {
"maxaeo": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://maxaeo.cn/geoapi/geodata/developer/mcp",
"--header",
"Authorization:${MAXAEO_AUTH}"
],
"env": {
"MAXAEO_AUTH": "Bearer gdev_你的完整Key"
}
}
}
}
```
`Authorization:${MAXAEO_AUTH}` 中冒号后不留空格,空格放在环境变量的值里,可以避开部分客户端对参数中空格的处理问题。 * 其他客户端 Cherry Studio 等其他客户端:添加 MCP 服务器时,传输类型选择 **Streamable HTTP**(可流式传输的 HTTP),填写: * URL:`https://maxaeo.cn/geoapi/geodata/developer/mcp` * 请求头:`Authorization`,值为 `Bearer gdev_你的完整Key` 只要客户端支持 Streamable HTTP 和自定义请求头,都可以用同样的方式接入。 保管好配置文件 写在配置文件里的 Key 等同于明文密码。不要把含 Key 的 `mcp.json` 提交到代码仓库;团队共享配置时,用客户端支持的环境变量或输入框方式传入 Key。 ## 验证连接 [Section titled “验证连接”](#验证连接) 连接时服务器就会校验 Key:Key 无效时客户端会显示连接失败或未授权(HTTP 401)。连接成功后,可以对 AI 助手说: > 列出 MaxAEO 支持的平台和单价。 助手会调用 `list_platforms` 并展示结果。这一步不消耗点数。 ## 使用示例 [Section titled “使用示例”](#使用示例) 接入后,直接用自然语言描述需求即可,例如: * 「问一下豆包:适合程序员的机械键盘推荐。等结果出来后,列出它引用的网页。」 * 「把『国产项目管理工具哪个好用』分别发给 DeepSeek 和 Kimi,用 P2,比较两边推荐了哪些品牌。」 * 「开启思考模式问 DeepSeek 同一个问题,告诉我它这次实际有没有开启思考。」 * 「我刚才提交的任务结果丢了,帮我在今天的任务里按『机械键盘』找回来。」 服务器在连接时会向 AI 助手说明推荐的调用流程:先 `list_platforms`,再 `submit_task`,然后反复 `get_task` 直到任务结束;提交结果不明时先用 `list_tasks` 查找,不要重复提交。 ## 相关页面 [Section titled “相关页面”](#相关页面) [MCP 工具参考](tools/)4 个工具的参数、返回内容与错误格式,以及协议细节。 [计费与点数](../guides/billing/)MCP 调用与开放 API 共用余额和计费规则。
# MCP 工具参考
> MaxAEO MCP 服务器的 list_platforms、submit_task、get_task、list_tasks 四个工具的输入参数、返回内容与错误格式,以及协议版本、鉴权失败、无状态传输等协议细节,附 JSON-RPC 调用示例。
MCP 服务器提供 4 个工具,与开放 API 一一对应。参数名、取值范围和业务规则都与对应接口相同,工具参数同样**拒绝未定义的字段**(如把 `task_id` 写成 `taskId`)。 | 工具 | 对应接口 | 只读 | 消耗点数 | | ---------------- | ----------------------------------- | -- | -------- | | `list_platforms` | [查询平台列表](../../api/list-platforms/) | 是 | 否 | | `submit_task` | [提交任务](../../api/submit-task/) | 否 | 成功的任务扣点数 | | `get_task` | [查询任务](../../api/get-task/) | 是 | 否 | | `list_tasks` | [任务列表](../../api/list-tasks/) | 是 | 否 | 工具的返回内容是一段 JSON 文本(MCP `content` 中的 `text`),字段命名与开放 API 相同。 ## list\_platforms [Section titled “list\_platforms”](#list_platforms) 列出已开放的平台(含维护中的平台)及其区域、状态、两档单价和近 24 小时统计。 **参数**:无。 **返回**:与[查询平台列表](../../api/list-platforms/#%E5%93%8D%E5%BA%94)的 `data.ent` 相同,即 `platforms` 和 `items`。 ## submit\_task [Section titled “submit\_task”](#submit_task) 向一个平台提交问题,创建新任务。**每次调用都会创建一个新任务,成功后扣点数。** | 参数 | 类型 | 必填 | 说明 | | -------------- | ------- | -- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `platform` | string | 是 | 平台标识,取自 `list_platforms`,跳过 `platform_status` 为 `maintenance` 的平台 | | `query` | string | 是 | 问题,最长 4096 个字符 | | `priority` | integer | 否 | `1` = P1 优先,`2` = P2 标准(默认) | | `thinking` | boolean | 否 | 是否请求平台的思考模式,默认 `false`。开启后明显更慢、不加价;没有思考开关的平台按关闭执行,实际模式见返回的 `effective_thinking`。见[思考模式](../../guides/platforms/#%E6%80%9D%E8%80%83%E6%A8%A1%E5%BC%8Fthinking) | | `country` | string | 否 | 两位字母国家代码,如 `US`;不保证该国家有专属出口 | | `monitor_date` | string | 否 | 业务日期 `YYYY-MM-DD`(北京时间),默认当天;带时区的 RFC 3339 时间会换算为北京时间的日期 | | `wait_seconds` | integer | 否 | `0`–`120`,默认 `0`:等待任务结束的秒数,到时间仍未结束则返回当时状态 | **返回**:任务摘要,字段同下方 `get_task`。不使用 `wait_seconds` 时,`status` 通常为 `queued`。 ## get\_task [Section titled “get\_task”](#get_task) 读取任务状态与结果。 | 参数 | 类型 | 必填 | 说明 | | ------------- | ------- | -- | ------------------------------------------------------- | | `task_id` | string | 是 | `submit_task` 或 `list_tasks` 返回的任务 ID | | `include_raw` | boolean | 否 | 为 `true` 时额外返回完整的 `raw_result`(执行过程、多媒体卡片、引用摘要等),内容可能很大 | **返回**:为了节省模型上下文,默认返回精简的任务摘要,不含 `result_json` 和完整 `raw_result`: | 字段 | 说明 | | ---------------------------------------------- | -------------------------------------------------------------------------- | | `task_id`、`status`、`platform`、`query` | 任务基本信息 | | `monitor_date`、`priority`、`country`、`thinking` | 提交参数;`thinking` 是请求的思考模式 | | `effective_thinking` | 实际是否开启了思考。拿到结果后(成功,或平台执行失败)才出现,为 `false` 时也会返回;不需要 `include_raw` | | `credits` | 扣除或预占的点数 | | `answer` | 回答正文(Markdown) | | `references` | 引用来源,每项只含 `rank`、`title`、`url`、`domain`、`cited` | | `share_link` | 平台分享链接 | | `error_code`、`error_message` | 任务级错误;`error_message` 是 `{"zh","en"}` JSON 字符串 | | `created_at`、`finished_at` | Unix 秒 | | `raw_result` | 仅当 `include_raw` 为 `true` 时返回,结构见[任务对象](../../api/task-object/#raw_result) | 除 `thinking`、`task_id`、`status`、`platform`、`query`、`credits` 外,值为空的字段会被省略(`effective_thinking` 的规则见上表)。`references[].cited` 同样是三态:字段不存在表示平台不区分,不能当作 `false`。 状态说明:`queued`、`dispatching`、`pending`、`running` 表示未结束;P2 任务可能从 `running` 回到 `pending` 再执行一次;`succeeded`、`failed`、`canceled` 为终态。 ## list\_tasks [Section titled “list\_tasks”](#list_tasks) 列出**当前连接所用 API Key** 提交的任务,按提交时间倒序,不含回答。用于在提交结果丢失时找回 `task_id`,再调用 `get_task`。 | 参数 | 类型 | 说明 | | ------------ | ------- | --------------------------------------------------------- | | `page` | integer | 页码,默认 `1` | | `page_size` | integer | 每页条数,默认 `20`,最大 `100` | | `status` | string | 只看该状态的任务;`pending` 会同时匹配 `queued`、`dispatching`、`pending` | | `platform` | string | 只看该平台的任务 | | `keyword` | string | 问题包含的文本,或完整的 `task_id` | | `start_time` | integer | 提交时间下限(Unix 秒,含) | | `end_time` | integer | 提交时间上限(Unix 秒,不含) | **返回**:与[任务列表](../../api/list-tasks/#%E5%93%8D%E5%BA%94)的 `data.ent` 相同:`total`、`page`、`page_size`、`items`。 ## 错误 [Section titled “错误”](#错误) MCP 中的错误分三类: | 类型 | 表现 | 例子 | | -------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------- | | **工具错误** | 正常的工具结果,`isError: true`,文本格式为 `error <错误码>: <英文提示> (<中文提示>)` | `error 1023: Insufficient credits. Please top up and try again. (点数余额不足,请充值后重试)` | | **鉴权失败** | HTTP `401`,JSON-RPC 错误码 `-32001`,响应头带 `WWW-Authenticate` | Key 缺失、无效、已停用、已过期,或使用中途被停用、重置 | | **协议错误** | JSON-RPC 错误 | 未知工具 `-32602`、未知方法 `-32601` | * 工具错误的错误码与开放 API 的 `ret` 相同,含义见[错误处理](../../guides/errors/#%E9%94%99%E8%AF%AF%E7%A0%81%E4%B8%80%E8%A7%88)。参数写错时文本为 `invalid arguments: …`,模型可以据此修正参数后重试。 * 服务暂时不可用时,工具错误文本为 `Service unavailable. Please retry later.`。 * 鉴权失败返回 HTTP 401 而不是工具错误,这样客户端会提示你重新配置 Key,而不是让模型反复重试。 ## 协议细节 [Section titled “协议细节”](#协议细节) 自行实现 MCP 客户端或排查连接问题时参考: | 项目 | 说明 | | ----- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | 端点 | 只接受 `POST`;`GET`(事件流)返回 `405` | | 会话 | 无状态,不下发 `Mcp-Session-Id` | | 响应 | 每个请求直接返回一个 JSON 响应(`Content-Type: application/json`),不使用 SSE | | 协议版本 | 支持 `2025-11-25`、`2025-06-18`、`2025-03-26`、`2024-11-05`;`initialize` 请求的版本不在其中时返回 `2025-11-25`。请求头 `MCP-Protocol-Version` 为不支持的版本时返回 HTTP `400` | | 能力 | 只提供 `tools`(`listChanged: false`) | | 服务器信息 | `serverInfo.name` 为 `geodata-developer` | | 鉴权时机 | `initialize`、`tools/list`、`tools/call` 都会校验 Key | | 通知 | 通知类消息(没有 `id`)返回 HTTP `202`,无响应体 | | 批量请求 | 不支持,请求体必须是单个 JSON-RPC 对象 | | 请求体大小 | 不超过 64 KiB,超出返回 HTTP `413` | ### JSON-RPC 示例 [Section titled “JSON-RPC 示例”](#json-rpc-示例)
```bash
# 初始化
curl -X POST "https://maxaeo.cn/geoapi/geodata/developer/mcp" \
-H "Authorization: Bearer $MAXAEO_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"my-client","version":"1.0.0"}}}'
# 调用工具
curl -X POST "https://maxaeo.cn/geoapi/geodata/developer/mcp" \
-H "Authorization: Bearer $MAXAEO_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "MCP-Protocol-Version: 2025-06-18" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"get_task","arguments":{"task_id":"task_3f6c1d2e-8a4b-4c1f-9e2d-7b5a0c9d1e23"}}}'
```
`tools/call` 的响应:
```json
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "{\"thinking\":false,\"effective_thinking\":false,\"task_id\":\"task_3f6c1d2e-8a4b-4c1f-9e2d-7b5a0c9d1e23\",\"status\":\"succeeded\",\"platform\":\"doubao\",\"query\":\"适合程序员的机械键盘推荐\",\"monitor_date\":\"2026-10-26\",\"priority\":2,\"credits\":3,\"answer\":\"给程序员选机械键盘……\",\"references\":[{\"rank\":1,\"title\":\"2026 年机械键盘选购指南\",\"url\":\"https://www.example.com/keyboard-guide\",\"domain\":\"www.example.com\",\"cited\":true}],\"share_link\":\"https://www.doubao.com/thread/…\",\"created_at\":1793018425,\"finished_at\":1793018497}"
}
]
}
}
```
# 快速开始
> 创建 API Key,查询可用平台,向豆包提交第一个问题并轮询拿到回答与引用来源,附 cURL、Python、Node.js 完整示例。
本页带你从零发出第一个请求:创建 API Key → 查询可用平台 → 提交问题 → 轮询结果 → 读取回答。全程只需要一个终端。 1. ## 创建 API Key [Section titled “创建 API Key”](#创建-api-key) 登录[开发者控制台](https://maxaeo.cn/developers/),进入 **API Key** 页,点「**创建 API Key**」,填写名称(如「本地测试」)并选择有效期。 创建成功后弹窗会显示完整 Key(形如 `gdev_` 开头的一串字符)。**完整 Key 只显示这一次**,复制后保存到环境变量:
```bash
export MAXAEO_API_KEY="gdev_你的完整Key"
```
更多 Key 管理操作见[管理 API Key](../console/api-keys/)。 2. ## 查询可用平台 [Section titled “查询可用平台”](#查询可用平台) 先用最简单的请求确认 Key 可用,同时拿到各平台的标识和单价:
```bash
curl -X POST "https://maxaeo.cn/geoapi/geodata/developer/platforms/get" \
-H "Authorization: Bearer $MAXAEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
```
返回(节选):
```json
{
"ret": 1,
"data": {
"ent": {
"platforms": ["kimi", "doubao", "yuanbao", "deepseek", "…"],
"items": [
{
"platform": "doubao",
"region": "domestic",
"platform_status": "normal",
"p1_credits": 6,
"p2_credits": 3,
"has_stats": true,
"success_rate": 0.96,
"p50_duration_seconds": 52,
"sample_count": 124,
"stats_updated_at": 1793018400
}
]
}
}
}
```
`ret` 为 `1` 表示成功。提交任务时 `platform` 填 `platforms` 里的标识(`platform_status` 为 `maintenance` 的平台暂停接单);`p1_credits` / `p2_credits` 是两档优先级每次**成功**调用的点数(上面数值仅为示例,以实际返回为准)。 如果返回 `{"ret":1030, …}`,说明 Key 无效,检查环境变量是否完整、Key 是否被停用,见[认证与 API Key](../authentication/)。 3. ## 提交任务 [Section titled “提交任务”](#提交任务) 向豆包提问。不传 `priority` 时按 P2 标准档执行和计价:
```bash
curl -X POST "https://maxaeo.cn/geoapi/geodata/developer/task/submit" \
-H "Authorization: Bearer $MAXAEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"platform": "doubao", "query": "适合程序员的机械键盘推荐"}'
```
接口立即返回任务,状态为 `queued`:
```json
{
"ret": 1,
"data": {
"ent": {
"task_id": "task_3f6c1d2e-8a4b-4c1f-9e2d-7b5a0c9d1e23",
"platform": "doubao",
"query": "适合程序员的机械键盘推荐",
"status": "queued",
"priority": 2,
"credits": 3,
"…": "…"
}
}
}
```
记下 `task_id`。此时 `credits` 是**预占**的点数:任务成功才真正扣除,失败或取消会退回。 4. ## 轮询结果 [Section titled “轮询结果”](#轮询结果) 每隔 15 秒查询一次,直到 `status` 变为 `succeeded`、`failed` 或 `canceled`:
```bash
curl -X POST "https://maxaeo.cn/geoapi/geodata/developer/task/get" \
-H "Authorization: Bearer $MAXAEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"task_id": "task_3f6c1d2e-8a4b-4c1f-9e2d-7b5a0c9d1e23"}'
```
抓取本身通常需要几十秒到两分钟,排队时间另算;平台繁忙时可能要等更久。中间状态 `dispatching`、`pending`、`running` 都是正常的,继续轮询即可,详见[任务生命周期](../guides/task-lifecycle/)。 5. ## 读取回答 [Section titled “读取回答”](#读取回答) 任务成功后,响应里: * `answer`:AI 回答原文(Markdown),保留平台自己的引用标记。 * `raw_result.references`:引用来源列表,`cited: true` 表示被回答正文引用。 * `share_link`:平台分享链接(平台未提供时为空)。 * `credits`:本次实际扣除的点数。 字段含义见[任务对象](../api/task-object/),解析技巧见[解析回答结果](../guides/results/)。 ## 完整示例 [Section titled “完整示例”](#完整示例) 下面的脚本串起提交、轮询和读取三步。API Key 从环境变量 `MAXAEO_API_KEY` 读取。 * Python quickstart.py
```python
import os
import time
import requests
BASE_URL = "https://maxaeo.cn/geoapi/geodata/developer"
HEADERS = {"Authorization": f"Bearer {os.environ['MAXAEO_API_KEY']}"}
TERMINAL = ("succeeded", "failed", "canceled")
def call(path, body):
resp = requests.post(BASE_URL + path, headers=HEADERS, json=body, timeout=30)
resp.raise_for_status()
data = resp.json()
if data["ret"] != 1:
raise RuntimeError(f"ret={data['ret']}: {data.get('msg')}")
return data["data"]["ent"]
task = call("/task/submit", {"platform": "doubao", "query": "适合程序员的机械键盘推荐"})
print("已提交", task["task_id"])
while task["status"] not in TERMINAL:
time.sleep(15)
task = call("/task/get", {"task_id": task["task_id"]})
print("当前状态", task["status"])
if task["status"] == "succeeded":
print(task["answer"])
for ref in (task.get("raw_result") or {}).get("references", []):
if ref.get("cited") is True:
print(ref.get("rank"), ref.get("title"), ref.get("url"))
print("扣除点数", task["credits"])
else:
print("任务未成功", task["error_code"], task["error_message"])
```
运行:`pip install requests && python quickstart.py` * Node.js quickstart.mjs
```js
const BASE_URL = "https://maxaeo.cn/geoapi/geodata/developer";
const headers = {
Authorization: `Bearer ${process.env.MAXAEO_API_KEY}`,
"Content-Type": "application/json",
};
const TERMINAL = ["succeeded", "failed", "canceled"];
async function call(path, body) {
const resp = await fetch(BASE_URL + path, { method: "POST", headers, body: JSON.stringify(body) });
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
const data = await resp.json();
if (data.ret !== 1) throw new Error(`ret=${data.ret}: ${data.msg}`);
return data.data.ent;
}
let task = await call("/task/submit", { platform: "doubao", query: "适合程序员的机械键盘推荐" });
console.log("已提交", task.task_id);
while (!TERMINAL.includes(task.status)) {
await new Promise((resolve) => setTimeout(resolve, 15_000));
task = await call("/task/get", { task_id: task.task_id });
console.log("当前状态", task.status);
}
if (task.status === "succeeded") {
console.log(task.answer);
for (const ref of task.raw_result?.references ?? []) {
if (ref.cited === true) console.log(ref.rank, ref.title, ref.url);
}
console.log("扣除点数", task.credits);
} else {
console.log("任务未成功", task.error_code, task.error_message);
}
```
运行:`node quickstart.mjs`(需要 Node.js 18 及以上,自带 `fetch`) * cURL
```bash
# 1. 提交,取出 task_id(需要 jq)
TASK_ID=$(curl -s -X POST "https://maxaeo.cn/geoapi/geodata/developer/task/submit" \
-H "Authorization: Bearer $MAXAEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"platform": "doubao", "query": "适合程序员的机械键盘推荐"}' | jq -r '.data.ent.task_id')
echo "已提交 $TASK_ID" # 输出 null 说明提交失败,单独执行提交命令查看 ret 与 msg
# 2. 每 15 秒查询一次,直到终态
while true; do
RESP=$(curl -s -X POST "https://maxaeo.cn/geoapi/geodata/developer/task/get" \
-H "Authorization: Bearer $MAXAEO_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"task_id\": \"$TASK_ID\"}")
STATUS=$(echo "$RESP" | jq -r 'if .ret == 1 then .data.ent.status else "error" end')
echo "当前状态 $STATUS"
case "$STATUS" in succeeded|failed|canceled) break ;; error) echo "$RESP"; break ;; esac
sleep 15
done
# 3. 输出回答
echo "$RESP" | jq -r '.data.ent.answer'
```
## 下一步 [Section titled “下一步”](#下一步) [平台、优先级与国家](../guides/platforms/)18 个平台的标识,P1 与 P2 怎么选,以及 country 参数。 [错误处理](../guides/errors/)请求级错误码与任务级错误码,以及重试策略。 [上线检查清单](../guides/production-checklist/)从脚本走向生产前,逐项核对安全、可靠性与成本。 [接入 MCP](../mcp/)不写代码,在 AI 客户端里直接调用。