Два интеграционных контура: входящий вебхук — запускает звонок робота HTTP-запросом из любой вашей системы (CRM, сайт, 1С, самописный бэкенд); исходящий вебхук — отдаёт результат разговора на ваш URL прямо из сценария. Токен — в кабинете, первый запрос — за минуту.
Оглавление: быстрый старт · запуск звонка · ответы · дедупликация · переменные · исходящий вебхук · статусы и исходы · Bitrix24 / AmoCRM · свой транк · безопасность · примеры кода · Partner API
Токен выдаётся на сценарий: кабинет → настройки сценария → «Откуда приходят звонки» → «Вебхук / API — запуск из CRM или вашей системы». Подключать CRM не нужно: готовый URL с токеном показан в поле «Webhook URL (содержит токен сценария)». Первый звонок — одна строка:
curl "https://app.botleadgen.ru/api/scenarios/ВАШ_ТОКЕН/start-call?phone=79001234567"
Ответ 200 со status: "accepted" — звонок в
очереди. Сохраните call_id: по нему вы свяжете результат
разговора (исходящий вебхук) со своей сущностью. URL в кабинете
оканчивается на /crm-webhook — это тот же эндпоинт, что
/start-call (см. ниже), используйте любой.
GET | POST https://app.botleadgen.ru/api/scenarios/{API_TOKEN}/start-call
Источник запуска — любой: ваш бэкенд, платформа, сайт, 1С, CRM.
Полный алиас того же эндпоинта — …/crm-webhook (исторический,
работает идентично). Данные принимаются в трёх форматах одновременно:
query-параметры, JSON-тело, form-urlencoded — при совпадении ключей
значение из тела перекрывает query.
| Поле | Обяз. | Что делает |
|---|---|---|
phone | да* | Номер абонента в любом привычном формате («+7 900…», «8 900…») — нормализуем сами. Если в поле несколько номеров через запятую/точку с запятой — возьмём первый. *Можно не передавать, если передан deal_id и подключена интеграция Bitrix24/AmoCRM — тогда телефон достанем из карточки сделки. |
name / contact_name | нет | Имя клиента → переменная {{name}} (робот может обращаться по имени). Если не передано, но есть deal_id + CRM-интеграция — возьмём из карточки. |
var_* | нет | Любые ваши данные: var_client_id → переменная {{client_id}}, var_order → {{order}}. Доступны в репликах робота, Webhook-блоке и отчёте — так вы «прошиваете» свой ID через весь цикл. До 30 полей, значение до 500 символов; системные имена переменных перекрыть нельзя. |
deal_id / dealId | нет | ID сделки → {{deal_id}} (и алиас {{lead_id}}); блоки «Действие в CRM» работают с этой сделкой; участвует в дедупликации. |
stage_id / stageId | нет | Этап → {{crm_stage_id}}. |
pipeline_id / pipelineId | нет | Воронка → {{crm_pipeline_id}}. |
contact_id / contactId | нет | ID контакта CRM — для сценариев, работающих с контактом, а не сделкой → {{contact_id}}. |
event_ts | нет | Время события у вас (ISO-8601 или Unix-время). Защита от «протухших» вебхуков: события старше момента включения приёма игнорируются с status: "ignored", reason: "stale_webhook" — полезно, если CRM ретраит старую очередь. |
{{lead.id}} (CRM не подставила
значение) распознаются и игнорируются — «фигурные скобки» не попадут
в звонок. Формат AmoCRM Salesbot (leads[status][0][id] и
т.п.) разбирается автоматически: lead_id, этап и воронку
достанем из него, телефон и имя передавайте query-параметрами.
Все «мягкие» исходы приходят с кодом 200 и различаются полем status:
status | Тело и что делать |
|---|---|
accepted | {"status":"accepted","scenario_id":"…","scenario_version_id":"…","call_id":"…","phone":"79001234567"} — звонок поставлен в очередь. Сохраните call_id. |
duplicate_ignored | {"status":"duplicate_ignored","call_id":"…","phone":"…","deal_id":"…"} — по этому номеру/сделке недавно уже был звонок этого сценария; call_id — ID того, прошлого звонка. Подробнее — дедупликация. |
ignored + reason: "phone_unresolved" | Телефон не передан и не достался из CRM. В теле — hint с подсказкой. Проверьте параметр phone или привязку контакта к сделке. |
ignored + reason: "stale_webhook" | Событие старше момента включения приёма (см. event_ts) — намеренно пропущено. |
| Код ошибки | Причина |
|---|---|
404 | Неверный токен. |
403 | Сценарий выключен в кабинете. |
400 | У сценария не выбран источник «Вебхук / API» (настройки сценария → «Откуда приходят звонки»). |
429 | Превышен лимит 600 запросов/мин с одного IP — повторите с паузой. |
503 | Режим техработ. Звонок не потерян — просто повторите запрос позже; ретраи по 503 безопасны. |
CRM любят слать один и тот же вебхук несколько раз (ретраи, двойные
триггеры автоматизаций). Платформа сама отсекает дубли: повторный запуск
по тому же номеру и той же сделке внутри настраиваемого окна вернёт
duplicate_ignored и НЕ создаст второй звонок. Окно
настраивается в кабинете (Настройки → Телефония → «Окно дедупа»);
если нужно легитимно перезвонить раньше — уменьшите окно.
Запрос ставит звонок в очередь всегда — даже при нулевом балансе лид не теряется, исполнение дождётся пополнения. Набор идёт с учётом окна обзвона линии и её лимита одновременных звонков; если запрос пришёл вне окна — звонок уйдёт при его открытии. Исполняется опубликованная версия сценария, зафиксированная в момент постановки: правки чернового сценария на звонки в очереди не влияют.
Переменные подставляются в реплики робота, в URL/тело Webhook-блока и
попадают в отчёт звонка. Синтаксис — {{имя}}.
| Переменная | Откуда |
|---|---|
{{call_id}}, {{phone}} | Всегда: ID звонка на платформе и набранный номер. |
{{name}} | Из запуска (name/contact_name) или из карточки CRM. |
{{deal_id}}, {{lead_id}}, {{crm_stage_id}}, {{crm_pipeline_id}}, {{contact_id}} | Из CRM-параметров запуска (см. выше). |
ваши var_* | Из запуска: var_client_id → {{client_id}} и т.д. |
| извлечённые из речи | Блоки распознавания в сценарии складывают данные (дата, бюджет, адрес — что настроите) в переменные с именами, которые задаёт автор сценария. |
{{business_outcome}} | Бизнес-итог: «Тег результата», указанный в финальном блоке ветки («Согласие», «Отказ», «Перезвон»…). |
{{system_disposition}}, {{system_details}} | Технический исход набора/разговора (см. статусы). |
{{last_webhook_status}}, {{last_webhook_response}} | HTTP-статус и тело (до 2000 символов) последнего ответа вашего сервера на Webhook-блок — можно ветвиться по ним дальше в сценарии. |
Блок «Webhook» ставится в любую точку сценария и
делает HTTP-запрос на ваш URL. Вы полностью управляете методом,
заголовками и телом; шаблоны {{…}} подставляются и в URL,
и в тело, и в заголовки:
POST https://ваш-сервис.ru/lead-result
Content-Type: application/json
{
"call_id": "{{call_id}}",
"phone": "{{phone}}",
"name": "{{name}}",
"deal_id": "{{deal_id}}",
"order": "{{order}}",
"result": "{{business_outcome}}",
"tech": "{{system_disposition}}"
}
| Параметр блока | Контракт |
|---|---|
| Метод | Любой HTTP-метод, по умолчанию POST. |
| Заголовки | Свои (например Authorization); по умолчанию Content-Type: application/json. |
| Тело | JSON-шаблон. После подстановки переменных должен оставаться валидным JSON — строковые значения берите в кавычки. |
| Таймаут | 1–60 секунд, по умолчанию 10. |
| Асинхронный режим (по умолчанию) | Fire-and-forget: разговор не ждёт ваш сервер, у блока один выход. Результат запроса виден в отчёте звонка. |
| Синхронный режим | Робот ждёт ответ и ветвится: «Успех» (HTTP < 400) / «Ошибка» (сеть или ≥ 400). Статус и тело ответа доступны дальше как {{last_webhook_status}} / {{last_webhook_response}}. |
| Идемпотентность | Если движок повторно проходит тот же блок с тем же телом (восстановление после сбоя) — запрос НЕ уходит второй раз. |
| Ретраи | С нашей стороны ретраев нет: запрос уходит один раз. Нужна гарантия доставки — используйте синхронный режим и обработайте ветку «Ошибка» (например, блоком с резервным URL). |
var_*-идентификатору.
Статус звонка (виден в кабинете и отчётах): queued →
dialing → active → финальный
(completed, caller_hangup,
no_answer, failed). Технический исход
дозвона/разговора приходит в {{system_disposition}};
основные значения:
| Значение | Что случилось |
|---|---|
answered | Абонент взял трубку, разговор состоялся. |
no_answer | Не дозвонились (не взял, отклонил, оператор не соединил). |
busy | Занято. |
unavailable | Недоступен / вне сети. |
caller_hangup | Абонент положил трубку до конца сценария. |
silence | Тишина в линии (часто автоответчик оператора). |
outside_call_window | Запуск вне окна обзвона — звонок перенесён. |
error | Непредвиденная ошибка исполнения (маршрутизируется в сценарии системным интентом «Ошибка»). |
Автоответчики и IVR-меню распознаются платформой и маршрутизируются внутри сценария системными интентами («Робот», «IVR») — автор сценария решает, что с ними делать (положить трубку, перезвонить позже и т.д.).
Отдельно от универсального API есть штатные двусторонние интеграции с этими CRM (смена стадии запускает звонок, итог разговора двигает сделку): робот для Битрикс24 и бот для AmoCRM. Для интеграции собственной платформы они не нужны — достаточно разделов 2 и 4.
Звонки могут идти как через нашу телефонию, так и через ваш SIP-транк: вы передаёте реквизиты транка, мы подключаем его линией к вашему аккаунту — набор выполняет наша платформа, но с ваших номеров, через вашего оператора и по вашим тарифам на связь. Ограничение одновременных звонков и темп набора настраиваются на линию.
| Что | Значение |
|---|---|
| Аутентификация | Секретный токен сценария в URL (bearer-семантика). Токен — как пароль: не публикуйте в клиентском коде, логах и трекерах. В наших логах он маскируется. |
| Ротация токена | Кнопка «↻ Перегенерировать токен» в настройках сценария (рядом с Webhook URL). Старый URL перестаёт работать немедленно — обновите его во всех внешних системах. |
| Транспорт | Только HTTPS. |
| Rate limit | 600 запросов/мин с одного IP — массовый перенос сотен сделок проходит спокойно; лимит режет только петли автоматизаций и перебор токенов. |
| Персональные данные | Записи, расшифровки и номера не покидают платформу — доступ только через кабинет (152-ФЗ). |
| Идемпотентность запуска | Каждый accepted = один звонок в очереди. Ретраи по 503/429 безопасны; случайные дубли по той же сделке отсекает дедупликация. |
# GET — минимум
curl "https://app.botleadgen.ru/api/scenarios/ВАШ_ТОКЕН/start-call?phone=79001234567&name=Иван"
# POST JSON — имя + сквозные данные var_*
curl -X POST "https://app.botleadgen.ru/api/scenarios/ВАШ_ТОКЕН/start-call" \
-H "Content-Type: application/json" \
-d '{
"phone": "79001234567",
"name": "Иван Петров",
"var_client_id": "acme-42",
"var_order": "A-1177"
}'
import requests
r = requests.post(
"https://app.botleadgen.ru/api/scenarios/ВАШ_ТОКЕН/start-call",
json={"phone": "79001234567", "name": "Иван Петров", "var_order": "A-1177"},
timeout=10,
)
data = r.json()
if r.ok and data.get("status") == "accepted":
save_call_id(data["call_id"]) # свяжете с результатом из вебхука
elif data.get("status") == "duplicate_ignored":
pass # звонок уже был — это не ошибка
else:
log.warning("botleadgen: %s %s", r.status_code, data)
$ch = curl_init("https://app.botleadgen.ru/api/scenarios/ВАШ_ТОКЕН/start-call");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ["Content-Type: application/json"],
CURLOPT_POSTFIELDS => json_encode([
"phone" => "79001234567",
"name" => "Иван Петров",
"var_order" => "A-1177",
]),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
]);
$response = json_decode(curl_exec($ch), true);
// $response["status"] === "accepted" → сохранить $response["call_id"]
Разделы 1–9 — простой путь «запустил звонок токеном → получил результат Webhook-блоком». Если вы строите свою платформу поверх нашего ядра (свой кабинет и отчётность), есть server-to-server Partner API с ключами аккаунта, финальным колбэком и записями по API. Ниже — что уже работает.
Ключ создаётся в кабинете (раздел «🔌 Интеграции CRM» → «🔑 API-ключи»).
Полный ключ и webhook-secret показываются один раз. Скоупы:
calls:write, calls:read,
scenarios:write, audio:write.
Authorization: Bearer blg_k1_XXXXXXXXXXXXXXXXXXXXXXXXXXXX
{scenario_ref} — идентификатор сценария: подойдёт токен
сценария из кабинета (то же, что в разделах 1–2), внутренний ID
сценария или ваш внешний ID (если сценарий загружен через ingest).
curl -X POST "https://app.botleadgen.ru/api/partner/v1/scenarios/{scenario_ref}/calls" \
-H "Authorization: Bearer ВАШ_КЛЮЧ" -H "Content-Type: application/json" \
-d '{"phone":"79001234567","name":"Иван","var_client_id":"acme-42"}'
# → 202 {"call_id":"…","status":"accepted","phone":"…"}
call.completed
Задайте callback_url у ключа — после каждого звонка на него
прилетит POST с полным отчётом: тег-итог, все переменные (включая ваши
var_*), расшифровка диалога целиком,
длительность, стоимость, флаг наличия записи. Подпись —
X-BLG-Signature: sha256=… (HMAC телом на webhook-secret).
Не доставили (не-2xx / таймаут) — ретраим с бэкоффом 1м→5м→30м→2ч→6ч,
6 попыток; и всегда можно забрать pull-запросом.
{
"event": "call.completed",
"call_id": "…", "partner_scenario_id": "acme-scn-1",
"phone": "79001234567", "duration_sec": 148,
"status": "completed", "system_disposition": "answered",
"business_outcome": "Согласие",
"variables": {"client_id": "acme-42", "budget": "150000"},
"transcript": [{"role":"bot","text":"Здравствуйте!"},{"role":"client","text":"да"}],
"cost": {"total_rub": 4.35, "duration_billed_sec": 148},
"recording_available": true
}
| Метод и путь | Ответ |
|---|---|
GET /api/partner/v1/calls/{call_id} | Тот же payload, что call.completed (+ status для незавершённых). |
GET /api/partner/v1/calls/{call_id}/recording | {"recording_url":"…","expires_in_sec":259200} — подписанная ссылка на wav, TTL 72ч; файл остаётся в нашем контуре (152-ФЗ). |