Claude Platform Docs
Managed Agents에이전트에 작업 위임

웹훅 구독하기

폴링 없이 주요 이벤트가 발생할 때 알림을 받으세요.

세션은 장기 실행되는 상호작용입니다. 대부분의 실시간 상호작용은 SSE 이벤트 스트림을 통해 이루어지지만, "webhook"(웹훅)은 주요 상태 변경을 알려 줍니다.

웹훅 이벤트는 전체 객체가 아니라 이벤트 type과 id를 반환합니다. 웹훅 이벤트를 수신하면 GET 호출로 객체를 직접 가져와야 합니다. 이렇게 하면 재시도 시 오래된 데이터가 전달되는 것을 방지하고 모든 전달을 작게 유지할 수 있습니다.

지원되는 이벤트 유형

이러한 이벤트 중 일부는 세션의 이벤트 스트림에 있는 대응 이벤트와 이름이 다릅니다. 예를 들어, 스트림의 session.status_idle 및 session.status_running은 session.status_idled 및 session.status_run_started 웹훅 이벤트에 해당합니다.

이벤트트리거
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스레드가 보관 처리되었거나 재시도를 모두 소진하여 멀티에이전트 스레드가 종료되었습니다. 작업을 마친 서브에이전트는 terminated가 아니라 idle 상태가 됩니다(어드바이저 스레드는 자문이 완료되면 종료되고, 워크플로 실행의 스레드는 실행이 끝날 때까지 서버가 보관 처리하면 종료됩니다). 하위 스레드에 대해서만 발생하며, 전체 세션 보관을 포함한 기본 스레드의 종료는 session.status_terminated로만 나타납니다.
session.outcome_evaluation_ended단일 반복에 대한 결과 평가가 완료되었습니다.
session.updated세션 속성이 변경되었습니다(예: 이름이나 구성이 업데이트됨).
session.deleted세션이 영구적으로 삭제되었습니다. 가져올 객체가 남아 있지 않으므로 이벤트 자체를 최종 상태로 취급하세요.

엔드포인트 등록하기

Claude Console에서 Webhooks 페이지(platform.claude.com/settings/workspaces/default/webhooks)로 이동하세요. 각 엔드포인트는 하나의 워크스페이스에 속합니다. 사이드바의 워크스페이스 선택기에서 원하는 워크스페이스를 선택하세요.

웹훅 엔드포인트는 다음으로 구성됩니다:

  • URL: 공개적으로 확인 가능한 호스트 이름을 가진 443 포트의 HTTPS여야 합니다.
  • 이벤트 유형: 이 엔드포인트가 수신하는 data.type 값의 목록입니다. 엔드포인트는 구독한 이벤트만 수신합니다.
  • 서명 시크릿: 생성 시 만들어지는 whsec_ 접두사가 붙은 32바이트 시크릿입니다. 한 번만 표시되므로 웹훅 전달을 검증할 수 있도록 안전하게 보관하세요.

서명 검증하기

모든 전달에는 webhook-id, webhook-timestamp, webhook-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를 전달합니다. 마지막 시도가 실패하면 이벤트는 삭제됩니다. 나중에 전달하기 위해 대기열에 추가되지 않으며 손실되었다는 신호도 없습니다. 웹훅은 영구적인 로그가 아니므로, 모든 전환을 관찰해야 한다면 API를 통해 리소스를 나열하거나 가져와서 조정하세요.

  • 타임스탬프: webhook-timestamp 헤더는 전달 시도가 서명될 때 기록되며 재시도할 때마다 다시 생성되므로, 재시도가 SDK의 최신성 검사에서 거부되지 않습니다. 이는 이벤트가 아니라 전달 시도의 시각입니다. 이벤트가 발생한 시점은 이벤트 페이로드의 created_at를 사용하세요.

  • 자동 비활성화: 엔드포인트는 다음 세 가지 경우에 기계가 읽을 수 있는 disabled_reason과 함께 자동으로 disabled로 설정됩니다:

    • 엔드포인트가 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?