BotCRMСправочный центр
Документация BotCRM

Всё для работы и интеграции

Инструкции для оператора и руководителя, а рядом — технический контракт разработчика. Здесь объясняется куда нажать, зачем это нужно, что произойдёт и как проверить результат.

Выберите маршрут
Начало работы

Первый вход и первый результат

Чистая установка не содержит придуманных клиентов. Данные появляются после подключения бота, импорта или ручного создания карточки.
1

Войдите под владельцем

Используйте email и пароль установки. В production пароль показывается один раз командой prod:init.

2

Подключите канал

«Боты и каналы» → «Подключить бота» → режим, endpoint и секреты официального API.

3

Напишите боту

Входящее автоматически создаёт контакт, идентификатор канала, диалог и сообщение.

4

Обработайте обращение

Откройте диалог, заберите его у бота, ответьте, создайте заметку, задачу или сделку.

Почему после установки всё пусто
Это ожидаемо. Демо-данные добавляются только командой npm run demo:seed; production её не выполняет.
Общие элементы

Навигация, поиск и realtime

Адрес хранится в hash (`#inbox`, `#contacts`, `#pipeline`), поэтому обновление браузера возвращает на ту же страницу.

Глобальный поиск

Ищет контакты, сообщения и сделки минимум по двум символам.

Realtime

Сообщения, счётчики и CRM-изменения приходят без перезагрузки.

Тема

Светлая/тёмная тема сохраняется в браузере.

Обновление

При проблеме проверьте конкретный раздел или connector.

Доступ по роли

Недоступные действия отключаются, а API повторно проверяет права.

Workspace

Данные изолированы через workspace_id.

Рабочее место оператора

Диалоги: как не потерять обращение

Трёхколоночный inbox объединяет очередь, переписку и карточку клиента.
Раздел Диалоги BotCRM
Слева — очередь, по центру — история и ответ, справа — клиент, сделка, переменные и задачи.

Список диалогов

Все

Полная текущая выборка.

Нужен оператор

Только режим HUMAN — бот остановлен.

Непрочитанные

Разговоры с новыми входящими.

Фильтры

Канал, бот и состояние видны вместе со списком.

Сортировка

Новые, непрочитанные или имя.

Закрыть диалог

Снимает выбор, не читая следующий случайно.

Непрочитанные

Диалог читается, когда он открыт. Новые сообщения в уже открытом разговоре сразу считаются прочитанными. Без выбранного диалога счётчик сохраняется.

BOT, HUMAN и PAUSED

BOT

Отвечает бот. Для ответа человеком нажмите «Перехватить».

HUMAN

Бот не получает входящие; работает оператор.

PAUSED

Автоответ запрещён, но разговор ещё не активен у оператора.

Mirror требует сотрудничества бота
Бот, который пишет напрямую в канал, невозможно остановить извне. Он должен проверять deliverToBot и отправлять через BotCRM.

Ответы и вложения

Enter отправляет, Shift+Enter переносит строку
Скрепка загружает файл через S3/MinIO
Есть emoji, аудио и быстрые ответы
Видны queued, sent, delivered, read и failed
Кнопка «К новым сообщениям» не сбивает чтение истории
CRM-карточка

Контакты: единый человек вместо набора ID

У одного контакта могут быть несколько каналов, разговоров и сделок.

Профиль

Имя, телефон, email, город, аватар и channel identities.

Теги и переменные

Командные метки и значения от ботов.

Заметки и задачи

Внутренний контекст не отправляется клиенту.

Объединение

Склеивайте только подтверждённые дубли, не людей с похожим именем.

Создание и редактирование

«+ Контакт» создаёт ручную карточку с контактами, тегами и JSON-переменными. Обычно карточка появляется автоматически после первого события.

Импорт и экспорт

CSV/JSON переносит существующую базу. Экспорт доступен руководителю, администратору и владельцу. Используйте UTF‑8 и проверьте уникальность телефонов/email.

Удаление означает обезличивание
OWNER/ADMIN очищает персональные поля и identities, отзывает маркетинговый статус и добавляет suppression, чтобы контакт не попал в рассылку.
Данные ботов

Переменные и динамические сегменты

Названия не зашиты в BotCRM. Бот может прислать lead_score, plan, risk_level или свой корректный ключ.
Технический ключ

lead_score

Используется в API и не меняется после создания.

Понятное название

Оценка интереса

Показывается в интерфейсе и может меняться.

Типы полей

