VOOZH about

URL: https://platform.claude.com/docs/en/managed-agents/webhooks

⇱ Subscribe to webhooks - Claude API Docs


Subscribe to webhooks
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...

Sessions are long-running interactions. While most real-time interactions happen through the SSE event stream, webhooks notify you of major state changes.

Webhook events return the event type and id, not the full object. When you receive a webhook event, you need to fetch the object directly with a GET call. This avoids delivering stale data on retries and keeps every delivery small.

Supported event types

Register an endpoint

Visit Manage > Webhooks in Console.

A webhook endpoint consists of:

  • URL: Must be HTTPS on port 443 with a publicly resolvable hostname.
  • Event types: The list of data.type values this endpoint receives. An endpoint only receives events it's subscribed to, plus test events (see Delivery behavior).
  • Signing secret: A 32-byte whsec_-prefixed secret generated at creation. It's shown only once, so store it securely to verify webhook deliveries.

Verify the signature

Every delivery carries an X-Webhook-Signature header. Use the SDK's unwrap() helper to verify the signature and parse the event in one step. It throws if the signature is invalid or the payload is more than five minutes old.

Set ANTHROPIC_WEBHOOK_SIGNING_KEY to the whsec_-prefixed secret shown at endpoint creation.

Handle an event

Parse the body, switch on data.type, and fetch the resource by ID. Return any 2xx to acknowledge. Anything else (including 3xx) counts as a failure and triggers a retry.

Every event payload has the same structure, including the event type, identifier, and timestamp of when the object was created.

{
 "type": "event",
 "id": "event_01ABC...",
 "created_at": "2026-03-18T14:05:22Z",
 "data": {
 "type": "session.status_idled",
 "id": "sesn_01XYZ...",
 "organization_id": "8a3d2f1e-...",
 "workspace_id": "c7b0e4d9-..."
 }
}

The top-level event.id is unique per event, not per delivery. If you receive the same event.id twice, it's a retry and you can discard it.

Delivery behavior

  • Ordering is not guaranteed. session.status_idled may arrive before session.outcome_evaluation_ended even if the outcome was produced first. Use the created_at timestamp to sort if ordering matters.
  • Retries: Anthropic retries at least once. The retry delivers the same event.id.
  • Redirects are not followed. A 3xx is treated as a failure. If your endpoint moves, update the URL in Console.
  • Auto-disable: An endpoint is automatically set to disabled with a machine-readable disabled_reason after roughly 20 consecutive failed deliveries, or immediately if the hostname resolves to a private IP or the endpoint returns a redirect. Re-enable manually in Console after resolving the issue.

Was this page helpful?

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() raises if the signature is invalid or the payload is stale
 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)
 # handle other event types

 return "", 200
if event.data.type == "session.status_idled":
 session = client.beta.sessions.retrieve(event.data.id)
 notify_user(session)
return "", 204