새로운 문서를 작성 중입니다.새 문서로 이동
ClawOps Docs

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.completedevent선택전사 완료 — TranscriptUrl 포함
transcript.failedevent선택전사 실패 — Stage/ErrorMessage 포함

요청 파라미터

모든 요청은 Content-Type: application/x-www-form-urlencoded POST 입니다. 이벤트마다 전달되는 파라미터가 다르니 아래 두 표를 참고하세요.

transcript.completed

전사가 정상 종료되어 결과 JSON 이 GCS 에 업로드된 직후 전송됩니다.

파라미터타입필수설명
CallIdstring필수통화 ID
AccountIdstring필수계정 ID
Fromstring필수발신 번호
Tostring필수수신 번호
Directionstring필수통화 방향 (inbound, outbound)
Eventstring필수고정값 transcript.completed
Timestampstring필수이벤트 발생 시각 (ISO 8601)
TranscriptUrlstring필수전사 결과 JSON GCS 서명 URL (7일 만료). 화자 분리와 타임스탬프가 포함된 segment 배열을 반환합니다.
DurationSecstring필수오디오 길이(초) — 과금 분량과 동일. 정수 또는 소수점 한 자리
SegmentCountstring필수전사된 세그먼트(발화 단위) 개수
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=23

transcript.failed

전사 Job 이 중단되어 결과가 생성되지 않았을 때 전송됩니다. Stage 로 실패 단계를, ErrorMessage 로 원인을 구분할 수 있습니다.

파라미터타입필수설명
CallIdstring필수통화 ID
AccountIdstring필수계정 ID
Fromstring필수발신 번호
Tostring필수수신 번호
Directionstring필수통화 방향 (inbound, outbound)
Eventstring필수고정값 transcript.failed
Timestampstring필수이벤트 발생 시각 (ISO 8601)
Stagestring필수실패 단계. download(녹음 파일 다운로드 실패) 또는 runtime(ASR/업로드 중 예외)
ErrorMessagestring필수사람 읽을 수 있는 오류 메시지
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+missing

TranscriptUrl 응답 형식

TranscriptUrl을 GET하면 다음 형태의 JSON이 반환됩니다.

[
  {
    "speaker": "speaker_0",
    "start": 0.42,
    "end": 2.11,
    "text": "안녕하세요, 예약 가능한가요?"
  },
  {
    "speaker": "speaker_1",
    "start": 2.35,
    "end": 4.80,
    "text": "네, 가능합니다. 언제로 도와드릴까요?"
  }
]

speaker 는 화자별로 부여되는 익명 식별자입니다. 2026년 8월 이후 전사는 speaker_0, speaker_1, … 형식이며, 전환(transfer) 통화처럼 참여자가 셋 이상이면 그만큼 늘어납니다. 그 이전 전사에는 AGENT / CUSTOMER 값이 그대로 남아 있으므로 두 형식을 모두 처리해야 합니다.

화자와 역할(고객 / 상담원 / AI)의 연결은 보장하지 않습니다. 라벨 번호와 실제 역할의 대응은 통화마다 달라질 수 있습니다.

예제

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 "", 204

Transcript Webhook 요청에도 X-Signature 헤더가 포함됩니다. 서명 검증 가이드를 참고하여 요청의 무결성을 확인하세요.

TranscriptUrl은 7일 후 만료됩니다. 장기 보관이 필요하면 webhook 수신 즉시 JSON을 다운로드해 자체 스토리지에 저장하세요.

Transcript Webhook은 전달 보장(at-least-once) 방식이므로 드물게 같은 이벤트가 두 번 이상 도착할 수 있습니다. 수신 서버에서 CallId를 idempotency key로 사용해 중복 처리를 방지하세요.