Claude Platform Docs
Managed Agents将工作委派给智能体

订阅 webhook

无需轮询即可在重大事件发生时获得通知。

会话是长时间运行的交互。虽然大多数实时交互通过 SSE 事件流进行,但 webhook 会在发生重大状态变更时通知您。

Webhook 事件返回事件的 typeid,而不是完整对象。当您收到 webhook 事件时,需要通过 GET 调用直接获取该对象。这样可以避免在重试时传递过时数据,并使每次传递都保持小巧。

支持的事件类型

其中一些事件的命名与会话事件流上对应事件的命名不同。例如,事件流中的 session.status_idlesession.status_running 分别对应 session.status_idledsession.status_run_started webhook 事件。

事件触发条件
session.status_run_started智能体开始执行。每次会话状态转换为 running 时都会触发。
session.status_idled智能体正在等待输入,例如工具权限批准或新的用户消息。
session.budget_reached会话达到其预算并已暂停。对于您设置的每个预算值最多触发一次;更改预算会重新启用该触发。
session.status_rescheduled发生了瞬时错误,会话正在自动重试。
session.status_terminated会话已终止,原因可能是不可恢复的错误,也可能是会话已被归档。
session.thread_created新的多智能体线程已打开:由协调者调用的另一个智能体正在开始工作,或者正在咨询会话的顾问
session.thread_idled多智能体交互中的某个智能体正在等待输入。
session.thread_terminated多智能体线程已终止,原因可能是线程已被归档,也可能是其重试次数已用尽。由协调者生成的子线程在完成工作后会进入 idle 状态,而不是 terminated(顾问线程在咨询完成后即终止)。仅针对子线程触发;主线程的结束(包括归档整个会话)仅以 session.status_terminated 的形式呈现。
session.outcome_evaluation_ended单次迭代的结果评估已完成。
session.updated会话属性已更改(例如,其名称或配置已更新)。
session.deleted会话已永久删除。没有可供获取的对象,因此请将事件本身视为最终结果。

注册端点

访问 Claude Console 中的 Manage > Webhooks

一个 webhook 端点由以下部分组成:

  • URL: 必须是 443 端口上的 HTTPS,且主机名可公开解析。
  • 事件类型: 此端点接收的 data.type 值列表。端点只会接收其已订阅的事件。
  • 签名密钥: 创建时生成的 32 字节、以 whsec_ 为前缀的密钥。它只显示一次,因此请安全存储以用于验证 webhook 传递。

验证签名

每次传递都携带 webhook-idwebhook-timestampwebhook-signature 标头。使用 SDK 的 unwrap() 辅助函数可一步完成签名验证和事件解析。如果签名无效或负载超过 5 分钟,它会抛出异常。

ANTHROPIC_WEBHOOK_SIGNING_KEY 设置为端点创建时显示的以 whsec_ 为前缀的密钥。

from flask import Flask, request
import anthropic

client = anthropic.Anthropic()  # reads ANTHROPIC_WEBHOOK_SIGNING_KEY from env
app = Flask(__name__)


@app.route("/webhook", methods=["POST"])
def webhook():
    try:
        # 若签名无效或负载已过期,unwrap() 会抛出异常
        event = client.beta.webhooks.unwrap(
            request.get_data(as_text=True),
            headers=dict(request.headers),
        )
    except Exception:
        return "invalid signature", 400

    if event.data.type == "session.status_idled":
        print("session idled:", event.data.id)
    # 处理其他事件类型

    return "", 200

处理事件

解析请求体,根据 data.type 进行分支处理,并按 ID 获取资源。返回任意 2xx 即表示确认。任何其他响应都会计入端点的失败记录:3xx 会立即禁用该端点(从不跟随重定向),而其他失败会被重试;有关重试和自动禁用规则,请参阅传递行为

每个事件负载都具有相同的结构,包括事件类型、标识符以及事件发生时的时间戳。

{
  "type": "event",
  "id": "whe_9d5c1f7e...",
  "created_at": "2026-03-18T14:05:22Z",
  "data": {
    "type": "session.status_idled",
    "id": "sesn_01XYZ...",
    "organization_id": "8a3d2f1e-...",
    "workspace_id": "c7b0e4d9-..."
  }
}
if event.data.type == "session.status_idled":
    session = client.beta.sessions.retrieve(event.data.id)
    notify_user(session)
return "", 204

顶层的 event.id 对每个事件唯一,而非对每次传递唯一。如果您两次收到相同的 event.id,则说明是重试,可以将其丢弃。

传递行为

  • 重复: 端点可能多次收到同一事件,且每次尝试都会传递相同的顶层 event.id(与 webhook-id 标头的值相同)。请据此去重。

  • 订阅范围: 事件仅传递给在其发出时刻已订阅该类型的端点。在没有任何端点订阅某类型时发出的该类型事件永远不会被传递,之后再订阅也不会补发,因此请在需要之前就订阅相应的事件类型。

  • 不保证顺序。 事件不会按其发生顺序传递:即使结果先产生,session.status_idled 也可能先于 session.outcome_evaluation_ended 到达;同一资源的 .deleted 事件也可能先于 .archived 事件到达。请根据您获取的资源来驱动状态,而不是根据事件到达的顺序。

  • 重试: 对于每个端点和事件,Anthropic 最多进行三次传递尝试(触发自动禁用的响应永远不会重试,详见本节后文),尝试之间采用 5 到 120 秒的带抖动指数退避。每次尝试都传递相同的 event.id。最后一次尝试失败后,事件将被丢弃:不会排队等待稍后传递,也没有任何信号表明它已丢失。Webhook 不是持久日志,因此如果您需要观察每一次状态转换,请通过 API 列出或获取资源来进行对账。

  • 时间戳: webhook-timestamp 标头在传递尝试签名时生成,并在每次重试时重新生成,因此重试不会被 SDK 的新鲜度检查拒绝。它是传递尝试的时钟,而非事件的时钟:请使用事件负载中的 created_at 来确定事件发生的时间。

  • 自动禁用: 在以下三种情况下,端点会被自动设置为 disabled,并附带机器可读的 disabled_reason

    • 端点返回 3xx 响应。从不跟随重定向;这会在第一次尝试时立即禁用端点,原因为 auto-disabled: endpoint URL returned a redirect (3xx)。如果您的端点已迁移,请在 Console 中更新 URL 并重新启用该端点。
    • 当 Anthropic 连接时,端点的 URL 解析为非公网 IP 地址。这会立即禁用端点,原因为 auto-disabled: endpoint URL resolved to an invalid address
    • 向端点的传递在一段持续时间内连续失败,原因为 auto-disabled after sustained delivery failures。触发条件是端点不间断失败的持续时长,而非传递次数。一次 2xx 即可重置该窗口,因此单个不稳定的事件不会导致端点被禁用。

    这三种情况都是可逆的:解决问题后,在 Console 中重新启用端点即可。端点被禁用期间发出的事件不会重放。

Was this page helpful?