CRM Integration Guide: Voice Channel API
📋 Руководство по интеграции голосовых каналов через API
Это руководство для разработчиков CRM-систем, которые хотят интегрировать создание и управление голосовыми каналами с AI-агентами.
🔐 Аутентификация
Все запросы требуют JWT токен в заголовке:
Authorization: Bearer YOUR_JWT_TOKENПолучение токена
POST /v1/auth/login
Content-Type: application/json
{
"email": "user@example.com",
"password": "your_password"
}Response:
{
"status": "success",
"data": {
"access_token": "eyJhbGciOiJSUzI1NiJ9...",
"refresh_token": "eyJhbGciOiJSUzI1NiJ9...",
"user": {
"id": "user-uuid",
"email": "user@example.com",
"tenant_id": "tenant-uuid"
}
}
}🎯 Шаг 1: Создание AI-агента
Сначала создайте AI-агента, который будет обрабатывать звонки:
POST /v1/agents
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: application/json
{
"name": "Customer Support Agent",
"language": "ru",
"prompt": "Вы - профессиональный помощник службы поддержки. Отвечайте вежливо и помогайте клиентам решать их вопросы.",
"voice_id": "21m00Tcm4TlvDq8ikWAM",
"workspace_id": "workspace-uuid"
}Response:
{
"status": "success",
"data": {
"id": "agent-uuid",
"name": "Customer Support Agent",
"language": "ru",
"provider_agent_id": "agent_xxxxxxxxxxxxxxxxxx",
"status": "active"
}
}💡 Важно: Сохраните
idагента - он понадобится для создания канала.
🎯 Шаг 2: Создание голосового канала (webvoice)
Базовый запрос
POST /v1/channels
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: application/json
{
"type": "webvoice",
"name": "Website Voice Widget",
"agent_id": "agent-uuid",
"workspace_id": "workspace-uuid",
"allowed_origins": ["https://yourwebsite.com", "https://www.yourwebsite.com"]
}Запрос с полной кастомизацией виджета
POST /v1/channels
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: application/json
{
"type": "webvoice",
"name": "Website Voice Widget",
"agent_id": "agent-uuid",
"workspace_id": "workspace-uuid",
"allowed_origins": ["https://yourwebsite.com"],
"greeting_message": "Здравствуйте! Чем могу помочь?",
"widget_variant": "expandable",
"widget_placement": "bottom-right",
"widget_btn_color": "#007bff",
"widget_btn_text_color": "#ffffff",
"widget_bg_color": "#f8f9fa",
"widget_text_color": "#212529",
"widget_avatar_type": "orb",
"widget_avatar_color_1": "#007bff",
"widget_avatar_color_2": "#0056b3",
"widget_disable_banner": true,
"voice_language": "ru",
"voice_stability": 0.5,
"voice_similarity_boost": 0.75
}Response:
{
"status": "success",
"data": {
"id": "channel-uuid",
"type": "webvoice",
"name": "Website Voice Widget",
"agent_id": "agent-uuid",
"status": "active",
"resource_ref": "wss://backend-dev.dmva.acebox.eu/v1/voice/webvoice/channel-uuid",
"widget_variant": "expandable",
"widget_placement": "bottom-right",
"widget_btn_color": "#007bff",
"widget_btn_text_color": "#ffffff",
"widget_bg_color": "#f8f9fa",
"widget_text_color": "#212529",
"widget_avatar_type": "orb",
"widget_avatar_color_1": "#007bff",
"widget_avatar_color_2": "#0056b3",
"widget_disable_banner": true,
"created_at": "2025-11-17T10:00:00.000Z"
}
}💡 Важно: Сохраните
idканала для дальнейшей настройки.
🎨 Шаг 3: Настройка виджета (опционально)
Если нужно изменить настройки виджета после создания канала:
Вариант 1: Dedicated endpoint (рекомендуется)
PATCH /v1/channels/{channel-id}/voice-widget-settings
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: application/json
{
"widget_variant": "full",
"widget_placement": "bottom-right",
"widget_btn_color": "#00d4ff",
"widget_btn_text_color": "#000000",
"widget_bg_color": "#ffffff",
"widget_text_color": "#333333",
"widget_avatar_type": "orb",
"widget_avatar_color_1": "#00d4ff",
"widget_avatar_color_2": "#0095ff",
"widget_disable_banner": true
}Response:
{
"status": "success",
"data": {
"id": "channel-uuid",
"widget_variant": "full",
"widget_placement": "bottom-right",
"widget_btn_color": "#00d4ff",
"widget_btn_text_color": "#000000",
"widget_bg_color": "#ffffff",
"widget_text_color": "#333333",
"widget_avatar_type": "orb",
"widget_avatar_color_1": "#00d4ff",
"widget_avatar_color_2": "#0095ff",
"widget_disable_banner": true,
"updated_at": "2025-11-17T11:00:00.000Z",
"synced": true
}
}✅ synced: true означает, что настройки автоматически синхронизированы с ElevenLabs.
Вариант 2: Общий endpoint канала
PATCH /v1/channels/{channel-id}
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: application/json
{
"widget_btn_color": "#ff0000",
"widget_text_color": "#ffffff"
}📊 Получение информации о канале
Получить один канал
GET /v1/channels/{channel-id}
Authorization: Bearer YOUR_JWT_TOKENResponse:
{
"status": "success",
"data": {
"id": "channel-uuid",
"type": "webvoice",
"name": "Website Voice Widget",
"agent_id": "agent-uuid",
"status": "active",
"resource_ref": "wss://...",
"widget_variant": "expandable",
"widget_placement": "bottom-right",
"widget_btn_color": "#007bff",
"widget_btn_text_color": "#ffffff",
"widget_bg_color": "#f8f9fa",
"widget_text_color": "#212529",
"widget_avatar_type": "orb",
"widget_avatar_color_1": "#007bff",
"widget_avatar_color_2": "#0056b3",
"widget_disable_banner": true,
"created_at": "2025-11-17T10:00:00.000Z",
"updated_at": "2025-11-17T11:00:00.000Z"
}
}Получить только настройки виджета
GET /v1/channels/{channel-id}/voice-widget-settings
Authorization: Bearer YOUR_JWT_TOKENResponse:
{
"status": "success",
"data": {
"id": "channel-uuid",
"widget_variant": "expandable",
"widget_placement": "bottom-right",
"widget_btn_color": "#007bff",
"widget_btn_text_color": "#ffffff",
"widget_bg_color": "#f8f9fa",
"widget_text_color": "#212529",
"widget_avatar_type": "orb",
"widget_avatar_color_1": "#007bff",
"widget_avatar_color_2": "#0056b3",
"widget_avatar_url": null,
"widget_disable_banner": true
}
}Получить все каналы
GET /v1/channels?type=webvoice&workspace_id={workspace-uuid}
Authorization: Bearer YOUR_JWT_TOKEN🚀 Шаг 4: Получить код для встраивания виджета
После создания webvoice канала, получите готовый код для встраивания на ваш сайт:
GET /v1/voice-widget/{channel-id}/directБазовый запрос
curl "https://backend-dev.dmva.acebox.eu/v1/voice-widget/30f45496-35a9-402c-9ca6-525fd8455d8c/direct"С кастомизацией через параметры
curl "https://backend-dev.dmva.acebox.eu/v1/voice-widget/{channel-id}/direct?theme=dark&language=ru&size=large"Доступные параметры:
theme-light|dark|customposition-bottom-right|bottom-left|top-right|top-leftsize-small|medium|largelanguage-en|ru|pl|de|frи т.д.color- Hex код цвета (например,%23007bff)hidebranding-true|false
Response
{
"status": "success",
"data": {
"agent_id": "agent_2701ka2qwdvsfsx8k1a7zk6rwhk4",
"channel_id": "30f45496-35a9-402c-9ca6-525fd8455d8c",
"channel_name": "Website Voice Widget",
"html_snippet": "<elevenlabs-convai agent-id=\"agent_xxx\" background-color=\"#007bff\"></elevenlabs-convai>",
"script_tag": "<script src=\"https://unpkg.com/@elevenlabs/convai-widget-embed\" async></script>",
"full_code": "<!-- Полный HTML код для вставки -->",
"configuration": {
"theme": "light",
"position": "bottom-right",
"size": "medium",
"language": "en",
"color": "#007bff",
"hide_branding": true
},
"usage_examples": {
"html": "<!-- HTML пример -->",
"react": "// React компонент",
"vue": "// Vue компонент"
}
}
}Встраивание на сайт
Шаг 1: Скопируйте full_code из ответа API
Шаг 2: Вставьте код перед закрывающим тегом </body> на вашей странице:
<!DOCTYPE html>
<html>
<head>
<title>Мой сайт</title>
</head>
<body>
<!-- Ваш контент -->
<h1>Добро пожаловать!</h1>
<!-- Voice Widget - вставьте здесь -->
<elevenlabs-convai
agent-id="agent_2701ka2qwdvsfsx8k1a7zk6rwhk4"
background-color="#007bff"
widget-position="bottom-right">
</elevenlabs-convai>
<script src="https://unpkg.com/@elevenlabs/convai-widget-embed" async></script>
</body>
</html>Готово! Виджет появится на вашей странице и будет готов к использованию.
Интеграция с React
import React, { useEffect } from 'react';
function VoiceWidget({ channelId }) {
useEffect(() => {
// Получаем код виджета
fetch(`https://backend-dev.dmva.acebox.eu/v1/voice-widget/${channelId}/direct`)
.then(res => res.json())
.then(data => {
// Вставляем виджет на страницу
const widget = document.createElement('div');
widget.innerHTML = data.data.html_snippet;
document.body.appendChild(widget);
// Загружаем скрипт ElevenLabs
const script = document.createElement('script');
script.src = 'https://unpkg.com/@elevenlabs/convai-widget-embed';
script.async = true;
document.body.appendChild(script);
});
}, [channelId]);
return null;
}
export default VoiceWidget;Интеграция с Vue.js
<template>
<div></div>
</template>
<script>
export default {
props: ['channelId'],
async mounted() {
const response = await fetch(
`https://backend-dev.dmva.acebox.eu/v1/voice-widget/${this.channelId}/direct`
);
const data = await response.json();
// Вставляем виджет
const widget = document.createElement('div');
widget.innerHTML = data.data.html_snippet;
document.body.appendChild(widget);
// Загружаем скрипт
const script = document.createElement('script');
script.src = 'https://unpkg.com/@elevenlabs/convai-widget-embed';
script.async = true;
document.body.appendChild(script);
}
}
</script>💡 Важно: Виджет интегрируется напрямую в DOM вашей страницы (БЕЗ iframe), что обеспечивает:
- ✅ Идеальное изменение размера при раскрытии/сворачивании
- ✅ Отличный UX на мобильных устройствах
- ✅ Плавные анимации
- ✅ Отсутствие проблем с CORS
- ✅ Быструю загрузку
🎨 Параметры кастомизации виджета
Widget Variant (внешний вид)
| Значение | Описание |
|---|---|
tiny | Минимальный размер, только иконка |
compact | Компактный вид с кнопкой |
full | Полноразмерный виджет |
expandable | Раскрывающийся виджет (рекомендуется) |
Widget Placement (позиция на странице)
| Значение | Описание |
|---|---|
top-left | Верхний левый угол |
top | Верх по центру |
top-right | Верхний правый угол |
bottom-left | Нижний левый угол |
bottom | Низ по центру |
bottom-right | Нижний правый угол (рекомендуется) |
Widget Colors (цвета в формате #RRGGBB)
| Параметр | Описание |
|---|---|
widget_btn_color | Цвет кнопки виджета |
widget_btn_text_color | Цвет текста на кнопке |
widget_bg_color | Цвет фона виджета |
widget_text_color | Цвет текста в виджете |
Widget Avatar (аватар ассистента)
widget_avatar_type:
orb- Анимированная сфера (использует color_1 и color_2)url- Изображение по URLimage- Загруженное изображение
Для type="orb":
{
"widget_avatar_type": "orb",
"widget_avatar_color_1": "#007bff",
"widget_avatar_color_2": "#0056b3"
}Для type="url":
{
"widget_avatar_type": "url",
"widget_avatar_url": "https://yourcdn.com/avatar.png"
}Widget Branding
| Параметр | Описание |
|---|---|
widget_disable_banner | true - скрыть "Powered by ElevenLabs" |
📞 Настройки голоса
Параметры голоса агента
{
"voice_language": "ru",
"voice_id": "21m00Tcm4TlvDq8ikWAM",
"voice_speed": 1.0,
"voice_stability": 0.5,
"voice_similarity_boost": 0.75,
"voice_style": 0.0,
"voice_optimize_latency": 3,
"voice_turn_timeout": 1500,
"voice_turn_eagerness": 1.0
}| Параметр | Тип | Диапазон | Описание |
|---|---|---|---|
voice_language | string | - | Код языка (ru, en, es, etc.) |
voice_id | string | - | ID голоса из ElevenLabs |
voice_speed | float | 0.5-2.0 | Скорость речи |
voice_stability | float | 0.0-1.0 | Стабильность голоса |
voice_similarity_boost | float | 0.0-1.0 | Похожесть на оригинал |
voice_style | float | 0.0-1.0 | Экспрессивность |
voice_optimize_latency | int | 0-4 | Оптимизация задержки |
voice_turn_timeout | int | мс | Таймаут ожидания ответа |
voice_turn_eagerness | float | 0.0-1.0 | Готовность прервать пользователя |
🔄 Полный пример: Создание и настройка канала
// 1. Получить токен
const loginResponse = await fetch('https://api.example.com/v1/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: 'user@example.com',
password: 'password'
})
});
const { data: { access_token } } = await loginResponse.json();
// 2. Создать агента
const agentResponse = await fetch('https://api.example.com/v1/agents', {
method: 'POST',
headers: {
'Authorization': `Bearer ${access_token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Support Agent',
language: 'ru',
prompt: 'Вы - помощник службы поддержки',
voice_id: '21m00Tcm4TlvDq8ikWAM',
workspace_id: 'workspace-uuid'
})
});
const { data: agent } = await agentResponse.json();
// 3. Создать webvoice канал с кастомным виджетом
const channelResponse = await fetch('https://api.example.com/v1/channels', {
method: 'POST',
headers: {
'Authorization': `Bearer ${access_token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
type: 'webvoice',
name: 'Website Voice Widget',
agent_id: agent.id,
workspace_id: 'workspace-uuid',
allowed_origins: ['https://yourwebsite.com'],
// Кастомизация виджета
widget_variant: 'expandable',
widget_placement: 'bottom-right',
widget_btn_color: '#007bff',
widget_btn_text_color: '#ffffff',
widget_bg_color: '#f8f9fa',
widget_text_color: '#212529',
widget_avatar_type: 'orb',
widget_avatar_color_1: '#007bff',
widget_avatar_color_2: '#0056b3',
widget_disable_banner: true,
// Настройки голоса
voice_language: 'ru',
voice_stability: 0.5,
voice_similarity_boost: 0.75
})
});
const { data: channel } = await channelResponse.json();
// 4. Опционально: Обновить настройки виджета позже
const updateResponse = await fetch(
`https://api.example.com/v1/channels/${channel.id}/voice-widget-settings`,
{
method: 'PATCH',
headers: {
'Authorization': `Bearer ${access_token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
widget_btn_color: '#ff0000',
widget_btn_text_color: '#ffffff'
})
}
);
const { data: updatedWidget } = await updateResponse.json();
console.log('Widget updated, synced:', updatedWidget.synced); // true🔌 Интеграция виджета на сайт
После создания канала, добавьте виджет на сайт клиента:
<!DOCTYPE html>
<html>
<head>
<title>Website with Voice Widget</title>
</head>
<body>
<!-- Ваш контент -->
<!-- ElevenLabs Voice Widget -->
<elevenlabs-convai agent-id="agent_xxxxxxxxxxxxxxxxxx"></elevenlabs-convai>
<script src="https://elevenlabs.io/convai-widget/index.js" async type="text/javascript"></script>
</body>
</html>💡 Используйте
provider_agent_idиз ответа создания агента вместоagent_xxxxxxxxxxxxxxxxxx.
🛠️ Управление каналами
Обновить канал
PATCH /v1/channels/{channel-id}
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: application/json
{
"name": "Updated Channel Name",
"status": "active",
"greeting_message": "Новое приветствие"
}Удалить канал
DELETE /v1/channels/{channel-id}
Authorization: Bearer YOUR_JWT_TOKENОтключить/включить канал
PATCH /v1/channels/{channel-id}
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: application/json
{
"status": "disabled" // или "active"
}📋 Список доступных голосов
Получить список голосов
GET /v1/voices
Authorization: Bearer YOUR_JWT_TOKENResponse:
{
"status": "success",
"data": [
{
"voice_id": "21m00Tcm4TlvDq8ikWAM",
"name": "Rachel",
"language": "en",
"gender": "female"
},
{
"voice_id": "AZnzlk1XvdvUeBnXmlld",
"name": "Domi",
"language": "en",
"gender": "female"
}
]
}❌ Обработка ошибок
Стандартный формат ошибок
{
"status": "error",
"message": "Описание ошибки",
"code": "ERROR_CODE"
}Типичные ошибки
| HTTP Code | Описание | Решение |
|---|---|---|
| 401 | Unauthorized | Проверьте токен авторизации |
| 403 | Forbidden | Недостаточно прав |
| 404 | Not Found | Канал/агент не найден |
| 400 | Bad Request | Проверьте формат данных |
| 422 | Validation Error | Проверьте обязательные поля |
| 500 | Server Error | Обратитесь в поддержку |
Пример обработки ошибок
try {
const response = await fetch('https://api.example.com/v1/channels', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(channelData)
});
const result = await response.json();
if (result.status === 'error') {
console.error('API Error:', result.message);
// Обработка ошибки
} else {
console.log('Channel created:', result.data);
}
} catch (error) {
console.error('Network error:', error);
}📞 Поддержка
При возникновении вопросов или проблем:
- Проверьте формат данных в запросе
- Убедитесь, что токен авторизации актуален
- Проверьте права доступа пользователя
- Обратитесь в техническую поддержку: support@example.com
🔗 Полезные ссылки
📝 Changelog
2025-11-17:
- ✅ Добавлены dedicated endpoints для настройки виджета
- ✅ Автоматическая синхронизация с ElevenLabs
- ✅ Исправлены названия полей (
widget_btn_color,widget_btn_text_color) - ✅ Поддержка кастомизации виджета при создании канала