> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tryvox.co/llms.txt
> Use this file to discover all available pages before exploring further.

# 웹훅

> 인바운드 웹훅과 통화 데이터 웹훅으로 외부 시스템과 실시간으로 연동하세요.

# 웹훅

웹훅을 사용하면 vox.ai 플랫폼과 외부 시스템 간에 실시간으로 데이터를 주고받을 수 있습니다. 에이전트 설정의 **웹훅** 섹션에서 두 종류의 웹훅을 각각 구성할 수 있습니다.

| 웹훅            | 방향                      | 시점                            | 용도                |
| ------------- | ----------------------- | ----------------------------- | ----------------- |
| **인바운드 웹훅**   | vox.ai → 외부 서버 → vox.ai | 통화 시작 직전                      | 통화 전 동적 변수 주입     |
| **통화 데이터 웹훅** | vox.ai → 외부 서버          | 통화 시작 · 중간 이벤트 · 종료 · 분석 완료 시 | 외부 시스템에 통화 이벤트 전송 |

## 인바운드 웹훅

인바운드 웹훅은 **통화가 시작되기 직전** 외부 시스템에 발신/수신 번호를 보내고, 응답으로 받은 키-값 쌍을 에이전트의 **동적 변수**로 주입합니다. 앞단 CRM에서 고객 정보를 조회해 에이전트 프롬프트에 바로 연결할 수 있습니다.

**요청 (vox.ai → 외부 서버)**:

```json theme={null}
{ "call_from": "01012345678", "call_to": "0212345678" }
```

**응답 (외부 서버 → vox.ai)**:

```json theme={null}
{
  "call_inbound": {
    "dynamic_variables": { "user_name": "홍길동" },
    "metadata": { "user_id": "17632" }
  }
}
```

