REST API

Всичко, което приложенията на Antimatter извършват, минава през един и същ HTTP API, така че и скриптовете ви могат да го направят. Тази страница обяснява как да се автентифицирате, кои ресурси ще използвате най-често, как изглеждат отговорите и грешките и как да следите събития в реално време през WebSocket.

Основни понятия

  • Базов URL: https://chat.example.com/api/v4. Всички ендпойнти по-долу са относителни към него.
  • Формат: JSON влязо и излязо, с изключение на качване на файлове (multipart). Изпращайте Content-Type: application/json.
  • Идентификатори: всеки обект има 26-символен id. Времето е в милисекунди от 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 …. Токените в query string (?access_token=) се приемат само за OAuth достъпни токени.

Лични достъпни токени (препоръчани за скриптове)

Личният достъпен токен действа от ваше име, не изтича, освен ако не му зададете срок на валидност, и може да бъде отменен по всяко време. Личните достъпни токени са изключени по подразбиране:

  1. Системният администратор активира Разреши маркери за личен достъп в Системна конзола › Интеграции › Управление на интеграциите (ServiceSettings.EnableUserAccessTokens, AM_SERVICESETTINGS_ENABLEUSERACCESSTOKENS).
  2. За всеки, който може да създава токени, системният администратор отваря Системна конзола › Управление на потребители › Потребители, избира Управление на роли от менюто на съответния човек и отметва Разреши на този акаунт да генерира лични достъпни токени. Системните администратори винаги могат да ги създават.
  3. Потребителят отваря аватара си в горния десен ъгъл, след което Профил и настройки › Сигурност. Под Лични маркери за достъп описва за какво е предназначен маркерът и избира Създайте маркер. Маркерът се показва само веднъж: копирайте го.

Чрез 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" за акаунт с мултифакторна автентикация. Сесиите изтичат според настройките за сесии на сървъра, а входният endpoint е с ограничение на честотата (5 заявки в секунда). POST /users/logout приключва сесията.

Браузърите се автентифицират с бисквитка. За заявки, автентифицирани с бисквитка, трябва да се изпраща и заглавието X-CSRF-Token за всичко, което не е GET; токен в заглавието Authorization не изисква CSRF заглавие.

Приложения за OAuth 2.0