Строка — тариф или источник
Число — балл, количество, сумма
Флаг — да/нет
Дата — оплата или окончание подписки
Enum / multiselect — варианты
Ссылка и JSON — технические данные

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

Динамические аудитории

1

Откройте «Контакты → Сегменты»

Например, создайте «Горячие лиды из Telegram».

2

Добавьте условия

Канал = Telegram И Оценка интереса ≥ 80.

3

Проверьте аудиторию

Система покажет всего, доступных и исключённых.

4

Используйте в рассылке

Сегмент живой, а список фиксируется при запуске кампании.

Продажи

Воронки и сделки

Воронка показывает сделки, а не диалоги. Контакт может быть в inbox без карточки на доске, пока сделка не создана.
Канбан BotCRM
Колонки — настраиваемые этапы; карточка показывает клиента, сумму и время на стадии.

Как создать этапы

1

Откройте настройки воронки

Нажмите настройку рядом с выбором текущей воронки.

2

Создайте воронку

Например: «Продажи», «Поддержка», «Онбординг».

3

Добавьте стадии

Укажите название, цвет и при необходимости финал WON/LOST.

4

Расставьте порядок

Он определяет колонки и расчёт конверсии.

Работа со сделкой

Создайте сделку из доски или контакта, задайте название и сумму. Перетаскивание использует optimistic locking: конфликт не перезапишет чужое более свежее изменение.

Профиль и доска читают одну сделку
После перемещения realtime обновляет inbox и канбан. При нескольких сделках профиль показывает текущую связанную с диалогом.
Коммуникации

Рассылки: от аудитории до результата

Кампания запускается после предпросмотра. Недоступные, отписавшиеся и suppression-контакты исключаются.
1

Название и канал

Контент и ограничения зависят от транспорта.

2

Сегмент

Проверьте доступных и причины исключений.

3

Сообщение

Вставляйте {{first_name}} через подсказку; токен выделяется и объясняется.

4

Медиа и кнопки

Изображения и ряды callback/URL-кнопок проверяются по capabilities.

5

Тест

Отправьте реальному контакту того же канала и проверьте подстановки.

6

Запуск

Сейчас или по времени выбранной зоны с показом текущего времени.

Состояния

ЧерновикЗапланированаВыполняетсяЗавершена

Выполнение можно поставить на паузу и продолжить. Отмена прекращает ожидающие отправки. Временные ошибки повторяются, постоянные попадают в failed/suppression.

Telegram и WhatsApp различаются
Telegram ограничивает скорость, поэтому очередь растягивает отправку. WhatsApp вне сервисного окна требует одобренный template.
CRM-правила

Автоматизации: событие → условие → действие

Это не сценарий бота. Правило реагирует на событие CRM: сообщение, изменение контакта или сделки, кампанию или неактивность.
СобытиеПришло сообщение
УсловияОценка ≥ 80
ДействияТег + стадия + задача

Пример

Выберите «Контакт обновлён», поле «Оценка интереса», оператор «≥», значение 80. Затем тег «Горячий», стадию «Квалификация» и задачу на 15 минут.

JSON API
{
  "name": "Горячий лид → квалификация",
  "enabled": true,
  "triggerType": "contact.updated",
  "conditionTree": {
    "match": "all",
    "conditions": [
      { "field": "attributes.lead_score", "operator": "gte", "value": 80 }
    ]
  },
  "actions": [
    { "type": "add_tag", "tag": "Горячий" },
    { "type": "move_deal", "stage": "qualification" },
    { "type": "create_task", "title": "Связаться в течение 15 минут", "dueMinutes": 15 }
  ],
  "maxDepth": 5
}
Правило включается и выключается
Есть тест на выбранном контакте
Журнал показывает matched/skipped/completed/failed
maxDepth и event ID защищают от циклов
Webhook разрешён только доменам allowlist
Отправка ботом блокируется в HUMAN
Оператор уже забрал разговор. Верните его в BOT либо осознанно отправляйте как оператор.
Администрирование

Боты и каналы

Бот — логический обработчик, connector — конкретный канал и credentials.
Подключено

Последняя проверка успешна.

Требует внимания

Таймаут, токен или неполная конфигурация.

Ожидает

Сохранён, но ещё не проверен.

1

Создайте бота у провайдера

Например, Telegram через BotFather.

2

Выберите Gateway или Mirror

Gateway отдаёт webhook BotCRM; Mirror оставляет transport у бота.

3

Укажите endpoint кода

Туда приходят события и control.returned.

4

Заполните секреты

