ФункцииAPI и интеграции

API и интеграции

Платформа поддерживает интеграцию с внешними системами: импорт контактов по API, автоматический экспорт лидов в CRM (amoCRM, Битрикс24) и получение уведомлений через webhook. На этой странице описаны технические детали каждого механизма.

Для партнёров. Если вы управляете клиентскими организациями ВойсЛайнс как партнёр, используйте отдельное Партнёрское API с PDF-контрактом и OpenAPI-спецификацией.

Загрузка контактов по API#

Для автоматической загрузки контактов из внешней системы (CRM, формы, таблицы) создайте интеграцию типа «Загрузка контактов по API» на вкладке «Интеграции» в базе контактов. Платформа сгенерирует уникальный URL — на него нужно отправлять POST-запросы с контактами.

Запрос#

POSThttps://voicelines.ru/api/v1/upload-contacts/{token}
Content-Type: application/json

Параметр {token} — уникальный ключ доступа, который отображается при создании интеграции. Аутентификация не требуется — токен в URL является единственным идентификатором.

Тело запроса#

JSON-массив объектов. Каждый объект — один контакт:

JSON
[
  {
    "phone": "+79001234567",
    "name": "Иванов Иван",
    "company": "ООО Ромашка",
    "city": "Москва"
  },
  {
    "phone": "+79007654321",
    "name": "Петрова Мария"
  },
  {
    "phone": "89005551234"
  }
]
ПолеТипОписание
phonestringОбязательное. Номер телефона в любом формате — система автоматически нормализует в E.164 (например, +79001234567) и всегда сохраняет как основное поле контакта
namestring Имя контакта. Всегда сохраняется как основное поле контакта и доступно в роботе через плейсхолдер {name}
любое другоеstring Дополнительные параметры (до 128 символов ключ, до 1000 символов значение). Ключи phone и name зарезервированы и не попадают сюда. Остальные поля доступны через плейсхолдеры {ключ}

Все дополнительные поля контакта сохраняются как есть и затем автоматически передаются в webhook в объекте contactFields. Зарезервированные поля phone и name не дублируются в contactFields, потому что они уже хранятся в основных полях контакта. Отдельной фильтрации по названиям или значениям сейчас нет, поэтому не передавайте в пользовательских полях чувствительные данные, если не готовы отправлять их во внешние системы.

Ограничения#

  • Максимум 10 000 контактов за один запрос
  • Дубликаты номеров (уже существующих в базе или повторяющихся в запросе) пропускаются
  • Невалидные номера пропускаются (система поддерживает российские мобильные номера)
  • Нечисловые значения полей конвертируются в строку

Ответ#

HTTP
HTTP 200 OK

{
  "totalReceived": 3,
  "imported": 2,
  "skipped": 1
}
ПолеТипОписание
totalReceivedintВсего контактов получено в запросе
importedintУспешно импортировано
skippedintПропущено (дубликаты, невалидные номера, пустые значения)

Коды ответов#

200Запрос обработан, результат в теле ответа
400Ошибка валидации: пустой массив, более 10 000 контактов, некорректный JSON
404Интеграция не найдена, неактивна или удалена

При ошибке тело ответа — JSON с описанием в поле detail. Пример ответа на запрос, в котором больше 10 000 контактов:

HTTP
HTTP 400 Bad Request
Content-Type: application/problem+json

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "Bad Request",
  "status": 400,
  "detail": "Максимум 10000 контактов за один запрос"
}

Пример (cURL)#

cURL
curl -X POST https://voicelines.ru/api/v1/upload-contacts/ВАШ_ТОКЕН \
  -H "Content-Type: application/json" \
  -d '[{"phone": "+79001234567", "name": "Иванов Иван", "company": "ООО Ромашка"}]'

Пример (Python)#

Python
import requests