За да позволите на хората да влизат в вашето приложение с акаунта си в Antimatter, регистрирайте OAuth 2.0 приложение. Antimatter става OAuth доставчик:

  1. Разреши доставчик OAuth 2.0 услуги трябва да е активиран (Системна конзола › Интеграции › Управление на интеграциите, ServiceSettings.EnableOAuthServiceProvider, активиран по подразбиране).
  2. Потребител с права за управление на OAuth приложенията (по подразбиране системните администратори) отваря Интеграции › OAuth 2.0 приложения (менюто на екипа › Настройки на екипа › Интеграции) и добавя приложението с неговите URL адреси за обратно извикване. Получава идентификатор на клиент и клиентска тайна.
  3. Приложението ви изпраща потребителите на https://chat.example.com/oauth/authorize с response_type=code, client_id, redirect_uri и state. Поддържа се PKCE с code_challenge_method=S256.
  4. Кодът се разменя на 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" (първото съобщение в нишка), за да отговорите в нишка, "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 (ID на съобщение). Те се връщат като списък със съобщения: {"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 добавя следните събития: agent_activity_changed и agent_post_stream (вижте Агенти), ai_tools_changed (вижте Агенти), community_rules_updated и community_rules_accepted (вижте Правила на общността), focus_ended (вижте Режим на фокус), community_attributes_updated, member_timeouts_updated, post_put_on_top, post_removed_from_top, server_categories_updated, channel_overrides_updated и category_overrides_updated. Новото влизане във вашия собствен акаунт изпраща session_created към другите ви сесии (session_id, create_at, platform, os, browser, mobile; никога не се изпраща токен), а обработването на предупреждението изпраща session_revoked или session_acknowledged (session_id) към всички тях.

Библиотеки за клиент

  • Отиди: 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; пакетът, публикуван на npm от Mattermost, не ги включва.
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/fields
POST същия път
PATCH, DELETE …/fields/{field_id}
Атрибути на общността: полетата на профила, които администраторите на общността дефинират за нейните членове (до 20). Членовете могат да ги четат; администраторите на общността ги създават и променят.
GET /teams/{team_id}/members/{user_id}/user_attributes
PATCH същия път
POST /teams/{team_id}/user_attributes/values/search
Стойностите на атрибутите на член, като {field_id: value}. Членовете задават собствените си (освен администрираните от администратори); администраторите задават на всеки. Търсенето приема {"user_ids": [...]} (до 200).
GET /teams/{team_id}/timeouts
PUT /teams/{team_id}/members/{user_id}/timeout
GET /teams/{team_id}/members/{user_id}/moderation
Изчаквания: {"until": time, "reason": "…"} спира някой да публикува, реагира и качва в общността до тогава (до 28 дни); "until": 0 го вдига. Изгледът за модерация показва кога са се присъединили и колко са публикували наскоро.
GET /channels/{channel_id}/on_top
PUT, DELETE /posts/{post_id}/on_top
Съобщения, задържани в горната част на канал (до 10). {"duration": ms}, максимум 30 дни; 0 ги задържа, докато не бъдат премахнати. Всеки, който може да чете канала, вижда списъка им. За да се постави съобщение в горната част или да се махне, е необходимо право за публикуване в канала и, в канал на общност, да се бъде администратор на канала или на общността, или да се има Управление на съобщения (delete_others_posts) там. В директно или групово съобщение това могат да направят неговите членове. В архивирани канали това се отхвърля.
GET, PUT /teams/{team_id}/rules
POST /teams/{team_id}/rules/accept
GET /teams/{team_id}/rules/stats
Правила на екипа: вижте Правила на екипа.
GET, POST, DELETE /users/me/focus
GET /users/me/focus/summary?since=&until=
POST /users/me/focus/summary/read
Режим на фокус: вижте Режим на фокус.
POST /channels/{channel_id}/message_requestДейства върху вашето искане за съобщение: {"action": "accept"}, "dismiss" или "request", за да върнете разговор сред исканията. Връща вашия член на канала.
GET, PUT /channels/{channel_id}/overrides
GET /channels/{channel_id}/overrides/effective
GET, PUT /channels/{channel_id}/role_access
Какво може да направи роля или човек в канал и кои роли виждат канал, достъпът до който е ограничен по роли.
GET, PUT /teams/{team_id}/server_categories
GET, PUT …/server_categories/overrides
Споделените категории канали на общността и изключенията, които се прилагат към всеки канал в дадена категория.
GET /groups/{group_id}/team_role
PUT …/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/connections
GET, PATCH, DELETE /ai/connections/{connection_id}
GET /ai/connections/usable
Връзки с модели, доставчиците на изкуствен интелект, които използват функциите и приложенията с ИИ на сървъра: вижте Връзки с модели.
GET, POST /ai/agents
GET, PATCH, DELETE /ai/agents/{agent_id}
POST /ai/agents/{agent_id}/tasks
GET /ai/agents/conversations
AI агенти, тяхната дейност и задачите и разговорите на AI чата: вижте Агенти.
GET /ai/agents/{agent_id}/tools
GET /ai/agents/tools/catalogue
POST /ai/tools/calls/{call_id}/confirm, /decline
GET, POST /ai/mcp_servers
GET, PATCH, DELETE /ai/mcp_servers/{server_id}
POST, DELETE /ai/mcp_servers/{server_id}/oauth
Инструментите на агента, каталогът с инструменти, които той може да използва, потвърждаването или отказването на чакащо извикване на инструмент и MCP сървърите, достъпни за агенти: вижте AI.
GET /channels/{channel_id}/message_actions
POST /posts/{post_id}/message_actions/{hook_id}
GET, POST /hooks/outgoing/{hook_id}/icon
Действия върху съобщения: изходящи Webhook-ове, които хората изпълняват от менюто на съобщението. Вижте Действия върху съобщения.
POST /users/me/sessions/acknowledgeПремахва предупреждението за ново влизане на една от вашите собствени сесии: {"session_id"}. Само влезлият потребител може да извика това за своите собствени сесии.
PUT /channels/{channel_id}/typeПроменя предварително зададеното състояние на канал или неговите настройки: вижте Типове канали.
GET /channels/{channel_id}/topics
PATCH /posts/{post_id}/topic
Темите във форум и приемането на отговор или задаването на статус на тема: вижте Типове канали.

Нови полета

  • Общности (Team и PUT /teams/{team_id}/patch): all_channels_membership (всички са членове на всеки канал, който могат да видят), default_channel_id (каналът, в който попадат новите потребители), welcome_channel_id (каналът, в който се изпращат съобщенията за присъединяване и напускане; оставете празно, за да няма такива), kind (community или workplace, показвани в интерфейса съответно като Guild и Workspace: при избор на guild се активира и all_channels_membership; новите общности получават стойността на TeamSettings.DefaultCommunityKind от сървъра, която по подразбиране е community/Guild), member_list_view (как списъкът с членове групира потребителите: choice (по подразбиране) позволява на всеки член да избере; roles или teams фиксира начина на групиране), hide_role_colors, require_team_badges, name_display (как общността показва имената на потребителите; оставете празно за сървърната настройка по подразбиране), както и onboarding и autolinks (и двете са JSON низове).
  • Каналът по подразбиране на ново общност е general (General), а не town-square. Апгрейдът до 0.9.0 преименува town-square на всяка общност в general, запазвайки идентификатора ѝ, освен ако общността вече няма канал general. Старите имена продължават да действат: GET /teams/{team_id}/channels/name/town-square, GET /teams/name/{team}/channels/name/town-square и channel на входящ webhook връщат канала по подразбиране на общността, когато няма канал с това име. Използвайте default_channel_id или името general в новия код.
  • Връзки към канали: #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: вижте Карти.
  • Канали (Channel): props на всеки канал в общността винаги съдържа am_type (text, voice или forum), am_mode, am_root_posts (members или moderators) и am_preset (идентификаторът на съответния набор от настройки или празен низ за персонализирани настройки), а за форуми – и am_forum_view (topics или imageboard). Ако в данните липсва am_type, това означава, че полето не е попълнено, а не че каналът е текстов. Директните и груповите съобщения не съдържат тези полета. Вижте Типове канали.

Типове канали

Канал в общност е text, voice или forum (типът се определя окончателно при създаването на канала), работи в един от режимите на своя тип и има допълнителни настройки. Наборът от настройки (preset) е именувано обединение на режим и настройки, което клиентът предлага като един избор; наборите не се съхраняват, затова am_preset на канала се извлича от неговите настройки и приема стойност "", когато те не съответстват на нито един набор ("Персонализирано").

Идентификатор на набораТипРежимroot_postsview
text_chattextchatmembers–
text_announcementtextchatmoderators–
voice_talkvoicetalkmembers–
voice_stagevoicestagemembers–
forum_agoraforumdiscussionmemberstopics
forum_qaforumqamemberstopics
forum_ideasforumideasmemberstopics
forum_announcementforumdiscussionmoderatorstopics
forum_imageboardforumdiscussionmembersimageboard

Създаване и промяна на типа на канал

POST /channels чете props.am_preset (който се разгръща първи), след което отделните props.am_type, am_mode, am_root_posts и am_forum_view върху него; всеки друг am_ параметър се игнорира. Създаването на гласов канал, когато приложението за гласови канали не е активно, се отказва (400 api.channel.type.voice_unavailable.app_error); създаването на директно или групово съобщение с параметри за тип се отказва (api.channel.type.direct.app_error).

curl -X POST https://chat.example.com/api/v4/channels \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"team_id": "'$TEAM_ID'", "name": "help-desk", "display_name": "Help desk", "type": "O",
       "props": {"am_preset": "forum_qa"}}'

