Skip to main content
이벤트별 페이로드 필드와 예시예요. 본문 키는 이벤트마다 call, operator_call, sms, campaign, sms_batch로 달라요. 본문 식별자는 call_id, operator_call_id, campaign_id, batch_id처럼 리소스별 키를 써서 REST API 응답의 id와 이름이 달라요. 비용과 분석 결과는 call_ended가 아니라 call_analyzed에서 받으세요.

통화 이벤트

통화 데이터 웹훅은 통화 진행 상태와 분석 완료 상태를 나눠 보내요. call_started, mid_call, call_ended가 통화 중에 오고, call_analyzed는 통화가 끝난 뒤 비동기로 와요. 통화 중에 맥락을 넣으면 요청마다 그 결과로 call_context도 와요. 통화 유형마다 오는 순서와 시점은 이벤트 라이프사이클에 있어요.

call_started

mid_call

AI 통화 중 플로우 전환이나 발화가 생기면 와요. 상담사에게 전환된 뒤의 발화는 상담사 구간의 mid_call에 있어요.

call_context

통화 중 맥락 넣기로 넣은 맥락의 결과가 정해지면 요청마다 한 번 와요. 통화 데이터 웹훅 URL이 있으면 따로 구독하지 않아도 와요. 맥락 본문은 담기지 않아요.
reply 값은 아래와 같아요. 웹훅은 결과가 정해진 뒤에 오므로 진행 중 값은 오지 않아요.
  • not_requested: response가 none이라 말하기를 요청하지 않았어요.
  • completed: 맥락에 대해 끝까지 말했어요.
  • interrupted: 말하다 끊겼어요. 다시 말하지 않지만 맥락은 이후 응답에 남아요.
  • merged: 따로 말하지 않고, 이 맥락이 담긴 일반 응답이 끝까지 재생됐어요. interrupt_agent 요청이 고객이 말하는 중에 도착하면 그 말에 대한 응답에 합쳐져 이 값으로 끝나요.
  • expired: expires_in_seconds 안에 말을 시작하지 못했어요.
  • canceled: 상담사 전환, 상담사 통화, 통화 종료 때문에 말하지 않았어요.
  • unknown: 결과를 남기기 전에 처리가 중단돼 알 수 없어요.
failure_reason 값은 아래와 같아요.
  • transfer_in_progress: 상담사 전환 중이에요.
  • operator_active: 상담사가 통화를 맡고 있어요.
  • call_ending: 통화가 끝나는 중이에요.
  • deadline: 기한이 지났어요.
  • limit_exceeded: 통화 하나의 맥락 한도를 넘었어요.
  • session_unavailable: 통화가 맥락을 받을 수 없는 상태였어요.
  • worker_lost: 처리가 중단돼 결과를 남기지 못했어요.
아직 값이 없는 상태나 시각은 필드를 빼지 않고 null로 보내요. none 요청은 반영되는 즉시 결과가 정해져 consumed가 보통 false이고, 그 뒤 응답에 쓰여도 웹훅을 다시 보내지 않아요. 웹훅 버전이 v1이면 webhook_version이 없고, call 대신 call_context 키에 같은 필드가 담겨요. agent 객체 대신 agent_id가 그 안에 와요.

call_ended

개인정보 마스킹을 켜면 종료 이벤트가 가리기 전에 와서 call.transcript가 비어 있을 수 있어요. 아래 예시는 마스킹을 끈 경우예요.
통화 시간은 end_at - start_at으로 계산하세요. recording_url은 인증이 필요한 엔드포인트예요. API 키로 녹음을 내려받는 방법과 스테레오 OGG 채널 분리 형식은 통화 녹음에 있어요.

스크립트 형식

transcript는 발화와 도구 호출 기록을 한 배열에 담아요. 도구를 쓰지 않은 통화에는 agent와 user 항목만 들어가요. 통화 데이터 저장 제외 설정이나 통화 처리 상태에 따라 null일 수 있어요. 도구 호출 결과에는 아래 두 필드가 함께 들어가요. 개인정보를 가린 결과에도 똑같이 들어 있어요.

call_analyzed

마스킹을 켜면 대화 내용, 요약, 도구 호출 인자와 결과는 가린 내용만 보내고, 추출 항목과 전화번호 필드는 원문을 유지해요. 가리기에 실패한 필드는 원문 대신 비워 둬요. 아래 예시는 마스킹을 끈 경우예요.

상담사 통화 이벤트