url = "https://voicelines.ru/api/v1/upload-contacts/ВАШ_ТОКЕН"
contacts = [
    {"phone": "+79001234567", "name": "Иванов Иван", "company": "ООО Ромашка"},
    {"phone": "+79007654321", "name": "Петрова Мария"}
]

response = requests.post(url, json=contacts)
print(response.json())
# {"totalReceived": 2, "imported": 2, "skipped": 0}

Интеграция с amoCRM#

Платформа умеет автоматически создавать сделки и контакты в amoCRM при достижении цели звонка, а также импортировать контакты из amoCRM для обзвона.

Подключение#

1

Создайте интеграцию — на вкладке «Интеграции» в базе контактов нажмите «Добавить» и выберите тип «amoCRM».

2

Укажите поддомен в поле «Поддомен amoCRM» — часть URL вашего аккаунта amoCRM. Например, если ваш аккаунт https://mycompany.amocrm.ru, введите mycompany.

3

Получите долгосрочный токен в amoCRM: откройте амоМаркет (иконка в левом боковом меню), справа вверху нажмите на кнопку «...», затем «+ Создать интеграцию», выберите «+ Создать Внешняя интеграция», сконфигурируйте интеграцию и сгенерируйте долгосрочный токен. Вставьте его в поле «Токен amoCRM».

4

Проверьте подключение — нажмите кнопку «Проверить подключение». Система проверит доступ к аккаунту и покажет результат.

Импорт контактов из amoCRM#

Если включён переключатель «Импорт контактов из amoCRM», платформа предоставит URL для вебхука. Настройте его в amoCRM:

1

Откройте амоМаркет (иконка в левом боковом меню amoCRM).

2

Справа вверху нажмите на кнопку «+ WebHooks».

3

Вставьте URL из настроек интеграции в поле адреса вебхука и отметьте событие «Создание контакта».

Также можно использовать Salesbot — настройте в нём отправку POST-запроса на этот же URL при нужном триггере.

Экспорт лидов в amoCRM#

Если включён переключатель «Экспорт лидов при достижении цели», при достижении цели звонка платформа автоматически создаст в amoCRM:

  • Новую сделку с названием, включающим имя или номер контакта
  • Новый контакт с телефонным номером
  • Примечание к сделке с названием кампании, транскрипцией диалога и ссылкой на запись звонка

Экспорт работает через очередь с автоматическими повторными попытками (до 5 раз с увеличивающимся интервалом). Статус последней отправки и ошибки отображаются в настройках интеграции.

Интеграция с Битрикс24#

Платформа умеет автоматически создавать лиды в Битрикс24 при достижении цели звонка. Интеграция работает через входящий вебхук Битрикс24 — для настройки не нужны приложения или OAuth.

Подключение#

1

Создайте интеграцию — на вкладке «Интеграции» в базе контактов нажмите «Добавить» и выберите тип «Битрикс24».

2

Создайте входящий вебхук в Битрикс24: откройте Приложения → Разработчикам, вкладка «Готовые сценарии» → Другое → «Входящий вебхук». В разделе «Настройка прав» отметьте CRM и нажмите «Сохранить».

3