PUT /channels/{channel_id}/type променя предварителната настройка или настройките на съществуващ канал: {"preset"?, "mode"?, "root_posts"?, "view"?}, като предварителната настройка се разгръща първо, както при създаването. Изисква се разрешаването manage_public_channel_properties или manage_private_channel_properties в канала (одиторско събитие updateChannelType) и връща попълнения канал. Тяло на заявката, което посочва друг type, се отказва (api.channel.type.fixed.app_error): самият тип никога не се променя. Други грешки: api.channel.type.invalid.app_error (неизвестна стойност, режим, който не е от типа на канала, или изглед за не-форум).

Масовият внос и износ (amctl import bulk) носят същите четири полета в реда на канала: am_type, am_mode, am_root_posts, am_forum_view. Реда на канал без тях се внася като обикновен текстов канал за чат, както преди въвеждането на типовете канали.

Кой може да започва разговори или да отваря теми

Публикуването на основно съобщение (за разлика от отговор) изисква разрешаването create_root_post, което в редактора за замяна на разрешенията се показва като Започване на разговори (текст, глас) или Отваряне на теми (форуми). Никоя роля не го притежава: преди замяната на разрешенията, всеки, който може да публикува, го има, когато root_posts е members, а само модераторите на канала (системни администратори, администратори на общност, администратори на канал и всеки с Управление на съобщения там) го имат, когато е moderators. Замяната на разрешението create_root_post за роля или човек се прилага отгоре, както за всяко друго разрешение. Отговорът (root_id зададен) изисква само обичайното право за публикуване.

