集成与上线
API 与 Webhook
一个端点即可从你自己的代码里运行集群:POST /api/swarm/run。配套限定范围的密钥、幂等重试,以及针对慢于一次请求的场景的签名回调。
API 密钥
从该集群的 部署 对话框创建。密钥形如 sk_swarm_… ,而密文只显示 一次 ——它以哈希形式存储,无法恢复,只能轮换。
| 属性 | 取值 | 说明 |
|---|---|---|
scopes | run, read_runs | 默认为 ['run']。数据库约束会拒绝其他任何取值,因此拼写错误在写入时就失败,而不是静默地什么都不授权。 |
expires_at | timestamp / null | 可选的过期时间。为某个特定集成用的密钥设一个。 |
revoked_at | timestamp / null | 撤销立即生效——下一次请求即失败拒绝。 |
rotated_from | 密钥 id | 设在替代密钥上,这样你能看出是谁取代了谁。 |
last_used_ip | text | 最近一次请求的源 IP——闲置的密钥一眼可辨,被盗的密钥可追溯。 |
reject_approvals | boolean | 设置后,遇到审批节点的运行会直接失败,而不是挂在那里等一个并没有在看的人。 |
webhook_secret | text | 用于给回调签名——见下文。 |
callback_url | url | 该密钥的默认回调地址;可按请求覆盖。 |
POST /api/swarm/run
请求头
| 请求头 | 必填 | 说明 |
|---|---|---|
Authorization: Bearer sk_swarm_… | 是 | — |
Content-Type: application/json | 是 | — |
Idempotency-Key | 否 | 由客户端指定。让重试返回原始结果,而不是重新运行一次。 |
请求体
| 字段 | 类型 | 用途 |
|---|---|---|
input | string | 集群输入节点的自由文本输入。 |
inputs | object | 对于输入节点声明了结构化表单的集群:每个字段名对应一个键。 |
history | {role, content}[] | 此前的对话轮次(user / assistant)。正是它把一个集群变成多轮聊天机器人。 |
async | boolean | 设为 true 会立即返回,并把结果投递到回调地址。 |
callback_url | url | 为本次运行覆盖该密钥的默认回调地址。 |
同步运行
curl -X POST https://your-instance.example.com/api/swarm/run \
-H "Authorization: Bearer $ZENSTUDIO_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-48213-summary" \
-d '{
"input": "Summarise ticket 48213 and suggest a reply",
"inputs": { "priority": "high" }
}'{
"output": "The customer reports a faulty hinge …",
"runId": "5f1c0f0e-…"
}异步运行
curl -X POST https://your-instance.example.com/api/swarm/run \
-H "Authorization: Bearer $ZENSTUDIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": "Produce the weekly summary",
"async": true,
"callback_url": "https://api.example.com/hooks/zenstudio"
}'{
"accepted": true,
"callback_url": "https://api.example.com/hooks/zenstudio"
}凡是耗时超出一次请求应有时长的场景都用异步——长图、审批关卡、大文档。
状态码
| 代码 | 含义 | 该怎么办 |
|---|---|---|
| 200 | 运行已完成(同步) | 读取 output 和 runId。 |
| 202 | 已接受(异步) | 等待回调。 |
| 401 | 密钥缺失、无效、已停用或已过期 | 检查密钥;不要盲目重试。 |
| 402 | 超出预算上限 | 触到消费上限——参见 预算. |
| 404 | 找不到该集群 | 该密钥对应的集群已被删除。 |
| 409 | 使用该 Idempotency-Key 的运行仍在进行中 | 退避后重试;不要发起第二次运行。 |
| 422 | 同一个 Idempotency-Key 配了不同的请求体 | 这是客户端的缺陷——要么复用完全相同的请求体,要么换一个新键。 |
| 429 | 超出速率限制 | 放慢速度后重试。 |
幂等性
发送一个 Idempotency-Key ,之后用同一个键重试会返回原始结果,而不是再跑一遍集群。
为什么这样设计
order-48213-summary),绝不要每次尝试都用一个随机值,否则每次重试都是一次全新的运行。| 情形 | 结果 |
|---|---|
| 同键、同请求体,首次调用已完成 | 返回 200 及此前保存的原始响应 |
| 同键、同请求体,首次调用仍在运行 | 返回 409——不要发起第二次运行 |
| 同键、请求体不同 | 返回 422——明确拒绝,而不是返回一个对不上的结果 |
幂等记录只保留一段有限的时间窗,之后会被清理。
限额
| 上限 | 用途 |
|---|---|
| 速率限制 | 每个密钥每个时间窗内的请求数,超出返回 429。 |
| 并发 | 每个密钥的并发运行数——这一项保护的是你的提供商配额。 |
| 运行超时 | 挂钟时间上限,这样带环的图不会永远跑下去。 |
| 预算上限 | 每个密钥的消费上限,超出返回 402。参见 预算. |
这些限制在所有实例间统一生效
Webhook 回调
每次投递都会带上以下请求头:
| 请求头 | 取值 |
|---|---|
X-ZenStudio-Event | swarm.run.completed |
X-ZenStudio-Timestamp | Unix 秒级时间戳,包含在签名内容中 |
X-ZenStudio-Signature | sha256=<hex> ——对 <timestamp>.<body> 做 HMAC-SHA256,使用该密钥的 Webhook 密钥 |
投递最多重试 3 次,每次尝试超时 15 秒。
校验签名
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(rawBody, headers, secret) {
const ts = headers["x-zenstudio-timestamp"];
const sig = headers["x-zenstudio-signature"]; // "sha256=<hex>"
// Reject old timestamps FIRST — this is what stops a captured
// delivery being replayed at you weeks later.
const age = Math.abs(Date.now() / 1000 - Number(ts));
if (!Number.isFinite(age) || age > 300) return false;
const expected =
"sha256=" + createHmac("sha256", secret).update(`${ts}.${rawBody}`).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(sig ?? "");
// Constant-time: a plain === leaks the answer through timing.
return a.length === b.length && timingSafeEqual(a, b);
}- 签名要针对 原始 请求体,在任何 JSON 解析之前——重新序列化会改变字节内容,签名就对不上了。
- 尽快返回 2xx,把实际工作异步处理;响应慢的端点会被重试。
- 把你的处理逻辑写成幂等的——重试可能把同一个结果投递两次。
出网安全
回调 URL 在投递前会被校验:私有地址、回环地址和链路本地地址——包括云元数据端点——都会被拒绝。同一套防护覆盖平台代你发出的每一个出站请求,包括 web_browse、集群 HTTP 节点和 MCP 端点,因此由模型选定的 URL 无法被用来探入你的内网。
遇到审批节点的运行
带有 审批节点 的集群会等人。对无人值守的集成来说那就是卡住,所以请在密钥上设置 reject_approvals ,让这类运行改为快速失败。无论哪种情况,审批都是失败即拒绝——运行绝不会因为超时而越过某个关卡。
查看发生了什么
每次由 API 触发的运行都会产生一条完整追踪,归属到触发它的那个密钥,可在此查看: 追踪记录,成本归属可在此查看: 分析。某个集成行为异常时,先从那里查,而不是先翻自己的日志——追踪会显示解析后的提示词和每一次工具调用。
调用笔记本而不是集群
位于 开发者工作区 的笔记本可以用同样的方式发布:在笔记本上点击 发布 生成一个 nbk_… 密钥,然后 POST /api/notebook/run ,带上 {"inputs": {…}}。请求体会到达笔记本的入口函数,其返回值作为响应返回;长时间运行会交回一个 runId ,可在此轮询: /api/notebook/run/status。当逻辑本来就是笔记本里已经跑通的 Python、且没必要先改造成集群时,用它。