Skip to main content
Webhook 让你通过 POST 而不是轮询接收任务生命周期更新。在任务上 注册回调 URL,任务每次状态切换都会命中它。
状态 —— P2-A 已完整落地:回调 (1) 用 HMAC-SHA256 可签名X-BeeOS-Signature), (2) 失败按文档化的指数退避重试(1m → 5m → 30m → 2h → 12h, 之后死信), (3) 通过 GET .../deliveriesPOST .../deliveries/{id}/redeliver 可审计 + 可重放
单次尝试 10s 超时仍按尝试生效,但失败尝试现在能熬过进程崩溃, 由后台重试 worker 接管。

1. 生命周期


2. 注册 webhook

请求

响应(201)

tokensecret任何 list / get 响应里都永不返回 —— 注册后仅服务端使用。has_secret 布尔值让 UI / SDK 不暴露 secret 本身的情况下显示 “已启用签名”。轮换 secret 用一个新值 Set 即可 (传 "" 不影响现有 secret —— 要清空请 DELETE + 重新注册)。

列出 / 删除

一个任务可以持有任意数量的 webhook(目前没有显式上限)。删除立即生效 —— 不取消进行中的投递,但删除后不再有新尝试。

3. 当前限制

约束投递契约的几点:

4. Payload 格式

BeeOS 支持三种 renderer,由注册时的 protocol_filter 列选择。 通过此 OpenAPI 端点注册的 webhook 始终用 openapi renderer。

openapi renderer —— TaskEvent 信封

匹配 GET /tasks/{id}/events 的 SSE 流 payload,可共享 decoder。 每次状态切换(中间态 + 终态)都发。
可能的 status 值:queuedrunninginput_requiredauth_requiredcompletedfailedcanceledtimeoutrejected(见 调用智能体 §状态参考)。 final: true 仅在终止态。

a2ageneric renderer

供 A2A JSON-RPC 客户端和无 protocol filter 注册的通用 / 旧版订阅者 使用。OpenAPI Gateway 不可选 —— 仅文档参考。详见 webhook_renderer.go

5. 接收方 checklist

针对当前投递语义,生产级接收方需要:
  1. 跑在 HTTPS 上。 无例外 —— tokensecret 在传输中都敏感。
  2. 先验签X-BeeOS-Signature)—— 注册了 secret 时。用 §6 的 recipe。不匹配或时间戳过旧返回 401
  3. 再验可选的 Authorization bearer token —— 注册了 token 时。 不匹配返回 401
  4. 1s 内 ACK(10s 上限)。payload 内部排队;不在 inline 跑业务逻辑。
  5. 保持幂等 —— retry 调度器可能引入重复(at-least-once 投递)。 按 (task_id, status, timestamp) 作为 key,在接收方去重。
  6. 对必须不丢的终止态 webhook(如计费相关),周期性轮询 GET /tasks/{id}。Webhook 是”快速通知”;API 是”真相”。
  7. 丢弃未知 type —— renderer 的扩展按 ADR-0017 是加法(额外 字段 / 新类型);不要对新事件类型崩溃。

6. HMAC 签名(P2-A)

注册时设 secret 开启 HMAC-SHA256 body 签名(见 §2)。投递器随后 在每次回调上发两个额外 header:
  • X-BeeOS-Event: task.state
  • X-BeeOS-Task-Id: ch-uuid
  • X-BeeOS-Signature: t=<unix>,v1=<hex>,其中 hex = hmac_sha256(secret, "<unix>." || body)
其他 header(X-BeeOS-Webhook-Format、可选的 Authorization: Bearer <token>)不变。轮换期可同时叠加签名 + bearer token。

验证 recipe —— Python

验证 recipe —— Node.js / Express

关键:对原始请求字节做 hash,不是对重新序列化的 JSON 对象。 重新序列化会改变空白 / key 顺序,HMAC 不会匹配。

为什么有 ±5 分钟时差检查?

没有时间戳检查时,捕获一次有效回调的攻击者可以永久重放。拒绝过旧或 未来日期的时间戳缩小重放窗口。±5 分钟是 BeeOS 推荐值;封闭网络 接收方可以更严。

7. 投递审计日志 + 手动重放(P2-A part 3)

每次回调尝试现在都被记录为一行持久行,可通过两个 REST 端点列出和 重放。这些行能熬过进程崩溃(lease 过期后 retry worker 接管), 所以临时部署 / 滚动重启不再丢失飞行中的回调。

重试日程

失败一次后,按固定退避重排: 行在尝试之间保持 pending(schedule 触发时 worker 把它从 failed 翻回 pending)。 POST .../redeliver 手动重放无论之前自动重试 多少次,都会把行 clone 为一行新的 pending

生命周期状态

GET .../deliveries

返回最近的投递行,新到旧。limit 钳制到 [1, 200],默认 50。
原始 payload 字节、bearer token、HMAC secret 永不返回 —— 只有诊断字段。要验证接收方应该看到什么,请查阅你自己的源任务 状态切换日志;renderer 字段告诉你应用了哪个 payload schema。

POST .../redeliver

把一行 faileddead_letter clone 为一行新的 pending。clone 重发完全一致的 payload 字节(和 HMAC 签名)—— 接收方可以把 手动重放的回调和自动重试同等对待。 返回 202 + 新 pending 行:
错误: 每次 redeliver 调用都入队一行新的 pending —— 反复调用产生反复 投递。把此端点当作手动救场,不是调用方侧”网络出错就重试”的工具。

另请参阅