웹훅 구독하기
폴링 없이 주요 이벤트가 발생할 때 알림을 받으세요.
세션은 장시간 실행되는 상호작용입니다. 대부분의 실시간 상호작용은 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에서 Manage > 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?