API Reference
WonderChat REST API позволяет управлять диалогами, каналами, контактами и шаблонами программно. Все запросы возвращают JSON.
Аутентификация REST API: либо JWT через Authorization: Bearer <jwt> после POST /auth/login, либо API-ключ из Настроек — в том же заголовке: Authorization: Bearer wc_... (ключ начинается с wc_).
Коды ответов: 200 OK, 201 Created, 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 429 Too Many Requests, 500 Server Error.
API-ключ и JWT не смешивайте в одном запросе: для ключа используйте только Bearer wc_.... WebSocket по-прежнему только с JWT.
Быстрый старт для CRM: iframe-инбокс и отправка по телефону — раздел Iframe и телефон ниже.
Ниже три типовых сценария для CRM и внутренних систем. Для iframe и вызовов /crm-api/* достаточно API-ключа из Настроек панели (рекомендуется). Интеграция comka.ru CRM и заголовок X-CRM-Secret остаются опциональным вариантом — см. CRM API.
1. Iframe со всеми чатами аккаунта
Вызовите POST https://panel.wonderchat.ru/api/v1/crm-api/embed-token с заголовком Authorization: Bearer wc_... (API-ключ из Настроек). В теле можно передать {"tenant_slug":"mytenant"} или пустой объект {} — тогда в ссылке будет tenant=default. Подробности и scope — в CRM API → embed-token.
Вставьте этот URL в <iframe src="...">. Токен в ссылке — короткоживущий JWT (до 24 ч), область видимости — один аккаунт WonderChat. Список диалогов в iframe — как в обычном Inbox.
2. Iframe одного чата (по контакту или диалогу)
Вариант A — по ID диалога. Дополнительно передайте в теле embed-token поле conversation_id (ID диалога в WonderChat). В URL добавится &conversation=<id> — откроется сразу этот чат.
Вариант B — по телефону. Передайте contact_phone — в точности как номер записан у контакта в WonderChat. Сервер найдёт контакт и добавит &contact=<contactId>; в iframe список отфильтруется по этому клиенту. Если контакт не найден, ссылка будет без фильтра (полный список).
Рекомендация: если номер в CRM и в WonderChat могут отличаться форматом, надёжнее получить contactId через GET /api/v1/contacts?search=... (с JWT или Authorization: Bearer wc_...) и передать в CRM свой маппинг, затем использовать conversation_id из GET /api/v1/conversations.
3. Отправка сообщения по номеру телефона (основной диалог)
Из своего бэкенда с JWT или API-ключом панели: POST /api/v1/conversations/send-by-phone — см. ниже. Номер нормализуется; выбирается контакт по индексу телефона и главный активный диалог: среди незакрытых диалогов контакта — самый ранний по времени создания, у которого канал в статусе подключён, иначе первый незакрытый.
Во все каналы сразу: POST /api/v1/conversations/send-by-phone-all-channels — отправляет в каждый подключённый канал, где у контакта есть открытый чат, а для WhatsApp, WABA и MAX (личный номер) при отсутствии чата пытается начать переписку: WA/WA Business — по номеру; MAX personal — по номеру через контакты/чаты в подключённом клиенте (если peer не найден, в results будет skipped). Остальные типы (Telegram, VK, Instagram, MAX бот…) без открытого диалога пропускаются.
Через CRM API (POST /api/v1/crm-api/send-by-phone): тот же смысл, авторизация Authorization: Bearer wc_... или X-CRM-Secret comka; в теле phone, message.text; tenant_slug при ключе необязательно.
Мультиканальная отправка из CRM: POST /api/v1/crm-api/send-by-phone-all-channels (только текст, те же правила каналов).
Для /crm-api/* по умолчанию используйте API-ключ из Настроек: Authorization: Bearer wc_... (см. раздел CRM API). Заголовок X-CRM-Secret — запасной вариант для comka.ru; при нём в credentials может быть задан tenantSlug, тогда tenant_slug в теле должен совпасть.
Тело запроса
| Поле | Тип | Описание |
|---|---|---|
| req | Email адрес | |
| password | req | Пароль (min 8 символов) |
| name | req | Имя пользователя |
Тело запроса
| Поле | Тип | Описание |
|---|---|---|
| req | ||
| password | req | Пароль |
| Поле | Тип | Описание |
|---|---|---|
| refreshToken | req | refresh токен из login |
Отозвание текущей сессии. Используйте /auth/logout-all для выхода со всех устройств.
| Поле | Тип | Описание |
|---|---|---|
| name | opt | Название аккаунта |
| Поле | Тип | Описание |
|---|---|---|
| req | Email нового пользователя | |
| name | req | Имя |
| password | req | Пароль |
| role | opt | admin | operator (деф. operator) |
| Поле | Тип | Описание |
|---|---|---|
| name | req | Название канала |
| type | req | telegram | telegram_bot | whatsapp | waba | vk | instagram | max | max_personal |
| credentials | req | Объект с параметрами канала |
{ "phone": "+79001234567" // необязательно, только для fallback-входа по коду }
| Поле | Тип | Описание |
|---|---|---|
| name | opt | Новое название |
| credentials | opt | Обновить креденшиалы (мержится с существующими) |
| healthCheckInterval | opt | Автопереподключение в минутах: 0..1440 |
ВКонтакте: credentials мержатся с существующими (токен не теряется), а при передаче confirmationCode/secretKey адаптер перезапускается автоматически через Redis.
Отключает канал и удаляет его. Ответ 204 No Content.
Для Telegram запускает auth flow (code/2FA), для остальных каналов публикует команду подключения в Redis. Для WhatsApp отдельный QR запрашивается через POST /channels/:id/qr, для MAX Personal — через POST /channels/:id/max-qr/start.
Только для WhatsApp. Генерирует новый QR-код.
Только для каналов max_personal. Запускает QR-авторизацию и возвращает QR URL.
Проверяет прогресс QR-авторизации: pending, connected, expired, failed.
Query параметры
| Параметр | Тип | Описание |
|---|---|---|
| channelId | opt | Фильтр по каналу |
| status | opt | open | closed |
| unread | opt | true — только непрочитанные |
| search | opt | Текстовый поиск |
| page | opt | Страница (деф. 1) |
| limit | opt | Диалогов на странице (деф. 30) |
| Поле | Тип | Описание |
|---|---|---|
| status | opt | open | closed |
| assignedTo | opt | ID пользователя |
| tags | opt | Массив строк — теги на чат |
Назначает ответственного и опционально отправляет клиенту системное сообщение «К чату подключен сотрудник …». Для чатов YCLIENTS round-robin учитывает филиал (yclientsIntegrationId диалога) и настройки сотрудников «филиалы для распределения».
| Поле | Тип | Описание |
|---|---|---|
| userId | opt | ID пользователя аккаунта. Обязателен, если не используется roundRobin |
| roundRobin | opt | true — взять следующего из очереди (нельзя вместе с userId) |
| announce | opt | По умолчанию true — отправить приветствие в чат клиенту |
Query параметры
| Параметр | Тип | Описание |
|---|---|---|
| before | opt | ID сообщения (пагинация назад) |
| limit | opt | Деф. 50 |
| Поле | Тип | Описание |
|---|---|---|
| type | req | text | image | video | document | audio |
| text | opt | Текст сообщения |
| mediaUrl | opt | URL медиа из /conversations/upload |
| replyToId | opt | ID ответного сообщения |
Ьлёт multipart/form-data с полем file. Юакже принимает JSON с полем url (если файл уже в сети).
Отмечает все сообщения диалога прочитанными, обнуляет unreadCount. Ответ 200.
Находит контакт по телефону и отправляет сообщение в его главный активный диалог.
Если в аккаунте есть дубли контактов с одинаковым номером, выбирается контакт, у которого есть активный диалог.
| Поле | Тип | Описание |
|---|---|---|
| phone | req | Телефон контакта в любом привычном формате |
| type | opt | По умолчанию text |
| text | opt | Текст сообщения |
| media | opt | Объект медиа как в POST /conversations/:id/messages |
Ошибки: 404 если контакт не найден или нет подходящего незакрытого диалога; нужен хотя бы text или media.
По одному контакту (как у send-by-phone) рассылает сообщение во все подключённые каналы аккаунта: везде, где есть открытый диалог с этим контактом, плюс для WhatsApp, WABA и max_personal при отсутствии чата создаётся диалог и отправляется первое сообщение (для MAX — если по номеру удаётся сопоставить чат в клиенте). Остальные типы без открытого чата дают skipped в results.
Тело как у send-by-phone (phone, text или media). Ответ 201: contactId, phone, sent (число успешных), results[] с полями channelId, channelType, status (sent | skipped | error), при успехе — conversationId, messageId.
400, если ни один канал не принял сообщение (в теле — results).
Расписание «онлайн» аккаунта для автоответов вне смены. Хранится на уровне аккаунта; чтение и запись — с JWT или API-ключом.
Возвращает enabled, timezone, days (mon…sun со слотами from/to), offlineMessage. Если записи нет — ответ с дефолтами.
Тело по схеме как в ответе GET: days.mon.enabled, days.mon.slots[] с временем HH:mm, и т.д.
Например {"online":true,"reason":"schedule_disabled"} или online: false, nextOpen, offlineMessage при выключенном дне или вне слотов.
API-ключи создаются в Настройки → API-ключи и могут использоваться вместо JWT для REST API.
Возвращает список активных ключей аккаунта без полного значения ключа.
| Поле | Тип | Описание |
|---|---|---|
| name | req | Понятное имя ключа, например CRM integration |
| scopes | req | Массив разрешений для учета и будущих ограничений |
| expiresAt | opt | Дата истечения в ISO-формате |
Удаляет ключ. После этого авторизация по нему сразу перестает работать.
Query
| Параметр | Тип | Описание |
|---|---|---|
| search | opt | Поиск по имени/телефону |
| tag | opt | Фильтр по тегу |
| page / limit | opt | Пагинация |
| Поле | Тип | Описание |
|---|---|---|
| name | req | Имя |
| phone | opt | Юелефон |
| opt | ||
| tags | opt | Массив строк |
| externalId | opt | ID во внешней системе |
Юе же поля, что при создании, все опциональны.
| Поле | Тип | Описание |
|---|---|---|
| primaryId | req | Главная запись |
| mergeIds | req | Массив ID для объединения |
| Поле | Тип | Описание |
|---|---|---|
| name | req | Название для поиска |
| content | req | Текст (поддерживает {{var}}) |
204 No Content.
Возвращает все рассылки аккаунта.
Тело запроса
| Поле | Тип | Описание |
|---|---|---|
| name | req | Название (1-200 символов) |
| channelId | req | ID канала отправки |
| message | req | Объект: { type, text, media } |
| message.type | req | text | image | video | document |
| message.text | opt | Текст сообщения (до 4096 символов) |
| message.media | opt | { url, contentType } — медиа-вложение |
| recipients | req | Объект: { mode, tags?, contactIds? } |
| recipients.mode | req | all | tags | contacts |
| recipients.tags | opt | Массив тегов (при mode=tags) |
| recipients.contactIds | opt | Массив ID контактов (при mode=contacts) |
| throttle | opt | Задержка между отправками, мс (200-60000, по умолч. 1000) |
| tagOnSend | opt | Тег, присваиваемый контакту при отправке |
Обновляет draft-рассылку. Те же поля, что и при создании.
Запускает асинхронную отправку. Статус рассылки меняется на sending. Прогресс доступен через GET /broadcasts/:id/stats.
Останавливает активную рассылку. Статус → cancelled.
Удаляет рассылку (только draft или completed). 204 No Content.
Возвращает все правила, отсортированные по приоритету (DESC).
Тело запроса
| Поле | Тип | Описание |
|---|---|---|
| name | req | Название (1-200) |
| trigger.type | req | keyword | contains | regex | any |
| trigger.value | opt | Значение триггера (до 500 символов) |
| actions | req | Массив действий (1-10) |
| actions[].type | req | reply | assign | tag | close |
| actions[].text | opt | Текст ответа (для reply) |
| actions[].assignTo | opt | ID оператора (для assign) |
| actions[].tag | opt | Тег (для tag) |
| channelId | opt | Ограничить конкретным каналом |
| priority | opt | Приоритет 0-1000 (по умолч. 0) |
| oncePerContact | opt | Сработать не более 1 раза на контакт |
Частичное обновление. Те же поля, что и при создании.
Переключает isActive. Возвращает обновлённый объект.
204 No Content.
Возвращает все каскады аккаунта (без подробных sends).
Тело запроса
| Поле | Тип | Описание |
|---|---|---|
| name | req | Название (1-200) |
| steps | req | Массив шагов (2-10) |
| steps[].channelId | req | ID канала для шага |
| steps[].timeout | opt | Таймаут в секундах (5-86400, по умолч. 300) |
Частичное обновление. Те же поля, что и при создании.
Тело запроса
| Поле | Тип | Описание |
|---|---|---|
| contactId | req | ID контакта-получателя |
| message | req | Объект: { type, text, media } |
Каскад отправляет сообщение через первый канал. Если не доставлено за timeout — переходит к следующему шагу.
204 No Content.
Возвращает все flows, отсортированные по дате обновления.
Тело запроса
| Поле | Тип | Описание |
|---|---|---|
| name | req | Название (1-200) |
| nodes | opt | Массив блоков: { id, type, position, data } |
| nodes[].type | req | trigger | condition | action | delay |
| nodes[].position | req | { x, y } — позиция на canvas |
| edges | opt | Массив связей: { id, source, target, label? } |
| isActive | opt | Активен ли (по умолч. false) |
Сохраняет обновлённый граф (nodes + edges). Те же поля, что и при создании.
Переключает isActive. Возвращает обновлённый объект.
204 No Content.
| Поле | Тип | Описание |
|---|---|---|
| url | req | HTTPS URL приёмника |
| events | req | Массив событий: ["new_message","message_status"] |
| secret | opt | Секрет для подписи HMAC-SHA256 |
Отправляет тестовое событие на Webhook и возвращает HTTP-код ответа.
204 No Content.
Управление интеграциями с amoCRM, Bitrix24, YCLIENTS и comka.ru (тип comkacrm). Креденшиалы хранятся в зашифрованном виде.
Возвращает все настроенные CRM-интеграции аккаунта. Поля credentials замаскированы (****).
| Параметр | Тип | Описание |
|---|---|---|
| type | string | amocrm | bitrix24 | yclients | comkacrm required |
| credentials | object | Объект с учётными данными (зависит от типа) required |
Credentials по типам:
amoCRM: domain, clientId, clientSecret, authCode
Bitrix24: webhookUrl или domain + clientId + clientSecret + authCode
YCLIENTS: обычно подключается через Marketplace. Для API-подключения достаточно companyId (токены берутся из server config при необходимости).
comka.ru: см. раздел comkacrm в панели интеграций (embed + webhooks + auto-create lead).
Обновляет credentials и/или isActive. Новые credentials мержатся с существующими.
Делает тестовый запрос к CRM API. Возвращает {"ok": true} или ошибку.
Удаляет интеграцию. Синхронизация прекращается немедленно.
Создаёт YCLIENTS-интеграцию из маркетплейс-события. Используется при установке приложения из YCLIENTS.
| Параметр | Тип | Описание |
|---|---|---|
| salonId | string | ID филиала в YCLIENTS required |
| salonName | string | Название филиала opt |
| userData | string | Base64 payload из Marketplace opt |
| userDataSign | string | HMAC подпись payload opt |
Импортирует пресеты шаблонов YCLIENTS (новая запись, подтверждение, перенос, отмена, напоминание, отзыв, день рождения).
Эти методы для внешних CRM и серверных скриптов. Основной способ авторизации — API-ключ из Настройки → API-ключи: заголовок Authorization: Bearer wc_... (как для остального REST). Альтернатива — X-CRM-Secret интеграции comka.ru CRM. JWT пользователя для этих путей не обязателен.
API-ключ — всегда в заголовке Authorization: Bearer wc_.... Какие scope включить при создании ключа:
POST /crm-api/embed-token— нужен scope conversations.read (чтение диалогов).POST /crm-api/send-message,send-by-phone,send-by-phone-all-channels— нужен messages.write (отправка сообщений).
X-CRM-Secret (comka) — значение поля Shared Secret в интеграции comka.ru CRM в разделе Интеграции; то же значение вставляется в comka как shared_secret.
tenant_slug — метка контекста для iframe (параметр tenant= в URL). При авторизации API-ключом поле можно не передавать — подставится default. Это не название аккаунта WonderChat. Для comka с заданным в credentials tenantSlug при использовании X-CRM-Secret значения должны совпасть.
Возвращает { "embed_url": "..." } — URL страницы /embed/inbox с одноразовым embed-JWT (срок ~24 ч), привязанным к аккаунту WonderChat.
| Поле | Тип | Описание |
|---|---|---|
| tenant_slug | opt | Метка для tenant= в URL; при API-ключе можно опустить (будет default). Для X-CRM-Secret + заданного в интеграции tenantSlug — должен совпасть |
| contact_phone | opt | Телефон как в карточке контакта WonderChat — добавит в URL &contact=<id> при совпадении |
| conversation_id | opt | ID диалога — добавит &conversation=<id> (iframe сразу откроет чат) |
| user_name / user_email | opt | Зарезервировано для подписи в журналах |
Находит контакт по contact_id или contact_phone (точное совпадение поля phone), берёт последний открытый диалог контакта и ставит исходящее текстовое сообщение от имени «CRM».
| Поле | Тип | Описание |
|---|---|---|
| tenant_slug | opt | Как в embed-token; при Bearer-ключе можно опустить |
| contact_id | opt | ID контакта в WonderChat |
| contact_phone | opt | Одно из двух: contact_id или contact_phone |
| message.text | opt | Текст (может быть пустым, если только вложения в будущем) |
404 — контакт не найден или нет открытого диалога.
Та же логика «главного» диалога, что и у POST /conversations/send-by-phone в панели: нормализация номера, выбор контакта и незакрытого диалога с приоритетом подключённого канала.
| Поле | Тип | Описание |
|---|---|---|
| tenant_slug | opt | Как в embed-token; при Bearer-ключе можно опустить |
| phone | req | Телефон контакта |
| message.text | req | Текст сообщения |
Тело как у send-by-phone (phone, message.text обязательны; tenant_slug при Bearer-ключе можно не передавать). Поведение совпадает с POST /conversations/send-by-phone-all-channels: открытые чаты + cold start WhatsApp / WABA / MAX personal (при успешном резолве номера в клиенте).
Ответ 200 с ok, sent, results; 400 если ни один канал не отправил.
Подключитесь по URL: wss://panel.wonderchat.ru?token=<jwt>. События приходят в формате {"type":"event_name","data":{...}}.
new_message
Новое входящее или исходящее сообщение.
message_status
Ютатус сообщения изменился: sent → delivered → read.
channel_status
Ютатус канала изменился: online | offline | connecting.
qr_code
Новый QR-код сгенерирован для WhatsApp.
typing
Пользователь пишет в выбранном диалоге.