用 API 驱动 Cursor Cloud Agent:endpoints 页的调用链
会来翻这套 API 文档的人,处境通常比较具体:想让流水线在某个事件发生时自动开一个云端任务,跑完把分支和结果回写到别的系统;或者给内部平台包一层壳。这时候要的不是「它能干什么」,而是一张确切的端点清单和字段表——哪些字段创建时定死、哪些每次 run 能改、返回值里哪个能当幂等键。
这篇沿着 cursor.com/docs/cloud-agent/api/endpoints 和 cursor.com/docs/cloud-agent/metadata 两页走。前者是从外部调的 HTTP API,后者是 agent 在自己 VM 里读自身信息的只读接口,名字容易混但是两套东西。
前置条件
endpoints 页顶部标着 Public beta:Cloud Agents API v1 处于公开测试阶段,文档写明接口在正式发布前可能变化。metadata 页顶部标的是 Preview,写明可能有破坏性变更。
- 认证:文档写明同时接受 Basic 与 Bearer 两种方式,密钥可以是控制台生成的用户 API key,也可以是 service account API key,细节统一放在
cursor.com/docs/api。 - 密钥类型不能随便挑:Fleet Management 那组端点文档写明必须用对应 pool 的 service account API key,其它类型会被拒绝;
/v1/sub-tokens要求 agent-scoped 的团队 service account key。 - Webhooks 是 coming soon,v1 目前没有;文档写明旧的 v0 API 仍支持 webhook。依赖回调的方案得继续用 v0,或者自己轮询、接 SSE。
- VM 内元数据只在 Cursor 托管 VM 上有,文档明确写明自托管 worker 尚未提供这套接口。
v1 与 v0 的结构差异文档也写了:v1 把工作拆成「一个持久的 agent 加上按 prompt 划分的多个 run」,v0 是更扁平的一层。这个拆分决定了后面所有端点的形状。
建 agent:字段都堆在这一个请求里
POST /v1/agents 创建 agent 并立刻把首个 run 入队,响应同时返回持久的 agent 和这次的 run。
请求体只有 prompt 必填。prompt.text 是指令文本,prompt.images 可选(每项要么给 data 加必需的 mimeType,要么给 http/https 的 url 让 Cursor 去取;文档列出可用 MIME 类型为 image/png、image/jpeg、image/gif、image/webp,并给了数量与单张体积上限,数值以官方文档为准)。
| 字段 | 文档写明的作用 |
|---|---|
model | 省略时依次解析用户默认模型、团队默认模型、系统默认;给了就必须给 model.id,取值来自 GET /v1/models |
model.params | 该模型自己的参数,形如 id / value 的数组,只能用所选模型支持的 |
name | 显示名,省略时由 prompt 自动生成 |
env.type | cloud 用 Cursor 托管 VM,pool 与 machine 路由到自托管 worker |
env.name | 具名托管环境、pool 名或机器名;env.type 为 pool 时省略则用 default |
repos | 仓库配置,与具名 cloud 环境互斥;repos[].url 必填 |
repos[].startingRef | 起点分支或 commit SHA,给了 prUrl 时被忽略 |
repos[].prUrl | GitHub PR 链接;用它时在该 PR 的仓库与分支上工作,但同项的 url 仍必须写 |
workOnCurrentBranch | 默认 false,此时提交推到自动生成的 cursor/... 新分支;true 则直接推到起点 ref |
autoCreatePR | run 完成时是否自动开 PR |
skipReviewerRequest | 是否跳过把用户加为 reviewer,文档写明只在 autoCreatePR 为 true 时生效 |
envVars | 会话级环境变量,静态加密、注入 agent 的 shell、随 agent 一起删除;名字不能以 CURSOR_ 开头 |
mcpServers | 内联 MCP server 定义,type 取 http / sse / stdio;远端支持 headers 或 OAuth auth |
customSubagents | 主 agent 可委派的自定义 subagent,每项需 name、description、prompt |
mode | 首个 run 的对话模式,默认 agent;plan 先探索并起草计划再动手 |
agentId | 客户端自带标识,形如 bc-<uuid> |
这张表里有四处文档专门写了会踩:
envVars标着 Beta、正在灰度。文档原话是账号未启用时该字段在创建时会被静默忽略而不是让请求失败,并要求先在首个 run 里确认这些值存在再在生产里依赖。这种「不报错但没生效」最难查,好在写在文档里了。agentId与envVars不能同用。agentId的用途是幂等创建——同一个agentId重复 POST 返回409 agent_id_conflict而不是再建一个;需要会话密钥时就得省掉它让服务端生成。env.name写错 pool 名立刻报错:文档写明未知 pool 名返回400,而不是让请求在队列里无限等待。customSubagents的name不能与内置撞车,文档举出的内置名有explore、debug、shell、computerUse等。
下面是官方文档里针对自托管 pool(含无仓库场景)的原样示例:
curl --request POST \
--url https://api.cursor.com/v1/agents \
-u YOUR_API_KEY: \
--header 'Content-Type: application/json' \
--data '{
"prompt": {
"text": "Clone the payments service and add a health check"
},
"env": {
"type": "pool",
"name": "sandbox"
}
}'
示例里的 YOUR_API_KEY 是占位符,换成你自己的密钥再执行,别把真实值写进仓库或提交历史。
Windows 侧单独说一句(以下是通用命令行做法,不是 Cursor 官方文档内容):--data '{...}' 这种单引号写法在 PowerShell 和 cmd 里都不成立——PowerShell 的 curl 默认是 Invoke-WebRequest 的别名,cmd 不认单引号包 JSON。把 JSON 存成文件用 curl.exe --data @body.json,或者在 Git Bash / WSL 里执行原样命令。这层差异官方文档没有说明。
追加 run:并发单位是 agent
POST /v1/agents/{id}/runs 给已有的活跃 agent 发追问,文档写明新 run 沿用该 agent 当前的对话与工作区状态。
硬约束是每个 agent 同时只能有一个活跃 run:已有 run 处于 CREATING 或 RUNNING 时再调返回 409 agent_busy,文档给的处置是等它终结或取消。要做并发队列的话,这条决定了你的并发单位是 agent 不是 run。
追加时能带的字段只有 prompt、mcpServers、mode 三个。其中 mcpServers 的语义要留意:文档写明这次提供的会替换创建时的内联配置(仅对本次 run 生效),省略则沿用;mode 省略则沿用之前几次 run 的模式。
读状态:执行状态在 run 上,不在 agent 上
这是 v1 拆分带来的最大口径变化。GET /v1/agents/{id} 返回持久元数据,文档明确让你取其中的 latestRunId 再调 Get A Run 读执行状态。几处容易读漏的:
GET /v1/agents的列表项只含持久身份字段,repos、workOnCurrentBranch、autoCreatePR要单独 GET 才有。- 分页游标
nextCursor在没有下一页时是被省略,不是返回null。写成判断不等于null的循环会多转一圈。 - 列表支持
limit、cursor、prUrl(按 PR 过滤)与includeArchived,后者默认为true,即默认包含已归档 agent。 - Get A Run 里
durationMs与result文档写明只有终态才有,终态包括FINISHED、ERROR、CANCELLED、EXPIRED。 git是 per-agent 状态而非 per-run:同一 agent 上每个 run 拿到的git快照都一样,要把改动归因到某次具体 run 得靠latestRunId或 SSE 流。而且git.branches[]里的repoUrl不带协议头(形如github.com/your-org/your-repo),和请求里带https://的repos[].url对不上,做字符串比对时会咬人。
接 SSE:两套事件是并行的
GET /v1/agents/{id}/runs/{runId}/stream 是 Server-Sent Events,文档写明流只作用于所请求的那一个 run,不重放之前的 run。事件类型文档列了九种:status、assistant、thinking、tool_call、interaction_update、heartbeat、result、error、done。
interaction_update 的定位特别:它与前面那些简化事件并行发出,负载形状与 TypeScript SDK 消费的 InteractionUpdate 一致。文档给的是二选一——只要纯文本和工具调用就处理简化事件、忽略它;想要 SDK 那套完整流就反过来。两边都处理会拿到重复内容。
tool_call 的信封是稳定的:callId 标识一次工具调用在多次更新间的同一性,name 是公开工具名(文档举例 read_file、run_terminal_cmd、mcp),status 只有 running 和 completed。args 与 result 太大放不进流时会被省略并置上对应的 truncated 标志,解析时别假设它们一定在。
断线重连的两个坑文档也写了:事件 id 是不透明字符串不要解析;开头那个 status 事件没有 id,它是每次重连都会在顶部重发的框架事件。重连时把最近收到的事件 id 放进 Last-Event-ID,且该 id 必须属于这个 run,否则返回 400 invalid_last_event_id。流响应带 X-Cursor-Stream-Retention-Seconds 头,过了保留窗口可能返回 410 stream_expired,文档给的处置是别再重试流、改用 Get A Run 读终态。
其余几组端点
- 取消:
POST .../runs/{runId}/cancel,文档写明取消是终态不可恢复,要继续对话只能在同一 agent 上开新 run;对已终态或从未活跃的 run 调用返回409 run_not_cancellable。 - 用量:
GET /v1/agents/{id}/usage按 run 拆分,返回totalUsage加runs[],每个usage含inputTokens、outputTokens、cacheWriteTokens、cacheReadTokens、totalTokens;未知runId返回404 run_not_found。还没产生用量的 run 也在列表里、各字段为零。 - 产物:列出的
path相对于工作区artifacts/目录,文档提醒 v1 只接受相对路径,v0 那种绝对路径不再接受;下载端点返回临时预签名 URL 加expiresAt。产物挂在 agent 而不是 run 上,文档自述的理由是工作区跨 run 持续存在。 - 生命周期:归档与取消归档都是幂等的,重复调用返回
200且不产生变化;DELETE /v1/agents/{id}是永久删除不可逆,文档建议可逆场景用归档。 - 机群管理:这组端点前缀是
/v0/private-workers...,与上面的/v1混在同一页。文档写明持久 pool 在最后一个 worker 断开后仍保持注册,可以缩容到零、等出现待分配请求再拉起;认领请求后启动 worker 要用同一个 worker id,通过CURSOR_AGENT_WORKER_ID传。 GET /v1/repositories文档加粗标了限流非常严格,且对可访问仓库很多的用户响应可能很慢,要求把「拿不到这个信息」当成正常情况处理。
另一套:VM 内的任务元数据
metadata 那一页讲的是 agent 在自己 VM 里读自身运行信息的接口,hooks 和安装脚本也能读。文档写明这是 agent 用自己的终端工具去调的,你不需要自己发这些请求。
访问方式是 Unix socket,路径取环境变量 CURSOR_AGENT_SOCKET,托管 VM 上默认值是 /run/cursor/api.sock。请求形如 GET /v1/meta-data[/<path>],无 body 无额外 header,URL 里的主机名被忽略,允许结尾带斜杠,缺失的键返回 404。文档给的列前缀示例:
curl --unix-socket "${CURSOR_AGENT_SOCKET:-/run/cursor/api.sock}" \
http://cursor-agent/v1/meta-data/
返回是 text/plain:请求键就是值本身(多值键一行一个),请求前缀就是排序后的子项、嵌套前缀以 / 结尾。键位分四个顶层前缀:
agent/:agent/id(就是bcId)、agent/name、agent/source(文档举出的取值有WEBSITE、API、SLACK、AUTOMATIONS)、agent/runtime(托管 VM 上是managed)。owner/:owner/user-id、owner/user-email、owner/service-account-id、owner/team-id。文档明确建议做白名单用 user-id 而不是 email,理由是邮箱会变。turn/:只在一次编码 turn 进行中存在,turn 之间会消失,文档要求不要跨 turn 缓存。含turn/id(与agent/id不是一回事)、turn/user-id、turn/user-email、turn/started-at(Unix 秒)、turn/model。最后这个文档特别说明:选了 Auto 时它给的是实际服务的模型而不是Auto。workspace/:workspace/repo-url是主仓库,形如host/path,主机名小写、不带协议、凭据、端口、query 和.git后缀;workspace/repo-urls才是全部仓库,主仓库在前其余排序、一行一个,文档提醒这个键缺失意味着「集合暂时不可知」,不等于只有一个仓库。另有workspace/branch-name、workspace/environment-id,以及自动化场景下的workspace/automation-id。
键什么时候出现也写死了:turn/ 在编码 turn 开始前不存在,workspace/branch-name 在这次 run 记录到分支前不存在,owner、team、仓库几类从 agent 创建起就可用;刚启动时 socket 可能没就绪,重试连接即可。
这套接口不是凭证。文档写得很重:元数据没有签名,能连到 socket 的任何进程——agent 本身、它跑起来的代码、hooks——都能读到全部键,要当作整个 run 都可见。需要向外部服务证明身份时,官方给的做法是让 agent 去签发 OIDC token 并验证那个 JWT,而不是把元数据值当凭据转发。
错误码文档给了一张表:404 not_found、405 method_not_allowed、429 rate_limited、503 saturated、500 host_error、502 / 504 backend_unreachable,其它归 backend_error。其中 429、503、500、502、504 退避重试,而 403 视为致命——这个 agent 不被允许读元数据。
边界与验证
集中列一下文档明说不保证或还没有的地方:v1 是 public beta、metadata 是 preview;Webhooks 是 coming soon;envVars 处于 Beta 灰度且未启用时静默忽略;自托管 worker 尚不提供 VM 内元数据 API。
还有一处对不上,值得你自己去核:metadata 页在区分概念时提到「用 SDK 或 Cloud Agents API 创建 agent 时设置的、调用方自有的 metadata 标签」,但 endpoints 页 Create An Agent 的请求体字段清单里我们没有找到对应字段的说明。两页放在一起看,这个字段在 endpoints 页的请求体清单里我们查不到——endpoints 页给了完整 OpenAPI spec 的链接,字段级细节以那份和官方文档最新内容为准。这套 API 迭代频繁,上面所有路径、字段名与默认值都随版本变动。
接对没接对,按依赖顺序验:
- 验密钥:
GET /v1/me返回apiKeyName与createdAt;用户级 key 还带userId、userEmail、userFirstName/userLastName,service account / 团队 key 不带userId。这一步顺便告诉你手里的 key 是哪一类,后面 Fleet Management 那组挑不挑得动就看它。 - 验模型取值:
GET /v1/models返回可传给model.id的值以及每个模型接受的parameters与variants,构造model.params从这里取合法组合,别硬编码。 - 验创建链路:创建响应里
run.status初始是CREATING,agent.latestRunId应当等于这个 run 的id;用它轮询到终态,此时才会出现durationMs与result。 - 验分支落点:看
git.branches[]。workOnCurrentBranch为默认值时分支名应是cursor/开头的自动分支,比对时把repoUrl不带协议头算进去。 - 验元数据:让 agent 先请求
/v1/meta-data/看列出哪几个前缀再按前缀取键。turn/没列出来通常是当前没有活跃 turn,不是配置错了。
curl --request GET \
--url https://api.cursor.com/v1/me \
-u YOUR_API_KEY:
以上为按官方文档中的参数语义组合的示例,未经实测,以官方文档与实际响应为准。
本文依据 Cursor 官方文档(cursor.com/docs 与 cursor.com/help)于 2026-08-18 的公开内容整理。
该产品闭源,本文只复述官方文档写明的机制,不推断其内部实现;
我们没有对文中涉及的功能做过实测,因此不涉及界面外观、操作手感与运行速度的任何描述。
该产品迭代频繁,文中涉及的设置项与命令随版本变动,请以官方文档最新内容为准。
本文不涉及订阅价格、额度与模型清单,相关信息请以官方定价与模型说明页为准。
安全与合规相关做法请结合自身环境评估,本文不构成安全方案建议。