Скопируйте URL вебхука целиком (он будет вида: https://mycompany.bitrix24.ru/rest/1/abc123secret/) и вставьте его в поле «URL вебхука» в настройках интеграции.

4

Проверьте подключение — нажмите кнопку «Проверить подключение». Система проверит доступ к порталу и покажет результат.

Экспорт лидов в Битрикс24#

Если включён переключатель «Экспорт лидов при достижении цели», при достижении цели звонка платформа автоматически создаст в CRM:

  • Новый лид с названием, номером телефона, именем контакта и транскрипцией разговора
  • Комментарий в таймлайне с транскрипцией диалога и ссылкой на запись звонка

Экспорт работает через очередь с автоматическими повторными попытками (до 5 раз с увеличивающимся интервалом). Статус последней отправки и ошибки отображаются в настройках интеграции.

Лид перед переводом сотруднику#

В настройках перевода базы контактов галочка «Отправлять лид до перевода» включена по умолчанию. Сам перевод включается отдельно. После подготовки перевода платформа начинает отправку лида в подключённые Telegram, CRM и webhook, чтобы сотрудник получил диалог с роботом. Получение сообщения до ответа сотрудника зависит от скорости доставки.

Результат раннего лида: «Цель достигнута в разговоре с роботом. Запрошен перевод сотруднику.» Длительность указана на момент подготовки перевода. Короткий диалог передаётся целиком; если длинный не помещается, в Telegram и CRM остаются последние реплики в исходном порядке. В Telegram учитывается ограничение всего сообщения в 4096 символов, в CRM — 4000 символов текста диалога. Полный диалог сохраняется в карточке звонка.

Ссылка на запись может быть недоступна до завершения всего разговора, включая сотрудника, и сохранения аудио. После окончания система может изменить статус в карточке звонка, но раннее сообщение автоматически не обновляется и второй лид не отправляется. Отдельного сообщения о готовности записи нет. При выключенной галочке действует обычная отправка после звонка.

Webhook-уведомления#

Webhook — это один из каналов уведомлений. При каждом подходящем звонке платформа отправляет HTTP POST-запрос на указанный URL с полными данными о звонке в формате JSON.

Базовые поля звонка передаются всегда. Если у контакта были дополнительные пользовательские поля из импорта, они приходят в объекте contactFields. Поле transcript передаётся только если в настройках webhook включена опция «Передавать полную транскрипцию разговора».

HTTP-запрос#

POSThttps://your-server.com/webhook HTTP/1.1
Content-Type: application/json
X-Webhook-Event: lead.goal_achieved
X-Webhook-Id: 3fa85f97-6e93-4c3a-aab1-8cb9d1a1d8f5
X-Webhook-Signature: sha256=a1b2c3d4e5f6...
ЗаголовокОписание
X-Webhook-Event Тип события: lead.goal_achieved (цель достигнута), call.completed (звонок завершён) или test (тестовый запрос)
X-Webhook-IdУникальный идентификатор отправки (UUID) — используйте для идемпотентности
X-Webhook-Signature HMAC-SHA256 подпись тела запроса (если настроен секретный ключ). Формат: sha256=<hex>

JSON-тело запроса#

JSON
{
  "callId": "3fa85f97-6e93-4c3a-aab1-8cb9d1a1d8f5",
  "organizationName": "Моя компания",
  "callListId": "d1a2b3c4-5678-9012-abcd-ef3456789012",
  "callListName": "Обзвон клиентов",
  "callListItemId": "e5f6a7b8-9012-3456-cdef-123456789abc",
  "phoneE164": "+79001234567",
  "contactName": "Иванов Иван",
  "status": "GoalAchieved",
  "isGoalAchieved": true,
  "goalSummary": "Клиент согласился на встречу",
  "goalConversationResume": "Обсудили условия. Встреча назначена на завтра в 14:00",
  "contactFields": {
    "company": "ООО Ромашка",
    "city": "Москва"
  },
  "transcript": "Робот: Добрый день, удобно говорить?\nКлиент: Да, пару минут есть.\nРобот: Тогда коротко расскажу...",
  "durationSeconds": 125,
  "recordingUrl": "https://voicelines.ru/public/recordings/3fa85f97.wav",
  "calledAtUtc": "2026-04-04T10:30:45Z"
}
ПолеТипОписание
callIdstring (UUID)Идентификатор звонка
organizationNamestringНазвание организации
callListIdstring (UUID)Идентификатор базы контактов
callListNamestring | nullНазвание базы контактов
callListItemIdstring (UUID)Идентификатор контакта в базе
phoneE164stringНомер телефона в формате E.164, например +79001234567
contactNamestring | nullИмя контакта (если задано)
statusstringСтатус звонка (см. таблицу ниже)
isGoalAchievedbooleantrue — цель достигнута
goalSummarystring | nullКраткий результат (заполняется при достижении цели)
goalConversationResumestring | nullРезюме разговора; в раннем лиде — результат робота и пометка о запросе перевода
contactFieldsobject | null Пользовательские поля контакта из импорта. Поле появляется только если у контакта есть дополнительные параметры. Все значения передаются без дополнительной фильтрации.
transcriptstring | null Полная транскрипция разговора одним текстом. Поле появляется только если для webhook включена опция передачи транскрипции.
durationSecondsintДлительность в секундах; в раннем лиде — на момент подготовки перевода
recordingUrlstring | nullСсылка на запись; в раннем лиде может отвечать 404 до окончания разговора и сохранения аудио
calledAtUtcstring (ISO 8601)Время звонка в UTC

Статусы звонка#

GoalAchievedЦель достигнута
CallLaterПерезвонить
NotInterestedНе интересно
HungUpСбросил
NegativeНегатив
NoAnswerКлиент не ответил
VoicemailСработал автоответчик
SilenceКлиент молчал или не дал распознаваемого ответа
ErrorЗвонок завершился ошибкой обработки

Initiated — технический промежуточный статус активного звонка; в webhook payload он не отправляется.

Проверка подписи (HMAC-SHA256)#

Если при создании webhook-уведомления указан секретный ключ, каждый запрос подписывается алгоритмом HMAC-SHA256. Подпись передаётся в заголовке X-Webhook-Signature в формате sha256=<hex>.

Алгоритм проверки:

  • Возьмите тело запроса как строку (raw body)
  • Вычислите HMAC-SHA256(body, secret) — результат в lowercase hex
  • Сравните с подписью из заголовка (без префикса sha256=)

Пример проверки (Node.js)#

Node.js
const crypto = require('crypto');

function verifySignature(rawBody, secret, signatureHeader) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  const received = signatureHeader.replace('sha256=', '');
  return crypto.timingSafeEqual(
    Buffer.from(expected), Buffer.from(received)
  );
}

