セッションは長時間実行されるインタラクションです。ほとんどのリアルタイムインタラクションはSSEイベントストリームを通じて行われますが、webhookは主要な状態変化を通知します。
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_プレフィックス付きシークレット。一度しか表示されないため、webhook配信を検証するために安全に保管してください。すべての配信にはwebhook-id、webhook-timestamp、webhook-signatureヘッダーが含まれます。SDKのunwrap()ヘルパーを使用して、署名の検証とイベントの解析を1ステップで行います。署名が無効な場合、またはペイロードが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を2回受信した場合、それはリトライであり、破棄できます。
重複: エンドポイントは同じイベントを複数回受信する可能性があり、すべての試行で同じトップレベルのevent.id(webhook-idヘッダーと同じ値)が配信されます。これを使って重複排除してください。
購読のスコープ: イベントは、発行された時点でそのタイプを購読しているエンドポイントにのみ配信されます。どのエンドポイントもそのタイプを購読していない間に発行されたイベントは決して配信されず、後から購読してもバックフィルされないため、必要になる前にイベントタイプを購読してください。
順序は保証されません。 イベントは発生した順序で配信されるとは限りません。アウトカムが先に生成された場合でも、session.status_idledがsession.outcome_evaluation_endedより先に到着する可能性があり、同じリソースに対して.deletedイベントが.archivedイベントより先に到着する可能性があります。イベントの到着順序ではなく、取得したリソースから状態を導出してください。
リトライ: 各エンドポイントとイベントに対して、Anthropicは5秒から120秒の間のジッター付き指数バックオフで最大3回の配信試行を行います(このセクションで後述する自動無効化をトリガーするレスポンスは決してリトライされません)。すべての試行で同じevent.idが配信されます。最後の試行が失敗した後、イベントは破棄されます。後で配信するためにキューに入れられることはなく、失われたことを示すシグナルもありません。Webhookは永続的なログではないため、すべての遷移を観察する必要がある場合は、APIを通じてリソースをリストまたは取得して照合してください。
タイムスタンプ: webhook-timestampヘッダーは配信試行が署名されるときに刻印され、リトライのたびに再生成されるため、リトライがSDKの鮮度チェックで拒否されることはありません。これはイベントではなく配信試行のクロックです。イベントが発生した時刻には、イベントペイロードのcreated_atを使用してください。
自動無効化: 以下の3つのケースでは、エンドポイントは機械可読なdisabled_reasonとともに自動的にdisabledに設定されます。
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でウィンドウがリセットされるため、1つの不安定なイベントでエンドポイントが無効化されることはありません。3つすべてが可逆的です。問題を解決した後、Consoleでエンドポイントを再度有効化してください。エンドポイントが無効化されている間に発行されたイベントは再送されません。
Was this page helpful?