endpoint 에서 호출자를 검증해야 하면 **인바운드 웹훅 서명**을 켜세요. 워크스페이스 웹훅과 같은 HMAC-SHA256 방식으로 서명됩니다 (기본 꺼짐) — [인바운드 웹훅 가이드의 보안 섹션](/docs/build/variables/inbound-webhook#보안)을 참고하세요.

<Card title="인바운드 웹훅 전체 가이드" icon="plug" href="/docs/build/variables/inbound-webhook">
  웹훅 URL 설정, 타임아웃·재시도 정책, 서버 구현 예시 (Python/JS), HMAC 서명,
  보안 권장 사항, SIP 헤더 보조 수단, 예외 상황까지 다룹니다.
</Card>

***

## 통화 데이터 웹훅

통화 데이터 웹훅은 통화의 주요 이벤트가 발생할 때마다 외부 시스템으로 페이로드를 전송합니다. CRM 연동, 실시간 모니터링, 로그 수집, 통화 후 스크립트 저장 등에 활용합니다.

<Info>
  이 섹션은 v2를 기준으로 설명합니다. 새 연동은 v2로 구현하세요.
  v2는 통화 종료 이벤트와 분석 완료 이벤트를 분리합니다.
</Info>

```mermaid theme={null}
sequenceDiagram
    participant V as vox.ai
    participant E as 외부 시스템
    V->>E: call_started
    Note over V,E: 통화 진행
    V->>E: mid_call (플로우 전환 · 발화)
    V->>E: mid_call ...
    Note over V,E: 통화 종료
    V->>E: call_ended (기본 통화 정보 · 스크립트)
    Note over V,E: 비용 · 분석 준비
    V->>E: call_analyzed (비용 · 분석 결과)
```

### 이벤트 유형

| 이벤트             | 시점      | 설명                                                                   |
| --------------- | ------- | -------------------------------------------------------------------- |
| `call_started`  | 통화 시작   | 통화가 연결된 직후 발생합니다.                                                    |
| `mid_call`      | 통화 진행 중 | 플로우 노드 전환(`flow_transition`)이나 개별 발화(`call_message`)가 발생할 때마다 전송됩니다. |
| `call_ended`    | 통화 종료   | 통화가 끝난 뒤 기본 통화 정보와 스크립트를 전송합니다.                                      |
| `call_analyzed` | 분석 완료   | 비용, 요약, 감정 분석, 통화 정보 추출 결과가 준비되면 전송합니다.                              |

### 최상위 페이로드 구조

모든 이벤트는 공통으로 `event` 필드를 가집니다.
v2는 `webhook_version`을 함께 보내고, 모든 이벤트를 `call` 객체 안에 담아 전송합니다.

```json theme={null}
{
  "event": "call_started | mid_call | call_ended | call_analyzed",
  "webhook_version": "v2",
  "call": {}
}
```

<Accordion title="v1 기존 유지용 구조">
  v1은 기존 수신 서버를 유지해야 하는 경우를 위한 형식입니다.
  `call_started`, `call_ended`는 `call` 객체를 사용하고, `mid_call`은 `mid_call` 객체를 사용합니다.

  ```json theme={null}
  {
    "event": "call_started | call_ended | mid_call",
    "call": {},
    "mid_call": {}
  }
  ```
</Accordion>

### v2 페이로드 예시

아래 예시는 새 연동에서 구현해야 하는 v2 기준 페이로드입니다.
`call_ended`는 통화 종료 데이터와 스크립트를 전송합니다.
비용과 분석 결과는 `call_analyzed`로 전송됩니다.

#### `call_started`

```json theme={null}
{
  "event": "call_started",
  "webhook_version": "v2",
  "call": {
    "call_id": "6b0f1f08-1c2b-4f0e-9c3a-0c1d9e6f5a82",
    "agent": {
      "agent_id": "a1f4c8d2-3e5b-4a7c-9d8e-2b1f6c4a9d3e",
      "agent_version": "v3"
    },
    "call_type": "inbound",
    "from_number": "01012345678",
    "to_number": "07012345678",
    "dynamic_variables": {
      "customer_name": "김철수"
    },
    "metadata": {
      "campaign": "봄_프로모션"
    },
    "start_at": 1775980200000,
    "opt_out_sensitive_data_storage": false
  }
}
```

#### `mid_call`

```json theme={null}
{
  "event": "mid_call",
  "webhook_version": "v2",
  "call": {
    "call_id": "6b0f1f08-1c2b-4f0e-9c3a-0c1d9e6f5a82",
    "agent": {
      "agent_id": "a1f4c8d2-3e5b-4a7c-9d8e-2b1f6c4a9d3e",
      "agent_version": "v3"
    },
    "occurred_at": 1775980380000,
    "event_type": "call_message",
    "event_data": {
      "role": "user",
      "content": "주문 번호는 ORD-2026-0042입니다."
    }
  }
}
```

#### `call_ended`

```json theme={null}
{
  "event": "call_ended",
  "webhook_version": "v2",
  "call": {
    "call_id": "6b0f1f08-1c2b-4f0e-9c3a-0c1d9e6f5a82",
    "agent": {
      "agent_id": "a1f4c8d2-3e5b-4a7c-9d8e-2b1f6c4a9d3e",
      "agent_version": "v3"
    },
    "call_type": "inbound",
    "from_number": "01012345678",
    "to_number": "07012345678",
    "dynamic_variables": {
      "customer_name": "김철수"
    },
    "metadata": {
      "campaign": "봄_프로모션"
    },
    "call_status": "ended",
    "disconnection_reason": "agent_hangup",
    "start_at": 1775980200000,
    "end_at": 1775980542000,
    "transcript": [
      { "role": "agent", "content": "안녕하세요, 무엇을 도와드릴까요?" },
      { "role": "user", "content": "주문 상태를 확인하고 싶습니다." }
    ],
    "recording_url": "https://www.tryvox.co/api/store/download/...",
    "opt_out_sensitive_data_storage": false
  }
}
```

#### `call_analyzed`

```json theme={null}
{
  "event": "call_analyzed",
  "webhook_version": "v2",
  "call": {
    "call_id": "6b0f1f08-1c2b-4f0e-9c3a-0c1d9e6f5a82",
    "agent": {
      "agent_id": "a1f4c8d2-3e5b-4a7c-9d8e-2b1f6c4a9d3e",
      "agent_version": "v3"
    },
    "call_type": "inbound",
    "from_number": "01012345678",
    "to_number": "07012345678",
    "dynamic_variables": {
      "customer_name": "김철수"
    },
    "metadata": {
      "campaign": "봄_프로모션"
    },
    "call_status": "ended",
    "disconnection_reason": "agent_hangup",
    "start_at": 1775980200000,
    "end_at": 1775980542000,
    "transcript": [
      { "role": "agent", "content": "안녕하세요, 무엇을 도와드릴까요?" },
      { "role": "user", "content": "주문 상태를 확인하고 싶습니다." }
    ],
    "recording_url": "https://www.tryvox.co/api/store/download/...",
    "call_cost": {
      "total_cost": 120
    },
    "call_analysis": {
      "summary": "고객이 주문 상태를 문의했고, 상담원이 배송 예정일을 안내했습니다.",
      "user_sentiment": "positive",
      "custom_analysis_data": [
        { "name": "inquiry_type", "value": "배송 상태 문의" },
        { "name": "resolved", "value": true }
      ]
    },
    "opt_out_sensitive_data_storage": false
  }
}
```

<Note>
  시간 필드는 모두 UNIX 타임스탬프 밀리초 단위입니다.
  v2에는 `duration_ms`가 없으므로 `end_at - start_at`으로 계산하세요.
  `agent.agent_version`은 특정 배포 버전이면 `v3`처럼 표시되고, 현재 설정으로 실행된 통화면 `current`입니다.
</Note>

<Accordion title="v1 기존 유지용 페이로드">
  v1 예시는 기존 수신 서버와의 호환을 위해 제공합니다.
  새 연동에서는 위의 v2 페이로드를 기준으로 구현하세요.

  #### v1 `call_started` 페이로드

  ```json theme={null}
  {
    "event": "call_started",
    "call": {
      "agent_id": "a1f4c8d2-3e5b-4a7c-9d8e-2b1f6c4a9d3e",
      "call_id": "6b0f1f08-1c2b-4f0e-9c3a-0c1d9e6f5a82",
      "call_type": "inbound",
      "call_from": "01012345678",
      "call_to": "07012345678",
      "dynamic_variables": {
        "customer_name": "김철수"
      },
      "metadata": {
        "campaign": "봄_프로모션"
      },
      "start_timestamp": 1775980200000,
      "opt_out_sensitive_data_storage": false
    }
  }
  ```

  #### v1 `call_ended` 페이로드

  ```json theme={null}
  {
    "event": "call_ended",
    "call": {
      "agent_id": "a1f4c8d2-3e5b-4a7c-9d8e-2b1f6c4a9d3e",
      "call_id": "6b0f1f08-1c2b-4f0e-9c3a-0c1d9e6f5a82",
      "call_type": "inbound",
      "call_from": "01012345678",
      "call_to": "07012345678",
      "dynamic_variables": {
        "customer_name": "김철수"
      },
      "metadata": {
        "campaign": "봄_프로모션"
      },
      "start_timestamp": 1775980200000,
      "end_timestamp": 1775980542000,
      "duration_ms": 342000,
      "disconnection_reason": "agent_hangup",
      "recording_url": "https://www.tryvox.co/api/store/download/...",
      "transcript": [
        { "role": "agent", "content": "안녕하세요, 무엇을 도와드릴까요?" },
        { "role": "user", "content": "주문 상태를 확인하고 싶습니다." }
      ],
      "call_cost": {
        "total_credits_used": 120,
        "duration_seconds": 342
      },
      "call_analysis": {
        "summary": "고객이 주문 ORD-2026-0042의 배송 상태를 문의했고, 3월 25일 도착 예정임을 안내했습니다.",
        "user_sentiment": "positive",
        "custom_analysis_data": [
          { "name": "inquiry_type", "value": "배송 상태 문의" },
          { "name": "resolved", "value": true }
        ]
      },
      "opt_out_sensitive_data_storage": false
    }
  }
  ```

  <Note>
    **시간 단위**: `start_timestamp`, `end_timestamp`는 UNIX 타임스탬프(**밀리초**)이고, `duration_ms`도 **밀리초**입니다. ISO 8601 문자열이 아니라는 점에 유의하세요. `call_cost.duration_seconds`만 과금 편의를 위해 초 단위로 제공됩니다.
  </Note>

  <Note>
    v1에서는 [통화 정보 추출](/docs/build/post-call/extraction)에서 정의한 필드가 `call.call_analysis.custom_analysis_data` 배열에 포함됩니다. v2에서는 같은 데이터가 `call_analyzed` 이벤트에 포함됩니다.
  </Note>

  #### v1 `mid_call` 페이로드

  `mid_call`은 통화가 진행되는 동안 발생하는 세부 이벤트를 스트림처럼 전달합니다. `event_type`에 따라 `event_data` 구조가 달라집니다.

  **플로우 노드 전환 (`flow_transition`):**

  ```json theme={null}
  {
    "event": "mid_call",
    "mid_call": {
      "agent_id": "a1f4c8d2-3e5b-4a7c-9d8e-2b1f6c4a9d3e",
      "call_id": "6b0f1f08-1c2b-4f0e-9c3a-0c1d9e6f5a82",
      "timestamp": 1775980380000,
      "event_type": "flow_transition",
      "event_data": {
        "from_node_id": "node_1",
        "to_node_id": "node_2",
        "from_node_name": "인사",
        "to_node_name": "주문 조회"
      }
    }
  }
  ```

  **개별 발화 (`call_message`):**

  ```json theme={null}
  {
    "event": "mid_call",
    "mid_call": {
      "agent_id": "a1f4c8d2-3e5b-4a7c-9d8e-2b1f6c4a9d3e",
      "call_id": "6b0f1f08-1c2b-4f0e-9c3a-0c1d9e6f5a82",
      "timestamp": 1775980380000,
      "event_type": "call_message",
      "event_data": {
        "role": "user",
        "content": "주문 번호는 ORD-2026-0042입니다."
      }
    }
  }
  ```
</Accordion>

### 종료 사유 (`disconnection_reason`)

`call_ended` 페이로드의 `disconnection_reason`에 쓰이는 값 목록과 의미는 [통화종료사유](/docs/operate/monitor/disconnection-reasons)에서 확인하세요. 대시보드 필터·API 응답과 동일한 값을 사용합니다.

## 관련 문서

* [동적 변수](/docs/build/variables/dynamic-variables)
* [시스템 변수](/docs/build/variables/system-variables)
* [통화 정보 추출](/docs/build/post-call/extraction)
* [민감한 데이터 저장 금지](/docs/build/security/data-opt-out)
* [웹훅 스키마](/docs/operate/monitor/webhooks/schema)

***

<Accordion title="연관 검색어">
  웹훅, webhook, 인바운드 웹훅, 통화 데이터 웹훅, call\_started, call\_ended, call\_analyzed, mid\_call, 페이로드, payload, webhook v2
</Accordion>
