웹훅 구독하기
폴링 없이 주요 이벤트가 발생할 때 알림을 받으세요.
세션은 장기 실행되는 상호작용입니다. 대부분의 실시간 상호작용은 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 | 세션이 영구적으로 삭제되었습니다. 가져올 객체가 남아 있지 않으므로 이벤트 자체를 최종 상태로 취급하세요. |
| 이벤트 | 트리거 |
|---|---|
vault.created | 볼트가 생성되었습니다. |
vault.archived | 볼트가 보관 처리되었습니다. 각 하위 자격 증명에 대해 vault_credential.archived 이벤트도 발생합니다. |
vault.deleted | 볼트가 삭제되었습니다. 각 하위 자격 증명에 대해 vault_credential.deleted 이벤트도 발생합니다. 가져올 객체가 남아 있지 않으므로 이벤트 자체를 최종 상태로 취급하세요. |
vault_credential.created | 자격 증명이 생성되었습니다. |
vault_credential.archived | 자격 증명이 직접 또는 볼트 보관의 결과로 보관 처리되었습니다. |
vault_credential.deleted | 자격 증명이 직접 또는 볼트 삭제의 결과로 삭제되었습니다. 가져올 객체가 남아 있지 않으므로 이벤트 자체를 최종 상태로 취급하세요. |
vault_credential.refresh_failed | mcp_oauth 자격 증명을 갱신할 수 없습니다(유효하지 않은 갱신 토큰 또는 OAuth 서버의 복구 불가능한 오류). |
이러한 이벤트는 워크스페이스에 있는 에이전트 리소스의 수명 주기를 추적하며, 세션의 이벤트 스트림에서 전달되는 에이전트 이벤트와는 다릅니다.
| 이벤트 | 트리거 |
|---|---|
agent.created | 에이전트가 생성되었습니다. |
agent.updated | 에이전트의 새 버전이 게시되었습니다. 새 버전을 생성하지 않는 업데이트는 이 이벤트를 트리거하지 않습니다. |
agent.archived | 에이전트가 보관 처리되었습니다. |
agent.deleted | 에이전트가 영구적으로 삭제되었습니다. 가져올 객체가 남아 있지 않으므로 이벤트 자체를 최종 상태로 취급하세요. |
| 이벤트 | 트리거 |
|---|---|
deployment.created | 예약된 배포가 생성되었습니다. |
deployment.updated | 배포 속성이 변경되었습니다(예: 일정이 업데이트됨). |
deployment.paused | 요청에 의해, 또는 예약된 실행이 보관된 서브에이전트나 보관된 환경과 같은 복구 불가능한 오류로 실패하여 자동으로 배포가 일시 중지되었습니다. 속도 제한을 포함한 복구 가능한 실패는 배포를 일시 중지하지 않습니다. 실패 동작을 참조하세요. |
deployment.unpaused | 배포의 일시 중지가 해제되어 일정이 재개되었습니다. |
deployment.archived | 배포가 직접 또는 해당 에이전트가 보관 처리되어 보관 처리되었습니다. 에이전트가 대신 삭제된 경우, 예약된 배포는 다음 예약 실행 시점에 보관 처리되며, 일정이 없는 배포는 자동으로 보관 처리되지 않습니다. |
deployment.deleted | 배포가 영구적으로 삭제되었습니다. 가져올 객체가 남아 있지 않으므로 이벤트 자체를 최종 상태로 취급하세요. |
| 이벤트 | 트리거 |
|---|---|
deployment_run.started | 예약된 실행이 시작되었습니다. 예약된 실행만 deployment_run 이벤트를 발생시키며, 수동 실행은 발생시키지 않습니다. |
deployment_run.succeeded | 예약된 실행이 세션을 생성했습니다. 이 이벤트는 해당 실행의 deployment_run.started 이벤트와 동일한 data.id(실행 ID)를 포함합니다. 세션의 작업을 추적하려면 해당 세션 이벤트(세션 이벤트 탭)를 구독하거나, 배포 실행을 가져와 session_id를 확인하세요. |
deployment_run.failed | 예약된 실행이 세션을 생성하지 못했습니다. 이 이벤트는 해당 실행의 deployment_run.started 이벤트와 동일한 data.id를 포함합니다. 오류 세부 정보는 배포 실행을 가져와 확인하세요. |
| 이벤트 | 트리거 |
|---|---|
environment.created | 환경이 생성되었습니다. |
environment.updated | 하나 이상의 필드가 변경되어 환경이 업데이트되었습니다. 변경 사항이 없는 업데이트는 아무것도 발생시키지 않습니다. |
environment.archived | 환경이 보관 처리되었습니다. 이미 보관된 환경을 다시 보관해도 아무것도 발생하지 않습니다. |
environment.deleted | 이미 보관된 환경의 삭제를 포함하여 환경이 삭제되었습니다. 가져올 객체가 남아 있지 않으므로 이벤트 자체를 최종 상태로 취급하세요. |
환경의 작업 항목은 웹훅 이벤트를 발생시키지 않습니다.
| 이벤트 | 트리거 |
|---|---|
memory_store.created | 사용자가 직접 또는 기존 스토어 중 하나를 복제하는 Anthropic 운영 프로세스에 의해 메모리 스토어가 생성되었습니다. |
memory_store.archived | 메모리 스토어가 보관 처리되었습니다. 이미 보관된 스토어를 다시 보관해도 아무것도 발생하지 않습니다. |
memory_store.deleted | 이미 보관된 스토어의 삭제를 포함하여 메모리 스토어가 삭제되었습니다. 스토어를 삭제하면 메모리별 이벤트를 발생시키지 않고 해당 메모리와 메모리 버전까지 연쇄적으로 삭제되며, 단일 memory_store.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?