После сохранения их можно только заменить.

5

Скопируйте webhook URL

В Gateway зарегистрируйте его у провайдера.

6

Нажмите «Проверить»

Health-check покажет конкретную ошибку.

Только официальные API
Не используются WhatsApp Web-эмуляция, пользовательские аккаунты VK или обход Avito. Для Avito нужен официальный Messenger API.
Управление

Аналитика: что означают показатели

Данные считаются из реальных диалогов и сделок. Период 7/30/90 дней влияет на сводку и каналы.
Аналитика BotCRM
Наведение показывает точное значение столбца или этапа.
Новые диалогиСозданные за период.
КонверсияДоля выигранных сделок.
Первый ответОт входящего до исходящего.
ВыручкаСумма сделок WON.
КаналыТолько каналы с диалогами.
ВоронкаСделки и суммы по этапам.
Пустой график — честный результат
Без сделок воронка показывает нули. Создайте и переместите сделку — realtime обновит данные.
Безопасность команды

Настройки, роли и учётные записи

В self-hosted версии приглашение не отправляется email. OWNER/ADMIN создаёт пользователя и безопасно передаёт временный пароль.

Участники

Имя, email, роль и состояние доступа.

Команды

Группы сотрудников отдельно от ролей.

Service tokens

Показываются полностью один раз, затем только отзываются.

MFA и сессии

TOTP и отзыв отдельных активных сессий.

1

Настройки → Участники

Доступно OWNER/ADMIN.

2

Имя, email, временный пароль

Не менее 12 символов; не отправляйте в общем чате.

3

Минимальная роль

Оператору не нужны настройки ботов или запуск кампаний.

4

Передача и MFA

Пользователь входит и подтверждает TOTP шестизначным кодом.

Примеры

Три рабочих сценария

Замените стадии, поля и сроки на свои процессы.
01 · Поддержка

Нужен человек

  1. Бот ставит needs_human=true.
  2. Правило меняет режим на HUMAN.
  3. Диалог попадает в «Нужен оператор».
  4. Оператор отвечает и возвращает управление.
Запрос не теряется в ленте.
02 · Продажа

Горячий лид

  1. lead_score=95.
  2. Добавляется тег «Горячий».
  3. Сделка идёт в «Квалификация».
  4. Задача менеджеру на 15 минут.
Скорость не зависит от ручного просмотра.
03 · Возврат

30 дней без активности

  1. Сегмент выбирает доступных.
  2. Кампания подставляет имя.
  3. Кнопка ведёт на предложение.
  4. Ответ открывает диалог.
Видны доставка и ответы.
Техническая документация

BotCRM между каналом и вашим кодом

Платформа не заменяет бизнес-логику: нормализует transport, хранит историю, управляет перехватом и ставит отправки в очередь.
Новый проект

Gateway

Webhook канала указывает на BotCRM. Платформа проверяет, сохраняет и вызывает endpoint бота только в BOT.

  • полный контроль;
  • единая доставка;
  • рекомендуется.
Работающий проект

Mirror / SDK

Бот принимает update сам, копирует входящие в /events и отвечает через /messages/send.

  • минимум изменений;
  • постепенная миграция;
  • нужен deliverToBot.
ПользовательКаналBotCRM / transportВаш обработчикQueueОтвет
Практика

Первый Telegram-бот с BotCRM

Он отвечает на /price, создаёт CRM-данные и прекращает отвечать после перехвата. Выберите язык.
1

Создайте бота в BotFather

Получите TELEGRAM_BOT_TOKEN. Для этого примера не ставьте webhook — используется polling.

2

Создайте Mirror-коннектор

Telegram → Mirror / SDK, имя, slug и token.

3

Создайте service token

Настройки → Сервисные токены. Скопируйте сразу.

4

Настройте окружение

.env
TELEGRAM_BOT_TOKEN=123456:telegram-secret
BOTCRM_URL=https://crm.example.ru
BOTCRM_WORKSPACE_ID=ws_demo
BOTCRM_BOT_ID=sales_assistant
BOTCRM_SERVICE_TOKEN=botcrm-service-secret
5

Проверьте перехват

Отправьте /price, заберите диалог и отправьте ещё сообщение: бот не должен ответить.

Установка
npm install @botcrm/sdk
# Для Telegram long polling нужен Node.js 22+ (fetch уже встроен)
TypeScript
import { BotCrmClient } from "@botcrm/sdk";