AI 통화에서 상담사에게 전환된 뒤의 이벤트예요. 안내 후 전환과 상담사 이어받기에 적용되고, 통화 데이터 웹훅 URL을 설정하면 따로 구독하지 않아도 와요. 오는 순서는 안내 후 전환 라이프사이클에 있어요.

operator_call_started

mid_call

고객이나 상담사의 발화가 확정되면 와요. AI 구간과 같은 mid_call 이벤트이고, call.operator_call_id로 구분해요.

operator_call_ended

시작 이벤트에는 start_at이 없고, occurred_at이 상담사 통화 조회 응답의 start_at과 같아요. 종료 이벤트의 occurred_at은 end_at과 같아요. 종료 이벤트의 recording_url은 만료되지 않아요. dynamic_variables, metadata, mode, source, handoff_id는 이벤트가 생긴 통화와 연결 경로를 설명하는 웹훅 전용 컨텍스트라, v3 API 참조의 상담사 통화 > 상담사 통화 조회 응답에는 들어 있지 않아요.
문서에 없던 takeover 이벤트를 받고 있었다면 이 두 이벤트로 바뀌어요. 본문 키는 operator_call이고 takeover_id, takeover_event_type, message_count, duration_ms는 없어요.

상담사 통화 상세 조회

대화록, 비용, 종료 이벤트에 없는 녹음 URL이 필요하면 v3 API 참조의 상담사 통화 > 상담사 통화 조회를 호출하세요.
cURL
단건 응답의 recording_url은 15분 뒤 만료되는 서명 URL이에요. URL을 저장해 두지 말고 재생할 때 다시 조회하세요. 일부 과거 통화는 만료가 없는 다운로드 URL로 올 수 있어요. 상담사 통화 조회는 통화 조회와 같은 워크스페이스 요청 한도를 함께 써요. 주기적으로 폴링하지 말고 웹훅을 받은 뒤 필요한 통화만 조회하세요.

전달 보장과 재시도

수신 서버가 응답을 돌려주면 상태 코드와 상관없이 그 시도는 끝나요. 4xx나 5xx로 재시도를 이끌어 낼 수 없어요. vox.ai는 요청마다 5초를 기다려요. 5초 안에 수신 서버와 연결되지 않을 때만 곧바로 한 번 더 보내요. 연결된 뒤 5초 안에 응답이 없거나, 연결이 거부되거나 끊기면 같은 이벤트를 다시 보내지 않아요. 같은 이벤트를 한 번만 처리하려면 다음 키를 쓰세요. 통화 이벤트는 (event, call_id), 상담사 통화 이벤트는 (event, operator_call_id)예요. call_context는 한 통화에서 요청마다 하나씩 오므로 (event, call_id, control_id)로 거르세요. mid_call은 AI 구간에서 call_id, 상담사 구간에서 operator_call_id를 쓰고, 여기에 event, occurred_at, event_type, event_data를 더해 키를 만드세요.
요청을 먼저 저장하고 5초 안에 2xx를 돌려준 뒤 후속 처리는 비동기로 실행하세요. 5초를 넘긴 이벤트는 다시 오지 않으니, 놓친 내용은 v3 API로 그 통화를 다시 조회해 채우세요.

sms_received

번호 상세에서 문자 수신을 신청하고 승인받은 뒤 쓰세요. sms_received는 워크스페이스 번호로 SMS나 MMS를 받을 때 와요. 워크스페이스 웹훅 전용이고, 설정 > 웹훅의 이벤트 구독에서 수신 문자를 켜고 저장한 워크스페이스에만 와요. 기본값은 꺼짐이고, 켠 뒤 받은 문자부터 와요. 서명 방식은 통화 데이터 웹훅과 같아요. 본문 키는 통화 이벤트와 달리 call이 아니라 sms예요. event 키로 분기하는 핸들러는 고치지 않아도 되지만, call 키를 무조건 읽는 핸들러는 sms_received를 따로 분기하세요.

첨부 파일 다운로드

file_key로 첨부 파일 원본을 받으려면 파일 다운로드 API를 호출하세요.
cURL
응답 본문이 파일 원본이에요. Content-Type은 image/jpeg, image/png, image/gif 가운데 저장된 MIME 타입을 그대로 따라요. 같은 워크스페이스가 가진 file_key만 받을 수 있어요. 전체 파라미터는 v3 API 참조의 파일 > 파일 다운로드에 있어요.

sms_sent

