IframeAuthAccountChannels ConversationsЧасыAPI KeysContacts TemplatesBroadcastsAutomations CascadesFlowsWebhooksCRM APIWebSocket

API Reference

WonderChat REST API позволяет управлять диалогами, каналами, контактами и шаблонами программно. Все запросы возвращают JSON.

Base URLhttps://panel.wonderchat.ru/api/v1

Аутентификация 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.

i

API-ключ и JWT не смешивайте в одном запросе: для ключа используйте только Bearer wc_.... WebSocket по-прежнему только с JWT.

Быстрый старт для CRM: iframe-инбокс и отправка по телефону — раздел 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
https://panel.wonderchat.ru/embed/inbox?token=<embed_jwt>&tenant=<tenant_slug>

Вставьте этот 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 в теле должен совпасть.

Аутентификация
Auth
POST /auth/register Регистрация

Тело запроса

ПолеТипОписание
emailreqEmail адрес
passwordreqПароль (min 8 символов)
namereqИмя пользователя
Ответ 201
{ "token": "eyJhbGci...", "refreshToken": "eyJhbGci...", "user": { "id": "u1", "email": "user@ex.ru", "name": "Иван" } }
POST /auth/login Авторизация

Тело запроса

ПолеТипОписание
emailreqEmail
passwordreqПароль
Пример запроса
curl https://panel.wonderchat.ru/api/v1/auth/login \ -X POST -H 'Content-Type: application/json' \ -d '{"email":"user@ex.ru","password":"Secret123!"}'
Ответ 200
{ "token": "eyJhbGci...", "refreshToken": "eyJhbGci..." }
POST /auth/refresh Обновить токен
ПолеТипОписание
refreshTokenreqrefresh токен из login
Ответ 200
{ "token": "eyJhbGci..." }
GET /auth/me Текущий пользователь
🔒 Требует Bearer токен
Ответ 200
{ "id": "u1", "email": "user@ex.ru", "name": "Иван", "role": "admin" }
POST /auth/logout Выход
🔒 Требует Bearer токен

Отозвание текущей сессии. Используйте /auth/logout-all для выхода со всех устройств.


Управление
Account
GET /account Информация об аккаунте
🔒 Bearer токен
Ответ 200
{ "id": "acc_1", "name": "Моя Компания", "plan": "pro", "createdAt": "2026-01-01T00:00:00Z" }
PATCH /account Обновить аккаунт
🔒 Bearer токен
ПолеТипОписание
nameoptНазвание аккаунта
GET /account/users Список пользователей
🔒 Bearer токен
Ответ 200
[ { "id": "u1", "name": "Иван", "email": "i@ex.ru", "role": "admin" } ]
POST /account/users Создать пользователя
🔒 Bearer токен
ПолеТипОписание
emailreqEmail нового пользователя
namereqИмя
passwordreqПароль
roleoptadmin | operator (деф. operator)