const telegramToken = required("TELEGRAM_BOT_TOKEN");
const crm = new BotCrmClient({
  baseUrl: required("BOTCRM_URL"),
  workspaceId: required("BOTCRM_WORKSPACE_ID"),
  botId: required("BOTCRM_BOT_ID"),
  serviceToken: required("BOTCRM_SERVICE_TOKEN")
});

async function telegram(method: string, body: unknown) {
  const response = await fetch(
    `https://api.telegram.org/bot${telegramToken}/${method}`,
    { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body) }
  );
  const result = await response.json();
  if (!response.ok || !result.ok) throw new Error(JSON.stringify(result));
  return result.result;
}

let offset = 0;
while (true) {
  const updates = await telegram("getUpdates", { offset, timeout: 25, allowed_updates: ["message"] });
  for (const update of updates) {
    offset = update.update_id + 1;
    const message = update.message;
    if (!message?.text || !message.from) continue;

    const accepted = await crm.incoming({
      eventId: `telegram:${update.update_id}`,
      channel: "telegram",
      chatId: String(message.chat.id),
      userId: String(message.from.id),
      externalMessageId: String(message.message_id),
      text: message.text,
      profile: {
        name: [message.from.first_name, message.from.last_name].filter(Boolean).join(" "),
      },
      attributes: { source: "telegram", last_command: message.text }
    });

    // false означает, что диалог забрал оператор или он поставлен на паузу.
    if (!accepted.deliverToBot || !accepted.conversationId) continue;

    const answer = message.text === "/price"
      ? "Тариф Pro стоит 4 900 ₽ в месяц. Напишите /manager, если нужна консультация."
      : "Привет! Команды: /price и /manager";

    await crm.send({
      conversationId: accepted.conversationId,
      text: answer,
      actor: "bot",
      idempotencyKey: `reply:${update.update_id}`
    });
  }
}

function required(name: string) {
  const value = process.env[name];
  if (!value) throw new Error(`Missing ${name}`);
  return value;
}
Замените тестовые ID данными коннектора. Секреты храните только в окружении.
Повторяйте с тем же ключом
При сетевом retry используйте прежний event_id или Idempotency-Key. Новый ключ создаст новое сообщение.
Каналы

Настройка коннектора

Секреты шифруются и после сохранения не показываются. Endpoint — адрес вашего кода, webhook URL — адрес BotCRM для провайдера канала.
КаналОбязательные поляЧто проверить
TelegrambotToken, webhookSecretТокен от BotFather; HTTPS webhook в Gateway.
VKaccessToken, API 5.199, confirmation secret/codeCallback API сообщества и подтверждение сервера.
WhatsApp CloudaccessToken, phoneNumberId, app secret, verify tokenWebhook Meta, подписка messages, одобренные templates.
AvitoaccessToken, accountId, outbound URL, signing secretОфициальный доступ Messenger API.
Generic RESToutbound URL, signing secretВаш endpoint принимает нормализованные события.

Gateway

Зарегистрируйте показанный BotCRM webhook у провайдера. Endpoint вашего бота получает уже проверенные события.

Mirror / SDK

Ваш бот сохраняет polling/webhook, но копирует события в API и соблюдает deliverToBot.

Локальный адрес недоступен Telegram
localhost работает только на вашем ПК. Для Gateway нужен публичный HTTPS-домен; для локальной проверки используйте Mirror/polling.
REST API

Адреса, авторизация и workspace

