AISARAISAR

Realtime-события по WebSocket

Какие WebSocket-каналы и события доступны при прямом подключении к AISAR Reverb, и как они соотносятся с вебхуками.

Помимо вебхуков (см. гайд «Вебхуки»), AISAR транслирует часть событий в реальном времени через Pusher-совместимый WebSocket-сервер (Reverb). Это полезно для собственных фронтендов, которым нужна мгновенная реакция на изменения (typing-индикаторы, счётчики, обновления диалогов) без опроса REST API.

Вебхуки и WebSocket дополняют друг друга, а не заменяют. Вебхуки — авторитетный, подписанный, с ретраями канал доставки для серверной интеграции. WebSocket — быстрый, но лучше-эффортный (best-effort) канал для UI: события, пропущенные во время дисконнекта, не переигрываются — после переподключения перечитайте состояние через REST.

Каналы

КаналФорматНазначение
Компанияprivate-company.{companyId}События диалогов/сообщений/контактов/сделок для всей команды
Пользовательprivate-user.{userId}Персональные события: счётчики, уведомления
Канал (мессенджер)private-channel.{channelId}Статус канала, синхронизация контактов/групп
Диалогprivate-conversation.{conversationId}Индикаторы набора текста и присутствия контакта

Активные события

Сообщения (канал: company)

Транслируются: message.created, message.updated, message.deleted, message.read, message.status.updated, message.reaction.updated. Тело события:

json
{
  "conversation_id": 750,
  "thread_id": 750,
  "message": { "...MessageResource..." }
}

Диалоги (канал: company)

Транслируются: conversation.created, conversation.updated, conversation.closed, conversation.reopened, conversation.assigned, conversation.unassigned.

Базовый payload
{ "conversation_id": 750 }
Для assigned / unassigned — дополнительно
{
  "conversation_id": 750,
  "action": "added",
  "participant": { "id": 1, "member_type": "user", "member_id": 5, "role": "agent" }
}

Счётчики (канал: user)

chat.counters.updated обновляет бейджи фильтров диалогов. Срабатывает при любом счётчик-влияющем событии (message.created/deleted/read, conversation.created/updated/closed/reopened/assigned/unassigned) — пересчитывается персонально для каждого пользователя компании.

json
{
  "counters": {
    "all": 42,
    "awaiting": 5,
    "unread": 8,
    "assigned": 15,
    "unassigned": 2,
    "archived": 18
  }
}

Уведомления (канал: user)

notification.created — новое персональное уведомление пользователя.

Каналы обмена сообщениями (канал: channel)

channel.realtime.update — единое событие с маршрутизацией по payload.type: channel_status (смена статуса канала), contacts_synced/contacts_updated, groups_synced/group_updated/group_participants_updated, history_sync_progress.

Сделки и AI-агенты (канал: company)

deal.updated — изменение сделки. ai-pending-action.updated — изменение статуса действия AI-агента, ожидающего подтверждения оператора (action: "created" | "approved" | "rejected"), payload { event_id, conversation_id, action }.

Broadcast-only события (не доставляются как вебхук)

Некоторые события транслируются только через WebSocket, без соответствующего исходящего HTTP-вебхука: contact.outbound_eligibility_updated (право контакта на исходящие/WhatsApp-звонки, payload {contact_id, channel_id} либо вариант с contact_account_id + call{...}) и nudges.updated (in-app nudge-баннер, payload {company_id}). Если вашей интеграции нужны именно эти сигналы — подписывайтесь на них через WebSocket, вебхук не сработает.

Надёжность

  • Broadcast-события, порождённые внутри транзакции БД, отправляются только после её коммита — вы никогда не увидите событие о сущности, которая затем откатилась.
  • Доставка синхронная (не через очередь) — задержка минимальна, но события не буферизуются на время дисконнекта.
  • Расчёт счётчика unread зависит от настройки компании shared_read_receipts: при true — максимум last_read_at по всем пользователям, при false — индивидуальный last_read_at каждого пользователя.

AISAR подключается к Reverb по Pusher-совместимому протоколу (wsHost: api.aisar.app, TLS-порт 443, authEndpoint: https://api.aisar.app/broadcasting/auth). Подписка на приватные каналы (private-*) требует токен-авторизации на /broadcasting/auth и проходит per-channel ACL — пользователь одной компании не может подписаться на канал другой. За реквизитами подключения (app key и т.п.) обратитесь в поддержку AISAR.