Коренов пост, който не отговаря на това изискване, връща 403: app.post.root_posts.moderators_only.app_error, когато root_posts е moderators, а автора не е модератор на канала, или app.post.root_posts.denied.app_error при явно забраняващо заместване. Проверката се извършва за REST API, ботове, входящи и изходящи webhooks (за създателя на hook-а) и отговори на команди с наклонена черта; постове от приложения (чрез Plugin API) и копия на преместени нишки не се проверяват (там се проверява лицето, което премества нишката). Масовият импорт също пропуска тази проверка.

Форумите приемат само теми

В форум кореновият пост изисква props.am_thread_title (заглавието на темата), с премахнати водещи и крайни интервали, между 1 и 100 знака, независимо от източника (включително приложения и преместени нишки): липсващото заглавие връща 400 app.post.forum.title_required.app_error, а твърде дългото – app.post.forum.title_too_long.app_error. Отговорите не изискват заглавие и всяко изпратено заглавие в отговор се игнорира. Редактирането на кореновия пост на тема без заглавие или с празно такова запазва съществуващото заглавие; непразното заглавие я преименува. Преместването на нишка във форум (по-долу) също изисква заглавие – от заявката или от самата нишка.

Приетият отговор на тема от тип Q&A (am_accepted_answer, ID на отговор) и статусът на тема от тип Ideas (am_topic_status, заедно с am_topic_status_by и am_topic_status_at) се записват единствено чрез PATCH /posts/{post_id}/topic; ако някое от тези три полета е изпратено при създаване, обновяване или patch от клиент или приложение, то се игнорира и съхранената стойност се запазва.

Изброяване на темите във форум

GET /channels/{channel_id}/topics?sort=votes&per_page=25

Изисква се право за четене на канала. Параметри на заявката:

  • sort: activity (по подразбиране), newest, votes, unanswered (само за Q&A) или status (само за Ideas).
  • answered (true/false, Q&A) и status (едно от open, planned, in_progress, done, declined, Ideas): филтрирайте по тези параметри. Използването на който и да е от тях извън съответния режим връща 400.
  • mine=true: само темите, които сте създали. following=true: само тези, които следвате.
  • q: съвпадение със заглавието или текста на първия пост, до 200 знака.
  • before: next_cursor от предишната страница. per_page: по подразбиране 25, най-много 100. replies: от 0 до 5 от най-новите отговори във всяка тема, за изглед като на борда с изображения.

Отговор: {"topics": [{"post", "reply_count", "last_reply_at", "participant_ids", "votes", "accepted_answer_id", "status", "on_top", "replies": [post, …]}], "next_cursor"}. Гласовете са реакции 👍 (+1 и thumbsup се броят заедно), минус автора на самата тема; accepted_answer_id се предоставя само във форуми Q&A, status – само във форуми Ideas. Темите, закачени отгоре в канала, са първи.

Приемане на отговор или задаване на статус на тема

curl -X PATCH https://chat.example.com/api/v4/posts/$POST_ID/topic \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"accepted_answer_id": "'$REPLY_ID'"}'

post_id трябва да е основната публикация на тема от форум, иначе 400 app.topic.not_a_topic.app_error. accepted_answer_id (ИД на отговор или "", за да го оттеглите) изисква форум Q&A; status изисква форум Ideas; ако е зададено в грешен режим, връща 400 app.topic.mode.app_error.

  • Приемане на отговор: само автора на въпроса в темата (докато все още може да публикува там) или модератор на канала; иначе 403 app.topic.accept.not_allowed.app_error. Отговорът трябва да е активен, несистемен отговор на тази тема, иначе 400 app.topic.accept.not_a_reply.app_error. Изтриването на приетия отговор изчиства отговора.
  • Задаване на статус: само за модератори на канала, иначе 403 app.topic.status.not_allowed.app_error; неизвестна стойност връща 400 app.topic.status.invalid.app_error.

Всяка промяна публикува системен отговор в темата (уведомяващ последователите ѝ) и връща основната публикация на темата, както е в момента. Във форум Ideas гласуването за тема ви прави и неин последовател.

Преместване на нишка

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 използва това. Отхвърля се, когато целевият канал е форум (400 app.post.move_thread.forum_flatten.app_error): отговорите му биха станали теми без заглавия.
  • title: заглавието на темата, когато целевият канал е форум. Без него се запазва собственото заглавие на нишката, ако има такова; липсата на което и да е от двете връща 400 app.post.move_thread.forum_title_required.app_error. Игнорира се за целеви канал, който не е форум.