Каналы
Channels
GET /channels Все каналы
🔒 Bearer токен
Ответ 200
[{ "id": "ch1", "name": "Мой Telegram", "type": "telegram", "status": "online", "createdAt": "2026-01-01T00:00:00Z" }]
POST /channels Создать канал
🔒 Bearer токен
ПолеТипОписание
namereqНазвание канала
typereqtelegram | telegram_bot | whatsapp | waba | vk | instagram | max | max_personal
credentialsreqОбъект с параметрами канала
credentials для telegram
// Для QR credentials можно оставить пустым, если TELEGRAM_API_ID/TELEGRAM_API_HASH заданы на сервере
{ "phone": "+79001234567" // необязательно, только для fallback-входа по коду }
credentials для telegram_bot
{ "token": "1234567890:AAFxxx..." }
credentials для waba
{ "phoneNumberId": "1234567890", "accessToken": "EAABxx..." }
credentials для vk
{ "token": "vk1.a.xxx" // groupId определяется автоматически }
credentials для max_personal (личный аккаунт)
// Токен можно передать при создании, а QR-подключение выполняется через // POST /channels/:id/max-qr/start и GET /channels/:id/max-qr/status
PATCH /channels/:id Обновить канал
🔒 Bearer токен
ПолеТипОписание
nameoptНовое название
credentialsoptОбновить креденшиалы (мержится с существующими)
healthCheckIntervaloptАвтопереподключение в минутах: 0..1440

ВКонтакте: credentials мержатся с существующими (токен не теряется), а при передаче confirmationCode/secretKey адаптер перезапускается автоматически через Redis.

DELETE /channels/:id Удалить канал
🔒 Bearer токен

Отключает канал и удаляет его. Ответ 204 No Content.

POST /channels/:id/connect Подключить канал
🔒 Bearer токен

Для Telegram запускает auth flow (code/2FA), для остальных каналов публикует команду подключения в Redis. Для WhatsApp отдельный QR запрашивается через POST /channels/:id/qr, для MAX Personal — через POST /channels/:id/max-qr/start.

Ответ для Telegram (требуется код)
{ "status": "code_required" }
Ответ для обычного подключения
{ "status": "connecting", "message": "Channel connection initiated" }
POST /channels/:id/qr Обновить QR
🔒 Bearer токен

Только для WhatsApp. Генерирует новый QR-код.

POST /channels/:id/max-qr/start Старт MAX Personal QR
🔒 Bearer токен

Только для каналов max_personal. Запускает QR-авторизацию и возвращает QR URL.

Ответ 200
{ "qrUrl": "https://max.ru/qr/track_xxx", "expiresAt": "2026-04-17T12:34:56.000Z" }
GET /channels/:id/max-qr/status Статус MAX Personal QR
🔒 Bearer токен

Проверяет прогресс QR-авторизации: pending, connected, expired, failed.

Ответ 200
{ "status": "pending" }

Диалоги
Conversations
GET /conversations Список диалогов
🔒 Bearer токен

Query параметры

ПараметрТипОписание
channelIdoptФильтр по каналу
statusoptopen | closed
unreadopttrue — только непрочитанные
searchoptТекстовый поиск
pageoptСтраница (деф. 1)
limitoptДиалогов на странице (деф. 30)
Ответ 200
{ "data": [{ "id": "c1", "contact": {...}, "lastMessage": {...}, "unreadCount": 3 }], "total": 42, "page": 1 }
GET /conversations/:id Один диалог
🔒 Bearer токен
PATCH /conversations/:id Обновить диалог
🔒 Bearer токен
ПолеТипОписание
statusoptopen | closed
assignedTooptID пользователя
tagsoptМассив строк — теги на чат
POST /conversations/:id/assign Назначить чат сотруднику
🔒 Bearer токен или API-ключ

Назначает ответственного и опционально отправляет клиенту системное сообщение «К чату подключен сотрудник …». Для чатов YCLIENTS round-robin учитывает филиал (yclientsIntegrationId диалога) и настройки сотрудников «филиалы для распределения».

ПолеТипОписание
userIdoptID пользователя аккаунта. Обязателен, если не используется roundRobin
roundRobinopttrue — взять следующего из очереди (нельзя вместе с userId)
announceoptПо умолчанию true — отправить приветствие в чат клиенту
Пример: конкретный сотрудник
{ "userId": "usr_abc", "announce": true }
Пример: по очереди
{ "roundRobin": true }
GET /conversations/:id/messages Сообщения
🔒 Bearer токен

Query параметры

ПараметрТипОписание
beforeoptID сообщения (пагинация назад)
limitoptДеф. 50
Ответ 200
[{ "id": "msg1", "type": "text", "text": "Здравствуйте!", "direction": "in", // "in" | "out" "status": "delivered", "createdAt": "2026-04-11T10:00:00Z" }]
POST /conversations/:id/messages Отправить сообщение
🔒 Bearer токен
ПолеТипОписание
typereqtext | image | video | document | audio
textoptТекст сообщения
mediaUrloptURL медиа из /conversations/upload
replyToIdoptID ответного сообщения
Пример
{ "type": "text", "text": "Ваш заказ оформлен!" }
POST /conversations/upload Загрузить файл
🔒 Bearer токен

Ьлёт multipart/form-data с полем file. Юакже принимает JSON с полем url (если файл уже в сети).

Ответ 200
{ "url": "https://...", "mimeType": "image/jpeg", "size": 204800 }
POST /conversations/:id/read Отметить прочитанным
🔒 Bearer токен

Отмечает все сообщения диалога прочитанными, обнуляет unreadCount. Ответ 200.

POST /conversations/send-by-phone Отправить по номеру телефона
🔒 Bearer токен или API-ключ

Находит контакт по телефону и отправляет сообщение в его главный активный диалог.

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

ПолеТипОписание
phonereqТелефон контакта в любом привычном формате
typeoptПо умолчанию text
textoptТекст сообщения
mediaoptОбъект медиа как в POST /conversations/:id/messages
Пример
{ "phone": "+79991234567", "text": "Добрый день! Напоминаем о записи." }
Ответ 201
{ "conversationId": "conv_...", "contactId": "ctc_...", "message": { ... } }

Ошибки: 404 если контакт не найден или нет подходящего незакрытого диалога; нужен хотя бы text или media.

POST /conversations/send-by-phone-all-channels Во все каналы по номеру
🔒 Bearer токен или API-ключ

По одному контакту (как у 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-ключом.

GET /working-hours Получить расписание
🔒 Bearer токен или API-ключ

Возвращает enabled, timezone, days (mon…sun со слотами from/to), offlineMessage. Если записи нет — ответ с дефолтами.

PUT /working-hours Сохранить расписание
🔒 Bearer токен или API-ключ

Тело по схеме как в ответе GET: days.mon.enabled, days.mon.slots[] с временем HH:mm, и т.д.

GET /working-hours/status Сейчас внутри смены?
🔒 Bearer токен или API-ключ

Например {"online":true,"reason":"schedule_disabled"} или online: false, nextOpen, offlineMessage при выключенном дне или вне слотов.


API-ключи
API Keys

API-ключи создаются в Настройки → API-ключи и могут использоваться вместо JWT для REST API.

GET /api-keys Список ключей
🔒 Bearer токен или API-ключ

Возвращает список активных ключей аккаунта без полного значения ключа.

POST /api-keys Создать ключ
🔒 Bearer токен или API-ключ
ПолеТипОписание
namereqПонятное имя ключа, например CRM integration
scopesreqМассив разрешений для учета и будущих ограничений
expiresAtoptДата истечения в ISO-формате
Пример ответа 201
{ "id": "key_123", "name": "CRM integration", "key": "wc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }
DELETE /api-keys/:id Отозвать ключ
🔒 Bearer токен или API-ключ

Удаляет ключ. После этого авторизация по нему сразу перестает работать.


Контакты
Contacts
GET /contacts Список контактов
🔒 Bearer токен

Query

ПараметрТипОписание
searchoptПоиск по имени/телефону
tagoptФильтр по тегу
page / limitoptПагинация
POST /contacts Создать контакт
🔒 Bearer токен
ПолеТипОписание
namereqИмя
phoneoptЮелефон
emailoptEmail
tagsoptМассив строк
externalIdoptID во внешней системе
PATCH /contacts/:id Обновить
🔒 Bearer токен

Юе же поля, что при создании, все опциональны.

POST /contacts/merge Объединить дубликаты
🔒 Bearer токен
ПолеТипОписание
primaryIdreqГлавная запись
mergeIdsreqМассив ID для объединения
GET /contacts/tags/all Все теги
🔒 Bearer токен

Возвращает отсортированный массив всех уникальных тегов контактов аккаунта.

Response 200
["VIP", "рассылка-июнь", "холодный"]

Шаблоны
Templates
GET /templates Список шаблонов
🔒 Bearer токен
Ответ 200
[{ "id": "tpl1", "name": "привет", "content": "Здравствуйте, {{name}}!" }]
POST /templates Создать шаблон
🔒 Bearer токен
ПолеТипОписание
namereqНазвание для поиска
contentreqТекст (поддерживает {{var}})
DELETE /templates/:id Удалить
🔒 Bearer токен

204 No Content.


Рассылки
Broadcasts
GET /broadcasts Список рассылок
🔒 Bearer токен

Возвращает все рассылки аккаунта.

POST /broadcasts Создать рассылку
🔒 Bearer токен · owner / admin

Тело запроса

ПолеТипОписание
namereqНазвание (1-200 символов)
channelIdreqID канала отправки
messagereqОбъект: { type, text, media }
message.typereqtext | image | video | document
message.textoptТекст сообщения (до 4096 символов)
message.mediaopt{ url, contentType } — медиа-вложение
recipientsreqОбъект: { mode, tags?, contactIds? }
recipients.modereqall | tags | contacts
recipients.tagsoptМассив тегов (при mode=tags)
recipients.contactIdsoptМассив ID контактов (при mode=contacts)
throttleoptЗадержка между отправками, мс (200-60000, по умолч. 1000)
tagOnSendoptТег, присваиваемый контакту при отправке
Request
{ "name": "Акция июнь", "channelId": "ch_abc", "message": { "type": "text", "text": "Скидка 20% только сегодня!" }, "recipients": { "mode": "tags", "tags": ["VIP"] }, "throttle": 1000, "tagOnSend": "акция-июнь" }
PATCH /broadcasts/:id Обновить рассылку
🔒 Bearer токен · owner / admin

Обновляет draft-рассылку. Те же поля, что и при создании.

POST /broadcasts/:id/send Запустить отправку
🔒 Bearer токен · owner / admin

Запускает асинхронную отправку. Статус рассылки меняется на sending. Прогресс доступен через GET /broadcasts/:id/stats.

POST /broadcasts/:id/cancel Отменить отправку
🔒 Bearer токен · owner / admin

Останавливает активную рассылку. Статус → cancelled.

GET /broadcasts/:id/stats Статистика
🔒 Bearer токен
Response 200
{ "total": 150, "sent": 120, "delivered": 115, "failed": 5 }
DELETE /broadcasts/:id Удалить рассылку
🔒 Bearer токен · owner / admin

Удаляет рассылку (только draft или completed). 204 No Content.


Автоответчики
Automations
GET /automations Список автоответчиков
🔒 Bearer токен

Возвращает все правила, отсортированные по приоритету (DESC).

POST /automations Создать правило
🔒 Bearer токен · owner / admin

Тело запроса

ПолеТипОписание
namereqНазвание (1-200)
trigger.typereqkeyword | contains | regex | any
trigger.valueoptЗначение триггера (до 500 символов)
actionsreqМассив действий (1-10)
actions[].typereqreply | assign | tag | close
actions[].textoptТекст ответа (для reply)
actions[].assignTooptID оператора (для assign)
actions[].tagoptТег (для tag)
channelIdoptОграничить конкретным каналом
priorityoptПриоритет 0-1000 (по умолч. 0)
oncePerContactoptСработать не более 1 раза на контакт
Request
{ "name": "Приветствие", "trigger": { "type": "any" }, "actions": [ { "type": "reply", "text": "Здравствуйте! Мы скоро ответим." } ], "priority": 10, "oncePerContact": true }
PATCH /automations/:id Обновить правило
🔒 Bearer токен · owner / admin

Частичное обновление. Те же поля, что и при создании.

POST /automations/:id/toggle Вкл / Выкл
🔒 Bearer токен · owner / admin

Переключает isActive. Возвращает обновлённый объект.

DELETE /automations/:id Удалить
🔒 Bearer токен · owner / admin

204 No Content.


Каскады
Cascades
GET /cascades Список каскадов
🔒 Bearer токен

Возвращает все каскады аккаунта (без подробных sends).

POST /cascades Создать каскад
🔒 Bearer токен · owner / admin

Тело запроса

ПолеТипОписание
namereqНазвание (1-200)
stepsreqМассив шагов (2-10)
steps[].channelIdreqID канала для шага
steps[].timeoutoptТаймаут в секундах (5-86400, по умолч. 300)
Request
{ "name": "WA → Telegram", "steps": [ { "channelId": "ch_wa", "timeout": 300 }, { "channelId": "ch_tg", "timeout": 600 } ] }
PATCH /cascades/:id Обновить каскад
🔒 Bearer токен · owner / admin

Частичное обновление. Те же поля, что и при создании.

POST /cascades/:id/send Отправить каскад
🔒 Bearer токен · owner / admin

Тело запроса

ПолеТипОписание
contactIdreqID контакта-получателя
messagereqОбъект: { type, text, media }
Response 202
{ "ok": true, "sendId": "snd_abc" }
ℹ️

Каскад отправляет сообщение через первый канал. Если не доставлено за timeout — переходит к следующему шагу.

DELETE /cascades/:id Удалить каскад
🔒 Bearer токен · owner / admin

204 No Content.


Flow-builder
Flows
GET /flows Список flows
🔒 Bearer токен

Возвращает все flows, отсортированные по дате обновления.

POST /flows Создать flow
🔒 Bearer токен · owner / admin

Тело запроса

ПолеТипОписание
namereqНазвание (1-200)
nodesoptМассив блоков: { id, type, position, data }
nodes[].typereqtrigger | condition | action | delay
nodes[].positionreq{ x, y } — позиция на canvas
edgesoptМассив связей: { id, source, target, label? }
isActiveoptАктивен ли (по умолч. false)
Request
{ "name": "Приветственный flow", "nodes": [ { "id": "n1", "type": "trigger", "position": {"x":100,"y":100} }, { "id": "n2", "type": "action", "position": {"x":100,"y":250}, "data": {"text":"Привет!"} } ], "edges": [ { "id": "e1", "source": "n1", "target": "n2" } ] }
PATCH /flows/:id Обновить flow
🔒 Bearer токен · owner / admin

Сохраняет обновлённый граф (nodes + edges). Те же поля, что и при создании.

POST /flows/:id/toggle Вкл / Выкл
🔒 Bearer токен · owner / admin

Переключает isActive. Возвращает обновлённый объект.

DELETE /flows/:id Удалить flow
🔒 Bearer токен · owner / admin

204 No Content.


Вебхуки
Webhooks
GET /webhooks Список
🔒 Bearer токен
POST /webhooks Создать
🔒 Bearer токен
ПолеТипОписание
urlreqHTTPS URL приёмника
eventsreqМассив событий: ["new_message","message_status"]
secretoptСекрет для подписи HMAC-SHA256
POST /webhooks/:id/test Тестовый запрос
🔒 Bearer токен

Отправляет тестовое событие на Webhook и возвращает HTTP-код ответа.

DELETE /webhooks/:id Удалить
🔒 Bearer токен

204 No Content.


CRM-интеграции
CRM Integrations

Управление интеграциями с amoCRM, Bitrix24, YCLIENTS и comka.ru (тип comkacrm). Креденшиалы хранятся в зашифрованном виде.

GET /crm Список CRM-интеграций

Возвращает все настроенные CRM-интеграции аккаунта. Поля credentials замаскированы (****).

Response 200
[{ "id": "abc123", "type": "amocrm", "isActive": true, "credentials": { "domain": "company.amocrm.ru", "clientId": "****" } }]
POST /crm Создать интеграцию
ПараметрТипОписание
typestringamocrm | bitrix24 | yclients | comkacrm required
credentialsobjectОбъект с учётными данными (зависит от типа) 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).

Request
{ "type": "bitrix24", "credentials": { "webhookUrl": "https://company.bitrix24.ru/rest/1/abc123/" } }
PATCH /crm/:id Обновить интеграцию

Обновляет credentials и/или isActive. Новые credentials мержатся с существующими.

Request
{ "isActive": false }
POST /crm/:id/test Проверить подключение

Делает тестовый запрос к CRM API. Возвращает {"ok": true} или ошибку.

DELETE /crm/:id Удалить интеграцию

Удаляет интеграцию. Синхронизация прекращается немедленно.

POST /crm/yclients/connect Marketplace-подключение YCLIENTS

Создаёт YCLIENTS-интеграцию из маркетплейс-события. Используется при установке приложения из YCLIENTS.

ПараметрТипОписание
salonIdstringID филиала в YCLIENTS required
salonNamestringНазвание филиала opt
userDatastringBase64 payload из Marketplace opt
userDataSignstringHMAC подпись payload opt
POST /crm/:id/yclients/import-templates Импорт шаблонов уведомлений YCLIENTS

Импортирует пресеты шаблонов YCLIENTS (новая запись, подтверждение, перенос, отмена, напоминание, отзыв, день рождения).

Ответ 200
{ "ok": true, "imported": 7 }

External CRM API
CRM API

Эти методы для внешних CRM и серверных скриптов. Основной способ авторизации — API-ключ из Настройки → API-ключи: заголовок Authorization: Bearer wc_... (как для остального REST). Альтернатива — X-CRM-Secret интеграции comka.ru CRM. JWT пользователя для этих путей не обязателен.

i

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 значения должны совпасть.

POST /crm-api/embed-token Ссылка для iframe
🔒 Authorization: Bearer wc_… или X-CRM-Secret

Возвращает { "embed_url": "..." } — URL страницы /embed/inbox с одноразовым embed-JWT (срок ~24 ч), привязанным к аккаунту WonderChat.

ПолеТипОписание
tenant_slugoptМетка для tenant= в URL; при API-ключе можно опустить (будет default). Для X-CRM-Secret + заданного в интеграции tenantSlug — должен совпасть
contact_phoneoptТелефон как в карточке контакта WonderChat — добавит в URL &contact=<id> при совпадении
conversation_idoptID диалога — добавит &conversation=<id> (iframe сразу откроет чат)
user_name / user_emailoptЗарезервировано для подписи в журналах
Пример: API-ключ (рекомендуется)
curl https://panel.wonderchat.ru/api/v1/crm-api/embed-token \ -H 'Content-Type: application/json' -H 'Authorization: Bearer wc_YOUR_KEY' \ -d '{}'
Пример: секрет comka (альтернатива)
curl https://panel.wonderchat.ru/api/v1/crm-api/embed-token \ -H 'Content-Type: application/json' -H 'X-CRM-Secret: YOUR_SHARED_SECRET' \ -d '{"tenant_slug":"mytenant"}'
POST /crm-api/send-message Отправка в открытый диалог
🔒 Authorization: Bearer wc_… или X-CRM-Secret

Находит контакт по contact_id или contact_phone (точное совпадение поля phone), берёт последний открытый диалог контакта и ставит исходящее текстовое сообщение от имени «CRM».

ПолеТипОписание
tenant_slugoptКак в embed-token; при Bearer-ключе можно опустить
contact_idoptID контакта в WonderChat
contact_phoneoptОдно из двух: contact_id или contact_phone
message.textoptТекст (может быть пустым, если только вложения в будущем)

404 — контакт не найден или нет открытого диалога.

POST /crm-api/send-by-phone Отправка по номеру в главный диалог
🔒 Authorization: Bearer wc_… или X-CRM-Secret

Та же логика «главного» диалога, что и у POST /conversations/send-by-phone в панели: нормализация номера, выбор контакта и незакрытого диалога с приоритетом подключённого канала.

ПолеТипОписание
tenant_slugoptКак в embed-token; при Bearer-ключе можно опустить
phonereqТелефон контакта
message.textreqТекст сообщения
Пример
{ "tenant_slug": "demo", "phone": "+79991234567", "message": { "text": "Напоминание о визите" } }
Ответ 200
{ "ok": true, "conversationId": "...", "contactId": "...", "messageId": "..." }
POST /crm-api/send-by-phone-all-channels Во все каналы по номеру
🔒 Authorization: Bearer wc_… или X-CRM-Secret

Тело как у 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 если ни один канал не отправил.


Real-time
WebSocket Events

Подключитесь по URL: wss://panel.wonderchat.ru?token=<jwt>. События приходят в формате {"type":"event_name","data":{...}}.

new_message

Новое входящее или исходящее сообщение.

{ "type": "new_message", "data": { "id": "msg1", "conversationId": "c1", "direction": "in", "type": "text", "text": "Привет!" } }

message_status

Ютатус сообщения изменился: sentdeliveredread.

{ "type": "message_status", "data": { "id": "msg1", "status": "read" } }

channel_status

Ютатус канала изменился: online | offline | connecting.

{ "type": "channel_status", "data": { "channelId": "ch1", "status": "online" } }

qr_code

Новый QR-код сгенерирован для WhatsApp.

{ "type": "qr_code", "data": { "channelId": "ch1", "qr": "data:image/png;base64,..." } }

typing

Пользователь пишет в выбранном диалоге.

{ "type": "typing", "data": { "conversationId": "c1" } }