Documentation Index Fetch the complete documentation index at: https://docs.tryvox.co/llms.txt
Use this file to discover all available pages before exploring further.
에이전트 단위 웹훅은 에이전트별 통화 이벤트 를 외부 서버로 전송합니다.
적용 우선순위는 웹훅 개요 를 참고하세요.
이 문서는 v2를 기준으로 설명합니다.
새 연동은 v2로 구현하세요.
v2는 통화 종료와 분석 완료를 별도 이벤트로 전송합니다.
v1 선택지는 기존 수신 서버를 그대로 유지하거나 v2로 전환할 때만 사용하세요.
신규 구축 기준은 v2입니다.
설정을 변경하지 않으면 기존 v1 연동은 기존 형식을 유지합니다.
지원되는 이벤트
아래 이벤트는 v2 기준입니다.
이벤트 설명 call_started통화가 시작되면 전송됩니다. mid_call통화 중 플로우 전환이나 발화가 발생하면 전송됩니다. call_ended통화가 끝나면 전송됩니다. 기본 통화 정보, 스크립트, 녹음 URL을 포함합니다. call_analyzed비용, 요약, 감정 분석, 통화 정보 추출 결과가 준비되면 전송됩니다.
v2의 call_ended에는 call_cost와 call_analysis가 포함되지 않습니다.
비용과 분석 결과가 필요하면 call_analyzed를 처리하세요.
v1은 call_analyzed를 사용하지 않습니다.
비용과 분석 결과는 call_ended에 함께 포함됩니다. 이벤트 설명 call_started통화가 시작되면 전송됩니다. mid_call통화 중 플로우 전환이나 발화가 발생하면 전송됩니다. call_ended통화 종료 정보, 스크립트, 비용, 분석 결과를 함께 포함합니다.
종료 이벤트 흐름
v2에서는 종료 사실과 분석 완료를 분리해서 받을 수 있습니다.
활용 사례
아래 표는 v2 기준입니다.
원하는 작업 처리할 이벤트 통화 종료 상태 저장 call_ended스크립트와 녹음 URL 저장 call_ended비용 저장 call_analyzed요약, 감정 분석, 추출 결과 저장 call_analyzed플로우 전환이나 실시간 발화 기록 mid_call
v1 기존 유지용 연동에서는 비용과 분석 결과도 call_ended에서 처리합니다.
웹훅 엔드포인트 구현
웹훅 요청을 수신할 HTTPS 엔드포인트를 준비하세요. from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
app = FastAPI()
@app.post ( "/webhook" )
async def handle_webhook ( request : Request):
data = await request.json()
event = data.get( "event" )
webhook_version = data.get( "webhook_version" )
call = data.get( "call" , {})
if webhook_version != "v2" :
return JSONResponse( status_code = 400 , content = { "error" : "unsupported version" })
if event == "call_ended" :
print ( "통화 종료:" , call.get( "call_id" ))
elif event == "call_analyzed" :
print ( "분석 완료:" , call.get( "call_analysis" ))
else :
print ( "이벤트:" , event)
return JSONResponse( status_code = 200 , content = { "received" : True })
에이전트별 웹훅 등록
대시보드 에이전트 설정 > 웹훅 설정 섹션에서 통화 데이터 웹훅 URL을 입력하세요.
새 연동은 v2 기준으로 구현하세요.
v1 선택지가 표시되면 기존 v1 수신 서버 유지 또는 v2 전환을 위한 마이그레이션용으로만 사용하세요.
v2 웹훅 페이로드 예시
v2는 모든 이벤트를 { "event": "...", "webhook_version": "v2", "call": { ... } } 형태로 전송합니다.
아래 예시는 새 연동에서 구현해야 하는 기준 페이로드입니다.
변경 지점 v2 v1 기존 유지용 버전 식별 webhook_version없음 에이전트 agent.agent_id, agent.agent_versionagent_id발신 번호 from_numbercall_from수신 번호 to_numbercall_to시작 시각 start_atstart_timestamp종료 시각 end_atend_timestamp중간 이벤트 시각 occurred_attimestamp스크립트 transcript로 통합transcript_with_tool_calls 별도 제공비용 call_cost.total_costcall_cost.total_credits_used
call_started
{
"event" : "call_started" ,
"webhook_version" : "v2" ,
"call" : {
"call_id" : "3079f46c-d141-4cd9-805f-69f212136b66" ,
"agent" : {
"agent_id" : "7ea3516d-08f6-4129-ab40-a731e379b320" ,
"agent_version" : "v3"
},
"call_type" : "inbound" ,
"from_number" : "01012345678" ,
"to_number" : "07012345678" ,
"dynamic_variables" : {
"customer_name" : "홍길동"
},
"metadata" : {
"source" : "crm"
},
"start_at" : 1741842354957 ,
"opt_out_sensitive_data_storage" : false
}
}
mid_call
{
"event" : "mid_call" ,
"webhook_version" : "v2" ,
"call" : {
"call_id" : "3079f46c-d141-4cd9-805f-69f212136b66" ,
"agent" : {
"agent_id" : "7ea3516d-08f6-4129-ab40-a731e379b320" ,
"agent_version" : "v3"
},
"occurred_at" : 1742158401445 ,
"event_type" : "call_message" ,
"event_data" : {
"role" : "user" ,
"content" : "주문한 제품이 언제 도착하나요?"
}
}
}
call_ended
{
"event" : "call_ended" ,
"webhook_version" : "v2" ,
"call" : {
"call_id" : "3079f46c-d141-4cd9-805f-69f212136b66" ,
"agent" : {
"agent_id" : "7ea3516d-08f6-4129-ab40-a731e379b320" ,
"agent_version" : "v3"
},
"call_type" : "inbound" ,
"from_number" : "01012345678" ,
"to_number" : "07012345678" ,
"dynamic_variables" : {
"customer_name" : "홍길동"
},
"metadata" : {
"source" : "crm"
},
"call_status" : "ended" ,
"disconnection_reason" : "user_hangup" ,
"start_at" : 1741652312146 ,
"end_at" : 1741652351189 ,
"transcript" : [
{ "role" : "agent" , "content" : "안녕하세요. 무엇을 도와드릴까요?" },
{ "role" : "user" , "content" : "주문 상태를 확인하고 싶습니다." }
],
"recording_url" : "https://storage.googleapis.com/agentify/egress/audio_recording.ogg" ,
"opt_out_sensitive_data_storage" : false
}
}
call_analyzed
{
"event" : "call_analyzed" ,
"webhook_version" : "v2" ,
"call" : {
"call_id" : "3079f46c-d141-4cd9-805f-69f212136b66" ,
"agent" : {
"agent_id" : "7ea3516d-08f6-4129-ab40-a731e379b320" ,
"agent_version" : "v3"
},
"call_type" : "inbound" ,
"from_number" : "01012345678" ,
"to_number" : "07012345678" ,
"dynamic_variables" : {
"customer_name" : "홍길동"
},
"metadata" : {
"source" : "crm"
},
"call_status" : "ended" ,
"disconnection_reason" : "user_hangup" ,
"start_at" : 1741652312146 ,
"end_at" : 1741652351189 ,
"transcript" : [
{ "role" : "agent" , "content" : "안녕하세요. 무엇을 도와드릴까요?" },
{ "role" : "user" , "content" : "주문 상태를 확인하고 싶습니다." }
],
"recording_url" : "https://storage.googleapis.com/agentify/egress/audio_recording.ogg" ,
"call_cost" : {
"total_cost" : 45
},
"call_analysis" : {
"summary" : "고객이 주문 상태를 문의했고, 상담원이 배송 예정일을 안내했습니다." ,
"user_sentiment" : "neutral" ,
"custom_analysis_data" : [
{ "type" : "string" , "name" : "문의 유형" , "value" : "배송 상태 문의" },
{ "type" : "boolean" , "name" : "문제 해결 여부" , "value" : true }
]
},
"opt_out_sensitive_data_storage" : false
}
}
시간 필드는 모두 UNIX 타임스탬프 밀리초 단위입니다.
v2에는 duration_ms가 없으므로 end_at - start_at으로 계산하세요.
agent.agent_version은 특정 배포 버전이면 v3처럼 표시되고, 현재 설정으로 실행된 통화면 current입니다.
v1은 기존 수신 서버와의 호환을 위한 형식입니다.
새 연동에서는 v2 예시를 기준으로 구현하세요. call_started {
"event" : "call_started" ,
"call" : {
"agent_id" : "7ea3516d-08f6-4129-ab40-a731e379b320" ,
"call_id" : "3079f46c-d141-4cd9-805f-69f212136b66" ,
"call_type" : "inbound" ,
"call_from" : "01012345678" ,
"call_to" : "07012345678" ,
"dynamic_variables" : {
"customer_name" : "홍길동"
},
"metadata" : {
"source" : "crm"
},
"start_timestamp" : 1741842354957 ,
"opt_out_sensitive_data_storage" : false
}
}
mid_call {
"event" : "mid_call" ,
"mid_call" : {
"agent_id" : "7ea3516d-08f6-4129-ab40-a731e379b320" ,
"call_id" : "3079f46c-d141-4cd9-805f-69f212136b66" ,
"timestamp" : 1742158401445 ,
"event_type" : "call_message" ,
"event_data" : {
"role" : "user" ,
"content" : "주문한 제품이 언제 도착하나요?"
}
}
}
call_ended {
"event" : "call_ended" ,
"call" : {
"agent_id" : "7ea3516d-08f6-4129-ab40-a731e379b320" ,
"call_id" : "3079f46c-d141-4cd9-805f-69f212136b66" ,
"call_type" : "inbound" ,
"call_from" : "01012345678" ,
"call_to" : "07012345678" ,
"dynamic_variables" : {
"customer_name" : "홍길동"
},
"metadata" : {
"source" : "crm"
},
"disconnection_reason" : "user_hangup" ,
"start_timestamp" : 1741652312146 ,
"end_timestamp" : 1741652351189 ,
"duration_ms" : 39043 ,
"transcript" : [
{ "role" : "agent" , "content" : "안녕하세요. 무엇을 도와드릴까요?" },
{ "role" : "user" , "content" : "주문 상태를 확인하고 싶습니다." }
],
"transcript_with_tool_calls" : [
{ "role" : "agent" , "content" : "안녕하세요. 무엇을 도와드릴까요?" },
{ "role" : "user" , "content" : "주문 상태를 확인하고 싶습니다." }
],
"recording_url" : "https://storage.googleapis.com/agentify/egress/audio_recording.ogg" ,
"call_cost" : {
"total_credits_used" : 45 ,
"duration_seconds" : 39
},
"call_analysis" : {
"summary" : "고객이 주문 상태를 문의했고, 상담원이 배송 예정일을 안내했습니다." ,
"user_sentiment" : "neutral" ,
"custom_analysis_data" : [
{ "type" : "string" , "name" : "문의 유형" , "value" : "배송 상태 문의" },
{ "type" : "boolean" , "name" : "문제 해결 여부" , "value" : true }
]
},
"opt_out_sensitive_data_storage" : false
}
}
민감 데이터 저장 금지를 활성화하면 일부 통화 정보가 비워질 수 있습니다.
데이터를 계속 활용하려면 웹훅 수신 서버에서 필요한 데이터를 별도 저장하세요.
관련 문서
에이전트 웹훅, agent webhook, call_started, call_ended, call_analyzed, mid_call, webhook v2, webhook v1, 페이로드, 통화 이벤트