Пример проверки (Python)#

Python
import hmac, hashlib

def verify_signature(raw_body: bytes, secret: str, signature_header: str) -> bool:
    expected = hmac.new(
        secret.encode(), raw_body, hashlib.sha256
    ).hexdigest()
    received = signature_header.replace("sha256=", "")
    return hmac.compare_digest(expected, received)

Webhook при переводе сотруднику#

При включённой ранней отправке приходит существующее событие lead.goal_achieved: status = GoalAchieved, isGoalAchieved = true. Поля goalSummary и goalConversationResume содержат результат робота и пометку о запросе перевода. Это не подтверждение успешного соединения с сотрудником. Полный transcript передаётся только при включённой опции передачи транскрипции; ограничение длины Telegram/CRM к нему не применяется.

После принятия раннего события автоматического финального webhook нет, включая call.completed при настройке «Все звонки». Последующее уточнение статуса не меняет уже отправленные данные. Явная ручная смена статуса сохраняет обычные правила уведомлений и может создать отдельное событие. Новых полей для признака ранней отправки или ссылки на запись нет.

Подтвердите получение webhook ответом 2xx, не ожидая готовности recordingUrl; загрузку записи можно выполнить позднее. При выключенной галочке, отсутствии перевода, получателей или успешной ранней постановки работают обычные правила отправки после звонка.

Таймаут и повторные попытки#

Платформа ожидает ответ от вашего сервера не более 10 секунд. При получении HTTP-ответа с кодом 2xx запрос считается доставленным. При любой другой ошибке (код 4xx/5xx, таймаут, ошибка подключения) система выполнит повторную попытку: всего до 5 попыток с растущей паузой. Если ни одна попытка не прошла, событие больше не отправляется.

Повторы одного события сохраняют тело запроса и X-Webhook-Id. Используйте этот идентификатор для защиты от повторной обработки. Один callId связывает события со звонком, но не отличает отдельное ручное уведомление от повтора доставки.