Die REST-API

Alles, was die Antimatter-Apps tun, läuft über dieselbe HTTP-API – Ihre Skripte können das also auch. Diese Seite erklärt, wie Sie sich authentifizieren, welche Ressourcen Sie am häufigsten verwenden, wie Antworten und Fehler aussehen und wie Sie Ereignisse live über den WebSocket verfolgen können.

Grundlagen

  • Basis-URL: https://chat.example.com/api/v4. Alle unten genannten Endpunkte sind relativ dazu.
  • Format: JSON als Eingang und Ausgang, außer bei Datei-Uploads (multipart). Senden Sie Content-Type: application/json.
  • IDs: Jedes Objekt hat eine 26 Zeichen lange id. Zeitangaben sind Millisekunden seit dem Unix-Epoch (create_at, update_at, delete_at; 0 bedeutet „nicht gelöscht“).
  • Communities sind Teams: Die API bezeichnet sie als teams mit einer team_id.
  • Sie selbst: Wo immer ein Pfad eine user_id erwartet, bedeutet me die angemeldete Person, wie in GET /users/me.

Die vollständige Liste der Endpunkte finden Sie im Code des Servers: Die Routen sind in server/channels/api4/*.go und die Typen in server/public/model deklariert. Die OpenAPI-Beschreibung im Ordner api/v4/source des Repositorys deckt die von Mattermost geerbten Endpunkte sowie einige Erweiterungen von Antimatter ab: das Verschieben von Threads, Modellverbindungen, Agenten, Community-Regeln, den Fokusmodus und Nachrichtenaktionen. Die übrigen sind nur im Code enthalten.

Authentifizierung

Jede Anfrage, mit Ausnahme des Anmeldevorgangs und einiger öffentlicher Endpunkte, benötigt ein Token im Authorization-Header:

curl -H "Authorization: Bearer $TOKEN" https://chat.example.com/api/v4/users/me

Dort werden drei Arten von Tokens akzeptiert: persönliche Zugriffstokens, Sitzungstokens und OAuth-Zugriffstokens. Auch Authorization: Token … wird akzeptiert. Tokens in der Abfragezeichenfolge (?access_token=) werden nur für OAuth-Zugriffstokens akzeptiert.

Persönliche Zugriffstokens (empfohlen für Skripte)

Ein persönliches Zugriffstoken handelt in Ihrem Namen, läuft nicht ab, es sei denn, Sie vergeben ein Ablaufdatum, und kann jederzeit widerrufen werden. Persönliche Zugriffstokens sind standardmäßig deaktiviert:

  1. Ein Systemadministrator aktiviert Persönliche Zugriffs-Token aktivieren in Systemkonsole › Integrationen › Integrationsverwaltung (ServiceSettings.EnableUserAccessTokens, AM_SERVICESETTINGS_ENABLEUSERACCESSTOKENS).
  2. Für jede Person, die Tokens erstellen darf, öffnet ein Systemadministrator die Systemkonsole › Benutzerverwaltung › Benutzer, wählt im Menü der Person Rollen verwalten und aktiviert Diesem Konto die Erstellung persönlicher Zugriffstokens erlauben. Systemadministratoren können diese immer erstellen.
  3. Die Person öffnet oben rechts das eigene Avatar und dann Profil & Einstellungen › Sicherheit. Unter Persönliche Zugriffs-Token wird beschrieben, wofür das Token verwendet wird, und Token erstellen ausgewählt. Das Token wird nur einmal angezeigt: Es muss kopiert werden.

Über die API: POST /users/{user_id}/tokens mit {"description": "backup script", "expires_at": 0} (expires_at in Millisekunden; 0 für keine Ablaufzeit). Das Feld token in der Antwort ist das Geheimnis; die id wird verwendet, um es zu widerrufen (POST /users/tokens/revoke mit {"token_id": "…"}). Von der Kommandozeile: amctl token generate <user> <description>.

Ein Systemadministrator kann die Gültigkeitsdauer von Tokens über Maximale Gültigkeitsdauer für persönliche Zugriffstokens (Tage) auf derselben Systemkonsole-Seite begrenzen.

Sitzungstokens

Bei der Anmeldung mit einem Passwort wird ein Sitzungstoken im Antwort-Header Token zurückgegeben, die gleiche Art von Sitzung, die die Apps verwenden:

curl -i -X POST https://chat.example.com/api/v4/users/login \
  -H 'Content-Type: application/json' \
  -d '{"login_id": "maya", "password": "…"}'

Fügen Sie für ein Konto mit Multi-Faktor-Authentifizierung "token": "123456" hinzu. Sitzungen laufen ab, wie es die Sitzungseinstellungen des Servers vorsehen, und der Anmelde-Endpunkt ist ratenbegrenzt (5 Anfragen pro Sekunde). POST /users/logout beendet die Sitzung.

Browser authentifizieren sich stattdessen mit einem Cookie. Eine durch das Cookie authentifizierte Anfrage muss für alles außer GET auch den Header X-CSRF-Token senden; ein Token im Header Authorization benötigt keinen CSRF-Header.

OAuth-2.0-Apps

Um es Personen zu ermöglichen, sich mit ihrem Antimatter-Konto in Ihrer Anwendung anzumelden, registrieren Sie eine OAuth-2.0-App. Antimatter ist dann der OAuth-Anbieter:

  1. Aktiviere OAuth-2.0-Dienstprovider muss aktiviert sein (Systemkonsole › Integrationen › Integrationsverwaltung, ServiceSettings.EnableOAuthServiceProvider, standardmäßig aktiviert).
  2. Eine Person mit der Berechtigung zur Verwaltung von OAuth-Apps (standardmäßig Systemadministratoren) öffnet Integrationen › OAuth-2.0-Apps (Community-Menü › Teameinstellungen › Integrationen) und fügt die App mit ihren Rückruf-URLs hinzu. Sie erhält eine Client-ID und ein Client-Secret.
  3. Ihre Anwendung leitet Personen an https://chat.example.com/oauth/authorize weiter, mit response_type=code, client_id, redirect_uri und state. PKCE mit code_challenge_method=S256 wird unterstützt.
  4. Sie tauscht den Code an POST https://chat.example.com/oauth/access_token ein (grant_type=authorization_code, dann refresh_token zur Erneuerung) und ruft die API mit Authorization: Bearer <access token> auf.

Personen sehen die Apps, die sie autorisiert haben, unter Profil & Einstellungen › Sicherheit › Von dir autorisierte Apps.

Wichtige Ressourcen

WasEndpunkte
Sie und andere PersonenGET /users/me, GET /users/{user_id}, GET /users/username/{username}, POST /users/ids (eine Liste von IDs), POST /users/search, GET /users?in_team=…&in_channel=…
CommunitiesGET /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
KanäleGET /users/me/teams/{team_id}/channels, GET /teams/name/{team}/channels/name/{channel}, POST /channels, POST /channels/direct (zwei Benutzer-IDs), POST /channels/group, POST /channels/{channel_id}/members
Nachrichten (Posts)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
ReaktionenPOST /reactions mit {"user_id", "post_id", "emoji_name"}, DELETE /users/{user_id}/posts/{post_id}/reactions/{emoji_name}
DateienPOST /files (Multipart: channel_id und files), dann die zurückgegebenen IDs in file_ids des Posts einfügen; GET /files/{file_id}
EinstellungenGET /users/me/preferences, PUT /users/me/preferences
Integrationen/hooks/incoming, /hooks/outgoing, /commands, /bots, /oauth/apps (siehe folgende Seiten)
ServerGET /system/ping (Status, kein Token erforderlich), GET /config/client?format=old (die Einstellungen, die Clients sehen)

Eine Nachricht senden

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

Nachrichten sind Markdown. Fügen Sie "root_id" (der erste Post eines Threads) hinzu, um in einem Thread zu antworten, "file_ids" für Dateien und "props" für Anhänge und andere Zusatzinformationen (siehe Anhänge).

Die ID eines Kanals finden

curl -H "Authorization: Bearer $TOKEN" \
  https://chat.example.com/api/v4/teams/name/lumen-labs/channels/name/ops-alerts

Die Namen sind die aus dem Link des Kanals: /lumen-labs/channels/ops-alerts.

Paginierung

Liste-Endpunkte akzeptieren page (ab 0) und per_page (Standard 60, höchstens 200). Fordern Sie die nächste Seite an, bis eine Seite zurückkommt, die kürzer ist als per_page.

Die Nachrichten eines Kanals (GET /channels/{channel_id}/posts) akzeptieren auch since (eine Zeit: alles, was sich seitdem geändert hat) oder before und after (eine Beitrags-ID). Sie werden als Beitragsliste zurückgegeben: {"order": [IDs, newest first], "posts": {ID: post}, "next_post_id", "prev_post_id"}.

Fehler

Fehler verwenden die üblichen HTTP-Statuscodes (400 ungültige Eingabe, 401 nicht angemeldet, 403 nicht erlaubt, 404 nicht gefunden, 501 Funktion deaktiviert) und einen JSON-Body:

{
  "id": "api.context.permissions.app_error",
  "message": "You do not have the appropriate permissions.",
  "detailed_error": "",
  "request_id": "jz8zm5nunpbt8f3gpqsz5dq6so",
  "status_code": 403
}

Verwenden Sie id in Ihrem Code: message wird in die Sprache des Nutzers übersetzt. detailed_error ist leer, es sei denn, der Server läuft im Entwicklermodus (ServiceSettings.EnableDeveloper). Nennen Sie dem Server-Administrator die request_id: Sie ist in den Logs zu finden.

Ratenbegrenzung

Die Geschwindigkeitsbegrenzung ist standardmäßig deaktiviert. Wenn ein Systemadministrator sie aktiviert (Systemkonsole › Umgebung › Geschwindigkeitsbegrenzung), erhält jeder Client standardmäßig 10 Anfragen pro Sekunde mit Burst-Werten von 100, gezählt nach IP-Adresse oder Benutzer. Die Antworten enthalten X-RateLimit-Limit, X-RateLimit-Remaining und X-RateLimit-Reset; bei Überschreitung des Limits antwortet der Server mit 429 und einem Retry-After-Header in Sekunden. Einige Endpunkte, wie das Anmelden, haben unabhängig von der Einstellung ein eigenes Limit.

Schreiben Sie Skripte, die bei 429 warten und erneut versuchen, und vermeiden Sie Polling: Verwenden Sie stattdessen den WebSocket.

Der WebSocket-Ereignisstrom

Verbinden Sie sich mit wss://chat.example.com/api/v4/websocket. Authentifizieren Sie sich entweder über den Authorization: Bearer-Header in der Verbindungsanfrage oder indem Sie dies als erste Nachricht senden:

{"seq": 1, "action": "authentication_challenge", "data": {"token": "…"}}

Der Server sendet ein hello-Ereignis, gefolgt von einem Ereignis für alles, was Sie sehen dürfen:

{
  "event": "posted",
  "data": {"channel_id": "…", "channel_type": "O", "post": "{\"id\":\"…\",\"message\":\"Hello\",…}"},
  "broadcast": {"channel_id": "…", "team_id": "", "user_id": "", "omit_users": null},
  "seq": 4
}

Beachten Sie, dass data.post der Post als JSON-String ist. Häufige Ereignisse: posted, post_edited, post_deleted, reaction_added, reaction_removed, typing, status_change, user_added, direct_added. Apps senden eigene Ereignisse, benannt als custom_<app id>_<event>.

Sie können auch Aktionen senden, jeweils mit einer steigenden seq: user_typing mit {"channel_id", "parent_id"} oder get_statuses. Stellen Sie die Verbindung wieder her, wenn sie abbricht, und holen Sie sich mit since das nach,, was Sie verpasst haben (siehe Paginierung).

Antimatter fügt diese Ereignisse hinzu: agent_activity_changed und agent_post_stream (siehe Agenten), ai_tools_changed (siehe Agenten), community_rules_updated und community_rules_accepted (siehe Community-Regeln), focus_ended (siehe Fokusmodus), community_attributes_updated, member_timeouts_updated, post_put_on_top, post_removed_from_top, server_categories_updated, channel_overrides_updated und category_overrides_updated. Eine neue Anmeldung bei Ihrem eigenen Konto sendet session_created an Ihre anderen Sitzungen (session_id, create_at, platform, os, browser, mobile; niemals ein Token), und die Bearbeitung der Warnung sendet session_revoked oder session_acknowledged (session_id) an alle diese Sitzungen.

Client-Bibliotheken

  • Los: model.Client4 in server/public/model (Import github.com/mattermost/mattermost/server/public/model). model.NewAPIv4Client(url), dann client.SetToken(token); model.NewWebSocketClient4(wsURL, token) folgt Ereignissen. Die Antimatter-Kopie fügt Methoden für eigene Endpunkte hinzu, wie UpdateMessageRequest, PutPostOnTop und ExportChannel.
  • TypeScript: die Client4-Klasse von @mattermost/client in webapp/platform/client, mit den Typen in webapp/platform/types. Die Kopie im Antimatter-Repository enthält die Endpunkte von Antimatter; das von Mattermost auf npm veröffentlichte Paket nicht.
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)
}

Was Antimatter zur API hinzufügt

Diese Endpunkte und Felder existieren nicht auf einem Mattermost-Server. Alle erfordern eine Sitzung.

EndpunktFunktion
GET /teams/{team_id}/user_attributes/fields
POST gleicher Pfad
PATCH, DELETE …/fields/{field_id}
Community-Attribute: die Profilfelder, die die Administratoren einer Community für ihre Mitglieder definieren (maximal 20). Mitglieder können sie lesen; Community-Administratoren erstellen und ändern sie.
GET /teams/{team_id}/members/{user_id}/user_attributes
PATCH gleicher Pfad
POST /teams/{team_id}/user_attributes/values/search
Die Attributwerte eines Mitglieds als {field_id: value}. Mitglieder setzen ihre eigenen (außer die von Administratoren verwalteten); Administratoren setzen die von beliebigen Mitgliedern. Die Suche akzeptiert {"user_ids": [...]} (maximal 200).
GET /teams/{team_id}/timeouts
PUT /teams/{team_id}/members/{user_id}/timeout
GET /teams/{team_id}/members/{user_id}/moderation
Timeouts: {"until": time, "reason": "…"} verhindert, dass jemand in der Community bis zu diesem Zeitpunkt postet, reagiert und hochlädt (maximal 28 Tage); "until": 0 hebt es auf. Die Moderationsansicht zeigt, wann sie beigetreten sind und wie viel sie kürzlich gepostet haben.
GET /channels/{channel_id}/on_top
PUT, DELETE /posts/{post_id}/on_top
Nachrichten, die oben in einem Kanal angeheftet werden (maximal 10). {"duration": ms}, höchstens 30 Tage; 0 behält sie bei, bis sie entfernt werden. Alle, die den Kanal lesen können, sehen die Liste. Um eine Nachricht oben anzuheften oder wieder zu entfernen, benötigt man das Recht, im Kanal zu posten, und – in einem Community-Kanal – die Rolle als Administrator des Kanals oder der Community oder das Recht Nachrichten verwalten (delete_others_posts) dort. In Direktnachrichten oder Gruppennachrichten können dies die Mitglieder. In archivierten Kanälen wird dies abgelehnt.
GET, PUT /teams/{team_id}/rules
POST /teams/{team_id}/rules/accept
GET /teams/{team_id}/rules/stats
Community-Regeln: siehe Community-Regeln.
GET, POST, DELETE /users/me/focus
GET /users/me/focus/summary?since=&until=
POST /users/me/focus/summary/read
Fokusmodus: siehe Fokusmodus.
POST /channels/{channel_id}/message_requestWirkt auf Ihre eigene Nachrichten-Anfrage: {"action": "accept"}, "dismiss" oder "request", um eine Konversation wieder unter den Anfragen zu platzieren. Gibt Ihr Kanalmitglied zurück.
GET, PUT /channels/{channel_id}/overrides
GET /channels/{channel_id}/overrides/effective
GET, PUT /channels/{channel_id}/role_access
Was eine Rolle oder Person in einem Kanal tun darf und welche Rollen einen rollengesteuerten Kanal sehen.
GET, PUT /teams/{team_id}/server_categories
GET, PUT …/server_categories/overrides
Die gemeinsam genutzten Kanal-Kategorien der Community und die Überschreibungen, die auf jeden Kanal in einer Kategorie angewendet werden.
GET /groups/{group_id}/team_role
PUT …/team_role/permissions
Die Berechtigungen, die eine Community-Rolle gewährt.
POST /teams/{team_id}/autolinks/previewTestet die Autolink-Regeln der Community an einem Text.
POST /channels/{channel_id}/export?format=csv&since=&until=Lädt die Nachrichten eines Kanals als CSV herunter (max. 50.000), für Personen, die den Kanal lesen dürfen.
GET /posts/{post_id}/speechDie vorgelesene Nachricht als Audio, wenn die Text-zu-Sprache-Umsetzung eingerichtet ist.
POST /posts/{post_id}/move_to_channelVerschiebt einen Thread in einen anderen Kanal derselben Community: siehe Thread verschieben.
GET, POST /ai/connections
GET, PATCH, DELETE /ai/connections/{connection_id}
GET /ai/connections/usable
Modellverbindungen, die KI-Anbieter, die die KI-Funktionen und Apps des Servers verwenden: siehe Modellverbindungen.
GET, POST /ai/agents
GET, PATCH, DELETE /ai/agents/{agent_id}
POST /ai/agents/{agent_id}/tasks
GET /ai/agents/conversations
KI-Agenten, deren Aktivität sowie die Aufgaben und Unterhaltungen des KI-Chats: siehe Agenten.
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
Die Tools eines Agenten, der Katalog der Tools, die er verwenden darf, das Bestätigen oder Ablehnen eines wartenden Tool-Aufrufs sowie die für Agenten verfügbaren MCP-Server: siehe KI.
GET /channels/{channel_id}/message_actions
POST /posts/{post_id}/message_actions/{hook_id}
GET, POST /hooks/outgoing/{hook_id}/icon
Nachrichtenaktionen: ausgehende Webhooks, die Personen über das Nachrichtenmenü ausführen. Siehe Nachrichtenaktionen.
POST /users/me/sessions/acknowledgeVerwirft die Warnung vor einer neuen Anmeldung bei einer Ihrer eigenen Sitzungen: {"session_id"}. Dies darf nur von der angemeldeten Person für ihre eigenen Sitzungen aufgerufen werden.
PUT /channels/{channel_id}/typeÄndert den Preset eines Kanals oder dessen Einstellungen: siehe Kanal-Typen.
GET /channels/{channel_id}/topics
PATCH /posts/{post_id}/topic
Themen eines Forums sowie das Annehmen einer Antwort oder das Festlegen des Status eines Themas: siehe Kanalarten.

Neue Felder

  • Communities (Team und PUT /teams/{team_id}/patch): all_channels_membership (alle sind in jedem Kanal, den sie sehen können), default_channel_id (wo Neueinsteiger landen), welcome_channel_id (wohin die Beitritts- und Austrittsnachrichten gehen, leer für keine), kind (community oder workplace, in der Oberfläche als Guild und Workspace angezeigt: eine Guild aktiviert auch all_channels_membership; neue Communities erhalten den Serverwert TeamSettings.DefaultCommunityKind, standardmäßig community/Guild), member_list_view (wie die Mitgliederliste die Mitglieder gruppiert: choice, die Standardeinstellung, lässt jedes Mitglied wählen; roles oder teams legt dies fest), hide_role_colors, require_team_badges, name_display (wie die Community Personen anzeigt: leer für die Server-Standardeinstellung), onboarding und autolinks (beide JSON-Zeichenketten).
  • Der Standardkanal einer neuen Community ist general (Allgemein), nicht town-square. Das Upgrade auf 0.9.0 benennt den town-square-Kanal jeder Community in general um, wobei die ID beibehalten wird, sofern die Community nicht bereits einen general-Kanal besitzt. Die alten Namen funktionieren weiterhin: GET /teams/{team_id}/channels/name/town-square, GET /teams/name/{team}/channels/name/town-square sowie das channel-Feld eines eingehenden Webhooks liefern den Standardkanal der Community, wenn kein Kanal diesen Namen trägt. Verwenden Sie in neuem Code default_channel_id oder den Namen general.
  • Kanallinks: #channel-name verlinkt einen Kanal, genau wie ~channel-name. Die channel_mentions-Eigenschaft des Beitrags listet die auf diese Weise verlinkten Kanäle auf; ein #word, der keinen Kanal benennt, bleibt ein Hashtag. Die Web-Oberfläche und die Mobile-App von Antimatter schreiben #name.
  • Archivierte Kanäle können weiterhin neue Mitglieder aufnehmen (POST /channels/{channel_id}/members), die deren Verlauf lesen können. Niemand kann dort posten, reagieren, anheften, Nachrichten nach oben setzen, den Kanal umbenennen oder die Rollen der Mitglieder ändern.
  • Inlinen-Antworten: Ein Beitrag mit "props": {"reply_to": "<post id>"} zitiert diese Nachricht aus demselben Kanal. Fügen Sie "reply_to_mention": false hinzu, um den Autor nicht zu benachrichtigen. Der Server füllt metadata.reply_to mit einer kurzen Beschreibung der zitierten Nachricht.
  • Spoiler: "props": {"spoiler": true} verbirgt den Text und die Dateien eines Beitrags, bis der Leser entscheidet, sie anzuzeigen.
  • Ignorieren und Sperren sind Einstellungen: Kategorie user_block, benannt nach der ID der anderen Person, mit dem Wert ignore oder block. Ob eine Direktnachricht als Anfrage wartet, steht in den notify_props.dm_request Ihres Kanalmitglieds (pending, accepted oder dismissed).
  • Nachrichtenanhänge können stages und ein chart enthalten: siehe Cards.
  • Kanäle (Channel): Die props jedes Community-Kanals enthalten immer am_type (text, voice oder forum), am_mode, am_root_posts (members oder moderators) und am_preset (die ID des entsprechenden Presets oder leer bei individuellen Einstellungen) sowie bei Foren am_forum_view (topics oder imageboard). Ein Payload ohne am_type bedeutet, dass das Feld nicht ausgefüllt wurde, niemals, dass der Kanal ein Textkanal ist. Direkte und Gruppennachrichten enthalten keine dieser Informationen. Siehe Kanalarten.

Kanalarten

Ein Community-Kanal ist text, voice oder forum (seine Art, die bei der Erstellung festgelegt wird), in einem der Modi seiner Art, mit darüber liegenden Einstellungen. Ein Preset ist eine benannte Kombination aus einem Modus und Einstellungen, die ein Client als eine einzige Auswahlmöglichkeit anbietet; Presets werden nicht gespeichert, daher wird das Preset eines Kanals (am_preset) aus seinen Einstellungen abgeleitet und liest "", wenn sie keinem Preset entsprechen („Custom“).

Preset-IDTypModusroot_postsview
text_chattextchatmembers–
text_announcementtextchatmoderators–
voice_talkvoicetalkmembers–
voice_stagevoicestagemembers–
forum_agoraforumdiscussionmemberstopics
forum_qaforumqamemberstopics
forum_ideasforumideasmemberstopics
forum_announcementforumdiscussionmoderatorstopics
forum_imageboardforumdiscussionmembersimageboard

Erstellen und Ändern der Kanalart

POST /channels liest props.am_preset (wird zuerst expandiert), danach die einzelnen props.am_type, am_mode, am_root_posts und am_forum_view darüber; jedes andere am_-Prop wird verworfen. Das Erstellen eines Sprachkanals, während die Voice Channels-App nicht aktiv ist, wird abgelehnt (400 api.channel.type.voice_unavailable.app_error); das Erstellen einer Direktnachricht oder Gruppennachricht mit Typ-Props wird abgelehnt (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 ändert den Preset oder die Einstellungen eines vorhandenen Kanals: {"preset"?, "mode"?, "root_posts"?, "view"?}, wobei der Preset zuerst wie beim Erstellen expandiert wird. Es werden manage_public_channel_properties oder manage_private_channel_properties im Kanal benötigt (Audit-Ereignis updateChannelType), und es wird der ausgefüllte Kanal zurückgegeben. Ein Body, der einen anderen type nennt, wird abgelehnt (api.channel.type.fixed.app_error): Der Typ selbst ändert sich nie. Weitere Fehler: api.channel.type.invalid.app_error (ein unbekannter Wert, ein Modus, der nicht zum Typ des Kanals gehört, oder eine Ansicht bei einem Nicht-Forum).

Der Massenimport und -export (amctl import bulk) führt dieselben vier Felder in der Zeile eines Kanals mit: am_type, am_mode, am_root_posts, am_forum_view. Eine Kanalzeile ohne diese Felder wird als einfacher Text-Chat-Kanal importiert, wie vor der Einführung von Kanaltypen.

Wer Konversationen startet oder Themen eröffnet

Das Posten einer Root-Nachricht (im Gegensatz zu einer Antwort) erfordert die Berechtigung create_root_post, die im Overrides-Editor als Konversationen starten (Text, Sprache) oder Themen eröffnen (Foren) angezeigt wird. Keine Rolle besitzt diese Berechtigung standardmäßig: Vor den Overrides besitzen sie alle, die posten dürfen, wenn root_posts auf members steht, und nur die Moderatoren des Kanals (Systemadministratoren, Community-Administratoren, Kanaladministratoren und alle, die dort über Nachrichten verwalten verfügen), wenn es auf moderators steht. Ein Rollen- oder Personen-Override für create_root_post wird dann darüber angewendet, wie bei jeder anderen Berechtigung. Eine Antwort (mit gesetzter root_id) benötigt nur das übliche Recht zu posten.

Ein Wurzelbeitrag, der diese Prüfung nicht besteht, führt zu 403: app.post.root_posts.moderators_only.app_error, wenn root_posts auf moderators gesetzt ist und der Verfasser kein Moderator des Kanals ist, oder app.post.root_posts.denied.app_error bei einer expliziten Ablehnung. Diese Prüfung erfolgt für die REST-API, Bots, eingehende und ausgehende Webhooks (basierend auf dem Ersteller des Hooks) sowie für Antworten von Slash-Befehlen; Beiträge von Apps (über die Plugin-API) und Kopien eines verschobenen Threads werden nicht geprüft (hier wird stattdessen die Person geprüft, die den Thread verschiebt). Auch der Massenimport überspringt diese Prüfung.

Foren akzeptieren nur Themen

In einem Forum benötigt ein Wurzelbeitrag props.am_thread_title (den Titel des Themas), ohne führende/abschließende Leerzeichen, mit einer Länge von 1 bis 100 Zeichen, unabhängig von der Quelle; dies gilt auch für Apps und verschobene Threads. Fehlt der Titel, wird 400 app.post.forum.title_required.app_error zurückgegeben; ist er zu lang, app.post.forum.title_too_long.app_error. Antworten benötigen keinen Titel; ein bei einer Antwort übermittelter Titel wird verworfen. Beim Bearbeiten des Wurzelbeitrags eines Themas ohne Titel oder mit einem leeren Titel bleibt der vorhandene Titel erhalten; ein nicht leerer Titel benennt das Thema um. Das Verschieben eines Threads in ein Forum (siehe unten) erfordert ebenfalls einen Titel, entweder aus der Anfrage oder aus dem Thread selbst.

Die akzeptierte Antwort eines Q&A-Themas (am_accepted_answer, die ID einer Antwort) und der Status eines Ideen-Themas (am_topic_status, zusammen mit am_topic_status_by und am_topic_status_at) werden ausschließlich über PATCH /posts/{post_id}/topic geschrieben. Wird einer dieser drei Werte beim Erstellen, Aktualisieren oder Patchen gesendet, sei es durch einen Client oder eine App, wird er verworfen und der gespeicherte Wert beibehalten.

Themen eines Forums auflisten

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

Erfordert das Recht, den Kanal zu lesen. Abfrageparameter:

  • sort: activity (Standard), newest, votes, unanswered (nur Q&A) oder status (nur Ideen).
  • answered (true/false, Q&A) und status (einer von open, planned, in_progress, done, declined, Ideen): Filtern Sie nach diesen Werten. Die Verwendung außerhalb des jeweiligen Modus führt zu 400.
  • mine=true: Nur die Themen, die Sie erstellt haben. following=true: Nur die Themen, denen Sie folgen.
  • q: Sucht im Titel oder im Text des ersten Beitrags, bis zu 200 Zeichen.
  • before: der next_cursor der vorherigen Seite. per_page: Standardwert 25, maximal 100. replies: die 0 bis 5 neuesten Antworten jedes Themas für eine Bildtafel-Ansicht.

Antwort: {"topics": [{"post", "reply_count", "last_reply_at", "participant_ids", "votes", "accepted_answer_id", "status", "on_top", "replies": [post, …]}], "next_cursor"}. Stimmen sind 👍-Reaktionen (+1 und thumbsup werden zusammengezählt), abzüglich der Autor:in des Themas selbst; accepted_answer_id wird nur in Q&A-Foren angegeben, status nur in Ideen-Foren. Themen, die im Kanal oben angeheftet sind, werden zuerst angezeigt.

Eine Antwort akzeptieren oder den Status eines Themas festlegen

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 muss der Root-Beitrag eines Forum-Themas sein, andernfalls 400 app.topic.not_a_topic.app_error. accepted_answer_id (die ID einer Antwort oder "", um die Akzeptanz zurückzunehmen) erfordert ein Q&A-Forum; status erfordert ein Ideen-Forum; die falsche Moduszuordnung führt zu 400 app.topic.mode.app_error.

  • Akzeptieren einer Antwort: Nur die Fragesteller:in des Themas (solange sie dort noch Beiträge verfassen kann) oder ein:e Kanalmoderator:in darf dies tun; andernfalls 403 app.topic.accept.not_allowed.app_error. Die Antwort muss eine aktive, nicht-systemische Antwort auf dieses Thema sein, andernfalls 400 app.topic.accept.not_a_reply.app_error. Wird die akzeptierte Antwort gelöscht, wird die Antwortmarkierung entfernt.
  • Festlegen eines Status: Nur Kanalmoderator:innen dürfen dies tun, andernfalls 403 app.topic.status.not_allowed.app_error; ein unbekannter Wert führt zu 400 app.topic.status.invalid.app_error.

Jede Änderung postet eine Systemantwort im Thema (und informiert dessen Follower) und antwortet mit dem Root-Beitrag des Themas, wie er nun ist. In einem Ideen-Forum führt das Abstimmen für ein Thema auch dazu, dass du ihm folgst.

Thread verschieben

POST /posts/{post_id}/move_to_channel verschiebt einen Thread, seine erste Nachricht und alle Antworten in einen anderen Kanal derselben Community. post_id kann die erste Nachricht oder eine beliebige Antwort sein.

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 (Pflichtfeld): Der Kanal, in den der Thread verschoben wird.
  • flatten (Standard false): true macht die Antworten zu Nachrichten des Zielkanals statt zu einem Thread. Fusion nutzt dies für Als Kanal festlegen. Wird abgelehnt, wenn das Ziel ein Forum ist (400 app.post.move_thread.forum_flatten.app_error), da die Antworten sonst zu Themen ohne Titel würden.
  • title: der Titel des Themas, wenn das Ziel ein Forum ist. Ohne diesen wird der eigene Titel des Threads beibehalten, falls vorhanden; fehlt beides, führt dies zu 400 app.post.move_thread.forum_title_required.app_error. Wird ignoriert, wenn das Ziel kein Forum ist.

Die Nachrichten behalten ihre Autoren, Zeitstempel, Reaktionen und Dateien. Ihre Kopien tragen die Eigenschaft silent_notification, sodass sie niemanden benachrichtigen. Die ursprünglichen Nachrichten werden gelöscht. Die Antwort ist die verschobene erste Nachricht mit ihrer neuen ID.

Wer einen Thread verschieben darf

  • Sie müssen in der Lage sein, den Thread zu lesen und im Zielkanal zu posten.
  • Die Administratoren des Kanals, die Administratoren der Community, Personen mit Nachrichten verwalten (delete_others_posts) im Kanal sowie Systemadministratoren dürfen jeden Thread verschieben.
  • Der Autor des Threads darf ihn verschieben, wenn beide Kanäle öffentlich sind oder wenn alle Nachrichten des Threads von ihm stammen. Andernfalls lautet die Antwort 403 mit der ID api.post.move_thread.private_needs_moderator.app_error.
  • Beide Kanäle müssen in derselben Community liegen (keine Direktnachrichten oder Gruppennachrichten), sich unterscheiden und dürfen nicht archiviert sein. Systemnachrichten und Nachrichten, die nach dem Lesen gelöscht werden, können nicht verschoben werden.
  • Ein Thread mit mehr als WranglerSettings.MoveThreadMaxCount Nachrichten (Standardmäßig 100; 0 für keine Grenze) wird abgelehnt.

Der Zeiger und die Notiz

Der Vorgang hinterlässt zwei Systemnachrichten vom Typ system_wrangler: einen Zeiger im alten Kanal („Ein Thread mit 13 Nachrichten wurde nach #target verschoben“) und eine Notiz im Zielkanal („Dieser Thread wurde aus #source verschoben“), unter dem verschobenen Thread oder, bei flatten, nach dessen Nachrichten. Neben dem Nachrichtentext ermöglichen deren Eigenschaften, dass ein Client den Kanalnamen als Link darstellt:

  • Der Zeiger: MovedThreadPermalink, NumMessages, MovedThreadChannelId, MovedThreadTeamName, MovedThreadPostId und, für ein öffentliches Ziel, MovedThreadChannelName und MovedThreadChannelDisplayName.
  • Die Notiz: MovedFromChannelId, MovedFromTeamName, MovedFromPostId (der Zeiger), MovedFromPermalink und, für eine öffentliche Quelle, MovedFromChannelName und MovedFromChannelDisplayName.

Beide haben auch eine TranslationID. Der Name eines privaten Kanals wird weggelassen: Leser sehen „ein anderer Kanal“. Der eigene POST /posts/{post_id}/move-Endpunkt von Mattermost ist in Antimatter deaktiviert; verwenden Sie diesen Endpunkt.

Community-Regeln

Administratoren einer Community können festlegen, dass ihre Mitglieder den Regeln zustimmen müssen, bevor sie in deren Kanälen posten. Solange die Regeln aktiviert sind, kann ein Mitglied, das der aktuellen Version nicht zugestimmt hat, nicht posten, antworten, Dateien senden, Nachrichten planen, bearbeiten oder wiederherstellen sowie Befehle ausführen, die in den Kanälen der Community posten: Der Server antwortet mit 403 und der ID api.post.community_rules_not_accepted, und eine für diesen Zeitpunkt geplante Nachricht schlägt mit dem Fehlercode community_rules_not_accepted fehl. Das Lesen, Reaktionen sowie Direktnachrichten und Gruppennachrichten sind nicht betroffen; ebenso wenig Bots, eingehende Webhooks, Systemnachrichten und die Administratoren der Community (manage_team, was auch Systemadministratoren haben).

EndpunktFunktion
GET /teams/{team_id}/rulesDie Regeln (enabled, text in Markdown, version), zusammen mit der neuesten Version, der Sie zugestimmt haben (accepted_version), und ob Sie zustimmen müssen, bevor Sie posten (must_accept). Für Mitglieder und für alle, die einer offenen Community beitreten können.
PUT /teams/{team_id}/rulesSpeichert sie mit {"enabled", "text", "ask_again"} (manage_team). ask_again erstellt eine neue Version, der alle erneut zustimmen müssen; der erste Speichervorgang erstellt Version 1. Der Text ist erforderlich, um die Regeln zu aktivieren, und darf höchstens 16.000 Zeichen lang sein.
POST /teams/{team_id}/rules/acceptStimmt als Mitglied der version zu, die Sie gelesen haben; 409, wenn seitdem eine neuere Version gespeichert wurde, und 0, wenn der aktuellen Version zugestimmt wird.
GET /teams/{team_id}/rules/statsWie viele Mitglieder der Community der aktuellen Version zugestimmt haben (manage_team).

Das Ereignis community_rules_updated wird an die Community gesendet, wenn ein Administrator die Regeln speichert (team_id, enabled, version), und community_rules_accepted an die Person, die zugestimmt hat, auf allen ihren Sitzungen (team_id, version).

Fokusmodus

Der Fokusmodus ist „Nicht stören“ mit einer Endzeit: Benachrichtigungen werden stummgeschaltet (keine Push-, E-Mail-, Desktop- oder persistenten Benachrichtigungen, einschließlich dringender Nachrichten), der Grund wird zum benutzerdefinierten Status mit dem 🎯-Emoji (dart), der am Ende abläuft, und die Apps von Antimatter blenden die eigenen ungelesenen Abzeichen der Person aus. Nur die Person selbst kann diese Endpunkte verwenden (me oder ihre eigene ID): Niemand anderes, auch keine Systemadministratoren, darf den Fokus oder dessen Zusammenfassung einer anderen Person starten, beenden oder lesen.

EndpunktFunktion
GET /users/me/focusDer aktuelle Fokus (active, start_at, end_at, reason), oder der letzte Fokus, nachdem er beendet wurde (ended_at gesetzt), oder alles null.
POST /users/me/focusBeginnt den Fokusmodus oder ändert während des Fokusmodus das Ende und den Grund: {"duration": "1h30m", "reason": "…"} oder stattdessen der Dauer {"end_at": ms}, von einer Minute bis zu einer Woche im Voraus. "duration": "tomorrow" endet am nächsten Tag um 09:00 Uhr in der Zeitzone der Person. Das Ende wird auf die volle Minute abgerundet; der Grund darf maximal 100 Zeichen lang sein. Erfordert aktivierte Benutzerstatus (ServiceSettings.EnableUserStatuses); Bots können keinen Fokusmodus aktivieren.
DELETE /users/me/focusBeendet den Fokusmodus sofort.
GET /users/me/focus/summary?since=&until=Was in diesem Zeitraum versäumt wurde (start_at und ended_at eines Fokusmodus): Kanäle mit ungelesenen Nachrichten von anderen (Direktnachrichten und Gruppennachrichten zuerst, dann solche mit Erwähnungen; stummgeschaltete Kanäle nur bei einer Erwähnung) und bei eingeklappten Antwort-Threads die gefolgten Threads mit neuen Antworten, jeweils mit Anzahl, Erwähnungen und letztem Absender.
POST /users/me/focus/summary/readMit {"since", "until"}: markiert diese Kanäle und Threads nur bis until als gelesen; was danach kam, bleibt ungelesen.

Während eine Person im Fokusmodus ist, hat ihr Benutzer die Eigenschaft focus_until (Millisekunden), die Clients nutzen, um den Fokusstatus anzuzeigen; sie kann nicht über das Profil geändert werden. Der Fokusmodus endet, wenn die Person ihn beendet, wenn die Zeit erreicht ist (innerhalb einer Minute) oder wenn sie selbst einen Status auswählt, der dann bestehen bleibt. Andernfalls werden der vorherige Status und der vorherige individuelle Status wiederhergestellt. Alle ihre Sitzungen erhalten dann das Ereignis focus_ended mit start_at, end_at und ended_by (user, timer oder status).

Modellverbindungen

Eine Modellverbindung ist die Adresse und der Schlüssel eines KI-Anbieters, die von einem Administrator eingerichtet werden. Die KI-Funktionen des Servers und die Apps, die den KI-Dienst aufrufen, nutzen sie. Systemadministratoren verwalten die serverweiten Verbindungen (manage_ai_connections); die Administratoren einer Community verwalten die eigenen ihrer Community (manage_team_ai_connections). Schlüssel sind nur schreibbar: Keine Antwort enthält einen, nur api_key_set und api_key_last4.

EndpunktFunktion
GET /ai/connections?scope=Die Verbindungen, die Sie verwalten. scope ist server oder die ID einer Community; ohne Angabe alle Bereiche, die Sie verwalten.
POST /ai/connectionsFügt eine Verbindung hinzu (antwortet mit 201).
POST /ai/connections/test, POST /ai/connections/modelsTestet eine Verbindung oder listet deren Modelle auf, bevor sie gespeichert wird. Gleicher Body wie beim Hinzufügen; es wird nichts gespeichert.
GET, PATCH (oder PUT), DELETE /ai/connections/{connection_id}Liest, ändert oder löscht eine Verbindung. Ein Patch enthält nur die Felder, die geändert werden sollen; lassen Sie api_key weg, um den Schlüssel beizubehalten.
POST /ai/connections/{connection_id}/testTestet eine gespeicherte Verbindung: {"ok", "error", "status_code", "latency_ms", "model_count"}.
GET /ai/connections/{connection_id}/modelsDie vom Anbieter angebotenen Modelle.
GET /ai/connections/{connection_id}/usageAnfragen und Token dieses Monats.
GET /ai/connections/usable?channel_id=&team_id=Für alle angemeldeten Benutzer: die dort verfügbaren Verbindungen samt deren Modellen und Funktionen – niemals deren Schlüssel oder Adressen.

Der Inhalt einer neuen Verbindung:

{
  "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 ist entweder openai_compatible oder anthropic. scope ist standardmäßig server; die ID einer Community macht daraus eine Verbindung dieser Community. In limits bedeutet 0 kein Limit; Anfragen pro Minute werden auf jedem Server gezählt, Token-Budgets gelten pro Kalendermonat (UTC) für den gesamten Cluster. sharing bestimmt, welche Communities eine serverweite Verbindung nutzen dürfen (für Direktnachrichten und Gruppennachrichten ist all_teams erforderlich), und audience, wer sie nutzen darf; Gäste nur mit allow_guests. Änderungen werden im Audit-Protokoll festgehalten. Die Administrator-Dokumentation erklärt die Einstellungen: siehe KI.

Agenten

Ein Agent ist ein Bot-Konto der Art agent (is_agent bei seinem Benutzer) mit seinen Einstellungen: seinem Geltungsbereich (server oder die ID einer Community), ob er integriert oder external ist, und bei einem integrierten Agenten seine Modellverbindung, das Modell, die System-Prompt und das Reasoning. Systemadministratoren verwalten serverweite Agenten (manage_system), Administratoren einer Community verwalten deren Agenten (manage_team); zusätzlich gibt es manage_own_agent für einen selbst erstellten Agenten und manage_others_agent für andere. Die ID des Agenten in diesen Pfaden ist seine Benutzer-ID. Das Ausführen eines externen Agenten und wie der Status eines integrierten Agenten festgelegt wird, ist unter Bots erklärt; PUT /users/{user_id}/status und die Endpunkte für individuelle Status lehnen die ID eines integrierten Agenten ab, auch für Systemadministratoren (403, api.status.agent.app_error).

EndpunktFunktion
GET /ai/agents?scope=Die von dir verwalteten Agenten: scope ist server oder die ID einer Community; ohne diese Angabe werden alle von dir verwalteten Agenten zurückgegeben.
POST /ai/agentsErstellt einen Agenten und dessen Konto (Antwort 201). Ein Agent einer Community tritt dieser Community bei.
GET, PATCH, DELETE /ai/agents/{agent_id}
POST …/enable, POST …/disable
Liest, ändert und löscht einen Agenten (dessen Konto wird deaktiviert, dessen Nachrichten bleiben erhalten) und schaltet ihn ein oder aus.
GET /ai/agents/connections?scope=
GET /ai/agents/connections/{connection_id}/models
Die Modellverbindungen, die ein Agent dieses Bereichs verwenden darf, sowie deren Modelle.
GET, PUT /ai/agents/{agent_id}/activity
POST /ai/agents/activity/ids
Was ein Agent gerade tut; wird von dessen eigenem Token oder dessen Verwaltern festgelegt. Der Stapel verarbeitet bis zu 200 Benutzer-IDs.
POST /ai/agents/{agent_id}/tasksFragt einen integrierten Agenten, den du für eine Aufgabe verwenden darfst: summarize_thread, find_action_items oder find_open_questions (basierend auf der post_id eines Threads oder einer channel_id ab since), summarize_channel, ask_channel (mit einer question) oder summarize_transcription (ein Transkriptionsbeitrag eines Anrufs). Die Anfrage wird als deine Nachricht in deiner Direktnachricht mit dem Agenten in deiner Sprache gesendet und dort beantwortet; die Antwort (201) ist diese Nachricht. Ein Beitrag oder Kanal, den du nicht lesen kannst, wird so behandelt, als existiere er nicht.
GET /ai/agents/conversations?agent_id=&before=&per_page=Deine Unterhaltungen mit den Agenten, die du verwenden darfst, beginnend mit der neuesten: die Threads, die du in deinen Direktnachrichten mit ihnen gestartet hast, sowie die Threads an anderen Orten, in denen einer dieser Agenten geantwortet hat und denen du folgst. before (ein Zeitpunkt) gibt die nächste Seite an; per_page beträgt maximal 100.

Der Inhalt eines neuen Agenten:

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

Ein leeres model verwendet das Chat-Modell der Verbindung. access.channel_ids bezieht sich auf die Mitglieder dieser Kanäle. Ein externer Agent hat keine Verbindung, kein Modell und keinen System-Prompt. GET /agents listet die Agenten auf, mit denen du sprechen kannst, so wie sie von der KI-Chat-App gelesen werden.