REST API
Все действия в приложениях Antimatter выполняются через один и тот же HTTP API, поэтому ваши скрипты могут делать то же самое. На этой странице описано, как аутентифицироваться, какие ресурсы используются чаще всего, как выглядят ответы и ошибки, а также как получать события в реальном времени через WebSocket.
Основы
- Базовый URL:
https://chat.example.com/api/v4. Все перечисленные ниже конечные точки указаны относительно него. - Формат: вход и выход в формате JSON, за исключением загрузки файлов (multipart). Отправляйте
Content-Type: application/json. - Идентификаторы: у каждого объекта есть
idдлиной 26 символов. Время указывается в миллисекундах с момента Unix epoch (create_at,update_at,delete_at; 0 означает «не удалено»). - Сообщества — это команды: в API они называются
teamsи имеютteam_id. - Себя: везде, где в пути используется
user_id,meозначает текущего пользователя, напримерGET /users/me.
Полный список конечных точек находится в коде сервера: маршруты объявлены в server/channels/api4/*.go, а типы — в server/public/model. Описание OpenAPI в папке api/v4/source репозитория охватывает конечные точки, унаследованные от Mattermost, и некоторые дополнения Antimatter: перемещение обсуждений, подключения моделей и действия с сообщениями. Остальные доступны только в коде.
Аутентификация
Каждый запрос, за исключением входа в систему и нескольких публичных конечных точек, требует токен в заголовке Authorization:
curl -H "Authorization: Bearer $TOKEN" https://chat.example.com/api/v4/users/me
Там принимаются три вида токенов: персональные токены доступа, токены сессии и токены доступа OAuth. Также принимается Authorization: Token …. Токены в строке запроса (?access_token=) принимаются только для токенов доступа OAuth.
Персональные токены доступа (рекомендуются для скриптов)
Персональный токен доступа действует от вашего имени, не истекает, если вы не задали дату истечения, и может быть отозван в любой момент. Персональные токены доступа отключены по умолчанию:
- Администратор системы включает Включить Персональные токены доступа в Системная консоль › Интеграции › Управление интеграцией (
ServiceSettings.EnableUserAccessTokens,AM_SERVICESETTINGS_ENABLEUSERACCESSTOKENS). - Для каждого пользователя, которому разрешено создавать токены, системный администратор открывает Системная консоль › Управление пользователями › Пользователи, выбирает Управление ролями в меню пользователя и отмечает Разрешить этому аккаунту создавать персональные токены доступа. Системные администраторы могут создавать их всегда.
- Пользователь нажимает на свой аватар в правом верхнем углу, затем выбирает Профиль и параметры › Безопасность. В разделе Персональные токены доступа он описывает назначение токена и нажимает Создать токен. Токен отображается только один раз: скопируйте его.
Через API: POST /users/{user_id}/tokens с телом {"description": "backup script", "expires_at": 0} (expires_at в миллисекундах; 0 — без срока действия). Поле token в ответе содержит секрет; его id используется для отмены токена (POST /users/tokens/revoke с {"token_id": "…"}). Из командной строки: amctl token generate <user> <description>.
Системный администратор может ограничить срок жизни токенов с помощью параметра Максимальный срок действия персонального токена доступа (дней) на той же странице Системной консоли.
Сессионные токены
При входе с паролем в заголовке ответа Token возвращается сессионный токен — того же типа, что используют приложения:
curl -i -X POST https://chat.example.com/api/v4/users/login \
-H 'Content-Type: application/json' \
-d '{"login_id": "maya", "password": "…"}'
Для аккаунта с многофакторной аутентификацией добавьте "token": "123456". Сессии истекают в соответствии с настройками сессий сервера, а точка входа ограничена по частоте (5 запросов в секунду). POST /users/logout завершает сессию.
X-CSRF-Token для всех методов, кроме GET; токен в заголовке Authorization не требует заголовка CSRF.Приложения OAuth 2.0
Чтобы позволить пользователям входить в ваше приложение с помощью аккаунта Antimatter, зарегистрируйте приложение OAuth 2.0. Antimatter в этом случае выступает провайдером OAuth:
- Включить поставщика услуг OAuth 2.0 должен быть включён (Системная консоль › Интеграции › Управление интеграцией,
ServiceSettings.EnableOAuthServiceProvider, включено по умолчанию). - Пользователь с правом управления приложениями OAuth (по умолчанию — системные администраторы) нажимает на свой аватар, затем выбирает Интеграции › Приложения OAuth 2.0 и добавляет приложение с URL обратного вызова. Он получает client ID и client secret.
- Ваше приложение перенаправляет пользователей на
https://chat.example.com/oauth/authorizeс параметрамиresponse_type=code,client_id,redirect_uriиstate. Поддерживается PKCE сcode_challenge_method=S256. - Затем оно обменивает код на
POST https://chat.example.com/oauth/access_token(сначалаgrant_type=authorization_code, затемrefresh_tokenдля обновления) и обращается к API с заголовкомAuthorization: Bearer <access token>.
Пользователи видят авторизованные ими приложения в Профиль и параметры › Безопасность › Авторизованные вами приложения.
Основные ресурсы
| Что | Эндпоинты |
|---|---|
| Вы и другие пользователи | GET /users/me, GET /users/{user_id}, GET /users/username/{username}, POST /users/ids (список ID), POST /users/search, GET /users?in_team=…&in_channel=… |
| Сообщества | GET /users/me/teams, GET /teams/{team_id}, GET /teams/name/{name}, PUT /teams/{team_id}/patch, GET /teams/{team_id}/members, POST /teams/{team_id}/members |
| Каналы | GET /users/me/teams/{team_id}/channels, GET /teams/name/{team}/channels/name/{channel}, POST /channels, POST /channels/direct (два ID пользователей), POST /channels/group, POST /channels/{channel_id}/members |
| Сообщения | POST /posts, GET /posts/{post_id}, PUT /posts/{post_id}/patch, DELETE /posts/{post_id}, GET /channels/{channel_id}/posts, GET /posts/{post_id}/thread, POST /teams/{team_id}/posts/search |
| Реакции | POST /reactions с телом {"user_id", "post_id", "emoji_name"}, DELETE /users/{user_id}/posts/{post_id}/reactions/{emoji_name} |
| Файлы | POST /files (multipart: channel_id и files), затем укажите возвращённые ID в поле file_ids сообщения; GET /files/{file_id} |
| Настройки | GET /users/me/preferences, PUT /users/me/preferences |
| Интеграции | /hooks/incoming, /hooks/outgoing, /commands, /bots, /oauth/apps (см. следующие страницы) |
| Сервер | GET /system/ping (проверка работоспособности, токен не требуется), GET /config/client?format=old (настройки, видимые клиентами) |
Отправить сообщение
curl -X POST https://chat.example.com/api/v4/posts \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"channel_id": "'$CHANNEL_ID'", "message": "Backup finished: **42 GB** in 3 min"}'
Сообщения используют Markdown. Добавьте "root_id" (ID первого сообщения в обсуждении), чтобы ответить в обсуждении, "file_ids" для файлов и "props" для вложений и других дополнительных данных (см. Вложения).
Узнать ID канала
curl -H "Authorization: Bearer $TOKEN" \
https://chat.example.com/api/v4/teams/name/lumen-labs/channels/name/ops-alerts
Имена соответствуют тем, что указаны в ссылке на канал: /lumen-labs/channels/ops-alerts.
Пагинация
Эндпоинты списков принимают параметры page (начиная с 0) и per_page (по умолчанию 60, максимум 200). Продолжайте запрашивать следующую страницу, пока возвращаемая страница не будет короче per_page.
Сообщения канала (GET /channels/{channel_id}/posts) также принимают параметры since (время: всё, что изменилось с этого момента), либо before и after (идентификатор сообщения). Ответ возвращается в виде списка сообщений: {"order": [IDs, newest first], "posts": {ID: post}, "next_post_id", "prev_post_id"}.
Ошибки
Для ошибок используются стандартные коды состояния HTTP (400 — некорректные данные, 401 — не авторизован, 403 — доступ запрещён, 404 — не найдено, 501 — функция отключена) и тело ответа в формате JSON:
{
"id": "api.context.permissions.app_error",
"message": "You do not have the appropriate permissions.",
"detailed_error": "",
"request_id": "jz8zm5nunpbt8f3gpqsz5dq6so",
"status_code": 403
}
В коде используйте id: message переводится на язык пользователя. detailed_error остаётся пустым, если сервер не работает в режиме разработчика (ServiceSettings.EnableDeveloper). Передайте request_id администратору сервера: он содержится в журналах.
Ограничение частоты запросов
Ограничение скорости выключено по умолчанию. Когда администратор системы включает его (Системная консоль › Окружение › Ограничение скорости), каждый клиент по умолчанию получает 10 запросов в секунду с возможностью всплеска до 100, подсчитываемых по IP-адресу или по пользователю. Ответы содержат заголовки X-RateLimit-Limit, X-RateLimit-Remaining и X-RateLimit-Reset; при превышении лимита сервер отвечает 429 с заголовком Retry-After в секундах. Некоторые конечные точки, такие как вход в систему, имеют собственный лимит независимо от настроек.
Пишите скрипты, которые ожидают и повторяют запросы при ответе 429, и избегайте опроса: используйте WebSocket.
Поток событий WebSocket
Подключитесь к wss://chat.example.com/api/v4/websocket. Авторизуйтесь с помощью заголовка Authorization: Bearer в запросе на подключение или отправив это как первое сообщение:
{"seq": 1, "action": "authentication_challenge", "data": {"token": "…"}}
Сервер отправляет событие hello, а затем события обо всём, что вам разрешено видеть:
{
"event": "posted",
"data": {"channel_id": "…", "channel_type": "O", "post": "{\"id\":\"…\",\"message\":\"Hello\",…}"},
"broadcast": {"channel_id": "…", "team_id": "", "user_id": "", "omit_users": null},
"seq": 4
}
Обратите внимание, что data.post — это сообщение в виде строки JSON. Частые события: posted, post_edited, post_deleted, reaction_added, reaction_removed, typing, status_change, user_added, direct_added. Приложения отправляют собственные события, называемые custom_<app id>_<event>.
Вы также можете отправлять действия, каждое с увеличивающимся seq: user_typing с {"channel_id", "parent_id"} или get_statuses. Переподключайтесь при обрыве соединения и получайте пропущенные данные с помощью since (см. Пагинация).
Antimatter добавляет следующие события: community_attributes_updated, member_timeouts_updated, post_put_on_top, post_removed_from_top, server_categories_updated, channel_overrides_updated и category_overrides_updated.
Библиотеки для клиентов
- Перейти:
model.Client4вserver/public/model(импортgithub.com/mattermost/mattermost/server/public/model).model.NewAPIv4Client(url), затемclient.SetToken(token);model.NewWebSocketClient4(wsURL, token)отслеживает события. Копия Antimatter добавляет методы для собственных конечных точек, такие какUpdateMessageRequest,PutPostOnTopиExportChannel. - TypeScript: класс
Client4из@mattermost/clientвwebapp/platform/client, с типами вwebapp/platform/types. Копия в репозитории Antimatter включает конечные точки Antimatter; пакет, опубликованный Mattermost на npm, их не содержит.
package main
import (
"context"
"log"
"github.com/mattermost/mattermost/server/public/model"
)
func main() {
client := model.NewAPIv4Client("https://chat.example.com")
client.SetToken("…")
post, _, err := client.CreatePost(context.Background(), &model.Post{
ChannelId: "…",
Message: "Hello from Go",
})
if err != nil {
log.Fatal(err)
}
log.Println("posted", post.Id)
}
Что Antimatter добавляет в API
Эти конечные точки и поля не существуют на сервере Mattermost. Для всех из них требуется сессия.
| Конечная точка | Назначение |
|---|---|
GET /teams/{team_id}/user_attributes/fieldsPOST тот же путьPATCH, DELETE …/fields/{field_id} | Атрибуты сообщества: поля профиля, которые администраторы сообщества определяют для его участников (до 20). Участники могут читать их; администраторы сообщества создают и изменяют их. |
GET /teams/{team_id}/members/{user_id}/user_attributesPATCH тот же путьPOST /teams/{team_id}/user_attributes/values/search | Значения атрибутов участника, в формате {field_id: value}. Участники устанавливают свои значения (кроме управляемых администраторами); администраторы устанавливают значения для любого участника. Поиск принимает {"user_ids": [...]} (до 200). |
GET /teams/{team_id}/timeoutsPUT /teams/{team_id}/members/{user_id}/timeoutGET /teams/{team_id}/members/{user_id}/moderation | Тайм-ауты: {"until": time, "reason": "…"} запрещает участнику публиковать сообщения, ставить реакции и загружать файлы в сообществе до указанного времени (максимум 28 дней); "until": 0 снимает ограничение. Вид модерации показывает, когда участник присоединился и сколько сообщений он опубликовал недавно. |
GET /channels/{channel_id}/on_topPUT, DELETE /posts/{post_id}/on_top | Сообщения, закреплённые вверху канала (до 10). {"duration": ms}, максимум 30 дней; 0 означает, что сообщение остаётся до удаления. Любой, кто может читать канал, видит список. Чтобы закрепить сообщение или снять его с закрепления, нужны права на публикацию в канале, а в канале сообщества — статус администратора канала или сообщества или право Управление сообщениями (delete_others_posts) в нём. В личных и групповых сообщениях это могут делать их участники. В архивированных каналах действие запрещено. |
POST /channels/{channel_id}/message_request | Действия с вашим собственным запросом на сообщение: {"action": "accept"}, "dismiss" или "request", чтобы вернуть разговор в список запросов. Возвращает данные вашего участника канала. |
GET, PUT /channels/{channel_id}/overridesGET /channels/{channel_id}/overrides/effectiveGET, PUT /channels/{channel_id}/role_access | Что роль или пользователь может делать в канале, а также какие роли имеют доступ к каналу с ограничением по ролям. |
GET, PUT /teams/{team_id}/server_categoriesGET, PUT …/server_categories/overrides | Общие категории каналов сообщества и переопределения, применяемые ко всем каналам в категории. |
GET /groups/{group_id}/team_rolePUT …/team_role/permissions | Права, которые предоставляет роль сообщества. |
POST /teams/{team_id}/autolinks/preview | Проверяет правила автоматических ссылок сообщества на тексте. |
POST /channels/{channel_id}/export?format=csv&since=&until= | Скачивает сообщения канала в формате CSV (до 50 000) для пользователей, имеющих право на чтение канала. |
GET /posts/{post_id}/speech | Аудиозапись сообщения, озвученная при настройке функции преобразования текста в речь. |
POST /posts/{post_id}/move_to_channel | Перемещает обсуждение в другой канал того же сообщества: см. Перемещение обсуждения. |
GET, POST /ai/connectionsGET, PATCH, DELETE /ai/connections/{connection_id}GET /ai/connections/usable | Подключения моделей, провайдеры ИИ, которые используют функции и приложения ИИ сервера: см. Подключения моделей. |
GET /channels/{channel_id}/message_actionsPOST /posts/{post_id}/message_actions/{hook_id}GET, POST /hooks/outgoing/{hook_id}/icon | Действия с сообщениями: исходящие вебхуки, которые пользователи запускают из меню сообщения. См. Действия с сообщениями. |
Новые поля
- Сообщества (
Team, иPUT /teams/{team_id}/patch):all_channels_membership(все находятся во всех каналах, которые им доступны),default_channel_id(куда попадают новички; пустое значение означает General),kind(communityилиworkplace: на рабочем месте администраторы каналов могут архивировать свои каналы; новым сообществам присваиваетсяTeamSettings.DefaultCommunityKindсервера, по умолчаниюcommunity),member_list_view(как список участников группирует участников:choice, значение по умолчанию, позволяет каждому участнику выбрать;rolesилиteamsфиксирует вариант),hide_role_colors,require_team_badges,onboardingиautolinks(оба — строки JSON). - The default channel of a new community is
general(General), nottown-square. The 0.9.0 upgrade renames each community'stown-squaretogeneral, keeping its ID, unless the community already has ageneralchannel. Old names keep working:GET /teams/{team_id}/channels/name/town-square,GET /teams/name/{team}/channels/name/town-squareand an incoming webhook'schannelgive the community's default channel when no channel has that name. Usedefault_channel_id, or the namegeneral, in new code. - Ссылки на каналы: ссылка
#channel-nameуказывает на канал, как и~channel-name. Свойствоchannel_mentionsсообщения перечисляет каналы, на которые ссылается сообщение любым из этих способов;#word, не совпадающий с именем канала, остаётся хэштегом. Веб-интерфейс и мобильное приложение Antimatter используют формат#name. - В Архивированные каналы можно добавлять новых участников (
POST /channels/{channel_id}/members), которые смогут просматривать историю. Публикация сообщений, добавление реакций, прикрепление, закрепление сообщений, переименование канала и изменение ролей участников в нём невозможны. - Встроенные ответы: сообщение с
"props": {"reply_to": "<post id>"}цитирует указанное сообщение из того же канала. Добавьте"reply_to_mention": false, чтобы не уведомлять автора цитируемого сообщения. Сервер заполняетmetadata.reply_toкратким описанием цитируемого сообщения. - Спойлеры:
"props": {"spoiler": true}скрывает текст сообщения и вложения, пока читатель не решит их просмотреть. - Игнорирование и блокировка — это настройки: категория
user_block, имя которой совпадает с ID другого пользователя, а значение —ignoreилиblock. То, ожидает ли личное сообщение как запрос, определяется вnotify_props.dm_requestвашего участника канала (pending,acceptedилиdismissed). - Вложения к сообщениям могут содержать
stagesиchart: см. Карточки.
Переместить обсуждение
Запрос POST /posts/{post_id}/move_to_channel перемещает обсуждение, его первое сообщение и все ответы в другой канал того же сообщества. В качестве post_id можно указать первое сообщение или любой из ответов.
curl -X POST https://chat.example.com/api/v4/posts/$POST_ID/move_to_channel \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"channel_id": "'$TARGET_CHANNEL_ID'", "flatten": false}'
channel_id(обязательный параметр): канал, в который перемещается обсуждение.flatten(по умолчаниюfalse): значениеtrueпревращает ответы в обычные сообщения целевого канала, а не в обсуждение. В Fusion для этого используется пункт Сделать каналом.
Сообщения сохраняют своих авторов, время создания, реакции и файлы. Их копии содержат свойство silent_notification, поэтому уведомления не отправляются. Исходные сообщения удаляются. В ответе возвращается первое сообщение после перемещения с новым ID.
Кто может перемещать обсуждение
- Вы должны иметь право просматривать обсуждение и публиковать сообщения в целевом канале.
- Администраторы канала, администраторы сообщества, пользователи с правом Управление сообщениями (
delete_others_posts) в канале и системные администраторы могут перемещать любое обсуждение. - Автор обсуждения может переместить его, если оба канала публичные, либо если все сообщения в обсуждении принадлежат ему. В противном случае возвращается ответ
403с идентификаторомapi.post.move_thread.private_needs_moderator.app_error. - Оба канала должны принадлежать одному сообществу (личные и групповые сообщения не поддерживаются), быть разными и не быть архивированными. Системные сообщения и сообщения, удаляемые после прочтения, переместить нельзя.
- Обсуждение, содержащее более
WranglerSettings.MoveThreadMaxCountсообщений (по умолчанию 100; 0 — без ограничения), будет отклонено.
Указатель и заметка
При перемещении создаются два системных сообщения типа system_wrangler: указатель в исходном канале («Обсуждение из 13 сообщений перемещено в #target») и заметка в целевом канале («Это обсуждение было перемещено из #source»). Они размещаются под перемещённым обсуждением или, при использовании flatten, после его сообщений. Помимо текста сообщения, их свойства позволяют клиенту отображать название канала в виде ссылки:
- Указатель:
MovedThreadPermalink,NumMessages,MovedThreadChannelId,MovedThreadTeamName,MovedThreadPostId, а для публичного целевого канала —MovedThreadChannelNameиMovedThreadChannelDisplayName. - Заметка:
MovedFromChannelId,MovedFromTeamName,MovedFromPostId(указатель),MovedFromPermalink, а для публичного исходного канала —MovedFromChannelNameиMovedFromChannelDisplayName.
Оба сообщения также содержат TranslationID. Название закрытого канала не указывается: пользователи видят «другой канал». Собственный метод Mattermost POST /posts/{post_id}/move в Antimatter отключён; используйте этот эндпоинт.
Подключения моделей
Соединение с моделью — это адрес и ключ провайдера ИИ, настроенные администратором. Они используются серверными функциями ИИ и приложениями, обращающимися к сервису ИИ. Системные администраторы управляют общесерверными соединениями (manage_ai_connections), а администраторы сообщества — соединениями своего сообщества (manage_team_ai_connections). Ключи доступны только для записи: в ответах они не передаются, возвращаются только api_key_set и api_key_last4.
| Конечная точка | Назначение |
|---|---|
GET /ai/connections?scope= | Списки соединений, которыми вы управляете. scope принимает значение server или ID сообщества; если параметр не указан, возвращаются все доступные вам области. |
POST /ai/connections | Добавляет соединение (возвращает 201). |
POST /ai/connections/test, POST /ai/connections/models | Проверяет соединение или получает список его моделей перед сохранением. Тело запроса такое же, как при добавлении; данные не сохраняются. |
GET, PATCH (или PUT), DELETE /ai/connections/{connection_id} | Чтение, изменение или удаление соединения. Патч содержит только изменяемые поля; не указывайте api_key, чтобы сохранить ключ. |
POST /ai/connections/{connection_id}/test | Проверяет сохранённое соединение: {"ok", "error", "status_code", "latency_ms", "model_count"}. |
GET /ai/connections/{connection_id}/models | Модели, предлагаемые провайдером. |
GET /ai/connections/{connection_id}/usage | Запросы и токены за этот месяц. |
GET /ai/connections/usable?channel_id=&team_id= | Для всех, кто вошёл в систему: доступные там подключения, их модели и возможности, но никогда не ключи или адреса. |
Тело нового подключения:
{
"name": "Local models",
"scope": "server",
"provider": "openai_compatible",
"base_url": "http://llm.internal:8000/v1",
"api_key": "…",
"extra_headers": {},
"models": {"chat": "qwen3-32b", "embeddings": "", "transcription": "", "decisions": ""},
"limits": {"requests_per_minute": 0, "monthly_token_budget": 0, "per_user_requests_per_minute": 0, "per_user_monthly_token_budget": 0},
"sharing": {"all_teams": true, "team_ids": []},
"audience": {"everyone": true, "group_ids": [], "roles": [], "allow_guests": false}
}
provider — это openai_compatible или anthropic. По умолчанию scope равно server; если указан идентификатор сообщества, подключение становится его собственным. В limits значение 0 означает отсутствие ограничений: запросы в минуту считаются на каждом сервере, а бюджеты токенов — за календарный месяц (UTC) для всего кластера. sharing определяет, какие сообщества могут использовать серверное подключение (для личных и групповых сообщений требуется all_teams), а audience — кто может им пользоваться; гости — только при allow_guests. Изменения записываются в журнал аудита. Настройки описаны в руководстве администратора: см. ИИ.