---
title: "Идемпотентно отправить текстовое сообщение"
method: POST
path: "/api/v1/chat/conversations/{id}/messages"
tags: ["Chat"]
---

# Идемпотентно отправить текстовое сообщение

`POST /api/v1/chat/conversations/{id}/messages`

## Request

- Base URL: `https://erp.akeda.ru`
- URL: `https://erp.akeda.ru/api/v1/chat/conversations/{id}/messages`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://erp.akeda.ru/oauth2/authorize`, token URL `https://erp.akeda.ru/oauth2/token`, scopes: `akeda:delegate`)

Один client_message_id с другим canonical body возвращает 409 без echo исходного текста. При создании сообщения сервер в той же транзакции отмечает для автора прочитанной предшествующую ленту до new_seq - 1; повтор запроса watermark заново не двигает. mention_user_ids — только участники беседы: упоминание постороннего отклоняет сообщение целиком (422, code=mention_not_member), уведомление не уходит. Исключение — беседа задачи: упомянутый до отправки становится наблюдателем задачи и участником беседы и получает уведомление (CHAT.md § 3.3).

## Request body

- ChatSendMessage
  - `client_message_id` string, uuid, required
  - `body` string: Текст сообщения; без attachment_ids обязателен, с ними — подпись к вложениям и может быть пустым. Предел считается в кодовых точках, а не в байтах: сервер режет по 10 000 кодовых точек
  - `reply_to_message_id` string, uuid
  - `mention_user_ids` integer[]
  - `attachment_ids` UUID[]: Готовые вложения этой беседы — id из завершения сессии загрузки или из списка вложений. Не сочетаются с mention_user_ids в одном сообщении
  - `reply_quote` string: Цитата части исходного сообщения, как в Телеграме: дословный кусок его текста, не длиннее 1024 кодовых точек. Только вместе с reply_to_message_id; фрагмента нет в исходном — 404. Пустая строка — ответ на сообщение целиком
  - `support_report` boolean: Сообщение формы «Сообщить об ошибке». В чате поддержки открывает новое обращение и новую заявку, даже если в беседе уже есть открытое; обычное сообщение продолжает открытое. В любой другой беседе — 400

## Response `200`

Повтор ранее зафиксированной отправки

- ChatSendMessageResult
  - `message` ChatMessage, required
    - `id` string, uuid, required
    - `conversation_id` string, uuid, required
    - `seq` integer, required
    - `sender_user_id` integer, nullable, required
    - `kind` 'text' | 'system' | 'application' | 'file', required
    - `body` string, required
    - `mentions` ChatMessageMention[], required
      - `user_id` integer, required
      - `display_name` string, required
    - `client_message_id` string, uuid, required
    - `created_at` string, date-time, required
    - `attachments` ChatAttachment[], required
      - `id` string, uuid, required
      - `original_name` string, required
      - `content_type` 'audio/mp4' | 'audio/webm' | 'audio/ogg' | 'video/mp4' | 'video/quicktime', required
      - `size_bytes` integer, required
      - `sha256_hex` string, required
      - `media_kind` 'voice' | 'video_circle', required
      - `duration_ms` integer, required
      - `content_url` string, required
    - `reply_to_message_id` string, uuid, nullable
    - `forwarded_from_message_id` string, uuid, nullable: Пересланное: исходное сообщение. Нет у обычных сообщений
    - `forwarded_from_user_id` integer: Пересланное: автор оригинала — участник кабинета (ERP-1964, «Переслано от …»). При пересылке пересланного — тот, кто написал первым. Нет у обычных и у старых пересланных сообщений
    - `forwarded_from_name` string: Пересланное: подпись автора оригинала, когда участника нет в справочнике людей, — имя под ответом поддержки или название исходной беседы. Нет у обычных и у старых пересланных сообщений
    - `reply_quote` string: Цитата части исходного сообщения; поля нет, когда ответ на сообщение целиком, исходное удалено или недоступно
    - `deleted_at` string, date-time, nullable: Надгробие: сообщение удалено у всех. Тела, вложений, упоминаний и реакций у него нет; показывать его в ленте не нужно
  - `created` boolean, required

## Other responses

- `201`: Новое сообщение
- `400`: Некорректный запрос или нарушение бизнес-правила
- `401`: Сессия, ключ или кабинет не подтверждены
- `403`: Текущая роль не имеет требуемого права
- `404`: Запись не найдена или не видима текущему пользователю
- `409`: Конфликт версии, идемпотентности или бизнес-состояния
- `422`: Запрос разобран, но бизнес-значение недопустимо

---

[API](https://skmtc.dev/akeda/apis/akeda-erp-client-api.md) · [All operations](https://skmtc.dev/akeda/apis/akeda-erp-client-api/llms.txt) · [OpenAPI document](https://skmtc.dev/akeda/apis/akeda-erp-client-api/revisions/3c60ded179f2?raw)
