GEOly Agent API
通过 HTTP 发一个问题,GEOly 托管的 GEO Agent 会自己研究你的 AI 可见度数据,以流式或 JSON 返回带出处的答案。使用 GEOly OAuth 令牌鉴权,用量消耗你所在组织自己的 credits。
GEOly Agent API 就是 geoly run 背后的 HTTP 接口。你发一个问题,GEOly 托管的 GEO Agent 自己挑选数据工具,读取你的监测数据(套餐包含时也会用到公开行业数据),返回答案和一张回执:用了哪些工具、走了几步、花了多少。你不需要写提示词,也不需要了解 GEOly 的数据结构——拿到的就是答案。
GEOly CLI 是这个接口的官方客户端:用它登录后,geoly run 会发送请求、跟随事件流、安全重试并保存回执。本页说明其下的 HTTP 接口——端点、请求与响应结构、流式、幂等和错误码——让你清楚一次运行会返回什么。
与 CLI、MCP 的关系
| 谁来推理 | 适合 | |
|---|---|---|
Agent API(POST /api/agent/runs) | GEOly 托管的 GEO Agent | 通过 HTTP 把完整结论接进你的系统 |
GEOly CLI:geoly run | 同一个托管 Agent,经由本接口 | 终端、脚本、编码 Agent |
GEOly CLI:geoly call,以及 GEOly MCP | 你自己的模型或 Agent,逐个调用 GEOly 数据工具 | 想拿原始数据、自己推理时 |
三者使用同一套 GEOly OAuth 授权、同样的组织与品牌、同样的权限。
快速开始
GEOly CLI 就是这个接口的官方客户端:geoly run 会替你登录、发送下文的请求、跟随事件流、安全重试并保存回执。
# 1. 安装 CLI 并登录一次
curl -fsSL https://geoly.ai/install.sh | sh
geoly auth login
# 2. 提问——背后就是一次 POST /api/agent/runs
geoly run "过去 7 天我们在 ChatGPT 上的可见度怎么变的?"
Agent 工作时 stderr 上会显示它的步骤和工具,结束后 stdout 输出一张 JSON 回执。本页其余部分说明 HTTP 接口本身:geoly run 发出什么、收到什么。
鉴权
用 GEOly CLI 登录:
geoly auth login # 打开浏览器登录
geoly auth login --remote # 本机没有浏览器:打印一个可在任意设备打开的链接……
geoly auth login --code <code> # ……再把页面上显示的授权码贴回来
授权同意页会让你选择组织、确认读取权限(需要时再勾选写入)——与 GEOly MCP 是同一个页面。登录会为你的 GEOly 账号签发一个 OAuth 访问令牌,有效期约 14 天;geoly auth status 可查看到期时间,重新登录即可续期。SSH、容器和 CI Runner 上的完整登录流程见 GEOly CLI 文档。
在协议层面,每个请求都带着这个令牌:
Authorization: Bearer <access_token>
不接受浏览器登录态的 Cookie。令牌代表你的 GEOly 用户以及你当时的授权:接口能访问的组织和权限与这份授权完全一致,不会更多。令牌缺失、无效或过期时返回 401。
接口一览
基础地址:https://app.geoly.ai
| 方法与路径 | 用途 |
|---|---|
POST /api/agent/runs | 发起一次运行:一个问题进,一个答案出(流式或 JSON) |
GET /api/agent/runs | 组织最近的运行(回执字段,按时间倒序) |
GET /api/agent/runs/{run_id} | 单次运行,包含问题与完整答案 |
发起一次运行
POST /api/agent/runs
Authorization: Bearer <access_token>
Content-Type: application/json
Accept: text/event-stream
Idempotency-Key: weekly-report-2026-09-22
{
"question": "对比过去 30 天我们和前三名竞品的 AI 可见度。",
"org_id": "<org_id>",
"brand_id": "<brand_id>",
"context": "我们在美国卖升降桌。答案控制在 300 字以内。",
"max_credits": 300
}
| 字段 | 是否必填 | 限制 | 说明 |
|---|---|---|---|
question | 是 | 最多 4,000 字符 | 要问的问题或要做的任务 |
org_id | 可访问多个组织时必填 | — | 读谁的数据、扣谁的 credits |
brand_id | 组织下有多个品牌时必填 | — | 这次运行针对哪个品牌 |
context | 否 | 最多 16,000 字符 | 背景信息、要求或期望的输出格式 |
max_credits | 否 | 整数,25–2000 | 本次运行的消耗上限。不传时,最多可用到组织剩余额度(上限 2,000) |
spec | 否 | 下文列出的名称之一 | 要求按服务端规范交付固定格式的结果并校验 |
allow_writes | 否 | 只认 true | 允许 Agent 使用你授权过的写入工具。只有字面量 true 才生效,其他值一律只读 |
需要 org_id 或 brand_id 却没传(或传错)时,400 报错会按名称列出可选项,例如 This organization has multiple brands. Pass brand_id explicitly …,或 brand_id "…" was not found in this organization. Did you mean …? Available: …。
流式(Server-Sent Events,推荐)
请求头带 Accept: text/event-stream,响应是如下格式的事件流:
event: started
data: {"run_id":"run_…","brand":{"id":"…","name":"…"},"model":"…"}
event: tool
data: {"name":"get_brand_overview","ok":true,"ms":1830,"args":{"time_range":"30d"},"output_chars":5120}
event: done
data: {"run_id":"run_…","answer":"…","stopped":"done", …}
| 事件 | 数据 | 含义 |
|---|---|---|
started | run_id、brand、model | 运行已开始,请记下 run_id。 |
step | index | Agent 开始第 N 步。 |
tool | name、ok、ms、args、output_chars | 一个工具执行完:名称、是否成功、耗时、入参预览、输出大小。 |
tools_loaded | query、names | Agent 按需检索并加载了更多工具。 |
text | delta | 答案正文的下一段。 |
step_error | message | 某一步遇到上游问题,Agent 会用已有数据继续。 |
heartbeat | {} | 静默期间每 10 秒一次。不是错误——客户端的空闲超时请设为 30 秒以上。 |
done | 回执 | 正常结束。 |
error | code、message | 运行失败,不收费。 |
流式模式下运行失败以 error 事件给出,HTTP 状态码仍是 200。
客户端断开后运行会继续跑完,结果照常保存。断开的流无法续接,但随时可以用 GET /api/agent/runs/{run_id} 取回结果。
JSON(同步)
不带 Accept: text/event-stream,运行结束后一次性返回 JSON 回执。只适合简单问题:这种模式下约 30 秒后 Agent 不再开始新的步骤,而且响应超过约 100 秒可能被网络边缘以网关错误中断。即便如此,运行仍会完成并保存,可以用 GET /api/agent/runs 找到它,再按 id 读取。运行失败时返回 502 和 {"error":"RUN_FAILED","message":"…"}。
回执
流式模式下的 done 事件,或 JSON 模式的响应体:
{
"run_id": "run_…",
"answer": "…Markdown…",
"stopped": "done",
"stopped_reason": "done",
"steps": 3,
"tools_used": ["get_brand_overview", "get_brand_board"],
"usage": { "input_tokens": 46253, "output_tokens": 1489 },
"credits_cost": 54,
"credits_remaining": 9946
}
| 字段 | 怎么读 |
|---|---|
answer | Markdown 格式的答案,语言跟随提问语言。 |
stopped | Agent 按自己的判断答完为 done,否则为 max_steps。 |
stopped_reason | done,或提前结束的原因:budget(触到 max_credits 或组织剩余额度)、deadline(运行时限)、max_steps(步数上限)、salvaged(上游故障,Agent 用已拿到的数据交卷)。不是 done 时答案可能不完整。 |
tools_used | Agent 调用过的工具——数字的来源。 |
credits_cost | 本次运行实际消耗,不会超过 max_credits。 |
credits_remaining | 本次之后组织剩余的 credits(数字、"unlimited",读取失败时为 null)。 |
deliverable | 仅在传了 spec 时出现:{ spec, version, valid, problems, … }。valid: false 时会逐条列出缺什么,答案照常返回。 |
取回运行记录
GET /api/agent/runs?org_id=<org_id>&limit=20
GET /api/agent/runs/{run_id}
GET /api/agent/runs 返回 { "runs": [ … ] },按时间倒序。每行包含 run_id、status、stopped、steps、credits_cost、created_at、finished_at、question(前 200 字符)和 brand_id。limit 为 1–50(默认 20);可访问多个组织时请传 org_id。
GET /api/agent/runs/{run_id} 返回保存的运行记录:
{
"run_id": "run_…",
"status": "succeeded",
"question": "…",
"answer": "…",
"stopped": "done",
"steps": 3,
"tools_used": ["…"],
"usage": { "input_tokens": 46253, "output_tokens": 1489 },
"credits_cost": 54,
"max_credits": 2000,
"error": null,
"created_at": "2026-09-22T08:00:00.000Z",
"finished_at": "2026-09-22T08:01:12.000Z"
}
- 这里的
status取值为running、succeeded或failed(CLI 会把succeeded显示为done)。 - 想等待运行结束,每隔几秒轮询一次这个接口,直到
status不再是running。 - 开始 15 分钟后仍标记为
running的运行,会按failed、error: "RUN_ABANDONED"返回。 - 你的令牌无权查看的运行一律返回
404 RUN_NOT_FOUND,不论它是否存在。
幂等:安全重试
发送 Idempotency-Key 请求头即可安全重试:
- 格式:8–128 位,字符限
A-Z a-z 0-9 _ - : .。带了这个头但格式不对(包括空值)会返回400 IDEMPOTENCY_KEY_INVALID。 - 作用范围:同一组织、同一品牌、同一个键。
- 原运行还在进行中时,同键请求一律返回那次运行。
- 原运行结束后,从它开始的时间算起 10 分钟内,同键请求都回放它;超过 10 分钟,同一个键会发起新的运行。
- 回放不会新开运行,也不会再扣费。无论
Accept填什么,回放都以 JSON 返回,响应体里带"replayed": true,响应头带Idempotent-Replayed: true。响应体结构与GET /api/agent/runs/{run_id}相同;如果其中status是running,轮询该接口即可。 - 如果暂时无法校验幂等键,请求会以
503 IDEMPOTENCY_UNAVAILABLE拒绝,而不是冒着重复运行的风险放行。请用同一个键重试。
建议用能标识任务的键,例如 weekly-report-<品牌>-<日期>。CLI 的键由组织、品牌、spec、问题、context、max_credits 和写入意愿共同生成。
Credits
Agent API 的用量消耗你所在组织自己的 credits。
- 给运行封顶: 用
max_credits(25–2000)。回执中的credits_cost不会超过它。 - 查看剩余: 每张回执里都有
credits_remaining;也可以用geoly credits,或在 GEOly 的 设置 → 账单 查看。 - 运行失败不收费。
- 组织剩余不足 25 credits 时,运行会以
402 INSUFFICIENT_CREDITS被拒绝(响应体带remaining,已知时还带period_end)。
固定格式交付物(spec)
传入 spec 后,Agent 按服务端维护的规范交付:章节固定、每个数字都来自工具、末尾附一段机器可读的 JSON。回执中的 deliverable 字段给出是否通过校验。带 spec 的流式运行时限更长。
spec | 交付什么 | 在 question 里写明 |
|---|---|---|
geo-weekly-brand-health | 周度品牌健康报告:可见度、提及率、引用率、分平台表现、竞品差距、下一步动作 | 品牌(通过 org_id / brand_id);可选时间范围 |
geo-content-brief | 单个关键词的内容简报:受众、SERP 与 AI 引用研究、大纲、FAQ、AEO 写作要点 | primary_keyword、domain;可选 article_title、target_prompt、country |
geo-keyword-research-report | 关键词研究报告:搜索量、意图分簇、实时 SERP、AI 检索词扇出、内容机会 | topic;可选 domain、country |
geo-serp-gap | 单个页面对比 Google 前 10 与 AI Overview 信源的内容差距 | url、query;可选 country |
把这些信息直接写进 question,例如 "url: https://example.com/blog/x, query: best standing desk for small apartments, country: us"。名称不存在时返回 400 SPEC_NOT_FOUND: … Available: …。
错误码
错误以 JSON 返回:{ "error": "<错误码或说明>" },部分错误带额外字段。
| HTTP | error | 含义与处理 |
|---|---|---|
| 400 | INVALID_JSON、INVALID_INPUT、QUESTION_REQUIRED | 修正请求体。 |
| 400 | MAX_CREDITS_OUT_OF_RANGE (25..2000) | max_credits 须为 25–2000 的整数。 |
| 400 | IDEMPOTENCY_KEY_INVALID | 修正 Idempotency-Key 请求头。 |
| 400 | SPEC_NOT_FOUND: … | 使用报错中列出的 spec 名称。 |
| 400 | 一句关于 org_id / brand_id 的说明 | 目标不明确或有误,报错里列出了可选项。 |
| 401 | Missing Authorization header、Invalid token 等 | 令牌缺失、无效或已过期,请用 geoly auth login 重新登录。 |
| 402 | INSUFFICIENT_CREDITS | 本期 credits 已用完(响应体带 remaining、period_end)。等待重置或提升额度。 |
| 402 | 其他说明文字 | 组织没有有效订阅。 |
| 403 | ORG_SELECTION_REQUIRED、BRAND_NOT_ALLOWED_FOR_TOKEN、Authorization not granted for this client. … | 授权范围不包含此操作。重新授权并选择组织。 |
| 404 | BRAND_NOT_FOUND、RUN_NOT_FOUND | 不存在,或该令牌无权查看。 |
| 413 | QUESTION_TOO_LONG、CONTEXT_TOO_LONG | 超过 4,000 / 16,000 字符。 |
| 429 | Rate limit exceeded. … | 请求过于频繁,退避后重试。 |
| 502 | RUN_FAILED | 仅 JSON 模式:运行失败,不收费,可重试。 |
| 503 | BILLING_UNAVAILABLE、IDEMPOTENCY_UNAVAILABLE | 暂时性问题,稍后重试(使用同一个 Idempotency-Key)。 |
频率与并发
- 请求与 GEOly MCP 共用同一个按账号、按分钟计的频率限制,超限返回
429,请退避后再试。 - 没有单独的并发运行上限。每次运行开始时会按自身预算预留额度,所以同时发起多次运行时,每一次都会占用组织的 credits。
示例:Python
import json
import os
import requests
TOKEN = os.environ["GEOLY_ACCESS_TOKEN"] # 你的 GEOly OAuth 访问令牌
resp = requests.post(
"https://app.geoly.ai/api/agent/runs",
headers={
"Authorization": f"Bearer {TOKEN}",
"Content-Type": "application/json",
"Accept": "text/event-stream",
"Idempotency-Key": "weekly-review-2026-09-22",
},
json={"question": "总结一下我们本周的 AI 可见度。", "max_credits": 300},
stream=True,
timeout=(10, 60), # 连接超时、空闲读取超时(心跳每 10 秒一次)
)
resp.raise_for_status()
if resp.headers.get("Content-Type", "").startswith("application/json"):
print(resp.json()) # 幂等回放了之前的运行
else:
event = None
for line in resp.iter_lines(decode_unicode=True):
if line.startswith("event:"):
event = line[len("event:"):].strip()
elif line.startswith("data:") and event in ("done", "error"):
payload = json.loads(line[len("data:"):])
print(event, payload.get("stopped_reason"), payload.get("answer") or payload.get("message"))
示例:用 curl 走 JSON 模式
curl https://app.geoly.ai/api/agent/runs \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{"question":"这个月我们在 Perplexity 上的提及率是多少?","max_credits":100}'
接入建议
- 优先用流式。 JSON 模式只用于确定几秒内就能答完的问题。
- 把
heartbeat当作正常事件,空闲超时设为 30 秒以上。 - 记下
run_id。 断线和超时都不会丢答案,按 id 取回即可。 - 先看
stopped_reason再用答案。 自动化任务里,不是done时可以重跑或调高max_credits。 - 一次问清楚。 在
question里写明时间范围、平台和输出形式,背景放进context。 - 可能重试的任务一律带
Idempotency-Key。
边界与限制
- 范围以授权为准。 接口只能访问令牌获得授权的组织与权限。
- 默认只读。 只有传
allow_writes: true,且在单组织授权中勾选了对应资源的写入权限,Agent 才会使用写入工具。按需触发监测(trigger_prompt)永远不对托管 Agent 开放。 - 套餐要求。 需要有效订阅;只有组织套餐包含公开行业情报时(Grow 及以上)才会用到它。
- 运行有上限。 单次运行最多 2,000 credits、20 步,并有时长限制(带
spec时更长)。提前结束会在stopped_reason中说明。 - 模型固定。 接口使用 GEOly 选定的模型,不支持自带模型。
- 运行记录会保存,令牌所在组织范围内可以通过
GET /api/agent/runs查看。
相关文档
- GEOly CLI——在终端或编码 Agent 里调用本接口最简单的方式。
- GEOly MCP 使用指南——在你自己的 AI 客户端里调用 GEOly 数据工具。
GEOLY文档