Перейти к содержимому
AISARAISAR
REST API

Диалоги

Диалог (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 (для остальных kindnull) как короткоживущая (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 компании.

GET/v1/conversations

Список диалогов компании с пагинацией и фильтрами.

POST/v1/conversations

Создать новый диалог для контакта.

GET/v1/conversations/{conversation}

Получить диалог по 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 до следующего входящего сообщения.

GET/v1/conversations/{conversation}/participants

Список участников диалога (операторы, команды, боты).

POST/v1/conversations/{conversation}/participants

Добавить участника — например назначить оператора ответственным (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) для контекст-панели «Файлы и медиа».

GET/v1/conversations/{conversation}/threads

Список тредов (переписок по каналам) внутри диалога.

POST/v1/conversations/{conversation}/threads

Создать новый тред в существующем диалоге для дополнительного канала.

GET/v1/conversations/{conversation}/threads/{thread}

Получить тред по id.

PATCH/v1/conversations/{conversation}/threads/{thread}

Обновить тред (воронка/стадия, 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, если у контакта уже есть активный диалог.

POST/v1/threads/{thread}/archive

Архивировать отдельный тред.

POST/v1/threads/{thread}/unarchive

Разархивировать отдельный тред.

GET/v1/conversations/{conversation}/reads

Read-статусы диалога (кто и до какого момента прочитал); фильтры thread_id/user_id.

POST/v1/conversations/{conversation}/reads

Выставить позицию прочтения текущего пользователя (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).

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 за один вызов.

GET/v1/dialogs/lookup

Найти существующий активный диалог по каналу и аккаунту (channel_id, account).

Примеры

Список неназначенных диалогов

Запрос

bash
curl -X GET "https://api.aisar.app/v1/conversations?thread_filter=unassigned&perPage=20" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json"

Ответ

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 }
  }
}

Фильтрация и сортировка списка

Запрос

bash
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"

Ответ

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 }
  }
}

Кросс-диалоговый список тредов

Запрос

bash
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"

Ответ

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 }
  }
}

Закрытие отдельного треда

Запрос

bash
curl -X POST "https://api.aisar.app/v1/threads/33/close" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "comment": "Вопрос по этому каналу закрыт."
  }'

Ответ

json
{
  "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-статусы диалога

Запрос

bash
curl -X GET "https://api.aisar.app/v1/conversations/15/reads" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json"

Ответ

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 }
  }
}

Выставить позицию прочтения

Запрос

bash
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
  }'

Ответ

json
{
  "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"
    }
  }
}

Отметить диалог непрочитанным

Запрос

bash
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
  }'

Ответ

json
{
  "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
  }
}

Черновик ответа ИИ-копилота

Запрос

bash
curl -X POST "https://api.aisar.app/v1/conversations/15/ai-suggestions/generate" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json"

Ответ

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"
  }
}

Принять подсказку копилота

Запрос

bash
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 дня, курьер согласует время."
  }'

Ответ

json
{
  "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"
  }
}

Закрытие диалога

Запрос

bash
curl -X POST "https://api.aisar.app/v1/conversations/15/close" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "comment": "Вопрос клиента решён, заказ подтверждён."
  }'

Ответ

json
{
  "data": {
    "message": "Conversation closed.",
    "conversation": {
      "id": 15,
      "lifecycle_status": "closed",
      "is_closed": true,
      "closed_at": "2026-02-09T18:20:00Z"
    }
  }
}

Создание диалога по номеру телефона

Запрос

bash
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": "Первое касание по заявке с сайта"
  }'

Ответ

json
{
  "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"
    }
  }
}

Поиск существующего диалога

Запрос

bash
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"

Ответ

json
{
  "data": {
    "thread_id": 42,
    "conversation_id": 15,
    "contact_account_id": 78
  }
}

Добавление треда в диалог (второй канал)

Запрос

bash
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
  }'

Ответ

json
{
  "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"
  }
}

Назначение оператора участником

Запрос

bash
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
  }'

Ответ

json
{
  "data": {
    "id": 61,
    "conversation_id": 15,
    "member_type": "user",
    "member_id": 5,
    "role": "assignee",
    "is_primary": true,
    "created_at": "2026-02-09T18:05:00Z"
  }
}

Запись события в хронологию диалога

Запрос

bash
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
  }'

Ответ

json
{
  "data": {
    "id": 900,
    "conversation_id": 15,
    "thread_id": 33,
    "type": "comment",
    "comment": "Клиент просит перезвонить после 18:00",
    "created_at": "2026-02-09T18:10:00Z"
  }
}

Добавление внутренней заметки

Запрос

bash
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
  }'

Ответ

json
{
  "data": {
    "id": 77,
    "conversation_id": 15,
    "thread_id": null,
    "body": "Постоянный клиент, дать скидку 10%",
    "is_private": true,
    "pinned_at": null,
    "created_at": "2026-02-09T18:12:00Z"
  }
}

Добавление метки к диалогу

Запрос

bash
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"
  }'

Ответ

json
{
  "data": {
    "id": 12,
    "conversation_id": 15,
    "name": "vip",
    "color": "#e11d48",
    "source": "manual",
    "created_at": "2026-02-09T18:15:00Z"
  }
}

Массовая отметка диалогов прочитанными (202 — ставится в очередь)

Запрос

bash
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]
  }'

Ответ

json
{
  "data": {
    "message": "Conversations marked as read."
  }
}

Действия ИИ-агента, ожидающие подтверждения

Запрос

bash
curl -X GET "https://api.aisar.app/v1/conversations/15/ai-pending-actions" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json"

Ответ

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
      }
    ]
  }
}

ИИ-резюме диалога для передачи смены

Запрос

bash
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"
  }'

Ответ

json
{
  "data": {
    "summary_text": "- Клиент спрашивал про сроки доставки по городу.\n- Оператор ответил, что доставка занимает 1–2 дня, курьер согласует время.\n- Статус: заказ подтверждён, клиент ожидает звонка курьера.",
    "message_count": 14,
    "tokens_used": 512
  }
}

Диалог пуст — резюме невозможно (422)

Запрос

bash
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 '{}'

Ответ

json
{
  "data": {
    "message": "Conversation has no messages to summarise",
    "code": "empty_conversation"
  }
}

Участники группового чата

Запрос

bash
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"

Ответ

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 }
  }
}

Обновление состава группового чата из рантайма

Запрос

bash
curl -X POST "https://api.aisar.app/v1/group-chats/8/refresh" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json"

Ответ

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)

Запрос

bash
curl -X POST "https://api.aisar.app/v1/group-chats/8/refresh" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json"

Ответ

json
{
  "message": "Channel has no runtime instance"
}

Пометить диалог «не требует ответа»

Запрос

bash
curl -X POST "https://api.aisar.app/v1/conversations/15/dismiss-awaiting" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Accept: application/json"

Ответ

json
{
  "data": {
    "id": 15,
    "awaiting_since": null
  }
}