ClawOps Docs

Recording Webhook

통화 녹음 파일 업로드 완료/실패 시 전송되는 Recording Webhook의 파라미터를 안내합니다.

Recording Webhook은 통화 녹음 파일이 GCS에 업로드되거나 업로드에 실패했을 때 설정된 URL로 알림을 전송합니다. 녹음은 통화 종료 직후 처리되며, 보통 수초 내에 webhook이 도착합니다. 계정 레벨에서 REST API로 등록합니다.

Recording Webhook을 받으려면 부가서비스 → 통화 녹음 이 활성화되어 있어야 합니다. 녹음이 시작되지 않은 통화 (예: 응답 없음, 회선 오류, 녹음 비활성 상태에서 발생한 통화) 는 recording.completed/recording.failed 둘 다 발생하지 않습니다.

등록

POST /v1/accounts/{accountId}/webhooks

Body:
{
  "url": "https://my-app.com/recording-webhook",
  "events": ["recording.completed", "recording.failed"]
}

배송 로그 조회

SDK로 웹훅 배송 로그를 확인할 수 있습니다.

page = client.webhook_logs.list("cmob6...", page=0, page_size=20)
for log in page.data:
    print(log)

이벤트 종류

파라미터타입필수설명
recording.completedevent선택녹음 mixed 파일 업로드 완료 — RecordingUrl 포함
recording.failedevent선택녹음 mixed 파일 업로드 실패 — Stage/ErrorMessage 포함

요청 파라미터

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

recording.completed

mixed 녹음 파일이 GCS에 업로드되고 DB에 recording_url 이 반영된 직후 전송됩니다.

파라미터타입필수설명
CallIdstring필수통화 ID
AccountIdstring필수계정 ID
Fromstring필수발신 번호
Tostring필수수신 번호
Directionstring필수통화 방향 (inbound, outbound)
Eventstring필수고정값 recording.completed
Timestampstring필수이벤트 발생 시각 (ISO 8601)
RecordingUrlstring필수녹음 파일 다운로드 API 엔드포인트 절대 URL. API key 인증으로 GET 하면 15분 TTL 의 GCS 서명 URL 로 302 redirect 됩니다 — HTTP 클라이언트가 자동 follow.
DurationSecstring선택통화 길이(초). 일부 케이스에서 미포함될 수 있음
CallId=CAabc123&AccountId=ACxxx&From=%2B821011112222&To=%2B821033334444
&Direction=inbound&Event=recording.completed&Timestamp=2026-04-23T09:12:44.123Z
&RecordingUrl=https%3A%2F%2Fapi.claw-ops.com%2Fv1%2Faccounts%2FACxxx%2Frecordings%2FCAabc123
&DurationSec=87

recording.failed

녹음은 시작되었으나 (mixed 파일이 생성됨) GCS 업로드 단계에서 최종 실패했을 때 전송됩니다.

파라미터타입필수설명
CallIdstring필수통화 ID
AccountIdstring필수계정 ID
Fromstring필수발신 번호
Tostring필수수신 번호
Directionstring필수통화 방향 (inbound, outbound)
Eventstring필수고정값 recording.failed
Timestampstring필수이벤트 발생 시각 (ISO 8601)
Stagestring필수실패 단계 — 현재 upload (GCS 업로드 재시도 후 최종 실패)
ErrorMessagestring필수사람 읽을 수 있는 오류 메시지
CallId=CAabc123&AccountId=ACxxx&From=%2B821011112222&To=%2B821033334444
&Direction=inbound&Event=recording.failed&Timestamp=2026-04-23T09:10:02.987Z
&Stage=upload&ErrorMessage=GCS+%EC%97%85%EB%A1%9C%EB%93%9C+%EC%B5%9C%EC%A2%85+%EC%8B%A4%ED%8C%A8+%28mixed%29

RecordingUrl 다운로드 동작

RecordingUrl 은 ClawOps API 엔드포인트 절대 URL 입니다 (서명 URL 이 아님). API key Bearer 인증으로 GET 하면 15분 TTL 의 GCS 서명 URL 로 302 redirect 됩니다.

GET https://api.claw-ops.com/v1/accounts/ACxxx/recordings/CAabc123
    Authorization: Bearer sk_...

→ 302 Location: https://storage.googleapis.com/...&X-Goog-Signature=...
→ 200 audio/wav (RIFF WAVE, 16-bit PCM mono 8kHz)

대부분의 HTTP 클라이언트 (requests, httpx, axios, curl -L, browser) 는 redirect 를 자동 follow 하므로 별도 처리가 필요 없습니다.

RecordingUrl 자체에는 자격증명이 들어가지 않습니다 — webhook payload 가 로그/메일에 새어도 API key 없이는 다운로드 불가합니다. 따라서 별도 만료 기간 없이 영구적으로 유효합니다 (단, 다운로드 시점마다 새 서명 URL 이 발급되며 그 서명만 15분 TTL).

예제

from flask import Flask, request
import requests

app = Flask(__name__)
CLAWOPS_API_KEY = "sk_..."

@app.route("/recording-webhook", methods=["POST"])
def recording_webhook():
    event = request.form.get("Event")
    call_id = request.form.get("CallId")

    if event == "recording.completed":
        url = request.form.get("RecordingUrl")
        duration = request.form.get("DurationSec")
        print(f"녹음 완료 [{call_id}]: {duration}s")

        # API key 로 GET → 자동 302 follow → wav 바이트 수신
        r = requests.get(url, headers={"Authorization": f"Bearer {CLAWOPS_API_KEY}"})
        r.raise_for_status()
        with open(f"{call_id}.wav", "wb") as f:
            f.write(r.content)

    elif event == "recording.failed":
        stage = request.form.get("Stage")
        err = request.form.get("ErrorMessage")
        print(f"녹음 실패 [{call_id}] ({stage}): {err}")

    return "", 204

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

녹음이 시작되지 않은 통화 (응답 없음, 회선 오류 등) 에는 recording.failed 가 발생하지 않습니다. "녹음 실패" 와 "녹음 안 됨" 을 구분해서 처리하세요 — 후자는 call.completed 의 status 와 hangup cause 로 판별합니다.

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