sms_sent는 발신한 문자가 sent, failed, blocked, canceled 가운데 하나로 끝났을 때 문자마다 한 번 와요. API, 대시보드, 에이전트의 문자 발신 도구, 대량 문자 발신 어느 경로로 보낸 문자든 같아요. 대량 발신의 문자는 한 건씩 오고, 대량 발신 전체 결과는 sms_batch로 와요. 이벤트는 통신사의 최종 결과가 나올 때 와요. 보통 발신하고 몇 초 안에 도착하고, 수신 휴대폰이 꺼져 있으면 최대 24시간이 걸려요. 24시간 안에 결과를 받지 못하면 failed(SMS_NO_RESULT)로 와요. 워크스페이스 웹훅 전용이고, 설정 > 웹훅의 이벤트 구독에서 문자 발신 결과를 켜고 저장한 워크스페이스에만 와요. 기본값은 꺼짐이고, 켠 뒤 끝난 문자부터 와요. 서명 방식은 통화 데이터 웹훅과 같아요. 본문 키는 sms_received처럼 sms예요.
sms 본문은 발신 문자 조회 API 응답에서 id를 sms_message_id로 바꾸고 occurred_at을 더한 구조예요. sms.error의 코드와 메시지는 다음과 같아요. SMS_CONTENT_BLOCKED, BILLING_SUSPENDED, BLOCKED_NUMBER, SMS_BLOCKED는 blocked, SMS_CANCELED는 canceled일 때 와요. 접수 단계의 검증에 걸려 failed가 된 문자는 FILE_NOT_FOUND처럼 그 검증의 코드와 메시지를 그대로 쓰고, 구체적인 사유가 없는 그 밖의 실패는 SMS_SEND_FAILED예요.

대량 발신 이벤트

campaign과 sms_batch를 받으려면 대시보드 설정 > 웹훅의 이벤트 구독에서 대량 발신 종결과 대량 문자 발신 종결을 켜고 저장하세요. 워크스페이스 설정 API의 webhook_event_subscriptions에 이벤트 값을 더해도 돼요. 두 이벤트도 워크스페이스 웹훅과 같은 서명 방식을 따르고, 중복 처리는 전달 보장과 재시도를 따르세요.

campaign

campaign은 대량 발신이 success나 canceled로 종결될 때 와요. 대량 발신을 시작, 일시정지, 재개할 때는 오지 않아요. 웹훅은 대량 발신 단위로 와요. 자동 재시도를 켠 대량 발신은 실패분을 다시 걸 때 새 건이 만들어지므로 종결 웹훅도 원본과 재시도분이 따로 와요. 재시도 건의 sheet_id는 원본과 같아요. 시트 전체가 끝났는지는 판정하지 않으니 수신 서버에서 모아 판단하세요.
campaign 본문은 대량 발신 조회 API 응답 필드에 sheet_id와 occurred_at을 더한 구조예요.

sms_batch

sms_batch는 대량 문자 발신이 success, fail, canceled로 종결될 때 와요. 발신이 시작되어 상태가 ongoing이 될 때나 일시정지, 재개할 때는 오지 않아요. 문자별 결과가 필요하면 sms_sent를 함께 구독하세요. 모든 문자를 보낸 뒤에도 통신사 결과를 기다리는 동안은 ongoing이에요. 모든 결과가 나오거나 마지막 문자를 발신하고 10분이 지나면 종결하고, 이벤트는 그때 한 번 와요.
sms_batch 본문은 대량 문자 발신 조회 API 응답에서 진행 중에만 쓰는 필드를 빼고 occurred_at을 더한 구조예요. success_count, failure_count, pending_count, blocked_count, canceled_count를 모두 더하면 total_count예요. 발신 중에 발신번호가 해지·만료되거나 발신표기번호가 삭제되면 아직 보내지 않은 항목은 실패해요. 문자별 결과는 v3 API 참조의 문자 > 발신 문자 목록 조회에 batch_id를 넘겨 확인하세요. 페이지는 cursor로 넘겨요.

서버 구현 체크리스트

  • 수신 스키마에 최상위 webhook_version 필드를 포함하세요.
  • call_ended에서 비용이나 분석 필드를 기대하지 마세요.
  • 분석 결과 저장, 후속 자동화, 비용 집계는 call_analyzed에서 실행하세요.
  • 통화 결과는 call_status와 disconnection_reason을 함께 확인하세요.
  • 통화 시간은 end_at - start_at으로 계산하세요.
  • call_context에서 에이전트가 맥락에 대해 말했는지는 consumed가 아니라 reply로 판단하세요.
  • event별로 본문 키를 분기하세요. operator_call_started와 operator_call_ended는 operator_call, 상담사 구간의 mid_call은 call, sms_received와 sms_sent는 sms, campaign, sms_batch는 각 리소스 키를 써요.

관련 문서