Съобщенията запазват авторите, времето, реакциите и файловете си. Копиите им носят свойството silent_notification, така че не известяват никого. Оригиналите се изтриват. Отговорът е преместеното първо съобщение с новото му ID.

Кой може да премества нишка

  • Трябва да можете да четете нишката и да публикувате в целевия канал.
  • Администраторите на канала, администраторите на общността, хората с Управление на съобщения (delete_others_posts) в канала и системните администратори могат да преместват всяка нишка.
  • Авторът на нишката може да я премести, когато и двата канала са публични, или когато всички съобщения в нишката са неговите. В противен случай отговорът е 403 с ID 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. Името на частен канал се пропуска: четците виждат „друг канал“. Собственият POST /posts/{post_id}/move на Mattermost остава изключен в Antimatter; използвайте този endpoint.

Правила на екипа

Администраторите на екип могат да изискат от членовете му да се съгласят с правилата, преди да публикуват в каналите му. Докато правилата са активни, член, който не е приел текущата версия, не може да публикува, да отговаря, да изпраща файлове, да планира, редактира или възстановява съобщение, нито да изпълнява команда, която публикува в каналите на екипа: сървърът отговаря с 403 и ID api.post.community_rules_not_accepted, а планирано съобщение, което трябва да бъде изпратено тогава, завършва с грешка с код community_rules_not_accepted. Четенето, реакциите и директните и групови съобщения не се ограничават; същото важи и за ботовете, входящите webhook-и, системните съобщения и администраторите на екипа (manage_team, което системните администратори също притежават).

ЕндпойнтКакво прави
GET /teams/{team_id}/rulesПравилата (enabled, text в Markdown, version), с последната версия, която сте приели (accepted_version), и дали трябва да приемете правилата, преди да публикувате (must_accept). За членове и за всеки, който може да се присъедини към отворена общност.
PUT /teams/{team_id}/rulesЗапазва ги с {"enabled", "text", "ask_again"} (manage_team). ask_again създава нова версия, която всеки трябва да приеме отново; първото запазване е версия 1. Текстът е задължителен, за да ги активирате, и е с максимална дължина 16 000 знака.
POST /teams/{team_id}/rules/acceptПриема като член version, която сте прочели; връща 409, ако е запазена по-нова версия, и 0, ако приемете текущата.
GET /teams/{team_id}/rules/statsБроят на членовете на общността, които са приели текущата версия (manage_team).

Събитието community_rules_updated се изпраща до общността, когато администратор запази правилата (team_id, enabled, version), а community_rules_accepted се изпраща до този, който ги е приел, във всички негови сесии (team_id, version).

Режим на фокус

Режимът на фокус е „Не ме безпокой“ с крайно време: известията се заглушават (без push, имейл, десктоп или постоянни известия, включително спешни съобщения), причината става персонализиран статус с емоджи 🎯 (dart), изтичащ в края на фокуса, и приложенията на Antimatter скриват собствените непрочетени маркери на потребителя. Само самият потребител може да използва тези крайни точки (me или неговия собствен ID): никой друг, включително системните администратори, не може да стартира, прекратява или чете фокуса на някого или неговото обобщение.

ЕндпойнтКакво прави
GET /users/me/focusТекущият фокус (active, start_at, end_at, reason) или последният, след като е приключил (ended_at е зададено), или всички нули.
POST /users/me/focusСтартира фокус или, докато сте във фокус, променя края и причината: {"duration": "1h30m", "reason": "…"}, или {"end_at": ms} вместо продължителност, от един минута до една седмица напред. "duration": "tomorrow" завършва в 09:00 на следващия ден в часовата зона на потребителя. Краят се закръгля надолу до минутата; причината е с максимална дължина 100 знака. Изисква статусите на потребителите да са активирани (ServiceSettings.EnableUserStatuses); ботовете не могат да използват фокус.
DELETE /users/me/focusПрекратява фокуса сега.
GET /users/me/focus/summary?since=&until=Какво е пропуснато в този прозорец (полетата start_at и ended_at на фокуса): каналите с непрочетени съобщения от други (първо директни и групови съобщения, след това тези с споменавания; заглушените канали само при споменаване) и, при свити нишки с отговори, следваните нишки с нови отговори, всяка със своя брой, споменавания и последен изпращач.
POST /users/me/focus/summary/readС {"since", "until"}: маркира тези канали и нишки като прочетени само до until; съобщенията след това остават непрочетени.

