---
title: 웹훅 구독하기
url: https://platform.claude.com/docs/ko/managed-agents/webhooks
description: 폴링 없이 주요 이벤트가 발생할 때 알림을 받으세요.
featureMetadata:
  topic:
    title: Managed Agents
    url: https://platform.claude.com/docs/en/managed-agents/overview
  status: beta
  betaHeader: managed-agents-2026-04-01
---

세션은 장기 실행되는 상호작용입니다. 대부분의 실시간 상호작용은 [SSE 이벤트 스트림](https://platform.claude.com/docs/ko/managed-agents/events-and-streaming)을 통해 이루어지지만, "webhook"(웹훅)은 주요 상태 변경을 알려 줍니다.

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

## 지원되는 이벤트 유형

<Tabs>
  <Tab title="세션 이벤트">
    이러한 이벤트 중 일부는 세션의 [이벤트 스트림](https://platform.claude.com/docs/ko/managed-agents/events-and-streaming)에 있는 대응 이벤트와 이름이 다릅니다. 예를 들어, 스트림의 `session.status_idle` 및 `session.status_running`은 `session.status_idled` 및 `session.status_run_started` 웹훅 이벤트에 해당합니다.

    | 이벤트                                | 트리거                                                                                                                                                                                                                                                                                                                                                                                                                  |
    | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `session.status_run_started`       | 에이전트 실행이 시작되었습니다. 세션 상태가 `running`으로 전환될 때마다 트리거됩니다.                                                                                                                                                                                                                                                                                                                                                                 |
    | `session.status_idled`             | 에이전트가 입력을 기다리고 있습니다. 예를 들어 도구 권한 승인이나 새 사용자 메시지를 기다리는 경우입니다.                                                                                                                                                                                                                                                                                                                                                         |
    | `session.budget_reached`           | 세션이 [예산](https://platform.claude.com/docs/ko/managed-agents/budgets)에 도달하여 일시 중지되었습니다. 설정한 각 예산 값에 대해 최대 한 번 발생하며, 예산을 변경하면 다시 활성화됩니다.                                                                                                                                                                                                                                                                               |
    | `session.status_rescheduled`       | 일시적인 오류가 발생하여 세션이 자동으로 재시도하고 있습니다.                                                                                                                                                                                                                                                                                                                                                                                   |
    | `session.status_terminated`        | 복구할 수 없는 오류로 인해 또는 보관 처리되어 세션이 종료되었습니다.                                                                                                                                                                                                                                                                                                                                                                              |
    | `session.thread_created`           | 새 [멀티에이전트 스레드](https://platform.claude.com/docs/ko/managed-agents/session-threads)가 열렸습니다. 세션이 실행하는 에이전트가 호출한 추가 에이전트가 작업을 시작하거나, 세션의 [어드바이저](https://platform.claude.com/docs/ko/managed-agents/multiagent-orchestration#give-the-session-an-advisor)에게 자문을 구하는 경우입니다. 또한 [워크플로 실행](https://platform.claude.com/docs/ko/managed-agents/workflow-runs#a-runs-threads)의 각 스레드에 대해서도 발생하며, 이 표의 다른 두 스레드 이벤트도 마찬가지입니다. |
    | `session.thread_idled`             | [멀티에이전트 상호작용](https://platform.claude.com/docs/ko/managed-agents/session-threads)의 에이전트가 입력을 기다리고 있습니다.                                                                                                                                                                                                                                                                                                              |
    | `session.thread_terminated`        | 스레드가 보관 처리되었거나 재시도를 모두 소진하여 [멀티에이전트 스레드](https://platform.claude.com/docs/ko/managed-agents/session-threads)가 종료되었습니다. 작업을 마친 서브에이전트는 `terminated`가 아니라 `idle` 상태가 됩니다(어드바이저 스레드는 자문이 완료되면 종료되고, 워크플로 실행의 스레드는 실행이 끝날 때까지 서버가 보관 처리하면 종료됩니다). 하위 스레드에 대해서만 발생하며, 전체 세션 보관을 포함한 기본 스레드의 종료는 `session.status_terminated`로만 나타납니다.                                                                                      |
    | `session.outcome_evaluation_ended` | 단일 반복에 대한 [결과 평가](https://platform.claude.com/docs/ko/managed-agents/define-outcomes)가 완료되었습니다.                                                                                                                                                                                                                                                                                                                      |
    | `session.updated`                  | 세션 속성이 변경되었습니다(예: 이름이나 구성이 업데이트됨).                                                                                                                                                                                                                                                                                                                                                                                   |
    | `session.deleted`                  | 세션이 영구적으로 삭제되었습니다. 가져올 객체가 남아 있지 않으므로 이벤트 자체를 최종 상태로 취급하세요.                                                                                                                                                                                                                                                                                                                                                          |
  </Tab>

  <Tab title="볼트 이벤트">
    | 이벤트                               | 트리거                                                                                                         |
    | --------------------------------- | ----------------------------------------------------------------------------------------------------------- |
    | `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 서버의 복구 불가능한 오류).                                       |
  </Tab>

  <Tab title="에이전트 이벤트">
    이러한 이벤트는 워크스페이스에 있는 에이전트 리소스의 수명 주기를 추적하며, 세션의 이벤트 스트림에서 전달되는 에이전트 이벤트와는 다릅니다.

    | 이벤트              | 트리거                                                                                                                                           |
    | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
    | `agent.created`  | 에이전트가 생성되었습니다.                                                                                                                                |
    | `agent.updated`  | [에이전트의 새 버전](https://platform.claude.com/docs/ko/managed-agents/agent-setup#update-an-agent)이 게시되었습니다. 새 버전을 생성하지 않는 업데이트는 이 이벤트를 트리거하지 않습니다. |
    | `agent.archived` | 에이전트가 보관 처리되었습니다.                                                                                                                             |
    | `agent.deleted`  | 에이전트가 영구적으로 삭제되었습니다. 가져올 객체가 남아 있지 않으므로 이벤트 자체를 최종 상태로 취급하세요.                                                                                 |
  </Tab>

  <Tab title="배포 이벤트">
    | 이벤트                   | 트리거                                                                                                                                                                                                                                |
    | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `deployment.created`  | [예약된 배포](https://platform.claude.com/docs/ko/managed-agents/scheduled-deployments)가 생성되었습니다.                                                                                                                                       |
    | `deployment.updated`  | 배포 속성이 변경되었습니다(예: 일정이 업데이트됨).                                                                                                                                                                                                      |
    | `deployment.paused`   | 요청에 의해, 또는 예약된 실행이 보관된 서브에이전트나 보관된 환경과 같은 복구 불가능한 오류로 실패하여 자동으로 배포가 일시 중지되었습니다. 속도 제한을 포함한 복구 가능한 실패는 배포를 일시 중지하지 않습니다. [실패 동작](https://platform.claude.com/docs/ko/managed-agents/scheduled-deployments#failure-behavior)을 참조하세요. |
    | `deployment.unpaused` | 배포의 일시 중지가 해제되어 일정이 재개되었습니다.                                                                                                                                                                                                       |
    | `deployment.archived` | 배포가 직접 또는 해당 에이전트가 보관 처리되어 보관 처리되었습니다. 에이전트가 대신 삭제된 경우, 예약된 배포는 다음 예약 실행 시점에 보관 처리되며, 일정이 없는 배포는 자동으로 보관 처리되지 않습니다.                                                                                                                |
    | `deployment.deleted`  | 배포가 영구적으로 삭제되었습니다. 가져올 객체가 남아 있지 않으므로 이벤트 자체를 최종 상태로 취급하세요.                                                                                                                                                                        |
  </Tab>

  <Tab title="배포 실행 이벤트">
    | 이벤트                        | 트리거                                                                                                                                                                                                                                                                                                                               |
    | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `deployment_run.started`   | 예약된 실행이 시작되었습니다. 예약된 실행만 `deployment_run` 이벤트를 발생시키며, [수동 실행](https://platform.claude.com/docs/ko/managed-agents/scheduled-deployments#trigger-a-manual-run)은 발생시키지 않습니다.                                                                                                                                                         |
    | `deployment_run.succeeded` | 예약된 실행이 세션을 생성했습니다. 이 이벤트는 해당 실행의 `deployment_run.started` 이벤트와 동일한 `data.id`(실행 ID)를 포함합니다. 세션의 작업을 추적하려면 해당 세션 이벤트(세션 이벤트 탭)를 구독하거나, [배포 실행](https://platform.claude.com/docs/ko/managed-agents/scheduled-deployments#deployment-runs)을 가져와 `session_id` (java: `sessionId`; php: `sessionID`; csharp, go: `SessionID`)를 확인하세요. |
    | `deployment_run.failed`    | 예약된 실행이 세션을 생성하지 못했습니다. 이 이벤트는 해당 실행의 `deployment_run.started` 이벤트와 동일한 `data.id`를 포함합니다. 오류 세부 정보는 [배포 실행](https://platform.claude.com/docs/ko/managed-agents/scheduled-deployments#deployment-runs)을 가져와 확인하세요.                                                                                                                 |
  </Tab>

  <Tab title="환경 이벤트">
    | 이벤트                    | 트리거                                                                       |
    | ---------------------- | ------------------------------------------------------------------------- |
    | `environment.created`  | 환경이 생성되었습니다.                                                              |
    | `environment.updated`  | 하나 이상의 필드가 변경되어 환경이 업데이트되었습니다. 변경 사항이 없는 업데이트는 아무것도 발생시키지 않습니다.           |
    | `environment.archived` | 환경이 보관 처리되었습니다. 이미 보관된 환경을 다시 보관해도 아무것도 발생하지 않습니다.                        |
    | `environment.deleted`  | 이미 보관된 환경의 삭제를 포함하여 환경이 삭제되었습니다. 가져올 객체가 남아 있지 않으므로 이벤트 자체를 최종 상태로 취급하세요. |

    환경의 [작업 항목](https://platform.claude.com/docs/ko/managed-agents/self-hosted-sandboxes)은 웹훅 이벤트를 발생시키지 않습니다.
  </Tab>

  <Tab title="메모리 스토어 이벤트">
    | 이벤트                     | 트리거                                                                                                                                                                               |
    | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `memory_store.created`  | 사용자가 직접 또는 기존 스토어 중 하나를 복제하는 Anthropic 운영 프로세스에 의해 메모리 스토어가 생성되었습니다.                                                                                                              |
    | `memory_store.archived` | 메모리 스토어가 보관 처리되었습니다. 이미 보관된 스토어를 다시 보관해도 아무것도 발생하지 않습니다.                                                                                                                          |
    | `memory_store.deleted`  | 이미 보관된 스토어의 삭제를 포함하여 메모리 스토어가 삭제되었습니다. 스토어를 삭제하면 메모리별 이벤트를 발생시키지 않고 해당 메모리와 메모리 버전까지 연쇄적으로 삭제되며, 단일 `memory_store.deleted` 이벤트가 그 신호입니다. 가져올 객체가 남아 있지 않으므로 이벤트 자체를 최종 상태로 취급하세요. |

    개별 [메모리](https://platform.claude.com/docs/ko/managed-agents/memory)와 메모리 버전은 웹훅 이벤트를 발생시키지 않습니다.
  </Tab>
</Tabs>

## 엔드포인트 등록하기

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

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

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

## 서명 검증하기

모든 전달에는 `webhook-id`, `webhook-timestamp`, `webhook-signature` 헤더가 포함됩니다. SDK의 `unwrap()` (csharp, go: `Unwrap()`) 헬퍼를 사용하면 서명 검증과 이벤트 파싱을 한 번에 수행할 수 있습니다. 서명이 유효하지 않거나 페이로드가 5분보다 오래된 경우 예외를 발생시킵니다.

`ANTHROPIC_WEBHOOK_SIGNING_KEY`를 엔드포인트 생성 시 표시된 `whsec_` 접두사가 붙은 시크릿으로 설정하세요.

<CodeGroup exclude="shell:cURL, shell:CLI">
  ```python Python
  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
  ```

  ```typescript TypeScript
  import express from "express";
  import Anthropic from "@anthropic-ai/sdk";

  const client = new Anthropic(); // reads ANTHROPIC_WEBHOOK_SIGNING_KEY from env
  const app = express();

  // 중요: express.json()이 아닌 express.raw()를 사용하세요. 서명은 원시 바이트를 기준으로 계산됩니다.
  app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
    let event;
    try {
      // unwrap()은 서명이 유효하지 않거나 페이로드가 오래된 경우 예외를 발생시킵니다
      event = client.beta.webhooks.unwrap(req.body.toString("utf8"), {
        headers: req.headers as Record<string, string>
      });
    } catch {
      return res.status(400).send("invalid signature");
    }

    switch (event.data.type) {
      case "session.status_idled":
        console.log("session idled:", event.data.id);
        break;
      // 다른 이벤트 유형을 처리합니다
    }

    res.sendStatus(200);
  });
  ```

  ```csharp C#
  using Anthropic;

  var client = new AnthropicClient(); // reads ANTHROPIC_WEBHOOK_SIGNING_KEY from env
  var app = WebApplication.Create(args);

  app.MapPost("/webhook", async (HttpRequest request) =>
  {
      using var reader = new StreamReader(request.Body);
      var body = await reader.ReadToEndAsync();
      var headers = request.Headers.ToDictionary(header => header.Key, header => header.Value.ToString());

      UnwrapWebhookEvent webhookEvent;
      try
      {
          // 서명이 유효하지 않거나 페이로드가 오래된 경우 Unwrap()은 예외를 발생시킵니다
          webhookEvent = client.Beta.Webhooks.Unwrap(body, headers);
      }
      catch
      {
          return Results.BadRequest("invalid signature");
      }

      if (webhookEvent.Data.TryPickSessionStatusIdled(out var idled))
      {
          Console.WriteLine($"session idled: {idled.ID}");
      }
      // 다른 이벤트 유형을 처리합니다

      return Results.Ok();
  });
  ```

  ```go Go
  package main

  import (
  	"fmt"
  	"io"
  	"net/http"

  	"github.com/anthropics/anthropic-sdk-go"
  )

  var client = anthropic.NewClient() // reads ANTHROPIC_WEBHOOK_SIGNING_KEY from env

  func webhook(w http.ResponseWriter, r *http.Request) {
  	body, err := io.ReadAll(r.Body)
  	if err != nil {
  		http.Error(w, "could not read body", http.StatusBadRequest)
  		return
  	}

  	// 서명이 유효하지 않거나 페이로드가 오래된 경우 Unwrap은 오류를 반환합니다
  	event, err := client.Beta.Webhooks.Unwrap(body, r.Header)
  	if err != nil {
  		http.Error(w, "invalid signature", http.StatusBadRequest)
  		return
  	}

  	switch event.Data.Type {
  	case "session.status_idled":
  		fmt.Println("session idled:", event.Data.ID)
  		// 다른 이벤트 유형을 처리합니다
  	}

  	w.WriteHeader(http.StatusOK)
  }

  func main() {
  	http.HandleFunc("/webhook", webhook)
  }
  ```

  ```java Java
  import com.anthropic.client.AnthropicClient;
  import com.anthropic.client.okhttp.AnthropicOkHttpClient;
  import com.anthropic.core.UnwrapWebhookParams;
  import com.anthropic.core.http.Headers;
  import com.sun.net.httpserver.HttpServer;

  // 환경 변수에서 ANTHROPIC_WEBHOOK_SIGNING_KEY를 읽습니다
  AnthropicClient client = AnthropicOkHttpClient.fromEnv();

  void main() throws Exception {
      var server = HttpServer.create(new InetSocketAddress(8000), 0);
      server.createContext("/webhook", exchange -> {
          var body = new String(exchange.getRequestBody().readAllBytes());
          var headers = Headers.builder();
          exchange.getRequestHeaders().forEach(headers::put);

          try {
              // 서명이 유효하지 않거나 페이로드가 오래된 경우 unwrap()이 예외를 발생시킵니다
              var event = client.beta().webhooks().unwrap(
                  UnwrapWebhookParams.builder()
                      .body(body)
                      .headers(headers.build())
                      .build());

              event.data().sessionStatusIdled().ifPresent(idled ->
                  IO.println("session idled: " + idled.id()));
              // 다른 이벤트 유형을 처리합니다

              exchange.sendResponseHeaders(200, -1);
          } catch (Exception _) {
              exchange.sendResponseHeaders(400, -1);
          }
          exchange.close();
      });
  }
  ```

  ```php PHP
  use Anthropic\Client;
  use Anthropic\Core\Exceptions\WebhookException;

  $client = new Client(); // reads ANTHROPIC_WEBHOOK_SIGNING_KEY from env

  $body = file_get_contents('php://input');
  $headers = getallheaders();

  try {
      // 서명이 유효하지 않거나 페이로드가 오래된 경우 unwrap()에서 예외가 발생합니다
      $event = $client->beta->webhooks->unwrap($body, headers: $headers);
  } catch (WebhookException) {
      http_response_code(400);
      exit('invalid signature');
  }

  match ($event->data->type) {
      'session.status_idled' => print "session idled: {$event->data->id}\n",
      // 다른 이벤트 유형을 처리합니다
      default => null,
  };

  http_response_code(200);
  ```

  ```ruby Ruby
  require "sinatra"
  require "anthropic"

  client = Anthropic::Client.new # reads ANTHROPIC_WEBHOOK_SIGNING_KEY from env

  post "/webhook" do
    headers = request.env
      .select { |key, _| key.start_with?("HTTP_") }
      .transform_keys { it.delete_prefix("HTTP_").downcase.tr("_", "-") }

    begin
      # 서명이 유효하지 않거나 페이로드가 오래된 경우 unwrap에서 예외가 발생합니다
      event = client.beta.webhooks.unwrap(request.body.read, headers: headers)
    rescue StandardError
      halt 400, "invalid signature"
    end

    if event.data.type == :"session.status_idled"
      puts "session idled: #{event.data.id}"
    end
    # 다른 이벤트 유형을 처리합니다

    status 200
  end
  ```
</CodeGroup>

## 이벤트 처리하기

본문을 파싱하고, `data.type`에 따라 분기한 다음, ID로 리소스를 가져오세요. 수신 확인을 위해 임의의 `2xx`를 반환하세요. 그 외의 응답은 엔드포인트에 불리하게 집계됩니다. `3xx`는 엔드포인트를 즉시 비활성화하며(리디렉션은 절대 따르지 않음), 다른 실패는 재시도됩니다. 재시도 및 자동 비활성화 규칙은 [전달 동작](https://platform.claude.com/docs/ko/managed-agents/webhooks#delivery-behavior)을 참조하세요.

모든 이벤트 페이로드는 이벤트 유형, 식별자, 이벤트 발생 시점의 타임스탬프를 포함하여 동일한 구조를 가집니다.

```json
{
  "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-..."
  }
}
```

<CodeGroup exclude="shell:cURL, shell:CLI">
  ```python Python
  if event.data.type == "session.status_idled":
      session = client.beta.sessions.retrieve(event.data.id)
      notify_user(session)
  return "", 204
  ```

  ```typescript TypeScript
  if (event.data.type === "session.status_idled") {
    const session = await client.beta.sessions.retrieve(event.data.id);
    notifyUser(session);
  }
  res.sendStatus(204);
  ```

  ```csharp C#
  if (webhookEvent.Data.TryPickSessionStatusIdled(out var idled))
  {
      var session = await client.Beta.Sessions.Retrieve(idled.ID);
      NotifyUser(session);
  }
  return Results.StatusCode(204);
  ```

  ```go Go
  if event.Data.Type == "session.status_idled" {
  	session, err := client.Beta.Sessions.Get(r.Context(), event.Data.ID, anthropic.BetaSessionGetParams{})
  	if err != nil {
  		panic(err)
  	}
  	notifyUser(session)
  }
  w.WriteHeader(http.StatusNoContent)
  ```

  ```java Java
  event.data().sessionStatusIdled().ifPresent(idled -> {
      var session = client.beta().sessions().retrieve(idled.id());
      notifyUser(session);
  });
  exchange.sendResponseHeaders(204, -1);
  ```

  ```php PHP
  if ($event->data->type === 'session.status_idled') {
      $session = $client->beta->sessions->retrieve($event->data->id);
      notifyUser($session);
  }
  http_response_code(204);
  ```

  ```ruby Ruby
  if event.data.type == :"session.status_idled"
    session = client.beta.sessions.retrieve(event.data.id)
    notify_user(session)
  end
  status 204
  ```
</CodeGroup>

최상위 `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` (java, php: `createdAt`; csharp, go: `CreatedAt`)를 사용하세요.

* **자동 비활성화:** 엔드포인트는 다음 세 가지 경우에 기계가 읽을 수 있는 `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에서 엔드포인트를 다시 활성화하세요. 엔드포인트가 비활성화된 동안 발생한 이벤트는 재전송되지 않습니다.
