Год назад я выложил здесь службу, через которую 1С отправляет сообщения в WhatsApp. Её ставили — и почти сразу становилось видно, чего в ней не хватает. Не функций: не хватало места, где живёт логика ответа. Всё, что сложнее «отправить текст», приходилось писать в конфигурации заказчика — и каждый раз заново.
Версия 2 переписана целиком. Ниже — не список возможностей, а один вечер одной переписки: что происходит с сообщением клиента от «пришло» до «ответ ушёл», и чем это собрано.
23:40, суббота
Клиент пишет в WhatsApp: «Добрый вечер, пришлите счёт по заказу 1234». Менеджер спит. Через восемь секунд клиент получает PDF со счётом.
Между этими двумя событиями — сценарий из пяти узлов, собранный мышью на холсте:

- Входящее сообщение — триггер. Сработал, потому что пришло сообщение на подключённый номер.
- Есть ли номер заказа — условие. В тексте нашлись четыре цифры подряд; если бы не нашлись, ветвь «Ложь» ответила бы дежурной фразой и позвала менеджера утром.
- Запрос в 1С — узел ходит в HTTP-сервис вашей базы: «заказ 1234, телефон такой-то — твой?». База отвечает суммой и ссылкой на печатную форму.
- Отправить файл — платформа скачивает PDF по ссылке сама и отправляет вложением. Через 1С файл не гоняется вовсе.
- Отправить текст — короткая подпись к счёту.
Ничего из этого не лежит в конфигурации заказчика. Обновится типовая — сценарий не заметит.
Что видно на следующее утро
Менеджер открывает журнал и видит не «сообщение обработано», а каждый шаг: что пришло на вход, что узел отдал, сколько это заняло.

Если бы 1С в этот момент лежала, прогон остановился бы на третьем шаге с текстом отказа. И его можно было бы повторить с этого самого шага — с сохранённого входа, а не с начала: клиенту не придёт второй счёт, потому что первые два шага заново не пойдут.
Рядом — вкладка прошлых прогонов с отбором по состоянию: посмотреть, что сценарий делал ночью, можно не запуская ничего.

Из чего собирают сценарии
Слева палитра узлов, посередине холст, справа настройки выбранного узла и данные, с которыми он работал. Внизу — замечания: пока они есть, сценарий не публикуется.

Триггеры: входящее сообщение, расписание (cron), вебхук от чужой системы, запуск вручную, обработчик падения другого сценария.
Шаги: отправка текста и файла, условие, развилка на несколько путей, слияние, перебор списка, ожидание (времени или входящего вызова), вызов другого сценария, HTTP-запрос, запрос в 1С, обращение к языковой модели, работа с данными — отбор, сортировка, дубликаты, JSON, CSV, XML, хэши — и код в песочнице, если без него никак.
Опубликованная версия сценария неизменяема. Правки идут в черновик, публикация создаёт следующую версию, и каждый прогон знает, по какой версии он шёл.
Проверить, не дожидаясь клиента
Триггер знает, как выглядят его данные, и подставляет образец: выражения в узлах пишутся сразу, а не после первого настоящего сообщения. Портал при этом честно помечает, что данные — образец, а не результат прогона.

Голосовое в 23:40
Тот же вечер, другой клиент: вместо текста — голосовое на девять секунд. Раньше такое сообщение доходило до платформы пустым: текста нет, вложения нет, в переписке — молчание.
Теперь приходит всё, что присылают: голосовое, фото, видео, документ, стикер. Голосовое слушается прямо в переписке портала, документ сохраняется в один щелчок.

Для интеграции важнее другое: у вложения есть адрес, и по нему приходят байты.
GET /api/v2/media/<идентификатор>
X-API-Key: <ключ>
Это и есть то, чего не хватало для голосовых: платформа отдаёт файл, а распознаёт речь сама 1С. Начиная с 8.3.23 у глобального контекста есть свойство РаботаСРечью — проверено на 8.3.23.2236, оно возвращает объект типа МенеджерРаботыСРечью. Его методами речь переводится в текст: и произносимая в микрофон, и записанная в звуковой файл — второе как раз наш случай.
Считать можно двумя способами, и у каждого своя цена:
- Облаком — сервисом «1С:Распознавание речи». Нужны действующая подписка на портале ИТС, подключённая интернет-поддержка и положительный баланс пакета. Оборудование заказчика при этом не нагружается, но запись уходит наружу.
- Локально — на скачанной модели распознавания (модель тянется через учётную запись ИТС). Не тарифицируется вовсе, и звук не покидает контур. Просит железа: для x64 — Core i5 или Ryzen 5 и от 12 ГБ памяти; на x32 качество ниже.
Предупрежу честно: сама 1С подаёт механизм как работающий в тестовом режиме и только на 8.3.23. Планировать на нём критичный участок я бы пока не стал — а расшифровать голосовое, чтобы менеджер утром прочитал его глазами, он уже позволяет.
Точные имена методов смотрите в синтакс-помощнике своей платформы. Здесь я их не привожу намеренно: в открытых источниках их нет, а переписанные по мотивам анонса дают «метод не обнаружен» — это первое, что проверит читатель.
Что видит человек, а не программист
Отдельная работа, которой в первой версии не было: карточка номера объясняет своё состояние словами. Не «status: logged_out», а что случилось, что делает система и что делать человеку.

