跳转到主要内容
当一条防火墙规则返回 pending_approval 判定时,网关会挂起这次工具调用并 带外通知你自己的审批系统。那条通知是一个签名的 HTTP POST——即防火墙 webhook 负载——而本页记录它确切的形状,让你能验证签名、路由该事件, 并回发你的决策。 这是 防火墙 页面所描述的控制台内 审批流程的异步姊妹。控制台路径(一名审查者点击批准/拒绝)完全不需要 webhook。webhook 用于当你想让一个机器——你自己的工单机器人、Slack 动作或智能体运行时——来解决这次挂起。两条路径都是首个写入者生效 (first-writer-wins),因此你可以并排运行它们。
该 webhook 是一个尽力而为的路由信号,而非权威的 HITL 通道。智能体 自己对 GET /api/v1/firewall/approvals/:id 的长轮询才是兜底——如果一条通知被丢弃或你的端点短暂下线,被挂起的调用 仍会出现在控制台并正常解决。webhook 只是让一个机器能比人更快地反应。

1. 防火墙 webhook 负载一览

OrcaRouter 向你配置的 URL POST 一个 JSON 信封,用一个共享密钥签名。 这是一次完整的投递——头部和正文:
POST /your-approval-endpoint HTTP/1.1
Content-Type: application/json
X-Orca-Event: firewall.approval.pending
X-Orca-Signature: sha256=9f86d0818988...c2c9a3e1b4d7

{
  "event": "firewall.approval.pending",
  "workspace_id": 42,
  "occurred_at": "2026-06-09T12:00:00.123456789Z",
  "data": {
    "approval_id": "665f1a2b3c4d5e6f7a8b9c0d",
    "tool_name": "db.export",
    "request_id": "req_01J9X...",
    "conversation_id": "conv_8f2a...",
    "policy_id": 7,
    "rule_id": 31
  }
}
这个信封与 OrcaRouter 用于每一个签名事件的形状相同,因此一个接收器可以 凭 X-Orca-Event 路由许多事件类型而无需解析正文。

2. 信封字段

对一次审批挂起总是 firewall.approval.pending。在 X-Orca-Event 头部里镜像,因此你可以在解析正文之前就路由。
其策略挂起了这次调用的工作区的整数 id。当一个端点接收来自多个工作区 的 webhook 时很有用。
网关把审批入队时刻的 RFC 3339 / UTC 时间戳(纳秒精度)。可被任何标准 事件工具解析。
你的回调用于解决该门控所需的那一块。字段见 §3

3. data 负载

data 块携带路由和解决这次挂起所需的一切——刻意地不含工具参数。 该 webhook 是一个路由信号;完整的调用上下文(工具、参数、触发的规则) 存在于控制台 Approvals 标签和审计日志里,那里有访问控制。
字段类型含义
approval_idstring你回发决策所针对的 id。
tool_namestring被挂起的工具,例如 db.export
request_idstring触发这次挂起的那次中继请求。
conversation_idstring智能体对话 / 会话 id。
policy_idint匹配到的防火墙策略。
rule_idint返回 pending_approval 的规则。
需要参数或匹配到的子句来做决策?从控制台 Approvals 标签(Developer+) 读取它们,或让你的智能体用它的网关令牌轮询 GET /api/v1/firewall/approvals/:id。该 webhook 刻意从不把参数带过线缆。

4. 验证签名

每一次投递都被签名,因此你可以拒绝伪造。签名头部是:
X-Orca-Signature: sha256=<hex HMAC-SHA256(secret, raw_body)>
其中 secret 是你在工作区上设置的审批 webhook 密钥,而 raw_body 是请求 正文的确切字节。在原始字节上计算 HMAC——重新序列化解析后的 JSON 会 改变空白并破坏比较。以恒定时间验证:
import hmac, hashlib

def verify(raw_body: bytes, header: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(), raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, header)
出站 webhook 签名只覆盖正文。你回发的入站回调§6)签名的是 approval_id + 一个换行 + 正文——一种不同的构造,有意为之,这样一个被捕获的 签名就无法在不同审批之间被重放。不要对两个方向复用同一个签名例程。

5. 配置 webhook

目的地 URL 和共享密钥是工作区设置——在控制台里一次性设置它们(或经由 设置 API;Developer+)。无需运维介入,也没有要部署的东西。
1

设置 URL 和密钥

在防火墙设置里,把你的 HTTPS 端点设为审批 webhook URL,并设一个强壮的 共享密钥。URL 必须是 https://——明文目的地会被拒绝——而密钥是只写的 (读取时永不返回;设置响应只报告是否已设置了一个)。
2

编写一条 pending_approval 规则

添加一条判定为 pending_approval 的防火墙规则(或使用 HITL 预设)。 参见 防火墙规则
3

接收并验证

你的端点会在下一次被挂起的调用上收到签名的 POST。验证签名 (§4),然后要么经由回调解决,要么把它 浮现给人工。
一次被挂起的调用在没有配置 webhook 时依然有效——它只是出现在控制台 里供人工解决。而如果你设置了 URL 但没设密钥,网关会完全跳过这次派发, 因为回调端点只接受签名的请求:一条你无法回头认证的通知是没有用的。

6. 回调:解决这次挂起

要由机器批准或拒绝,回发到:
POST /api/v1/firewall/approvals/:id/callback
带上你作为 approval_id 收到的同一个 :id,用同一个共享密钥签名。正文 是一个决策:
BODY='{"decision":"approved","reason":"ticket OPS-4821 approved by on-call"}'
SIG="sha256=$(printf '%s\n%s' "$APPROVAL_ID" "$BODY" \
  | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')"

curl https://api.orcarouter.ai/api/v1/firewall/approvals/$APPROVAL_ID/callback \
  -H "Content-Type: application/json" \
  -H "X-Orca-Signature: $SIG" \
  -d "$BODY"
正文字段必填取值
decisionapprovedrejected
reason自由文本备注,记录在审计日志中。
一个 approved 决策让智能体的下一次尝试通过一次——智能体携带一次性的 X-OrcaRouter-Firewall-Approval 头重新提交原始调用。一个 rejected 决策 让这次调用保持被拦。
解决是幂等且首个写入者生效的。如果一名人工已经从控制台解决了这次 挂起——或者一个重复回调到达——端点返回 200,带 already_resolved: true, 并保留原始决策。可安全重试。

7. 审批状态

一次被挂起的调用经历这些状态;你的回调驱动它脱离 pending 的跃迁:
状态含义
pending等待一个决策(webhook 发出时的状态)。
approved已解决——被门控的调用可以进行一次。
rejected已解决——被门控的调用保持被拦。
expired这次挂起在没有决策的情况下超期失效。

8. 相关参考

防火墙 —— HITL 流程

pending_approval 如何挂起一次调用,以及智能体如何携带一次性审批头 重新提交。

错误码

firewall_approval_pending 以及其他防火墙 HTTP 响应。

判定词汇表

每一个防火墙判定,包括 pending_approval

防火墙 API

完整的控制台 + 网关路由参考。
关于挂起如何契合更宏观的控制模型,参见 执行模式危险的工具调用