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": "CUSTOMER",
    "start": 0.42,
    "end": 2.11,
    "text": "안녕하세요, 예약 가능한가요?"
  },
  {
    "speaker": "AGENT",
    "start": 2.35,
    "end": 4.80,
    "text": "네, 가능합니다. 언제로 도와드릴까요?"
  }
]

speakerCUSTOMER(발신자 쪽 오디오) 또는 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 "", 204

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

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

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