В production используйте тот же публичный домен, что и панель. Reverse proxy направляет /api/* в API, поэтому отдельный открытый порт не нужен.
HTTP
POST https://crm.example.ru/api/v1/events
Authorization: Bearer <service-token>
X-Service-Token: <service-token>
X-Workspace-Id: ws_demo
Idempotency-Key: telegram:482991204
Content-Type: application/json
Authorization

Bearer service token. Заголовок X-Service-Token поддерживается для SDK и внутренних интеграций.

X-Workspace-Id

Обязательная граница данных. Токен также привязан к workspace; несовпадение отклоняется.

Idempotency-Key

Стабильный ключ операции. Повтор того же запроса не создаёт вторую отправку.

Cookie session

Только для браузерной панели. Не копируйте пользовательские cookies в бот.

Service token показывается один раз
Создайте его в «Настройки → Сервисные токены», сохраните в secret manager и отзовите при утечке. Не помещайте токен в frontend, git или лог.
Контракт

Входящие события

Mirror-бот отправляет событие в POST /api/v1/events. Gateway создаёт тот же объект автоматически после проверки канального webhook.
JSON
{
  "event_id": "telegram:482991204",
  "schema_version": "1.0",
  "occurred_at": "2026-08-23T10:15:00.000Z",
  "workspace_id": "ws_demo",
  "bot_id": "sales_assistant",
  "channel": "telegram",
  "external_chat_id": "84120931",
  "external_user_id": "84120931",
  "type": "message.received",
  "message": {
    "external_id": "502",
    "text": "Хочу узнать стоимость"
  },
  "profile": {
    "name": "Анна",
    "city": "Москва",
    "avatar_file_id": "telegram-file-id"
  },
  "attributes": {
    "intent": "pricing",
    "lead_score": 70
  }
}

Ответ платформы

JSON
{
  "duplicate": false,
  "contactId": "a60d55b4-...",
  "conversationId": "55c3df22-...",
  "deliverToBot": true
}
event_id

Глобально стабильный ID исходного update. При retry не меняется.

occurred_at

Время у источника в ISO 8601 UTC. Оно определяет порядок сообщений.

external_chat_id

Диалог у канала; не путать с внутренним UUID conversation.

profile

Имя, username, телефон, email, город и avatar. Передавайте только известные данные.

attributes

Произвольные типизированные данные. Новые ключи появляются в реестре переменных.

deliverToBot

false означает HUMAN/PAUSED: сохраните событие, но не запускайте ответ бота.

Поддерживаемые типы
Основные: message.received, message.sent, button.clicked, статусы доставки и control.returned. Неизвестный raw payload сохраняйте только для диагностики и с ограниченным retention.
Исходящие

Сообщения, вложения и статусы

Бот и оператор отправляют через один API, чтобы история, ограничения канала и delivery status не расходились.
HTTP + JSON
POST /api/v1/messages/send
X-Workspace-Id: ws_demo
X-Service-Token: <service-token>
Idempotency-Key: reply:telegram:502
Content-Type: application/json

{
  "conversationId": "55c3df22-...",
  "actor": "bot",
  "text": "Тариф Pro стоит 4 900 ₽ в месяц"
}

Загрузка медиа

HTTP
# 1. Зарезервировать загрузку
POST /api/v1/media/uploads
{
  "filename": "proposal.pdf",
  "mimeType": "application/pdf",
  "size": 184230
}

# 2. Загрузить байты по выданному uploadUrl
PUT <uploadUrl>
Content-Type: application/pdf

<binary body>

# 3. Подтвердить загрузку
POST /api/v1/media/uploads/<uploadId>/complete

# 4. Передать uploadId при отправке
POST /api/v1/messages/send
{
  "conversationId": "...",
  "actor": "bot",
  "text": "Отправляю предложение",
  "attachmentIds": ["<uploadId>"]
}
1

Создать upload

Передайте имя, MIME и размер; получите upload URL/id.

2

Загрузить байты

Отправьте файл по выданному URL, не кодируйте большое изображение в JSON.

3

Подтвердить

POST /media/uploads/:id/complete проверит объект.

4

Отправить attachment id

Добавьте его в message. Worker адаптирует формат канала.

queuedsentdeliveredread

Не каждый канал присылает delivered/read. UI показывает только реально поддерживаемый уровень. failed содержит безопасную причину и признак временной ошибки.

Перехват

BOT, HUMAN и PAUSED без гонок

Состояние меняется атомарно. Передавайте последнюю версию conversation: два оператора не смогут незаметно перезаписать друг друга.
HTTP
GET /api/v1/conversations/{conversationId}/control

PATCH /api/v1/conversations/{conversationId}/control
Content-Type: application/json

{
  "mode": "HUMAN",
  "expectedVersion": 7,
  "reason": "operator_claim"
}
BOT

События доставляются endpoint бота.

HUMAN

Отвечает оператор; бот получает deliverToBot=false.

PAUSED

Автоматические ответы приостановлены.

Возврат управления
После HUMAN → BOT платформа создаёт control.returned. Бот может восстановить контекст, но не должен повторять старый ответ.
Исходящий webhook

Проверка подписи до разбора JSON

BotCRM вызывает endpoint бота подписанным POST. Проверяйте HMAC по исходным байтам body, затем timestamp и только после этого JSON.
TypeScript / Fastify
import { verifyBotCrmWebhook } from "@botcrm/sdk";

app.post("/botcrm-events", express.raw({ type: "application/json" }), (req, res) => {
  const signature = req.header("x-botcrm-signature");
  if (!verifyBotCrmWebhook(req.body, signature, process.env.BOTCRM_WEBHOOK_SECRET!)) {
    return res.status(401).send("invalid signature");
  }

  const event = JSON.parse(req.body.toString("utf8"));
  // Сначала быстро подтвердите приём, тяжёлую работу отправьте в очередь.
  res.status(202).json({ accepted: true, eventId: event.event_id });
});
ЗаголовокНазначение
x-botcrm-event-idСтабильный ID бизнес-события.
x-botcrm-delivery-idID конкретной попытки доставки.
x-botcrm-timestampUnix timestamp; отклоняйте слишком старые запросы.
x-botcrm-signaturesha256=HMAC_SHA256(rawBody, signingSecret).
Сначала ACK, затем тяжёлая работа
Верните 2xx после безопасной постановки события в свою очередь. Долгая обработка приводит к timeout и повторной доставке.
Production-контракт

Повторы, порядок, 429 и ошибки

Сеть не гарантирует ровно одну доставку. Корректная интеграция должна быть безопасна при at-least-once.
СитуацияПоведение интеграции
Повтор входящего webhookТот же event_id; API вернёт duplicate: true.
Повтор отправкиТот же Idempotency-Key; не генерировать его заново при retry.
HTTP 429Ждать Retry-After, не крутить цикл немедленно.
HTTP 5xx / timeoutExponential backoff с jitter и ограничением попыток.
Обычный HTTP 4xxПостоянная ошибка: исправить payload/доступ, не повторять бесконечно.
События пришли не по порядкуСортировать сообщения по occurred_at и стабильному sequence/id.
Endpoint недоступенПосле попыток запись попадает в DLQ и видна в журнале.
У события стабильный внешний ID
У отправки стабильный idempotency key
Секреты ротируются без простоя
Логи не содержат токены и raw персональные данные
Есть timeout и ограничение размера body
Метрики различают temporary/permanent failure
Capabilities

Разные каналы — разные возможности

Перед показом кнопок и форматов проверяйте capabilities коннектора. Платформа блокирует неподдерживаемые действия, но код бота тоже не должен их предполагать.
КаналСильные стороныОграничения, которые важно учесть
Telegram Bot APIТекст, медиа, inline-кнопки, reply, edit/deleteЛимиты на чат и массовую отправку; бот не пишет первым произвольному человеку.
VK CommunityСообщения сообщества, вложения, клавиатураНужны права сообщества, confirmation и актуальная версия API.
WhatsApp CloudТелефонная identity, статусы доставки, templatesВне сервисного окна — только одобренный шаблон; ограничения бизнеса Meta.
Avito MessengerПереписка по объявлениямТолько аккаунты с официально выданным API-доступом.
GenericЛюбой сайт, приложение или собственный transportDelivery/read/edit доступны только если их реализует ваш адаптер.
Один контакт, несколько identity
Telegram ID, VK ID и телефон WhatsApp не объединяются по похожему имени. Автослияние допустимо только по подтверждённому телефону/email или вашему устойчивому external ID.
Справочник

Автоматизации: все поддерживаемые элементы

Названия в UI переведены, а API использует стабильные технические ключи.

Триггеры

message.receivedmessage.sentcontact.updatedconversation.createddeal.createddeal.stage_changedbutton.clickedconversation.inactivecampaign.deliveredcampaign.failed

Операторы условий

equalsnot_equalscontainsnot_containsgtgteltlteexistsnot_existsin

Действия

set_attributeadd_tagmove_dealassign_usercreate_taskset_controlsend_messagewebhooksuppress_contact

Правило принимает до 20 условий и от 1 до 10 действий. maxDepth задаётся от 1 до 10. Внешний webhook разрешается только доменам из AUTOMATION_WEBHOOK_ALLOWLIST и подписывается AUTOMATION_WEBHOOK_SECRET.

Почему нужен allowlist
Без него правило могло бы обращаться к localhost, metadata cloud или внутренним сервисам. Allowlist ограничивает исходящие запросы заранее известными доменами.
Доступ

Матрица ролей

Выдавайте минимальную роль. Точное разрешение endpoint всегда проверяет backend; скрытая кнопка в UI не является защитой.
ВозможностьВладелецАдминРуководительОператор
Диалоги и ответыДаДаДаДа
Контакты, сделки, задачиДаДаДаПо назначению
Сегменты и просмотр аналитикиДаДаДаОграниченно
Запуск рассылки и автоматизацииДаДаДаНет
Каналы, пользователи, команды, service tokenДаДаНетНет
Удаление workspace / передача владенияДаНетНетНет

Сервисный аккаунт не входит в интерфейс и получает только явно предусмотренный API-доступ через отзываемый токен.

REST

Карта API

Ниже — обзор групп. Полные request/response schemas и интерактивные запросы находятся в OpenAPI.
Auth/api/v1/auth/*

login, me, logout, MFA, sessions.

Events/api/v1/events

Нормализованные входящие события.

Messages/api/v1/messages/send

Текст, buttons, media и idempotency.

Contacts/api/v1/contacts/*

upsert, поля, tags, import/export, merge.

Conversations/api/v1/conversations/*

read, control, notes и tasks.

CRM/api/v1/pipelines/*

pipelines, stages, deals.

Audience/api/v1/segments/*

Фильтры, preview и сохранение.

Campaigns/api/v1/campaigns/*

draft, test, schedule, pause, results.

Automations/api/v1/automations/*

rules, test и runs.

Administration/api/v1/admin/*

users, teams, service tokens.

Operations/health

Liveness/readiness и connector health.

OpenAPI/api-docs

Интерактивная схема текущей версии.

Self-hosted

Установка на сервер и собственный домен

Production-compose поднимает web, API, worker, PostgreSQL, Redis, MinIO и Caddy. Снаружи открыты только 80/443; TLS получает Caddy.

Что понадобится

VPS с Linux x86_64, минимум 4 vCPU / 8 GB RAM для комфортного старта
Docker Engine 27+ и Compose plugin
Два DNS-имени: CRM и закрытое S3-хранилище медиа
Открытые TCP 80/443 и UDP 443; PostgreSQL/Redis/MinIO не публикуются
SMTP не обязателен: участников создаёт OWNER/ADMIN
1

Создайте DNS

A/AAAA для crm.example.ru и media.crm.example.ru должны указывать на сервер до первого запуска.

2

Скачайте проект и сгенерируйте конфигурацию

bash
git clone <your-repository-url> botcrm
cd botcrm
npm ci
npm run prod:init -- --domain crm.example.ru --storage-domain media.crm.example.ru --email owner@example.ru --owner-name "Иван" --workspace-name "Моя команда" --timezone Europe/Moscow
3

Заполните .env.production

Домены, email ACME, workspace, timezone и независимые длинные секреты. Не переносите dev-пароль.

4

Проверьте compose

bash
npm run prod:check
npm run prod:config
5

Соберите и запустите

bash
npm run prod:up
npm run prod:ps
npm run prod:logs
6

Проверьте снаружи

Откройте https://crm.example.ru, /docs, /api-docs и /api/v1/health. Затем войдите владельцем и включите MFA.

Критические переменные

BOTCRM_DOMAIN

Публичный домен панели и API.

BOTCRM_STORAGE_DOMAIN

Отдельный HTTPS host для медиа.

BOOTSTRAP_OWNER_*

Первый владелец; пароль минимум 16 случайных символов.

MASTER_ENCRYPTION_KEY

Шифрует credentials каналов. Потеря ключа делает их нечитаемыми.

POSTGRES/REDIS/MINIO

Независимые секреты внутренних сервисов.

TRUST_PROXY=true

Корректный HTTPS, IP и secure cookies за Caddy.

Не публикуйте внутренние порты
Не добавляйте наружу 5432, 6379, 9000 и служебные порты API/worker. Доступ к приложению идёт через Caddy и backend network.
Эксплуатация

Обновления, backup и восстановление

Резервная копия считается рабочей только после тестового восстановления. Перед каждым обновлением сохраните PostgreSQL, S3 и файл production-конфигурации.
Ежедневно

Резервная копия

bash
npm run prod:backup

Скопируйте архив за пределы VPS и зашифруйте его отдельным ключом.

Регулярная проверка

Восстановление

bash
npm run prod:restore -- --from <backup-directory>

Сначала проводите drill на отдельном сервере/volume, не поверх production.

Безопасное обновление

1

Прочитайте release notes

Особенно migrations, новые переменные и изменения channel adapters.

2

Сделайте backup

База, object storage, .env.production и master encryption key.

3

Получите версию и проверьте config

bash
git pull --ff-only
npm run prod:check
npm run prod:config
4

Запустите миграции и сервисы

bash
npm run prod:migrate
npm run prod:up
5

Smoke test

Вход, входящее/исходящее сообщение, realtime, upload, тест кампании и connector health.

Что мониторить

Healthweb, API, PostgreSQL, Redis, MinIO.
Queuesглубина, oldest job, DLQ.
Channelstoken expiry, 401/403/429, latency.
Resourcesdisk, RAM, CPU, inode и object storage.
Securitylogin throttling, audit, MFA, revoked sessions.
Backupsвозраст последнего и результат restore drill.
Минимальная аварийная последовательность
Остановите источник повреждения, сохраните логи и текущее состояние, поднимите чистые volumes, восстановите последнюю проверенную копию, смените скомпрометированные токены и только потом верните DNS/трафик.
Диагностика

Проблемы и точные проверки

Начинайте со статуса коннектора, журнала доставки и health-check. Не меняйте сразу несколько настроек: иначе теряется причина.
Сообщение появилось в Telegram, но не в BotCRM
  1. Проверьте, запущен ли Mirror-процесс или установлен ли Gateway webhook.
  2. Посмотрите connector health и срок токена.
  3. Проверьте, что event_id, chat/user id и workspace заполнены.
  4. Для Gateway убедитесь, что домен доступен по HTTPS извне.
BotCRM принял сообщение, но бот не ответил
  1. Посмотрите deliverToBot: при HUMAN/PAUSED он false.
  2. Проверьте endpoint и его TLS-сертификат.
  3. Убедитесь, что endpoint вернул 2xx до timeout.
  4. Проверьте DLQ и логи worker по event/delivery id.
Бот отвечает одновременно с оператором
  1. Исходящие бота должны идти через /messages/send.
  2. Mirror-код обязан читать deliverToBot до бизнес-логики.
  3. Не отправляйте в Telegram напрямую после того, как событие уже передано BotCRM.
Появились одинаковые сообщения
  1. На retry используйте прежний event_id.
  2. Для отправки сохраняйте прежний Idempotency-Key.
  3. Не запускайте параллельно две копии polling без распределённой блокировки.
Медиа даёт Internal server error
  1. Проверьте MIME, размер и разрешённый формат канала.
  2. Завершите upload через /complete перед отправкой.
  3. Проверьте доступ API и worker к S3/MinIO.
  4. Посмотрите статус attachment — файл мог не загрузиться полностью.
Переменная в рассылке не подставилась
  1. Вставьте токен из подсказки, не набирайте имя по памяти.
  2. Проверьте область поля: contact/bot/deal/conversation.
  3. Откройте preview получателей: там видны пропущенные значения.
  4. Задайте fallback либо исключите контакт фильтром exists.
Webhook автоматизации заблокирован
  1. Добавьте только нужный hostname в AUTOMATION_WEBHOOK_ALLOWLIST.
  2. Используйте публичный HTTPS URL.
  3. Задайте AUTOMATION_WEBHOOK_SECRET и проверяйте подпись у получателя.
  4. Не разрешайте широкие wildcard и внутренние адреса.
После деплоя вход или realtime не работают
  1. Проверьте APP_URL, NEXT_PUBLIC_API_URL, trusted proxy и HTTPS.
  2. Убедитесь, что reverse proxy передаёт cookies и upgrade/streaming.
  3. Проверьте CORS/cookie domain, если UI и API всё же на разных доменах.
  4. Синхронизируйте время сервера — оно нужно сессиям и webhook signatures.
Термины

Короткий словарь BotCRM

Одинаковые слова используются в панели, API и журналах.
Workspace
Изолированное рабочее пространство команды.
Bot
Ваша бизнес-логика и её логический идентификатор.
Connector
Настроенное подключение транспорта с credentials и capabilities.
Contact
Человек, объединяющий подтверждённые identity разных каналов.
Channel identity
Telegram/VK ID, WhatsApp phone или другой внешний идентификатор.
Conversation
Конкретная переписка контакта с ботом/каналом.
Deal
Коммерческий или процессный объект на этапе pipeline.
Attribute
Типизированная переменная контакта, диалога, сделки или связи с ботом.
Segment
Сохранённый динамический фильтр аудитории.
Campaign
Управляемая массовая отправка с очередью и результатами.
Suppression
Запрет отправки контакту/identity по отписке или постоянной ошибке.
Idempotency
Гарантия, что безопасный повтор операции не создаёт дубль.
DLQ
Очередь событий, которые не удалось доставить после повторов.
Capability
Заявленная возможность канала: кнопки, edit, read status и т. п.
Документация соответствует текущей реализации

Начните с одного реального диалога

Подключите тестового бота, отправьте событие, перехватите разговор и верните управление. Это проверит transport, realtime, права и очередь одной короткой цепочкой.