Подключение номера — код на экране с обратным отсчётом: код живёт минуту, и портал сам предложит новый, когда старый истечёт.

Первый запуск
Раньше установка начиналась с команд в консоли: завести администратора, выпустить ключ, положить в переменные окружения. Теперь портал спрашивает сам — организация, администратор, пароль — и выдаёт ключ API для интеграции.

Ключ показывается один раз, поэтому рядом с ним стоит кнопка копирования.

Установка
Образ опубликован на Docker Hub: 0101001001001011/rkwa.
docker pull 0101001001001011/rkwa:latest
docker-compose.yml:
services:
postgres:
image: postgres:17-alpine
environment:
POSTGRES_DB: rkwa
POSTGRES_USER: rkwa
POSTGRES_PASSWORD: смените-меня
volumes:
- ./pgdata:/var/lib/postgresql/data
restart: unless-stopped
api:
image: 0101001001001011/rkwa:latest
depends_on: [postgres]
ports:
- '3000:3000'
environment:
RK_DATABASE_URL: postgres://rkwa:смените-меня@postgres:5432/rkwa
# Ровно 32 байта в base64. Потеря ключа = потеря всех сессий WhatsApp.
RK_MASTER_KEY_ENV: RK_MASTER_KEY
RK_MASTER_KEY: сгенерируйте-свой
RK_JWT_SECRET_ENV: RK_JWT_SECRET
RK_JWT_SECRET: сгенерируйте-свой
# Адрес, по которому установка видна снаружи: нужен сценариям,
# которые ждут входящего вызова.
RK_PUBLIC_URL: https://ваш-домен
volumes:
- ./media:/app/media
restart: unless-stopped
docker compose up -d
Ключи генерируются так:
openssl rand -base64 32
Дальше http://localhost:3000/app — и портал проведёт настройку.
Для небольшой установки PostgreSQL не обязателен: RK_DATABASE_URL=file:./data/rkwa.sqlite — и служба работает на SQLite. Поведение одинаковое: оба диалекта проверяются одними и теми же тестами.
Сторона 1С
К статье приложена внешняя обработка. Конфигурацию она не трогает: открывается через Файл → Открыть и работает в любой конфигурации на 8.3. Исходники — в открытом репозитории rk-wa-1c-external-processor.
Адрес платформы и ключ API вводятся один раз и хранятся в общем хранилище настроек базы. Ключ вводится в режиме пароля и после сохранения на экране не показывается.

Номер подключается не выходя из 1С: «Добавить номер» → «Запустить» → «Показать код для входа» → отсканировать в WhatsApp.

Отправка, чтение переписки и контактов — оттуда же.

Минимальная отправка
Ключ предъявляется заголовком X-API-Key:
Функция ОтправитьСообщение(Инстанс, Получатель, Текст, КлючИдемпотентности)
Запрос = Новый HTTPЗапрос("/api/v2/instances/" + Инстанс + "/messages");
Запрос.Заголовки.Вставить("X-API-Key", КлючAPI);
Запрос.Заголовки.Вставить("Content-Type", "application/json");
Тело = Новый Структура;
Тело.Вставить("to", Получатель);
Тело.Вставить("text", Текст);
// Тот же ключ означает то же сообщение. Повтор запроса по таймауту
// не отправит человеку второе — это не украшение, а единственное,
// что отличает надёжную отправку от «кажется, дошло».
Тело.Вставить("idempotencyKey", КлючИдемпотентности);
Запись = Новый ЗаписьJSON;
Запись.УстановитьСтроку();
ЗаписатьJSON(Запись, Тело);
Запрос.УстановитьТелоИзСтроки(Запись.Закрыть(), КодировкаТекста.UTF8);
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Если Ответ.КодСостояния >= 400 Тогда
ВызватьИсключение "Платформа ответила " + Ответ.КодСостояния;
КонецЕсли;
Возврат ПрочитатьJSON(Ответ.ПолучитьТелоКакСтроку());
КонецФункции
Про idempotencyKey стоит сказать отдельно. Запрос отвалился по таймауту — отправлено сообщение или нет? Без ключа ответа нет, и повтор рискует прислать человеку второе. С ключом повтор безопасен: тот же ключ означает то же сообщение. Проверяется это не рассуждением, а счётом: три вызова отправки с двумя разными ключами дают в переписке ровно два сообщения.
Файл по ссылке
Счёт, накладную, акт не нужно кодировать в base64 и гнать через 1С. Достаточно дать ссылку — платформа скачает файл сама:
Тело = Новый Структура;
Тело.Вставить("to", "79990000001");
Тело.Вставить("url", "https://1c.ваш-домен/hs/печать/счёт/1234");
Тело.Вставить("fileName", "Счёт 00-1234.pdf");
Тело.Вставить("as", "document");
Тело.Вставить("caption", "Счёт по заказу 00-1234");
Тело.Вставить("idempotencyKey", "счёт-1234");
Имя файла — то, что увидит получатель, а не то, как файл называется на диске. as решает, показать картинку прямо в переписке (image) или отдать вложением (document).
Обратная сторона: 1С отвечает сценарию
Узел «Запрос в 1С» ходит в HTTP-сервисы и OData вашей базы — это тот самый третий шаг из вечернего сценария. Учётные данные лежат в платформе шифрованными и в сценарий не попадают: узел получает готовый запрос, пароля он не видит.

