会话是长时间运行的交互。虽然大多数实时交互通过 SSE 事件流进行,但 webhooks 会在重大状态变化时通知您。
Webhook 事件返回事件的 type 和 id,而不是完整的对象。当您收到 webhook 事件时,需要通过 GET 调用直接获取该对象。这可以避免在重试时传递过时的数据,并使每次传递保持小巧。
| 事件 | 触发条件 |
|---|---|
session.status_run_started | 代理执行已启动。每当会话状态转换为 running 时都会触发。 |
session.status_idled | 代理正在等待输入,例如工具权限批准或新的用户消息。 |
session.status_rescheduled | 发生了瞬时错误,会话正在自动重试。 |
session.status_terminated | 会话已终止,原因是错误或完成。 |
session.thread_created | 新的多代理线程已打开,这意味着协调器调用的另一个代理正在开始工作。 |
session.thread_idled | 多代理交互中的某个代理正在等待输入。 |
session.thread_terminated | 一个多代理线程已终止,原因是子代理完成了其工作或该线程被归档。仅对子线程触发;主线程的结束以 session.status_terminated 的形式呈现。 |
session.outcome_evaluation_ended | 单次迭代的结果评估已完成。 |
session.updated | 会话属性已更改(例如,其名称或配置已更新)。 |
session.deleted | 会话已被永久删除。没有可供获取的对象,因此将该事件本身视为最终结果。 |
访问 Console 中的 Manage > Webhooks。
一个 webhook 端点包括:
data.type 值列表。端点只接收其已订阅的事件。whsec_ 为前缀的 32 字节密钥。它只显示一次,因此请安全地存储它以验证 webhook 传递。每次传递都携带 webhook-id、webhook-timestamp 和 webhook-signature 标头。使用 SDK 的 unwrap() 辅助函数一步完成签名验证和事件解析。如果签名无效或负载超过五分钟,它会抛出异常。
将 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。最后一次尝试失败后,该事件将被丢弃:它不会排队等待稍后传递,也没有任何信号表明它已丢失。Webhooks 不是持久化日志,因此如果您需要观察每一次转换,请通过 API 列出或获取资源来进行对账。
时间戳: webhook-timestamp 标头在传递尝试被签名时打上时间戳,并在每次重试时重新生成,因此重试不会被 SDK 的新鲜度检查拒绝。它是传递尝试的时钟,而不是事件的时钟:请使用事件负载的 created_at 来确定事件发生的时间。
自动禁用: 在以下三种情况下,端点会被自动设置为 disabled,并带有机器可读的 disabled_reason:
3xx 响应。重定向永远不会被跟随;这会在第一次尝试时立即禁用端点,原因为 auto-disabled: endpoint URL returned a redirect (3xx)。如果您的端点迁移了,请在 Console 中更新 URL 并重新启用该端点。auto-disabled: endpoint URL resolved to an invalid address。auto-disabled after sustained delivery failures。触发条件是端点不间断失败的持续时长,而不是传递次数。单次 2xx 会重置该窗口,因此一个偶发失败的事件不会禁用端点。这三种情况都是可逆的:在解决问题后,在 Console 中重新启用该端点。端点被禁用期间发出的事件不会被重放。
Was this page helpful?