Докато някой е на фокус, потребителят му има свойството focus_until (в милисекунди), което клиентите използват за показване на статуса на фокус; то не може да се променя през профила. Фокусът приключва, когато човекът го прекрати, когато изтече времето му (в рамките на една минута) или когато той сам избере статус, който след това остава. В противен случай се възстановяват предишният статус и персонализиран статус. Тогава всички негови сесии получават събитието focus_ended, с start_at, end_at и ended_by (user, timer или status).

Връзки с модели

Моделно свързване е адресът и ключът на AI доставчик, настроени от администратор. Функциите за изкуствен интелект на сървъра и приложенията, които извикват AI услугата, ги използват. Системните администратори управляват свързванията за целия сървър (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; ID на общност я прави връзка за тази общност. В limits, 0 означава без ограничение; заявките на минута се броят на всеки сървър, а бюджетът на токени е на календарен месец (UTC) за целия клъстер. sharing посочва кои общности могат да използват сървърна връзка (директните и груповите съобщения изискват all_teams), а audience — кой може да я използва; гости само при allow_guests. Промените се записват в журнала за одит. Ръководството за администратори обяснява настройките: вижте AI.

Агенти

Агентът е бот акаунт от тип agent (is_agent в потребителските данни), със следните настройки: обхват (server или ID на общност), тип – вграден или external, а за вграден агент – връзка с модела, модел, системен промпт и разсъждения. Системните администратори управляват агентите за цял сървър (manage_system), а администраторите на общност – тези на своята общност (manage_team). Освен това има права manage_own_agent за агент, създаден от потребителя, и manage_others_agent за останалите агенти. В тези пътища ID на агента е неговото потребителско ID. Стартирането на външен агент и начинът, по който се задава статусът на вграден агент, са описани в раздел Ботове. Крайните точки PUT /users/{user_id}/status и тези за персонализиран статус отказват ID на вграден агент, дори за системни администратори (403, api.status.agent.app_error).

ЕндпойнтКакво прави
GET /ai/agents?scope=Агентите, които управлявате: scope е server или ID на общност; без него – всеки агент, който управлявате.
POST /ai/agentsСъздава агент и неговия акаунт (връща 201). Агент на общност се присъединява към общността.
GET, PATCH, DELETE /ai/agents/{agent_id}
POST …/enable, POST …/disable
Чете, променя, изтрива (акаунтът му се деактивира, съобщенията му остават), включва или изключва агент.
GET /ai/agents/connections?scope=
GET /ai/agents/connections/{connection_id}/models
Връзките с модели, които агент от този обхват може да използва, и техните модели.
GET, PUT /ai/agents/{agent_id}/activity
POST /ai/agents/activity/ids
Какво прави агента; задава се от неговия собствен токен или от неговите управители. Пакетът приема до 200 потребителски ID-та.
POST /ai/agents/{agent_id}/tasksЗадава въпрос на вграден агент, който можете да използвате за задача: summarize_thread, find_action_items или find_open_questions (за post_id на нишка или channel_id от since нататък), summarize_channel, ask_channel (с question) или summarize_transcription (запис на транскрипция от обаждане). Заявката се превръща във вашето съобщение в директното съобщение с агента, на вашия език, и получава отговор там; отговорът (201) е това съобщение. Пост или канал, които не можете да прочетете, се разглеждат като несъществуващи.
GET /ai/agents/conversations?agent_id=&before=&per_page=Вашите разговори с агентите, които можете да използвате, най-новите първи: нишките, които сте започнали в директните си съобщения с тях, и нишките на други места, в които някой от тях е отговорил и които следите. before (време) дава следващата страница; per_page е най-много 100.

Тялото на нов агент:

{
  "username": "researcher",
  "display_name": "Researcher",
  "description": "Answers with sources",
  "scope": "server",
  "external": false,
  "connection_id": "…",
  "model": "",
  "system_prompt": "You research questions and answer with sources.",
  "reasoning": {"enabled": false, "effort": "", "budget_tokens": 0},
  "max_tool_turns": 0,
  "access": {"everyone": true, "team_ids": [], "channel_ids": [], "roles": [], "user_ids": [], "allow_guests": false}
}

Празен model използва модела за чат на връзката. access.channel_ids означава членовете на тези канали. Външният агент няма връзка, модел или системен промпт. GET /agents изброява агентите, с които можете да разговаряте, както ги вижда приложението за AI чат.