Диалоги
Диалог (conversation) — карточка общения с одним контактом, объединяющая один или несколько тредов (переписок в конкретных каналах: WhatsApp, Telegram, Instagram и т.д.). Через эти эндпоинты вы ведёте жизненный цикл диалога — открываете и закрываете его, назначаете участников (операторов) через participants, добавляете внутренние заметки и метки, читаете единую хронологию событий (events) и тред-структуру. Большинство операций мутируют лог событий диалога, доступный через GET /conversations/{id}/events.
Создание диалога
Создать диалог можно двумя путями: POST /conversations для уже известного контакта либо POST /dialogs — интеграторский вход, который по идентификатору account (телефон или username) за один вызов создаёт или переиспользует связку contact → contact_account → conversation → thread; для телефонных каналов (sms, whatsapp) account нормализуется как телефон. GET /dialogs/lookup ищет существующий активный диалог с учётом родственных типов каналов (whatsapp/whatsapp_business/sms, telegram/telegram_bot, instagram/instagram_business).
Список и фильтры
Список GET /conversations использует постраничную пагинацию (page/perPage, ответ содержит блок pagination {page, perPage, total, lastPage}) и поддерживает фильтры thread_filter (all|awaiting|unread|assigned|unassigned|my_team|archived|groups), channel_id, funnel_id, funnel_stage_ids (id стадий воронки через запятую), contact_id, lifecycle_status (active|closed), is_archived, unread_only, search, сортировку sortBy (id|last_message_at|created_at|updated_at) / sortDir (asc|desc) и include_counters=1 (добавить в ответ блок counters).
Ключ счётчика `aisar_notifications`
Блок counters (в списке диалогов при include_counters=1 и в GET /conversations/counters) несёт ключ aisar_notifications — присутствует всегда, включая пустой ответ для компании без активной подписки. Смена семантики (2026-08-24, без нового префикса версии): до 24.08 ключ считал служебные диалоги AISAR внутри самих диалогов (см. историю ниже); теперь платформенные уведомления вынесены в отдельный ресурс GET /platform-notifications, и counters.aisar_notifications — это число НЕПРОЧИТАННЫХ записей platform_notifications компании: записей за последние 90 дней с created_at позже курсора ui_preferences.aisar_notifications.seen_until текущего пользователя (курсор null — считаются все записи в окне). Формат значения (целое число) не изменился, изменился только источник данных и то, что он теперь считается per-user, а не per-company.
Ожидание ответа (`awaiting_since`) и «Не требует ответа»
ConversationResource (и в списке GET /conversations, и в GET /conversations/{id}) содержит вычисляемое поле awaiting_since (ISO-8601 строка либо null) — момент первого неотвеченного входящего сообщения; null, если диалог сейчас не ожидает ответа. Семантика совпадает с thread_filter=awaiting. Значение считается обратным сканированием истории диалога (не более 100 последних сообщений); для диалога с исключительно длинным неотвеченным хвостом это приближение — момент самого старого входящего сообщения в пределах этого окна, а не гарантированно первого за всю историю.
POST /conversations/{conversation}/dismiss-awaiting (2026-08-24, право conversation.update) — оператор помечает диалог как «не требует ответа»: сервер выставляет служебное поле awaiting_dismissed_at и с этого момента awaiting_since в ответе диалога держится null, пока не придёт следующее входящее сообщение (оно снова взводит awaiting_since как обычно). Ответ — { "data": { "id": <conversation_id>, "awaiting_since": null } }.
Треды как самостоятельная сущность
Тред можно листать и как самостоятельную сущность: GET /threads возвращает кросс-диалоговый список тредов (режим отображения «по каналам») с теми же фильтрами, пагинацией и счётчиками, а POST /threads/{id}/close|open|archive|unarchive меняет состояние конкретного треда независимо от диалога (переоткрытие вернёт 422, если у контакта уже есть другой активный диалог).
Статусы прочтения
Read-статусы отдаёт GET /conversations/{id}/reads — кто из операторов и до какого сообщения прочитал диалог (per-user last_read_message_id/last_read_at), а POST /conversations/{id}/reads выставляет позицию прочтения текущего пользователя. У POST /conversations/mark-read поле conversation_ids необязательно (без него помечаются все диалоги компании), а read-статус диалога обновляется и автоматически при исходящем сообщении оператора. Поскольку для крупной компании массовая отметка может занять десятки секунд, POST /conversations/mark-read ставит upsert и рассылку CRM-бейджей в очередь и отвечает 202 Accepted без поля updated_count в теле — реальное число обновлённых диалогов приходит только асинхронно, через WebSocket-событие message.read с bulk: true и updated_count. Вызов с пустым массивом conversation_ids: [] в очередь не ставится и отвечает обычным 200.
POST /conversations/{conversation}/mark-unread — обратная операция: отматывает курсор прочтения на секунду раньше последнего входящего сообщения диалога (или его треда — необязательный thread_id), так что это сообщение снова становится непрочитанным. Область действия зависит от настройки компании shared_read_receipts: при общем счётчике отматывается курсор КАЖДОГО оператора, у кого он был позже новой отметки; при индивидуальном — только курсор текущего пользователя. Если во всём диалоге (или треде) вообще нет входящих сообщений — 422 { "data": { "message": "Conversation has no inbound messages to mark as unread." } }. Успешный ответ: { "data": { message, item, unread_count, shared_read_receipts } } — item в той же форме, что и у reads (может быть null), unread_count — сколько входящих сообщений теперь непрочитано у текущего пользователя, shared_read_receipts эхом отдаёт настройку компании.
ИИ-копилот и действия ИИ-агента
ИИ-копилот: POST /conversations/{id}/ai-suggestions/generate генерирует черновик ответа для диалога, а .../ai-suggestions/{id}/accept (с опциональной правкой final_text) и .../reject фиксируют решение оператора по подсказке.
.../ai-suggestions/generate не требует фичи ai_agents на уровне маршрута — она проверяется внутри самой генерации, вместе с тарифным лимитом ИИ-ответов, и различает несколько отказов: агенту не назначен диалог — 404 (без тела с кодом); агент неактивен — 422 { "code": "agent_inactive" }; исчерпан собственный $-бюджет агента (настраивается компанией) — 422 { "code": "budget_exceeded" }; исчерпан тарифный лимит ИИ-ответов за расчётный период (ai_replies_included) — в том числе если тариф компании вовсе не несёт ai_agents (например, после даунгрейда) — 422 { "code": "plan_limit_exceeded" }; использование достигло технического порога защиты от абьюза (кратно тарифному лимиту) — 422 { "code": "usage_abuse_stopped" }; слишком частые вызовы — 429 (без тела с кодом).
ИИ-агент может предлагать действия, требующие подтверждения оператора (например закрытие диалога, блокировка контакта, удаление сообщений) — очередь таких предложений по конкретному диалогу отдаёт GET /conversations/{id}/ai-pending-actions: каждый элемент несёт tool_key, человекочитаемый comment, произвольный payload и approval_status (pending|approved|rejected); само решение фиксируется company-scoped маршрутами approve/reject.
POST /conversations/{id}/ai-tools/summary возвращает краткое ИИ-резюме диалога для передачи смены (summary_text, message_count, tokens_used); требует фичи ai_agents на уровне маршрута (без неё — 403 feature_not_available), принимает необязательный locale (иначе берётся язык приложения), действует лимит 60 запросов ИИ-ассистента в час на компанию (429 ai_assist_rate_limited), пустой диалог — 422 empty_conversation, ошибка провайдера — 502 ai_provider_error.
Групповые чаты
Групповые чаты (WhatsApp-группы и т.п.) обслуживаются отдельными маршрутами: GET /group-chats/{id}/participants возвращает карточку группы и постраничный (page/per_page, по умолчанию 50) список участников с ролями (superadmin|admin|member, отсортированы по старшинству), а POST /group-chats/{id}/refresh принудительно перезапрашивает метаданные группы из мессенджер-рантайма (503, если у канала нет рантайм-инстанса или рантайм не принял запрос) и отдаёт обновлённый состав.
Значения перечислений
Значения перечислений в телах запросов:
- Участники добавляются с
member_type(user|team|bot). - События — с
type(created|comment|status_changed|archived|unarchived|assigned|unassigned). - Метки — с
source(manual|automation|integration).
Файлы и медиа
GET /conversations/{conversation}/attachments отдаёт постраничную галерею вложений диалога для контекст-панели (все треды диалога, с учётом доступных пользователю каналов); необязательный kind фильтрует по image|video|document|audio. Каждая строка — {attachment_id, message_id, kind, mime_type, size, name, thumb_url, created_at}; thumb_url минтится только для image/video (для остальных kind — null) как короткоживущая (20 минут) подписанная ссылка на тот же роут .../media с w=640 (webp-превью) — в отличие от постоянной подписи MessageAttachmentResource.url, срок жизни ограничен намеренно, чтобы страница галереи не была способом массово выгрузить бессрочные ссылки на медиа.
Эндпоинты
| Метод | Путь | Описание |
|---|---|---|
| GET | /v1/conversations/countersСчётчики диалогов по статусам (all/awaiting/unread/assigned/unassigned/my_team/archived/groups/aisar_notifications); aisar_notifications = число непрочитанных platform_notifications компании. | Счётчики диалогов по статусам (all/awaiting/unread/assigned/unassigned/my_team/archived/groups/aisar_notifications); aisar_notifications = число непрочитанных platform_notifications компании. |
| GET | /v1/conversationsСписок диалогов компании с пагинацией и фильтрами. | Список диалогов компании с пагинацией и фильтрами. |
| POST | /v1/conversationsСоздать новый диалог для контакта. | Создать новый диалог для контакта. |
| GET | /v1/conversations/{conversation}Получить диалог по id (с контактом, тредами, участниками). | Получить диалог по id (с контактом, тредами, участниками). |
| PATCH | /v1/conversations/{conversation}Обновить поля диалога (тема, статус жизненного цикла, архивация). | Обновить поля диалога (тема, статус жизненного цикла, архивация). |
| DELETE | /v1/conversations/{conversation}Удалить диалог (мягкое удаление). | Удалить диалог (мягкое удаление). |
| POST | /v1/conversations/{conversation}/closeЗакрыть диалог с обязательным комментарием. | Закрыть диалог с обязательным комментарием. |
| POST | /v1/conversations/{conversation}/openОткрыть (переоткрыть) закрытый диалог. | Открыть (переоткрыть) закрытый диалог. |
| POST | /v1/conversations/{conversation}/archiveАрхивировать диалог. | Архивировать диалог. |
| POST | /v1/conversations/{conversation}/unarchiveРазархивировать диалог. | Разархивировать диалог. |
| POST | /v1/conversations/{conversation}/dismiss-awaitingПометить диалог как «не требует ответа» — обнуляет awaiting_since до следующего входящего сообщения. | Пометить диалог как «не требует ответа» — обнуляет awaiting_since до следующего входящего сообщения. |
| GET | /v1/conversations/{conversation}/participantsСписок участников диалога (операторы, команды, боты). | Список участников диалога (операторы, команды, боты). |
| POST | /v1/conversations/{conversation}/participantsДобавить участника — например назначить оператора ответственным (is_primary). | Добавить участника — например назначить оператора ответственным (is_primary). |
| DELETE | /v1/conversations/{conversation}/participants/{participant}Удалить участника из диалога (снять назначение). | Удалить участника из диалога (снять назначение). |
| GET | /v1/conversations/{conversation}/tagsСписок меток диалога. | Список меток диалога. |
| POST | /v1/conversations/{conversation}/tagsДобавить метку к диалогу. | Добавить метку к диалогу. |
| DELETE | /v1/conversations/{conversation}/tags/{tag}Снять метку с диалога. | Снять метку с диалога. |
| GET | /v1/conversations/{conversation}/notesСписок внутренних заметок по диалогу. | Список внутренних заметок по диалогу. |
| POST | /v1/conversations/{conversation}/notesДобавить внутреннюю заметку (не видна контакту). | Добавить внутреннюю заметку (не видна контакту). |
| PATCH | /v1/conversations/{conversation}/notes/{note}Изменить текст заметки. | Изменить текст заметки. |
| DELETE | /v1/conversations/{conversation}/notes/{note}Удалить заметку. | Удалить заметку. |
| GET | /v1/conversations/{conversation}/eventsХронология событий диалога (создание, комментарии, смена статуса, назначения). | Хронология событий диалога (создание, комментарии, смена статуса, назначения). |
| POST | /v1/conversations/{conversation}/eventsЗаписать событие в хронологию диалога (например комментарий оператора). | Записать событие в хронологию диалога (например комментарий оператора). |
| GET | /v1/conversations/{conversation}/attachmentsПостраничная галерея вложений диалога (все треды; фильтр kind=image|video|document|audio) для контекст-панели «Файлы и медиа». | Постраничная галерея вложений диалога (все треды; фильтр kind=image|video|document|audio) для контекст-панели «Файлы и медиа». |
| GET | /v1/conversations/{conversation}/threadsСписок тредов (переписок по каналам) внутри диалога. | Список тредов (переписок по каналам) внутри диалога. |
| POST | /v1/conversations/{conversation}/threadsСоздать новый тред в существующем диалоге для дополнительного канала. | Создать новый тред в существующем диалоге для дополнительного канала. |
| GET | /v1/conversations/{conversation}/threads/{thread}Получить тред по id. | Получить тред по id. |
| PATCH | /v1/conversations/{conversation}/threads/{thread}Обновить тред (воронка/стадия, external_thread_id и др.). | Обновить тред (воронка/стадия, external_thread_id и др.). |
| GET | /v1/conversations/{conversation}/threads/{thread}/eventsХронология событий конкретного треда. | Хронология событий конкретного треда. |
| POST | /v1/conversations/{conversation}/threads/{thread}/eventsЗаписать событие в хронологию треда. | Записать событие в хронологию треда. |
| GET | /v1/threadsКросс-диалоговый список тредов (режим отображения «по каналам») с фильтрами, пагинацией и счётчиками. | Кросс-диалоговый список тредов (режим отображения «по каналам») с фильтрами, пагинацией и счётчиками. |
| POST | /v1/threads/{thread}/closeЗакрыть отдельный тред (независимо от диалога). | Закрыть отдельный тред (независимо от диалога). |
| POST | /v1/threads/{thread}/openОткрыть (переоткрыть) отдельный тред; 422, если у контакта уже есть активный диалог. | Открыть (переоткрыть) отдельный тред; 422, если у контакта уже есть активный диалог. |
| POST | /v1/threads/{thread}/archiveАрхивировать отдельный тред. | Архивировать отдельный тред. |
| POST | /v1/threads/{thread}/unarchiveРазархивировать отдельный тред. | Разархивировать отдельный тред. |
| GET | /v1/conversations/{conversation}/readsRead-статусы диалога (кто и до какого момента прочитал); фильтры thread_id/user_id. | Read-статусы диалога (кто и до какого момента прочитал); фильтры thread_id/user_id. |
| POST | /v1/conversations/{conversation}/readsВыставить позицию прочтения текущего пользователя (last_read_message_id / last_read_at). | Выставить позицию прочтения текущего пользователя (last_read_message_id / last_read_at). |
| POST | /v1/conversations/mark-readПометить все (или указанные) диалоги компании прочитанными. | Пометить все (или указанные) диалоги компании прочитанными. |
| POST | /v1/conversations/{conversation}/mark-readПометить конкретный диалог (или тред в нём) прочитанным. | Пометить конкретный диалог (или тред в нём) прочитанным. |
| POST | /v1/conversations/{conversation}/mark-unreadОтметить диалог (или его тред) непрочитанным — отматывает курсор к последнему входящему сообщению. | Отметить диалог (или его тред) непрочитанным — отматывает курсор к последнему входящему сообщению. |
| POST | /v1/conversations/{conversation}/ai-suggestions/generateСгенерировать черновик ответа ИИ-копилота для диалога. | Сгенерировать черновик ответа ИИ-копилота для диалога. |
| POST | /v1/conversations/{conversation}/ai-suggestions/{suggestion}/acceptПринять подсказку (опционально с отредактированным final_text). | Принять подсказку (опционально с отредактированным final_text). |
| POST | /v1/conversations/{conversation}/ai-suggestions/{suggestion}/rejectОтклонить подсказку копилота. | Отклонить подсказку копилота. |
| GET | /v1/conversations/{conversation}/ai-pending-actionsОчередь действий ИИ-агента по диалогу, ожидающих подтверждения оператора. | Очередь действий ИИ-агента по диалогу, ожидающих подтверждения оператора. |
| POST | /v1/conversations/{conversation}/ai-tools/summaryСгенерировать краткое ИИ-резюме диалога (для передачи смены). | Сгенерировать краткое ИИ-резюме диалога (для передачи смены). |
| GET | /v1/group-chats/{groupChat}/participantsКарточка группового чата и постраничный список участников с ролями. | Карточка группового чата и постраничный список участников с ролями. |
| POST | /v1/group-chats/{groupChat}/refreshПерезапросить метаданные и состав группового чата из мессенджер-рантайма. | Перезапросить метаданные и состав группового чата из мессенджер-рантайма. |
| POST | /v1/dialogsСоздать диалог по идентификатору аккаунта: contact → conversation → thread за один вызов. | Создать диалог по идентификатору аккаунта: contact → conversation → thread за один вызов. |
| GET | /v1/dialogs/lookupНайти существующий активный диалог по каналу и аккаунту (channel_id, account). | Найти существующий активный диалог по каналу и аккаунту (channel_id, account). |
Примеры
Список неназначенных диалогов
Запрос
curl -X GET "https://api.aisar.app/v1/conversations?thread_filter=unassigned&perPage=20" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"Ответ
{
"data": {
"items": [
{
"id": 15,
"company_id": 1,
"contact_id": 45,
"subject": null,
"lifecycle_status": "active",
"is_closed": false,
"is_archived": false,
"last_message_id": 1001,
"last_message_at": "2026-02-09T18:00:00Z",
"last_message": { "id": 1001, "message_content": { "text": "Здравствуйте, подскажите по заказу" }, "direction": "inbound" },
"unread_count_for_current_user": 1,
"awaiting_since": "2026-02-09T18:00:00Z",
"closed_at": null,
"archived_at": null,
"created_at": "2026-02-09T17:00:00Z",
"updated_at": "2026-02-09T18:00:00Z",
"contact": { "id": 45, "displayName": "John Doe", "phones": [{ "phone": "+77001234567", "type": "mobile" }] },
"threads": [{ "id": 33, "channel_id": 3, "is_group": false }]
}
],
"pagination": { "page": 1, "perPage": 20, "total": 1, "lastPage": 1 },
"counters": { "all": 120, "awaiting": 21, "unread": 14, "assigned": 47, "unassigned": 73, "my_team": 32, "archived": 9, "groups": 6, "aisar_notifications": 3 }
}
}Фильтрация и сортировка списка
Запрос
curl -X GET "https://api.aisar.app/v1/conversations?funnel_id=1&funnel_stage_ids=3,4&unread_only=1&sortBy=last_message_at&sortDir=desc&perPage=20&include_counters=1" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"Ответ
{
"data": {
"items": [
{
"id": 22,
"company_id": 1,
"contact_id": 51,
"lifecycle_status": "active",
"is_archived": false,
"last_message_id": 1104,
"last_message_at": "2026-02-09T19:40:00Z",
"unread_count_for_current_user": 2,
"awaiting_since": null,
"contact": { "id": 51, "displayName": "Jane Roe", "phones": [{ "phone": "+77000000456", "type": "mobile" }] },
"threads": [{ "id": 40, "channel_id": 3, "is_group": false }]
}
],
"pagination": { "page": 1, "perPage": 20, "total": 1, "lastPage": 1 },
"counters": { "all": 120, "awaiting": 21, "unread": 14, "assigned": 47, "unassigned": 73, "my_team": 32, "archived": 9, "groups": 6, "aisar_notifications": 3 }
}
}Кросс-диалоговый список тредов
Запрос
curl -X GET "https://api.aisar.app/v1/threads?thread_filter=unread&sortBy=last_message_at&sortDir=desc&perPage=20" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"Ответ
{
"data": {
"items": [
{
"id": 33,
"conversation_id": 15,
"company_id": 1,
"channel_id": 3,
"contact_account_id": 78,
"is_group": false,
"external_thread_id": null,
"lifecycle_status": "active",
"is_closed": false,
"is_archived": false,
"closed_at": null,
"archived_at": null,
"last_message_id": 1001,
"last_message_at": "2026-02-09T18:00:00Z",
"unread_count_for_current_user": 1,
"contact_id": 45,
"created_at": "2026-02-09T17:00:00Z",
"updated_at": "2026-02-09T18:00:00Z"
}
],
"pagination": { "page": 1, "perPage": 20, "total": 1, "lastPage": 1 },
"counters": { "all": 84, "awaiting": 12, "unread": 6, "assigned": 30, "unassigned": 54, "my_team": 18, "archived": 4 }
}
}Закрытие отдельного треда
Запрос
curl -X POST "https://api.aisar.app/v1/threads/33/close" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"comment": "Вопрос по этому каналу закрыт."
}'Ответ
{
"data": {
"message": "Thread closed.",
"thread": {
"id": 33,
"conversation_id": 15,
"channel_id": 3,
"lifecycle_status": "closed",
"is_closed": true,
"is_archived": false,
"closed_at": "2026-02-09T19:00:00Z"
}
}
}Read-статусы диалога
Запрос
curl -X GET "https://api.aisar.app/v1/conversations/15/reads" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"Ответ
{
"data": {
"items": [
{
"id": 8,
"company_id": 1,
"conversation_id": 15,
"thread_id": 33,
"user_id": 5,
"last_read_message_id": 1001,
"first_read_at": "2026-02-09T18:02:00Z",
"last_read_at": "2026-02-09T18:20:00Z",
"created_at": "2026-02-09T18:02:00Z",
"updated_at": "2026-02-09T18:20:00Z",
"user": { "id": 5, "name": "Alex", "lastname": "Ivanov", "email": "alex@example.com" }
}
],
"pagination": { "page": 1, "perPage": 20, "total": 1, "lastPage": 1 }
}
}Выставить позицию прочтения
Запрос
curl -X POST "https://api.aisar.app/v1/conversations/15/reads" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"thread_id": 33,
"last_read_message_id": 1001
}'Ответ
{
"data": {
"message": "Conversation read state updated.",
"item": {
"id": 8,
"company_id": 1,
"conversation_id": 15,
"thread_id": 33,
"user_id": 5,
"last_read_message_id": 1001,
"first_read_at": "2026-02-09T18:02:00Z",
"last_read_at": "2026-02-09T18:00:00Z",
"created_at": "2026-02-09T18:02:00Z",
"updated_at": "2026-02-09T18:25:00Z"
}
}
}Отметить диалог непрочитанным
Запрос
curl -X POST "https://api.aisar.app/v1/conversations/15/mark-unread" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"thread_id": 33
}'Ответ
{
"data": {
"message": "Conversation marked as unread.",
"item": {
"id": 8,
"company_id": 1,
"conversation_id": 15,
"thread_id": 33,
"user_id": 5,
"last_read_message_id": 999,
"first_read_at": "2026-02-09T18:02:00Z",
"last_read_at": "2026-02-09T17:59:59Z",
"created_at": "2026-02-09T18:02:00Z",
"updated_at": "2026-02-09T18:35:00Z"
},
"unread_count": 1,
"shared_read_receipts": false
}
}Черновик ответа ИИ-копилота
Запрос
curl -X POST "https://api.aisar.app/v1/conversations/15/ai-suggestions/generate" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"Ответ
{
"data": {
"id": 5821,
"instance_id": 12,
"conversation_id": 15,
"message_id": null,
"suggested_text": "Здравствуйте! Доставка по городу занимает 1-2 дня.",
"status": "pending",
"accepted_by": null,
"final_text": null,
"tokens_used": 184,
"created_at": "2026-02-09T18:30:00Z",
"updated_at": "2026-02-09T18:30:00Z"
}
}Принять подсказку копилота
Запрос
curl -X POST "https://api.aisar.app/v1/conversations/15/ai-suggestions/5821/accept" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"final_text": "Здравствуйте! Доставка по городу занимает 1-2 дня, курьер согласует время."
}'Ответ
{
"data": {
"id": 5821,
"instance_id": 12,
"conversation_id": 15,
"message_id": null,
"suggested_text": "Здравствуйте! Доставка по городу занимает 1-2 дня.",
"status": "accepted",
"accepted_by": 5,
"final_text": "Здравствуйте! Доставка по городу занимает 1-2 дня, курьер согласует время.",
"tokens_used": 184,
"created_at": "2026-02-09T18:30:00Z",
"updated_at": "2026-02-09T18:31:00Z"
}
}Закрытие диалога
Запрос
curl -X POST "https://api.aisar.app/v1/conversations/15/close" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"comment": "Вопрос клиента решён, заказ подтверждён."
}'Ответ
{
"data": {
"message": "Conversation closed.",
"conversation": {
"id": 15,
"lifecycle_status": "closed",
"is_closed": true,
"closed_at": "2026-02-09T18:20:00Z"
}
}
}Создание диалога по номеру телефона
Запрос
curl -X POST "https://api.aisar.app/v1/dialogs" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"channel_id": 3,
"account": "+77000000123",
"is_group": false,
"comment": "Первое касание по заявке с сайта"
}'Ответ
{
"data": {
"message": "Dialog created.",
"thread": {
"id": 33,
"conversation_id": 15,
"channel_id": 3,
"contact_account_id": 78,
"is_group": false,
"created_at": "2026-02-09T17:00:00Z"
}
}
}Поиск существующего диалога
Запрос
curl -X GET "https://api.aisar.app/v1/dialogs/lookup?channel_id=3&account=%2B77000000123" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"Ответ
{
"data": {
"thread_id": 42,
"conversation_id": 15,
"contact_account_id": 78
}
}Добавление треда в диалог (второй канал)
Запрос
curl -X POST "https://api.aisar.app/v1/conversations/15/threads" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"channel_id": 7,
"contact_account_id": 78,
"funnel_id": 1,
"funnel_stage_id": 3,
"is_group": false,
"external_thread_id": null
}'Ответ
{
"data": {
"id": 34,
"conversation_id": 15,
"channel_id": 7,
"contact_account_id": 78,
"funnel_id": 1,
"funnel_stage_id": 3,
"is_group": false,
"external_thread_id": null,
"created_at": "2026-02-09T18:30:00Z"
}
}Назначение оператора участником
Запрос
curl -X POST "https://api.aisar.app/v1/conversations/15/participants" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"member_type": "user",
"member_id": 5,
"role": "assignee",
"is_primary": true
}'Ответ
{
"data": {
"id": 61,
"conversation_id": 15,
"member_type": "user",
"member_id": 5,
"role": "assignee",
"is_primary": true,
"created_at": "2026-02-09T18:05:00Z"
}
}Запись события в хронологию диалога
Запрос
curl -X POST "https://api.aisar.app/v1/conversations/15/events" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "comment",
"comment": "Клиент просит перезвонить после 18:00",
"thread_id": 33
}'Ответ
{
"data": {
"id": 900,
"conversation_id": 15,
"thread_id": 33,
"type": "comment",
"comment": "Клиент просит перезвонить после 18:00",
"created_at": "2026-02-09T18:10:00Z"
}
}Добавление внутренней заметки
Запрос
curl -X POST "https://api.aisar.app/v1/conversations/15/notes" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"body": "Постоянный клиент, дать скидку 10%",
"is_private": true,
"thread_id": null
}'Ответ
{
"data": {
"id": 77,
"conversation_id": 15,
"thread_id": null,
"body": "Постоянный клиент, дать скидку 10%",
"is_private": true,
"pinned_at": null,
"created_at": "2026-02-09T18:12:00Z"
}
}Добавление метки к диалогу
Запрос
curl -X POST "https://api.aisar.app/v1/conversations/15/tags" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "vip",
"color": "#e11d48",
"source": "manual"
}'Ответ
{
"data": {
"id": 12,
"conversation_id": 15,
"name": "vip",
"color": "#e11d48",
"source": "manual",
"created_at": "2026-02-09T18:15:00Z"
}
}Массовая отметка диалогов прочитанными (202 — ставится в очередь)
Запрос
curl -X POST "https://api.aisar.app/v1/conversations/mark-read" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"conversation_ids": [15, 16, 22]
}'Ответ
{
"data": {
"message": "Conversations marked as read."
}
}Действия ИИ-агента, ожидающие подтверждения
Запрос
curl -X GET "https://api.aisar.app/v1/conversations/15/ai-pending-actions" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"Ответ
{
"data": {
"items": [
{
"id": 4120,
"conversation_id": 15,
"tool_key": "close_conversation",
"comment": "AI agent proposed to close the conversation (reason: customer confirmed the order)",
"payload": {
"tool_key": "close_conversation",
"ai_agent_instance_id": 12,
"reason": "customer confirmed the order"
},
"approval_status": "pending",
"resolved_at": null,
"approved_by_user_id": null,
"rejected_by_user_id": null,
"rejected_reason": null,
"execution_result": null,
"created_at": "2026-02-09T18:40:00.000000Z",
"conversation": null
}
]
}
}ИИ-резюме диалога для передачи смены
Запрос
curl -X POST "https://api.aisar.app/v1/conversations/15/ai-tools/summary" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"locale": "ru"
}'Ответ
{
"data": {
"summary_text": "- Клиент спрашивал про сроки доставки по городу.\n- Оператор ответил, что доставка занимает 1–2 дня, курьер согласует время.\n- Статус: заказ подтверждён, клиент ожидает звонка курьера.",
"message_count": 14,
"tokens_used": 512
}
}Диалог пуст — резюме невозможно (422)
Запрос
curl -X POST "https://api.aisar.app/v1/conversations/15/ai-tools/summary" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'Ответ
{
"data": {
"message": "Conversation has no messages to summarise",
"code": "empty_conversation"
}
}Участники группового чата
Запрос
curl -X GET "https://api.aisar.app/v1/group-chats/8/participants?page=1&per_page=50" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"Ответ
{
"data": {
"group_chat": {
"id": 8,
"external_group_id": "120363000000000001@g.us",
"subject": "Отдел продаж — клиенты",
"description": "Рабочая группа по заявкам",
"photo": null,
"announce": false,
"restrict": false,
"size": 3,
"updated_at": "2026-02-09T18:00:00.000000Z"
},
"participants": [
{
"id": 51,
"role": "superadmin",
"display_name": "Alex Ivanov",
"photo": null,
"phone": "77000000123",
"contact_account_id": 78,
"external_id": "77000000123"
},
{
"id": 52,
"role": "member",
"display_name": "Jane Roe",
"photo": null,
"phone": "77000000456",
"contact_account_id": 79,
"external_id": "77000000456"
}
],
"pagination": { "page": 1, "per_page": 50, "total": 3, "last_page": 1 }
}
}Обновление состава группового чата из рантайма
Запрос
curl -X POST "https://api.aisar.app/v1/group-chats/8/refresh" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"Ответ
{
"data": {
"group_chat": {
"id": 8,
"external_group_id": "120363000000000001@g.us",
"subject": "Отдел продаж — клиенты",
"description": "Рабочая группа по заявкам",
"photo": null,
"announce": false,
"restrict": false,
"size": 4,
"updated_at": "2026-02-09T18:45:00.000000Z"
},
"participants": [],
"pagination": { "page": 1, "per_page": 50, "total": 4, "last_page": 1 }
}
}Обновление невозможно — у канала нет рантайм-инстанса (503)
Запрос
curl -X POST "https://api.aisar.app/v1/group-chats/8/refresh" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"Ответ
{
"message": "Channel has no runtime instance"
}Пометить диалог «не требует ответа»
Запрос
curl -X POST "https://api.aisar.app/v1/conversations/15/dismiss-awaiting" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"Ответ
{
"data": {
"id": 15,
"awaiting_since": null
}
}