사용자 지정 채널

웹훅으로 외부 텍스트 채널을 ElevenLabs 에이전트에 연결

개요

Custom Channel은 외부 메시징 시스템을 ElevenLabs 에이전트에 연결합니다. 사용자 메시지를 ElevenLabs 웹훅으로 전송한 후, 자체 HTTPS 엔드포인트에서 에이전트 응답을 받으세요.

Custom Channel은 알파 버전입니다.
제로 보존 모드를 사용하는 에이전트 또는 워크스페이스에서는 Custom Channel을 사용할 수 없습니다.

기능

기능지원 여부
제로 보존 모드(ZRM)지원하지 않음 — ZRM 워크스페이스 및 ZRM 에이전트에서는 사용 불가
메시지의 첨부 파일지원하지 않음 — 메시지는 텍스트만 지원

설정

1

Custom Channel 열기

에이전트를 열고 Channels를 선택한 다음 Custom Channel을 선택하고 Add trigger를 클릭합니다.

2

트리거 구성

기존 연결을 선택하거나 새로 만든 후 Reply Webhook URL을 입력합니다.

3

자격 증명 복사

Add를 클릭한 다음 Inbound Webhook URL, Inbound Secret, Outbound Signing Secret을 복사합니다.

4

서비스 구성

X-Webhook-Secret에 인바운드 시크릿을 넣어 인바운드 웹훅 URL로 사용자 메시지를 전송합니다. 아웃바운드 서명 시크릿을 사용해 각 응답을 확인합니다.

메시지 전송

생성된 웹훅 URL에 POST 요청을 보냅니다.

POST /v1/convai/api-integrations/custom_channel/triggers/{trigger_connection_id}/async_message
X-Webhook-Secret: <inbound-secret>
Content-Type: application/json
{
"data": {
"type": "user_message",
"text": "Where is my order?",
"user_identifier": "customer_8427"
},
"user_message_id": "msg_01k1e6z3f4t8n9c2",
"dynamic_variables": {
"order_id": "order_72491"
}
}
필드필수 여부설명
data.type예user_message여야 합니다.
data.text예비어 있지 않은 사용자 메시지입니다.
data.user_identifier아니요외부 사용자의 식별자입니다.
user_message_id예시스템에서 제공하는 비어 있지 않은 멱등성 키입니다.
conversation_id아니요대화를 계속하려면 반환된 ID를 포함합니다. 새 대화를 시작하려면 생략합니다.
dynamic_variables아니요이번 턴에 에이전트에 제공되는 동적 변수입니다.

ElevenLabs는 턴을 처리하기 전에 202 Accepted를 반환합니다.

{
"conversation_id": "conv_01k1e72d4x8p6v3m",
"status": "queued"
}

대화를 계속하려면 해당 conversation_id와 새 user_message_id를 포함해 다른 요청을 보냅니다.

응답 수신

ElevenLabs는 각 턴이 끝난 후 응답 웹훅 URL에 POST 요청을 보냅니다.

{
"version": "1",
"conversation_id": "conv_01k1e72d4x8p6v3m",
"user_message_ids": ["msg_01k1e6z3f4t8n9c2"],
"status": "completed",
"data": [
{
"type": "agent_response",
"event": {
"agent_response": "Your order is scheduled to arrive tomorrow.",
"response_id": "9f2c1a7e-4b3d-4e8a-9c1f-2d6b8e0a5f31",
"event_id": 4
}
},
{
"type": "agent_tool_response",
"event": {
"tool_name": "end_call",
"tool_call_id": "toolu_01k1e70r4b8y",
"tool_type": "system",
"event_id": 4,
"is_called": true,
"is_error": false,
"is_blocked": false,
"status": "success"
}
}
],
"error": null
}

처리에 실패하면 status는 failed이고, data는 []이며, error에 설명이 포함됩니다.

data는 턴 순서대로 이벤트를 나열합니다. 각 항목에는 type과 event가 있습니다.

  • agent_response에는 에이전트 발화 1개가 포함됩니다. response_id는 발화를 고유하게 식별하고, event_id는 이를 턴에 연결합니다. 채널에서 턴당 하나의 텍스트 버블을 표시한다면 agent_response 값을 결합하세요.
  • agent_tool_response는 도구 결과를 보고하며 해당 턴의 event_id를 공유합니다. status는 success, error, blocked, skipped 중 하나입니다. tool_type: "system", tool_name: "end_call", status: "success"인 응답은 에이전트가 대화를 종료했음을 의미합니다.

여러 인바운드 메시지가 하나의 턴으로 병합될 수 있습니다. user_message_ids에는 이 응답이 답변하는 사용자 메시지 ID가 나열됩니다.

응답 서명 확인

각 응답에는 ElevenLabs-Signature 헤더가 포함됩니다.

t=1753876800,v0=<hex-digest>

다이제스트는 아웃바운드 서명 시크릿을 사용하여 {timestamp}.{raw_request_body}에 대해 생성한 HMAC-SHA256 서명입니다. JSON을 파싱하기 전에 원시 본문을 확인하고 오래된 타임스탬프는 거부하세요.

import hashlib
import hmac
import time
def verify_signature(raw_body: bytes, header: str, secret: str) -> None:
values = dict(part.split("=", 1) for part in header.split(","))
timestamp = values["t"]
if abs(time.time() - int(timestamp)) > 30 * 60:
raise ValueError("Stale webhook signature")
expected = hmac.new(
secret.encode(),
timestamp.encode() + b"." + raw_body,
hashlib.sha256,
).hexdigest()
if not hmac.compare_digest(expected, values["v0"]):
raise ValueError("Invalid webhook signature")

전송 동작

ElevenLabs는 약 0초, 0.5초, 2초에 총 3회의 프로세스 내 전송을 시도합니다. 2xx 응답을 받으면 전송이 성공한 것으로 처리합니다.

요청 본문은 최대 256 KiB로 제한됩니다.