Что изменилось против первой версии
| Первая версия | Эта | |
|---|---|---|
| Логика ответов | код в конфигурации | конструктор сценариев |
| Что видно о номере | статус в ответе API | состояние словами и следующий шаг |
| Входящие вложения | — | голосовые, фото, видео, документы, стикеры |
| Хранилище | MongoDB или SQLite | PostgreSQL или SQLite |
| Первый запуск | команды в консоли | настройка в браузере |
| Медиа | загрузка файлом | файл по ссылке |
| Интеграции | вебхуки | вебхуки, 1С, языковые модели, OAuth2 |
| Секреты | в настройках | шифрование конвертом, разграничение прав |
Темп отправки
Мелочь, которая стоит дороже всего остального: между сообщениями с одного номера выдерживается пауза — по умолчанию от полутора до трёх секунд, со случайным разбросом. Рассылка, выпущенная без пауз, кончается блокировкой номера, а номер — это не переменная в конфиге, его восстанавливают неделями.
Тёмное оформление
Портал открывают на весь день, поэтому оформление переключается: как в системе, светлое, тёмное.

Чего пока нет
Честный список — чтобы не выяснять это после установки:
- Голосовые принимаются, но не отправляются. Прислать голосовое клиенту платформа не умеет: WhatsApp принимает их только в ogg/opus, а перекодировать на своей стороне мы пока не беремся.
- Списков рассылки WhatsApp нет. Рассылка идёт обходом получателей по одному, с выдержанным темпом. Библиотека, на которой работает канал, в списки рассылки не отправляет — ни в текущей версии, ни в следующей. Штатный механизм появится, когда появится способ им пользоваться.
- Видеокружков нет.
- Векторного поиска по переписке нет — модель отвечает по тому, что дали ей в сценарии.
- OAuth2 работает по паре «клиент и секрет»; вход с переходом к провайдеру и возвратом ещё не сделан.
- Заголовки групповых чатов пока не показываются — только участники и сообщения.
Про надёжность
Несколько вещей, о которых обычно не пишут, но которые решают, будет ли это работать без присмотра:
- Каждый номер живёт в своём потоке. Падение одного не задевает остальные.
- Прогон, оборванный падением процесса, продолжается с последнего зафиксированного шага, а не начинается заново.
- Ожидание переживает перезапуск: сценарий, ждущий до завтра, дождётся, даже если служба за ночь перезапускалась.
- Прогон исполняет ровно один узел установки — в конфигурации из нескольких узлов сообщения не задваиваются.
- Сценарий не публикуется, если в нём есть выражение, которое не сможет выполниться: портал не одобряет то, что молча не сработает в работе.
- Присланные файлы удаляются вместе с перепиской по сроку хранения — не только записи в базе, но и сами файлы.
- Данные не покидают вашу установку. Платформа ставится у вас, переписка и вложения остаются у вас.
Что приложено к статье
- Внешняя обработка 1С —
RKWhatsApp.epf. Настройка интеграции, подключение номера с кодом для входа, отправка сообщений и файлов, чтение переписки и контактов.
Сама платформа ставится образом из Docker Hub — 0101001001001011/rkwa, там же полное описание и переменные окружения.
Вопросы и замечания — в комментарии. Отвечаю.
Проверено на следующих конфигурациях и релизах:
- Розница, редакция 3.0, релизы 3.0.10.178
Вступайте в нашу телеграмм-группу Инфостарт