Transcript Webhook
통화 트랜스크립션(전사) 완료/실패 시 전송되는 Transcript Webhook의 파라미터를 안내합니다.
Transcript Webhook은 통화 녹음에 대한 STT(Speech-to-Text) 전사가 완료되거나 실패했을 때 설정된 URL로 알림을 전송합니다. 전사는 통화 종료 후 시작되며, 오디오 길이에 비례한 처리 시간이 필요합니다. 계정 레벨에서 REST API로 등록합니다.
Transcript Webhook을 받으려면 먼저 조직 설정 → 통화 받아쓰기 옵션을 활성화해야 합니다. 받아쓰기는 통화 녹음이 켜져 있을 때만 동작하며, 전사된 분량만큼 사용량 기반으로 과금되는 유료 기능입니다.
등록
POST /v1/accounts/{accountId}/webhooks
Body:
{
"url": "https://my-app.com/transcript-webhook",
"events": ["transcript.completed", "transcript.failed"]
}배송 로그 조회
SDK로 웹훅 배송 로그를 확인할 수 있습니다.
page = client.webhook_logs.list("cmob6...", page=0, page_size=20)
for log in page.data:
print(log)이벤트 종류
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| transcript.completed | event | 선택 | 전사 완료 — TranscriptUrl 포함 |
| transcript.failed | event | 선택 | 전사 실패 — Stage/ErrorMessage 포함 |
요청 파라미터
모든 요청은 Content-Type: application/x-www-form-urlencoded POST 입니다.
이벤트마다 전달되는 파라미터가 다르니 아래 두 표를 참고하세요.
transcript.completed
전사가 정상 종료되어 결과 JSON 이 GCS 에 업로드된 직후 전송됩니다.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| CallId | string | 필수 | 통화 ID |
| AccountId | string | 필수 | 계정 ID |
| From | string | 필수 | 발신 번호 |
| To | string | 필수 | 수신 번호 |
| Direction | string | 필수 | 통화 방향 (inbound, outbound) |
| Event | string | 필수 | 고정값 transcript.completed |
| Timestamp | string | 필수 | 이벤트 발생 시각 (ISO 8601) |
| TranscriptUrl | string | 필수 | 전사 결과 JSON GCS 서명 URL (7일 만료). 화자 분리와 타임스탬프가 포함된 segment 배열을 반환합니다. |
| DurationSec | string | 필수 | 오디오 길이(초) — 과금 분량과 동일. 정수 또는 소수점 한 자리 |
| SegmentCount | string | 필수 | 전사된 세그먼트(발화 단위) 개수 |
CallId=CAabc123&AccountId=ACxxx&From=%2B821011112222&To=%2B821033334444
&Direction=inbound&Event=transcript.completed&Timestamp=2026-04-23T09:12:44.123Z
&TranscriptUrl=https%3A%2F%2Fstorage.googleapis.com%2F...&DurationSec=87.4
&SegmentCount=23transcript.failed
전사 Job 이 중단되어 결과가 생성되지 않았을 때 전송됩니다.
Stage 로 실패 단계를, ErrorMessage 로 원인을 구분할 수 있습니다.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| CallId | string | 필수 | 통화 ID |
| AccountId | string | 필수 | 계정 ID |
| From | string | 필수 | 발신 번호 |
| To | string | 필수 | 수신 번호 |
| Direction | string | 필수 | 통화 방향 (inbound, outbound) |
| Event | string | 필수 | 고정값 transcript.failed |
| Timestamp | string | 필수 | 이벤트 발생 시각 (ISO 8601) |
| Stage | string | 필수 | 실패 단계. download(녹음 파일 다운로드 실패) 또는 runtime(ASR/업로드 중 예외) |
| ErrorMessage | string | 필수 | 사람 읽을 수 있는 오류 메시지 |
CallId=CAabc123&AccountId=ACxxx&From=%2B821011112222&To=%2B821033334444
&Direction=inbound&Event=transcript.failed&Timestamp=2026-04-23T09:10:02.987Z
&Stage=download&ErrorMessage=rx%2Ftx+missingTranscriptUrl 응답 형식
TranscriptUrl을 GET하면 다음 형태의 JSON이 반환됩니다.
[
{
"speaker": "CUSTOMER",
"start": 0.42,
"end": 2.11,
"text": "안녕하세요, 예약 가능한가요?"
},
{
"speaker": "AGENT",
"start": 2.35,
"end": 4.80,
"text": "네, 가능합니다. 언제로 도와드릴까요?"
}
]speaker는 CUSTOMER(발신자 쪽 오디오) 또는 AGENT(수신/에이전트 쪽 오디오)로 구분됩니다.
예제
from flask import Flask, request
import urllib.request
import json
app = Flask(__name__)
@app.route("/transcript-webhook", methods=["POST"])
def transcript_webhook():
event = request.form.get("Event")
call_id = request.form.get("CallId")
if event == "transcript.completed":
url = request.form.get("TranscriptUrl")
duration = request.form.get("DurationSec")
count = request.form.get("SegmentCount")
print(f"전사 완료 [{call_id}]: {count} segments, {duration}s")
# 서명 URL 로 전사 본문 받기
with urllib.request.urlopen(url) as r:
segments = json.loads(r.read())
for seg in segments:
print(f" [{seg['speaker']}] {seg['text']}")
elif event == "transcript.failed":
stage = request.form.get("Stage")
err = request.form.get("ErrorMessage")
print(f"전사 실패 [{call_id}] ({stage}): {err}")
return "", 204Transcript Webhook 요청에도 X-Signature 헤더가 포함됩니다. 서명 검증 가이드를 참고하여 요청의 무결성을 확인하세요.
TranscriptUrl은 7일 후 만료됩니다. 장기 보관이 필요하면 webhook 수신 즉시 JSON을 다운로드해 자체 스토리지에 저장하세요.
Transcript Webhook은 전달 보장(at-least-once) 방식이므로 드물게 같은 이벤트가 두 번 이상 도착할 수 있습니다.
수신 서버에서 CallId를 idempotency key로 사용해 중복 처리를 방지하세요.