Интеграции без открытых сообщений.
Управляйте чатами, участниками, сообщениями, файлами и уведомлениями через единый REST API. Шифрование и расшифровка выполняются в вашем доверенном клиенте.
Авторизация
Создайте API-токен в настройках приложения. Передавайте его в заголовке Authorization: Bearer <token>. Scope read разрешает чтение, write — изменение; для обоих действий нужны оба scope. Срок токена — до 365 дней. Управление токенами требует обычной сессии.
curl https://chat.example.com/api/v1/chats \ -H 'Authorization: Bearer YOUR_TOKEN'
Все идентификаторы — UUID, даты — RFC3339, JSON — camelCase. Ошибки: {"error":{"code":"...","message":"Сообщение на русском"}}.
Как отправить сообщение
- Получите актуальный чат и публичные ключи участников.
- Зашифруйте файлы отдельными AES-256-GCM ключами, загрузите ciphertext и получите ID.
- Зашифруйте
MessageContentсвежим ключом AES-256-GCM; оберните ключ для каждого участника через RSA-OAEP SHA-256. - Подпишите envelope ключом отправителя ECDSA P-256 и отправьте его вместе с
clientIdи ID вложений.
Ключи API-токена недостаточно для расшифровки. Приватные ключи аккаунта должны оставаться в доверенной среде интеграции. Recovery key у новых аккаунтов — 5 английских слов; старые base64url ключи остаются совместимы. Точная канонизация подписи и AAD описана в описании протокола. Схемы MessageContent и Attachment относятся к расшифрованным данным клиента.
Онлайн-консультации
Зарегистрированный оператор создаёт модуль POST /api/v1/livechat/site и вставляет выданный скрипт на сайт. Виджет открывается в iframe, создаёт гостевого посетителя и групповой чат с оператором. Переписка использует тот же E2EE envelope; сервер хранит только зашифрованные сообщения.
AI-ассистент
POST /api/v1/ai/messages отправляет текст в закреплённый чат STIX AI. Этот отдельный чат не является E2EE: его текст нужен серверу для запроса к OpenAI. Обычные личные, групповые и livechat-чаты ассистенту недоступны.
Обновления и повтор запросов
SSE доступен через GET /api/v1/events с Authorization. После переподключения перечитайте REST-данные. Повтор отправки с тем же clientId идемпотентен. При изменении состава группы получите чат снова и заново зашифруйте сообщение для актуальных участников.
Методы
GET/api/v1/configКонфигурация клиента
Публичный метод
Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Config"
}
}
}
},
"503": {
"$ref": "#/components/responses/Unavailable"
},
"403": {
"$ref": "#/components/responses/Forbidden"
}
}GET/api/v1/statsПубличная статистика
Публичный метод
Возвращает только агрегированное число активных обычных зарегистрированных аккаунтов. Персональные данные не раскрываются.
Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PublicStats"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}POST/api/v1/auth/start-loginНачать вход без SMS
Публичный метод
Публичный шаг входа. Если номер зарегистрирован, сервер возвращает профиль, keyBackup и одноразовый challenge. Клиент расшифровывает keyBackup локально ключом из 5 слов или QR-переносом и подписывает challenge приватным P-256 ключом. SMS не отправляется. Если номера нет, вернётся registered=false, после чего клиент запрашивает SMS для регистрации.
Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"phone": {
"type": "string",
"pattern": "^\\+[1-9][0-9]{7,14}$",
"examples": [
"+79991234567"
]
}
},
"required": [
"phone"
]
}
}
}
}Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StartLoginResult"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"429": {
"$ref": "#/components/responses/RateLimited"
},
"503": {
"$ref": "#/components/responses/Unavailable"
},
"403": {
"$ref": "#/components/responses/Forbidden"
}
}POST/api/v1/auth/complete-loginЗавершить вход подписью ключа
Публичный метод
Клиент подписывает UTF-8 payload `STIX Chat login v1 {challengeId} {challenge}` приватным P-256 ключом аккаунта. Подпись передаётся как 64 байт r||s в unpadded base64url. Recovery key никогда не отправляется на сервер.
Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"challengeId": {
"type": "string",
"format": "uuid"
},
"signature": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$"
}
},
"required": [
"challengeId",
"signature"
]
}
}
}
}Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Session"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"429": {
"$ref": "#/components/responses/RateLimited"
},
"503": {
"$ref": "#/components/responses/Unavailable"
},
"403": {
"$ref": "#/components/responses/Forbidden"
}
}POST/api/v1/auth/request-codeОтправить код по SMS
Публичный метод
Нормализованный E.164. SMS-код нужен для регистрации нового пользователя и подтверждения восстановления/QR на уже авторизованном устройстве. Обычный вход существующего аккаунта использует start-login/complete-login без SMS. Код из 6 цифр действует 5 минут, максимум 5 попыток. Лимиты по IP и телефону. dev-file разрешён только в development; код не возвращается в HTTP.
Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"phone": {
"type": "string",
"pattern": "^\\+[1-9][0-9]{7,14}$",
"examples": [
"+79991234567"
]
}
},
"required": [
"phone"
]
}
}
}
}Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Challenge"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"429": {
"$ref": "#/components/responses/RateLimited"
},
"503": {
"$ref": "#/components/responses/Unavailable"
},
"403": {
"$ref": "#/components/responses/Forbidden"
}
}POST/api/v1/auth/verify-codeПроверить SMS-код
Публичный метод
Код расходуется атомарно. Для нового номера возвращается registrationToken на 10 минут. Ответ с сессией для существующего аккаунта сохранён только для совместимости старых клиентов; новый вход использует start-login/complete-login без SMS.
Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"challengeId": {
"type": "string",
"format": "uuid"
},
"code": {
"type": "string",
"pattern": "^[0-9]{6}$"
}
},
"required": [
"challengeId",
"code"
]
}
}
}
}Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/Session"
},
{
"$ref": "#/components/schemas/RegistrationRequired"
}
]
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"429": {
"$ref": "#/components/responses/RateLimited"
},
"403": {
"$ref": "#/components/responses/Forbidden"
}
}POST/api/v1/auth/registerЗавершить регистрацию
Публичный метод
Username приводится к нижнему регистру и уникален. Ключи создаются на клиенте. Сервер получает только публичные ключи и зашифрованную резервную копию.
Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"registrationToken": {
"type": "string"
},
"username": {
"type": "string",
"minLength": 3,
"maxLength": 32,
"pattern": "^[a-zA-Z0-9_]+$"
},
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"publicKey": {
"$ref": "#/components/schemas/PublicKeys"
},
"keyBackup": {
"$ref": "#/components/schemas/KeyBackup"
}
},
"required": [
"registrationToken",
"username",
"name",
"publicKey",
"keyBackup"
]
}
}
}
}Ответы
{
"201": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Session"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"409": {
"$ref": "#/components/responses/Conflict"
},
"429": {
"$ref": "#/components/responses/RateLimited"
},
"403": {
"$ref": "#/components/responses/Forbidden"
}
}POST/api/v1/auth/logoutОтозвать текущую сессию
Только сессия
Ответы
{
"204": {
"description": "Успешно, без тела ответа."
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}GET/api/v1/meТекущий профиль и резервная копия ключей
Сессия или API-токен
Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}PATCH/api/v1/meИзменить профиль
Сессия или API-токен
Ключи идентичности и телефон этим методом не изменяются.
Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"username": {
"type": "string",
"minLength": 3,
"maxLength": 32,
"pattern": "^[a-zA-Z0-9_]+$"
},
"avatarUrl": {
"type": "string",
"maxLength": 131072,
"description": "Small public data URL. Empty string removes the avatar."
}
},
"required": [],
"minProperties": 1
}
}
}
}Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"409": {
"$ref": "#/components/responses/Conflict"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}DELETE/api/v1/meНавсегда удалить аккаунт
Только сессия
Удаляет профиль, телефон, ключи, сессии, свои сообщения и файлы. Личные/AI/livechat-чаты удаляются; в группах сохраняются сообщения других участников и назначается новый владелец. Удаление ciphertext из хранилища имеет durable retry. Сохранённые получателями копии и резервные копии до истечения срока хранения отозвать невозможно.
Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"confirmation": {
"type": "string",
"const": "DELETE"
}
},
"required": [
"confirmation"
]
}
}
}
}Ответы
{
"204": {
"description": "Успешно, без тела ответа."
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}PUT/api/v1/me/key-backupОбновить резервную копию ключей
Только сессия
Только пользовательская сессия. Клиент сначала локально проверяет текущий recovery key, затем загружает заново зашифрованную резервную копию. Публичная identity и история сообщений не меняются.
Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"keyBackup": {
"$ref": "#/components/schemas/KeyBackup"
}
},
"required": [
"keyBackup"
]
}
}
}
}Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}PUT/api/v1/me/identityСбросить криптографическую identity
Только сессия
Только пользовательская сессия и явное действие пользователя при полной потере recovery key и всех устройств. Создаёт новые публичные ключи и encrypted backup для будущих сообщений; старую E2EE-историю этим методом расшифровать нельзя.
Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"publicKey": {
"$ref": "#/components/schemas/PublicKeys"
},
"keyBackup": {
"$ref": "#/components/schemas/KeyBackup"
}
},
"required": [
"publicKey",
"keyBackup"
]
}
}
}
}Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}GET/api/v1/blocksСписок заблокированных пользователей
Сессия или API-токен
Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PublicUser"
}
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}PUT/api/v1/blocks/{userId}Заблокировать пользователя
Сессия или API-токен
Сервер запрещает отправку и загрузку вложений между заблокированной парой, включая общие группы. Создание чата или добавление участников с блокировкой запрещается. История сохраняется; остальные участники группы продолжают переписку.
Параметры
[
{
"name": "userId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
]Ответы
{
"204": {
"description": "Успешно, без тела ответа."
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}DELETE/api/v1/blocks/{userId}Снять свою блокировку
Сессия или API-токен
Параметры
[
{
"name": "userId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
]Ответы
{
"204": {
"description": "Успешно, без тела ответа."
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}POST/api/v1/reportsПожаловаться модератору
Только сессия
Только собеседник может пожаловаться. messageId требует chatId и должен быть видимым сообщением указанного отправителя. Жалоба на системного AI-ассистента допускается только с messageId его ответа в своём AI-чате. details/evidenceText — добровольно переданные модератору незашифрованные данные; клиент обязан ясно запросить согласие. Лимит 20 жалоб в сутки. Прочие сообщения сервер не расшифровывает.
Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"userId": {
"type": "string",
"format": "uuid"
},
"chatId": {
"type": "string",
"format": "uuid"
},
"messageId": {
"type": "string",
"format": "uuid"
},
"reason": {
"type": "string",
"enum": [
"spam",
"harassment",
"illegal",
"sexual",
"violence",
"other"
]
},
"details": {
"type": "string",
"maxLength": 2000
},
"evidenceText": {
"type": "string",
"maxLength": 10000
}
},
"required": [
"userId",
"reason"
]
}
}
}
}Ответы
{
"201": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"status": {
"type": "string",
"const": "pending"
}
},
"required": [
"id",
"status"
]
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}PUT/api/v1/push/apnsЗарегистрировать native iOS push
Только сессия
Уведомления содержат только общий текст, chatId и userId. Регистрация токена переводит уведомления этого устройства на текущий аккаунт; токен не передавать третьим лицам. Для TestFlight/App Store production, debug development profile sandbox. Конфигурация APNs обязательна на сервере.
Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"deviceToken": {
"type": "string",
"pattern": "^(?:[0-9a-fA-F]{2}){32,256}$"
},
"environment": {
"type": "string",
"enum": [
"production",
"sandbox"
]
},
"deviceLabel": {
"type": "string",
"maxLength": 100
}
},
"required": [
"deviceToken",
"environment"
]
}
}
}
}Ответы
{
"204": {
"description": "Успешно, без тела ответа."
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"409": {
"$ref": "#/components/responses/Conflict"
},
"503": {
"$ref": "#/components/responses/Unavailable"
}
}DELETE/api/v1/push/apnsОтключить native iOS push
Только сессия
Удаляет токен только у текущего аккаунта, в обоих APNs environments.
Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"deviceToken": {
"type": "string",
"pattern": "^(?:[0-9a-fA-F]{2}){32,256}$"
}
},
"required": [
"deviceToken"
]
}
}
}
}Ответы
{
"204": {
"description": "Успешно, без тела ответа."
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}GET/api/v1/usersНайти пользователя
Сессия или API-токен
Только авторизованные запросы. Телефоны других пользователей не возвращаются. Поиск ограничен по частоте.
Параметры
[
{
"name": "q",
"in": "query",
"required": true,
"schema": {
"type": "string",
"minLength": 3
},
"description": "Точный E.164 телефон либо префикс username от 3 символов, без @."
}
]Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PublicUser"
},
"maxItems": 20
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}POST/api/v1/contacts/resolveНайти зарегистрированные контакты
Сессия или API-токен
Bulk lookup для адресной книги. Клиент отправляет только локальный ref и нормализованный телефон; имена контактов остаются на устройстве. Ответ возвращает ref + PublicUser без телефона. Только registered пользователи текущего review-сегмента, suspended исключаются; self исключается.
Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"contacts": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"ref": {
"type": "string",
"maxLength": 128
},
"phone": {
"type": "string",
"pattern": "^\\+[1-9][0-9]{7,14}$",
"examples": [
"+79991234567"
]
}
},
"required": [
"ref",
"phone"
]
},
"minItems": 1,
"maxItems": 500
}
},
"required": [
"contacts"
]
}
}
}
}Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ContactResolveMatch"
},
"maxItems": 500
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}GET/api/v1/chatsСписок своих чатов
Сессия или API-токен
До 100 чатов, новые сверху (updatedAt DESC).
Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Chat"
},
"maxItems": 100
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}POST/api/v1/chatsСоздать личный или групповой чат
Сессия или API-токен
Текущий пользователь добавляется автоматически. direct: ровно один другой участник; существующий личный чат переиспользуется. group: 2–100 участников, title обязателен.
Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"kind": {
"type": "string",
"enum": [
"direct",
"group"
]
},
"title": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"memberIds": {
"type": "array",
"items": {
"type": "string",
"format": "uuid"
},
"minItems": 1,
"maxItems": 99,
"uniqueItems": true
}
},
"required": [
"kind",
"memberIds"
]
}
}
}
}Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Chat"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
},
"201": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Chat"
}
}
}
}
}GET/api/v1/chats/{chatId}Получить чат и актуальный состав
Сессия или API-токен
Параметры
[
{
"name": "chatId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
]Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Chat"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}DELETE/api/v1/chats/{chatId}Удалить чат у себя или у всех
Сессия или API-токен
scope=self скрывает чат только у текущего аккаунта, очищает unread/push и обрезает видимую историю: при повторном открытии старые сообщения и файлы не возвращаются. Новое сообщение снова покажет чат. scope=all полностью удаляет direct-чат для обоих участников; группу у всех может удалить только владелец. AI-чат не удаляется.
Параметры
[
{
"name": "chatId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
]Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"scope": {
"type": "string",
"enum": [
"self",
"all"
],
"default": "self"
}
},
"required": [
"scope"
]
}
}
}
}Ответы
{
"204": {
"description": "Успешно, без тела ответа."
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}PATCH/api/v1/chats/{chatId}Переименовать группу
Сессия или API-токен
Только владелец группы.
Параметры
[
{
"name": "chatId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
]Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"title": {
"type": "string",
"minLength": 1,
"maxLength": 100
}
},
"required": [
"title"
]
}
}
}
}Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Chat"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}POST/api/v1/chats/{chatId}/membersДобавить участника в группу
Сессия или API-токен
Только владелец. Новый участник видит сообщения после момента вступления. После изменения состава отправители должны обновить набор ключей.
Параметры
[
{
"name": "chatId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
]Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"userId": {
"type": "string",
"format": "uuid"
}
},
"required": [
"userId"
]
}
}
}
}Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Chat"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}DELETE/api/v1/chats/{chatId}/members/{userId}Удалить участника или выйти из группы
Сессия или API-токен
Владелец удаляет других участников; участник может выйти сам. Владелец сначала передаёт владение. Удалённый участник теряет серверный доступ, но уже сохранённые им данные отозвать невозможно.
Параметры
[
{
"name": "chatId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
},
{
"name": "userId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
]Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Chat"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}PATCH/api/v1/chats/{chatId}/ownerПередать владение группой
Сессия или API-токен
Только владелец; получатель должен быть текущим участником.
Параметры
[
{
"name": "chatId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
]Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"userId": {
"type": "string",
"format": "uuid"
}
},
"required": [
"userId"
]
}
}
}
}Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Chat"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}GET/api/v1/chats/{chatId}/messagesИстория сообщений
Сессия или API-токен
По умолчанию последняя страница; сообщения внутри страницы упорядочены по возрастанию. История скрыта до вступления и до последнего локального удаления чата у себя. Cursor обязан принадлежать видимой части чата.
Параметры
[
{
"name": "chatId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
},
{
"name": "before",
"in": "query",
"required": false,
"schema": {
"type": "string",
"format": "uuid"
},
"description": "UUID сообщения из этого чата; пагинация назад."
},
{
"name": "limit",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"default": 50
},
"description": ""
}
]Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"messages": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Message"
}
},
"hasMore": {
"type": "boolean"
}
},
"required": [
"messages",
"hasMore"
]
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}POST/api/v1/chats/{chatId}/messagesОтправить зашифрованное сообщение
Сессия или API-токен
Идемпотентность по (chatId, senderId, clientId). Ключи envelope.keys точно соответствуют текущим участникам. Сервер проверяет подпись и принадлежность вложений отправителю/чату. При конфликте состава обновите чат и повторно зашифруйте сообщение.
Параметры
[
{
"name": "chatId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
]Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"clientId": {
"type": "string",
"format": "uuid"
},
"envelope": {
"$ref": "#/components/schemas/Envelope"
},
"attachmentIds": {
"type": "array",
"items": {
"type": "string",
"format": "uuid"
},
"maxItems": 10,
"uniqueItems": true
}
},
"required": [
"clientId",
"envelope",
"attachmentIds"
]
},
"examples": {
"encryptedMessage": {
"summary": "Real encryption and signature; illustrative account IDs, use your own keys.",
"value": {
"clientId": "a2480949-214c-42f7-89f7-96a73c25fef1",
"envelope": {
"version": 1,
"ciphertext": "V5UxRNH65m0xPA5yXUGw_eWo0aLrjzIml84mGKa0x3Pwkr-kRrsOwNp1b_Y6K93R3ekPJQgSndTfym0sVAac2R3G0tj2NRKZtKl5VnVJuKMizv7rDNd4AINWH4fdvD79VroSyWvmbD8",
"iv": "j5IJPyjMtzX3ALZa",
"keys": {
"0f52009a-c706-4380-9d8e-1ec81861fe0c": "BWKH4pTfgu8uqwnP4ZEILXIjbI0bglc_qyfeVeGSW9odjtKT1IXML_NKfJzXXQqPB-x50yt4wehqLKFXibYMWqpZKWJUGM89CD1PO-EZM9cXiqDe2x6IhfIVb7EYZBvwQTGYGDT65gBw2RHfzrWidnsRv9SVWS7xle5vPFThQ4oX1DdZYNA47hTxNoY03_GPNVPvsRGBtLoR5Q2KbFA2gBYVqV3Jwe6p3yAagzPepbttvHwy7O1kVPdNOCl9gJYuF7J7kj8IeMsU48o3lf0Msvv-PRSry_httTlQGPZmpACAHU3vy-f4JMDMfKz8uK9Oh1kH7tNkMmkKWrQUmdBMam4ZGVQdOiyxxn5u7w-eOsNtuIRIkQ1cOizoz4q19xma_unjoBl2ssnhbPYPKBmvqANBpYFT1rSnBnhq250NDwsZoTOT4I7p39rUxHCzdrIIYq18ZgTVTsj-qb2AYg08GthyiHcKeqeAoGvZ2ryUFng7q7O907KOqiT9VMmTEMni",
"baf3a165-a631-4214-8a53-c356105db635": "VO7DWZ6_Mm1FDf2eGpKwPoCA50TTrcy0JH559MhZViFG9rlZ312TV31Pw0nRSBb-ACOgRlhvyycXgyOhghofALIE5NkRF3TCmMKtBqr3ofg46UjOrUDMKQa9S2bJeJNgoCsCENAtTYBJeErIQ3UAbGsweuqUtDhzJRC4uKq5hnxFNvGM_lowg-DVNTVoTJk_Ru6ZBxE4yWm20WQeK90HunLqiYV14hqDkJGY_MF0s9O6CKgDWfqQj3ksF2QQlrf12oSiCCH2tc8krZatfJDmpkoxEROVYxhU06jsm9z-BWofji4bTY2WYtmevJEJzr39_dFL-wpj8GFSjILKCLggvQznTqXAru5fTSO5taUNfrLICVfc1s5qRQsiLbetm_f9NUJRe-ZmLz072YbYgifrkJoFdzI4gqosddAft85H5uJcVap5JQXNKQ682hPf19GwM6kl6OVrfkv0X221rLvmswlVC08525ZCAriplyopEdX1XczARc9EXTRB2BZSsS-h"
},
"signature": "pl7HY86koBnCAujtZ09RGbf2R_2W0Tyzn0TuKOwJlgoQbNcexFCowuwOxbKaVTMU7ZVcW-yddcr1PPICEW_GmQ"
},
"attachmentIds": []
}
}
}
}
}
}Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Message"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"409": {
"$ref": "#/components/responses/Conflict"
},
"429": {
"$ref": "#/components/responses/RateLimited"
},
"201": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Message"
}
}
}
}
}PATCH/api/v1/chats/{chatId}/messages/{messageId}Изменить своё сообщение
Сессия или API-токен
Только отправитель. При изменении содержимого сохраняется исходный clientId, генерируются свежие ключ/IV/подпись для актуального состава. Повтор того же envelope и списка вложений возвращает сохранённую версию без изменения editedAt.
Параметры
[
{
"name": "chatId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
},
{
"name": "messageId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
]Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"envelope": {
"$ref": "#/components/schemas/Envelope"
},
"attachmentIds": {
"type": "array",
"items": {
"type": "string",
"format": "uuid"
},
"maxItems": 10,
"uniqueItems": true
}
},
"required": [
"envelope",
"attachmentIds"
]
}
}
}
}Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Message"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"409": {
"$ref": "#/components/responses/Conflict"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}DELETE/api/v1/chats/{chatId}/messages/{messageId}Удалить своё сообщение
Сессия или API-токен
Только отправитель. В истории остаётся отметка удаления. Уже сохранённые получателями копии отозвать невозможно.
Параметры
[
{
"name": "chatId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
},
{
"name": "messageId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
]Ответы
{
"204": {
"description": "Успешно, без тела ответа."
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}POST/api/v1/chats/{chatId}/readОтметить сообщения прочитанными
Сессия или API-токен
Указатель прочтения только продвигается вперёд. Сообщение должно быть доступно участнику.
Параметры
[
{
"name": "chatId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
]Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"messageId": {
"type": "string",
"format": "uuid"
}
},
"required": [
"messageId"
]
}
}
}
}Ответы
{
"204": {
"description": "Успешно, без тела ответа."
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}POST/api/v1/chats/{chatId}/filesЗагрузить зашифрованный файл
Сессия или API-токен
Тело — AES-256-GCM ciphertext с тегом, application/octet-stream. До 50 MiB исходного файла + 16 байт GCM tag. Без имени, MIME и других открытых метаданных. Свяжите id с сообщением через attachmentIds. Лимит загрузки на пользователя — 2 GiB за последние 24 часа.
Параметры
[
{
"name": "chatId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
]Тело запроса
{
"required": true,
"content": {
"application/octet-stream": {
"schema": {
"type": "string",
"format": "binary",
"maxLength": 52428816
}
}
}
}Ответы
{
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"413": {
"$ref": "#/components/responses/BadRequest"
},
"429": {
"$ref": "#/components/responses/RateLimited"
},
"201": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"size": {
"type": "integer",
"minimum": 16,
"maximum": 52428816
}
},
"required": [
"id",
"size"
]
}
}
}
}
}GET/api/v1/files/{fileId}Скачать зашифрованный файл
Сессия или API-токен
Получатель имеет доступ только к файлам доступных ему сообщений после вступления и после последнего локального удаления чата у себя. Загрузивший пользователь может скачать своё ещё не прикреплённое вложение, пока чат не скрыт у него локальным удалением. Исходное имя файла не возвращается.
Параметры
[
{
"name": "fileId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
]Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/octet-stream": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}GET/api/v1/eventsПоток изменений SSE
Сессия или API-токен
Используйте fetch с Authorization, не EventSource с токеном в URL. Событие change содержит Event. Heartbeat каждые 20 секунд. После переподключения перечитайте данные через REST; SSE не гарантирует воспроизведение пропущенного. Отзыв/истечение сессии закрывает доступ.
Ответы
{
"200": {
"description": "Успешно.",
"content": {
"text/event-stream": {
"schema": {
"type": "string"
},
"example": "event: change\ndata: {\"type\":\"message\",\"chatId\":\"8ed92c28-397f-4b1f-8016-b7b484e809ef\"}\n\n"
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}PUT/api/v1/push/subscriptionПодписать устройство на push
Сессия или API-токен
HTTPS endpoint разрешённого публичного push-провайдера; upsert по пользователю и endpoint. Уведомление содержит только общий текст и ссылку на чат. Содержимое сообщений не передаётся push-провайдеру.
Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PushSubscription"
}
}
}
}Ответы
{
"204": {
"description": "Успешно, без тела ответа."
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}DELETE/api/v1/push/subscriptionУдалить push-подписку
Сессия или API-токен
Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"endpoint": {
"type": "string",
"format": "uri"
}
},
"required": [
"endpoint"
]
}
}
}
}Ответы
{
"204": {
"description": "Успешно, без тела ответа."
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}GET/api/v1/tokensСписок интеграционных токенов
Только сессия
Требует пользовательскую сессию. Значения ранее выданных токенов не возвращаются.
Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Token"
}
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}POST/api/v1/tokensВыпустить интеграционный токен
Только сессия
Только пользовательская сессия. read разрешает чтение, write — изменения; для обоих видов запросов выдавайте оба scope. Токен не предоставляет приватные ключи и не обходит E2EE. Его значение возвращается один раз.
Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"scopes": {
"type": "array",
"items": {
"type": "string",
"enum": [
"read",
"write"
]
},
"minItems": 1,
"maxItems": 2,
"uniqueItems": true
},
"expiresInDays": {
"type": "integer",
"minimum": 1,
"maximum": 365
}
},
"required": [
"name",
"scopes",
"expiresInDays"
]
}
}
}
}Ответы
{
"201": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CreatedToken"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}DELETE/api/v1/tokens/{tokenId}Отозвать интеграционный токен
Только сессия
Параметры
[
{
"name": "tokenId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
]Ответы
{
"204": {
"description": "Успешно, без тела ответа."
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}POST/api/v1/ai/messagesОтправить сообщение закреплённому AI-ассистенту
Сессия или API-токен
Только зарегистрированная сессия или API-токен с write scope. Сервер создаёт закреплённый чат kind=ai, сохраняет текст этого AI-чата в plaintext и отправляет историю этого AI-чата в OpenAI через настроенный SSH/SOCKS proxy. Обычные E2EE-чаты и файлы ассистенту недоступны.
Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AIMessageRequest"
}
}
}
}Ответы
{
"201": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AIMessageResult"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
},
"503": {
"$ref": "#/components/responses/Unavailable"
}
}GET/api/v1/livechat/siteПолучить модуль онлайн-консультаций
Сессия или API-токен
Возвращает скрипт и HTML-код для установки виджета на сайт. Требует зарегистрированный аккаунт; гостевые посетители не допускаются. API-токену нужен scope read.
Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LiveChatSite"
}
}
}
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}POST/api/v1/livechat/siteСоздать или обновить модуль онлайн-консультаций
Только сессия
Один активный модуль на аккаунт оператора. Виджет создаёт зашифрованные чаты с этим аккаунтом, а ответы оператор пишет в обычном STIX Chat. API-токену нужен scope write.
Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 80
}
},
"required": [
"name"
]
}
}
}
}Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LiveChatSite"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
}
}POST/api/v1/livechat/sessionsОткрыть сессию посетителя сайта
Публичный метод
Публичный endpoint для iframe-виджета. При первом обращении создаёт guest-аккаунт visitor, групповой чат с владельцем модуля и возвращает visitorToken для этого браузера. При повторном обращении с visitorToken выдаёт новую сессию к тому же чату. Сервер не получает открытый текст сообщений.
Тело запроса
{
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LiveChatSessionRequest"
}
}
}
}Ответы
{
"201": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LiveChatSession"
}
}
}
},
"400": {
"$ref": "#/components/responses/BadRequest"
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"429": {
"$ref": "#/components/responses/RateLimited"
},
"403": {
"$ref": "#/components/responses/Forbidden"
},
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LiveChatSession"
}
}
}
}
}GET/healthzПроверка процесса
Публичный метод
Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
},
"503": {
"$ref": "#/components/responses/Unavailable"
},
"403": {
"$ref": "#/components/responses/Forbidden"
}
}GET/readyzГотовность и соединение с БД
Публичный метод
Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
},
"503": {
"$ref": "#/components/responses/Unavailable"
},
"403": {
"$ref": "#/components/responses/Forbidden"
}
}GET/openapi.yamlСпецификация OpenAPI
Публичный метод
Ответы
{
"200": {
"description": "Успешно.",
"content": {
"application/yaml": {
"schema": {
"type": "string"
}
}
}
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"403": {
"$ref": "#/components/responses/Forbidden"
}
}GET/api-docsЛокальная документация API
Публичный метод
Ответы
{
"200": {
"description": "Успешно.",
"content": {
"text/html": {
"schema": {
"type": "string"
}
}
}
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"403": {
"$ref": "#/components/responses/Forbidden"
}
}Схемы данных
Error
{
"type": "object",
"additionalProperties": false,
"properties": {
"error": {
"type": "object",
"additionalProperties": false,
"properties": {
"code": {
"type": "string"
},
"message": {
"type": "string",
"description": "Сообщение на русском языке."
}
},
"required": [
"code",
"message"
]
}
},
"required": [
"error"
]
}RSAPublicKey
{
"type": "object",
"additionalProperties": false,
"properties": {
"kty": {
"type": "string",
"const": "RSA"
},
"n": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$"
},
"e": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$"
},
"alg": {
"type": "string"
},
"ext": {
"type": "boolean"
},
"key_ops": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"kty",
"n",
"e"
],
"description": "RSA-OAEP SHA-256, 3072 bits; public JWK only. Private key fields are rejected."
}SigningPublicKey
{
"type": "object",
"additionalProperties": false,
"properties": {
"kty": {
"type": "string",
"const": "EC"
},
"crv": {
"type": "string",
"const": "P-256"
},
"x": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$"
},
"y": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$"
},
"alg": {
"type": "string"
},
"ext": {
"type": "boolean"
},
"key_ops": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"kty",
"crv",
"x",
"y"
],
"description": "ECDSA P-256 SHA-256 public JWK. Private key fields are rejected."
}PublicKeys
{
"type": "object",
"additionalProperties": false,
"properties": {
"encryption": {
"$ref": "#/components/schemas/RSAPublicKey"
},
"signing": {
"$ref": "#/components/schemas/SigningPublicKey"
}
},
"required": [
"encryption",
"signing"
]
}KeyBackup
{
"type": "object",
"additionalProperties": false,
"properties": {
"version": {
"type": "integer",
"const": 1
},
"iv": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$"
},
"ciphertext": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$"
}
},
"required": [
"version",
"iv",
"ciphertext"
],
"description": "Private identity encrypted with AES-256-GCM and a random recovery key. Recovery key never reaches the server."
}PublicUser
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"username": {
"type": "string",
"minLength": 3,
"maxLength": 32,
"pattern": "^[a-zA-Z0-9_]+$"
},
"name": {
"type": "string",
"maxLength": 100
},
"avatarUrl": {
"type": "string",
"description": "Optional public avatar as a small data:image/png/jpeg/webp URL."
},
"publicKey": {
"$ref": "#/components/schemas/PublicKeys"
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"id",
"username",
"name",
"publicKey",
"createdAt"
],
"description": "Phone is excluded from all public user responses."
}User
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"username": {
"type": "string",
"minLength": 3,
"maxLength": 32,
"pattern": "^[a-zA-Z0-9_]+$"
},
"name": {
"type": "string",
"maxLength": 100
},
"avatarUrl": {
"type": "string",
"description": "Optional public avatar as a small data:image/png/jpeg/webp URL."
},
"publicKey": {
"$ref": "#/components/schemas/PublicKeys"
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"phone": {
"type": "string",
"pattern": "^\\+[1-9][0-9]{7,14}$",
"examples": [
"+79991234567"
]
},
"keyBackup": {
"$ref": "#/components/schemas/KeyBackup"
}
},
"required": [
"id",
"username",
"name",
"publicKey",
"createdAt",
"phone",
"keyBackup"
]
}Member
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"username": {
"type": "string",
"minLength": 3,
"maxLength": 32,
"pattern": "^[a-zA-Z0-9_]+$"
},
"name": {
"type": "string",
"maxLength": 100
},
"avatarUrl": {
"type": "string",
"description": "Optional public avatar as a small data:image/png/jpeg/webp URL."
},
"publicKey": {
"$ref": "#/components/schemas/PublicKeys"
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"role": {
"type": "string",
"enum": [
"owner",
"member"
]
},
"joinedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"id",
"username",
"name",
"publicKey",
"createdAt",
"role",
"joinedAt"
]
}Envelope
{
"type": "object",
"additionalProperties": false,
"properties": {
"version": {
"type": "integer",
"const": 1
},
"ciphertext": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$"
},
"iv": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$"
},
"keys": {
"type": "object",
"propertyNames": {
"type": "string",
"format": "uuid"
},
"additionalProperties": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$"
},
"minProperties": 1,
"maxProperties": 100
},
"signature": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$"
}
},
"required": [
"version",
"ciphertext",
"iv",
"keys",
"signature"
],
"description": "Fresh AES-256-GCM key per message, wrapped with each current member's RSA-OAEP key. All binary values use unpadded base64url. Signature and AAD are specified in SECURITY.md. Maximum serialized envelope is 128 KiB."
}Message
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"chatId": {
"type": "string",
"format": "uuid"
},
"senderId": {
"type": "string",
"format": "uuid"
},
"sender": {
"$ref": "#/components/schemas/PublicUser"
},
"clientId": {
"type": "string",
"format": "uuid"
},
"envelope": {
"oneOf": [
{
"$ref": "#/components/schemas/Envelope"
},
{
"type": "object",
"additionalProperties": false,
"properties": {},
"required": [],
"description": "Empty object for a deleted or AI plaintext message."
}
]
},
"attachmentIds": {
"type": "array",
"items": {
"type": "string",
"format": "uuid"
},
"maxItems": 10,
"uniqueItems": true
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"editedAt": {
"type": "string",
"format": "date-time"
},
"deletedAt": {
"type": "string",
"format": "date-time"
},
"plaintext": {
"type": "string",
"description": "Only present in the dedicated AI assistant chat; ordinary chats remain E2EE."
},
"deliveryStatus": {
"type": "string",
"enum": [
"sent",
"delivered",
"read"
],
"description": "Present for messages sent by the current user. Delivered means accepted by the server and available to active recipients; read means every active recipient for that message has read up to it."
}
},
"required": [
"id",
"chatId",
"senderId",
"sender",
"clientId",
"envelope",
"attachmentIds",
"createdAt"
],
"description": "Sender identity accompanies history so signatures remain verifiable after the sender leaves a group. Deletion retains a tombstone."
}Chat
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"kind": {
"type": "string",
"enum": [
"direct",
"group",
"ai"
]
},
"title": {
"type": "string",
"maxLength": 100
},
"members": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Member"
},
"minItems": 1,
"maxItems": 100
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"updatedAt": {
"type": "string",
"format": "date-time"
},
"unreadCount": {
"type": "integer",
"minimum": 0
},
"pinnedAt": {
"type": "string",
"format": "date-time"
},
"lastMessage": {
"$ref": "#/components/schemas/Message"
}
},
"required": [
"id",
"kind",
"title",
"members",
"createdAt",
"updatedAt",
"unreadCount"
]
}Attachment
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"name": {
"type": "string"
},
"mime": {
"type": "string"
},
"size": {
"type": "integer",
"minimum": 0,
"maximum": 52428800
},
"kind": {
"type": "string",
"enum": [
"image",
"video",
"pdf",
"stl",
"audio",
"text",
"code",
"table",
"svg",
"file"
]
},
"key": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$"
},
"iv": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$"
},
"duration": {
"type": "number",
"minimum": 0
}
},
"required": [
"id",
"name",
"mime",
"size",
"kind",
"key",
"iv"
],
"description": "CLIENT-ONLY decrypted attachment descriptor inside MessageContent. Filename, MIME type, plaintext size and decryption material never go to plaintext API fields."
}MessageContent
{
"type": "object",
"additionalProperties": false,
"properties": {
"text": {
"type": "string"
},
"attachments": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Attachment"
}
},
"replyTo": {
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"text": {
"type": "string"
},
"senderName": {
"type": "string"
}
},
"required": [
"id",
"text",
"senderName"
]
}
},
"required": [
"text",
"attachments"
],
"description": "CLIENT-ONLY plaintext schema, encrypted into Envelope.ciphertext before sending."
}Config
{
"type": "object",
"additionalProperties": false,
"properties": {
"smsConfigured": {
"type": "boolean"
},
"pushPublicKey": {
"type": "string"
},
"apnsConfigured": {
"type": "boolean"
},
"maxFileBytes": {
"type": "integer",
"examples": [
52428800
]
},
"environment": {
"type": "string",
"enum": [
"development",
"production",
"test"
]
}
},
"required": [
"smsConfigured",
"pushPublicKey",
"apnsConfigured",
"maxFileBytes",
"environment"
]
}PublicStats
{
"type": "object",
"additionalProperties": false,
"properties": {
"registeredAccounts": {
"type": "integer",
"minimum": 0
},
"generatedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"registeredAccounts",
"generatedAt"
],
"description": "Public aggregate counter. Excludes system, visitor, suspended and App Review test accounts."
}Challenge
{
"type": "object",
"additionalProperties": false,
"properties": {
"challengeId": {
"type": "string",
"format": "uuid"
},
"retryAfter": {
"type": "integer",
"examples": [
60
]
},
"expiresIn": {
"type": "integer",
"examples": [
300
]
}
},
"required": [
"challengeId",
"retryAfter",
"expiresIn"
]
}StartLoginResult
{
"oneOf": [
{
"type": "object",
"additionalProperties": false,
"properties": {
"registered": {
"type": "boolean",
"const": false
}
},
"required": [
"registered"
]
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"registered": {
"type": "boolean",
"const": true
},
"challengeId": {
"type": "string",
"format": "uuid"
},
"challenge": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$"
},
"user": {
"$ref": "#/components/schemas/User"
}
},
"required": [
"registered",
"challengeId",
"challenge",
"user"
]
}
]
}Session
{
"type": "object",
"additionalProperties": false,
"properties": {
"token": {
"type": "string",
"description": "Opaque bearer token; save securely, never put in URL."
},
"user": {
"$ref": "#/components/schemas/User"
}
},
"required": [
"token",
"user"
]
}RegistrationRequired
{
"type": "object",
"additionalProperties": false,
"properties": {
"registrationToken": {
"type": "string",
"description": "Single-use token expiring after 10 minutes."
}
},
"required": [
"registrationToken"
]
}Token
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"name": {
"type": "string",
"maxLength": 100
},
"scopes": {
"type": "array",
"items": {
"type": "string",
"enum": [
"read",
"write"
]
},
"minItems": 1,
"maxItems": 2,
"uniqueItems": true
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"expiresAt": {
"type": "string",
"format": "date-time"
},
"lastUsedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"id",
"name",
"scopes",
"createdAt",
"expiresAt"
]
}CreatedToken
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"token": {
"type": "string",
"description": "Returned once; store securely."
},
"name": {
"type": "string"
},
"scopes": {
"type": "array",
"items": {
"type": "string",
"enum": [
"read",
"write"
]
},
"minItems": 1,
"maxItems": 2,
"uniqueItems": true
},
"expiresAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"id",
"token",
"name",
"scopes",
"expiresAt"
]
}AIMessageRequest
{
"type": "object",
"additionalProperties": false,
"properties": {
"chatId": {
"type": "string",
"format": "uuid"
},
"text": {
"type": "string",
"minLength": 1,
"maxLength": 4000
}
},
"required": [
"chatId",
"text"
]
}AIMessageResult
{
"type": "object",
"additionalProperties": false,
"properties": {
"userMessage": {
"$ref": "#/components/schemas/Message"
},
"assistantMessage": {
"$ref": "#/components/schemas/Message"
}
},
"required": [
"userMessage",
"assistantMessage"
]
}ContactResolveMatch
{
"type": "object",
"additionalProperties": false,
"properties": {
"ref": {
"type": "string",
"maxLength": 128
},
"user": {
"$ref": "#/components/schemas/PublicUser"
}
},
"required": [
"ref",
"user"
],
"description": "Contact phone is never returned. The caller maps ref back to its local address book entry."
}LiveChatSite
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"name": {
"type": "string",
"maxLength": 80
},
"scriptUrl": {
"type": "string",
"format": "uri"
},
"embedCode": {
"type": "string"
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"id",
"name",
"scriptUrl",
"embedCode",
"createdAt"
],
"description": "Embeddable live consultation module owned by a registered operator account."
}LiveChatSessionRequest
{
"type": "object",
"additionalProperties": false,
"properties": {
"siteId": {
"type": "string",
"format": "uuid"
},
"visitorToken": {
"type": "string"
},
"name": {
"type": "string",
"minLength": 1,
"maxLength": 80
},
"pageUrl": {
"type": "string",
"format": "uri",
"maxLength": 500
},
"publicKey": {
"$ref": "#/components/schemas/PublicKeys"
},
"keyBackup": {
"$ref": "#/components/schemas/KeyBackup"
}
},
"required": [
"siteId",
"name"
],
"description": "visitorToken resumes an existing browser visitor. New visitors must also send publicKey and keyBackup generated in the widget."
}LiveChatSession
{
"type": "object",
"additionalProperties": false,
"properties": {
"token": {
"type": "string",
"description": "30-day visitor bearer token for this browser session."
},
"visitorToken": {
"type": "string",
"description": "Persistent browser token returned only when the visitor is created."
},
"user": {
"$ref": "#/components/schemas/PublicUser"
},
"chat": {
"$ref": "#/components/schemas/Chat"
}
},
"required": [
"token",
"user",
"chat"
]
}PushSubscription
{
"type": "object",
"additionalProperties": false,
"properties": {
"endpoint": {
"type": "string",
"format": "uri",
"pattern": "^https://"
},
"keys": {
"type": "object",
"additionalProperties": false,
"properties": {
"p256dh": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$"
},
"auth": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$"
}
},
"required": [
"p256dh",
"auth"
]
},
"deviceLabel": {
"type": "string",
"maxLength": 100
},
"platform": {
"type": "string",
"maxLength": 40
},
"isIOS": {
"type": "boolean"
},
"isStandalone": {
"type": "boolean"
}
},
"required": [
"endpoint",
"keys"
]
}Event
{
"type": "object",
"additionalProperties": false,
"properties": {
"chatId": {
"type": "string",
"format": "uuid"
},
"type": {
"type": "string",
"enum": [
"message",
"chat",
"read"
]
}
},
"required": [
"type"
]
}