L'API REST
Tout ce que les applications Antimatter font passe par la même API HTTP, vos scripts peuvent donc en faire autant. Cette page explique comment s'authentifier, les ressources que vous utiliserez le plus, l'aspect des réponses et des erreurs, et comment suivre les événements en direct via WebSocket.
Bases
- URL de base :
https://chat.example.com/api/v4. Tous les points de terminaison ci-dessous sont relatifs à celle-ci. - Format : JSON en entrée et en sortie, à l'exception des envois de fichiers (multipart). Envoyez
Content-Type: application/json. - Identifiants : chaque objet possède un
idde 26 caractères. Les dates sont en millisecondes depuis l'époque Unix (create_at,update_at,delete_at; 0 signifie « non supprimé »). - Les communautés sont des équipes : l'API les appelle
teams, avec unteam_id. - Vous-même : partout où un chemin prend un
user_id,medésigne l'utilisateur connecté, comme dansGET /users/me.
La liste complète des points d'entrée se trouve dans le code du serveur : les routes sont déclarées dans server/channels/api4/*.go et les types dans server/public/model. La description OpenAPI du dossier api/v4/source du dépôt couvre les points d'entrée hérités de Mattermost, ainsi que certaines des ajouts d'Antimatter : déplacement des fils de discussion, connexions de modèles et actions sur les messages. Les autres ne sont disponibles que dans le code.
Authentification
Chaque requête, à l'exception de la connexion et de quelques points de terminaison publics, nécessite un jeton dans l'en-tête Authorization :
curl -H "Authorization: Bearer $TOKEN" https://chat.example.com/api/v4/users/me
Trois types de jetons y sont acceptés : jetons d'accès personnels, jetons de session et jetons d'accès OAuth. Authorization: Token … est également accepté. Les jetons dans la chaîne de requête (?access_token=) ne sont acceptés que pour les jetons d'accès OAuth.
Jetons d'accès personnels (recommandés pour les scripts)
Un jeton d'accès personnel agit en votre nom, n'expire pas à moins que vous ne lui donniez une date d'expiration, et peut être révoqué à tout moment. Les jetons d'accès personnels sont désactivés par défaut :
- Un admin système active Activer les jetons d'accès personnel dans Console système › Intégrations › Gestion des intégrations (
ServiceSettings.EnableUserAccessTokens,AM_SERVICESETTINGS_ENABLEUSERACCESSTOKENS). - Pour chaque personne pouvant créer des jetons, un administrateur système ouvre Console système › Gestion des utilisateurs › Utilisateurs, choisit Gérer les rôles dans le menu de la personne et coche Permettre à ce compte de générer des jetons d'accès personnels. Les administrateurs système peuvent toujours les créer.
- La personne ouvre son avatar en haut à droite, puis Profil et paramètres › Sécurité. Sous Jetons d'accès personnel, elle décrit l'usage du jeton et choisit Créer un nouveau jeton. Le jeton n'est affiché qu'une seule fois : copiez-le.
Via l'API : POST /users/{user_id}/tokens avec {"description": "backup script", "expires_at": 0} (expires_at en millisecondes ; 0 pour aucune). Le champ token de la réponse est le secret ; son id est ce que vous utilisez pour le révoquer (POST /users/tokens/revoke avec {"token_id": "…"}). Depuis la ligne de commande : amctl token generate <user> <description>.
Un admin système peut limiter la durée de validité des jetons avec Durée de validité maximale des jetons d’accès personnels (jours) sur la même page de la Console système.
Jetons de session
La connexion avec un mot de passe renvoie un jeton de session dans l'en-tête de réponse Token, le même type de session utilisé par les applications :
curl -i -X POST https://chat.example.com/api/v4/users/login \
-H 'Content-Type: application/json' \
-d '{"login_id": "maya", "password": "…"}'
Ajoutez "token": "123456" pour un compte avec authentification multifacteur. Les sessions expirent selon les paramètres de session du serveur, et le point de terminaison de connexion est limité en débit (5 requêtes par seconde). POST /users/logout met fin à la session.
X-CSRF-Token pour tout ce qui n'est pas une requête GET ; un jeton dans l'en-tête Authorization n'a pas besoin d'en-tête CSRF.Applications OAuth 2.0
Pour permettre aux personnes de se connecter à votre application avec leur compte Antimatter, enregistrez une application OAuth 2.0. Antimatter est alors le fournisseur OAuth :
- Activer le fournisseur de service OAuth 2.0 doit être activé (Console système › Intégrations › Gestion des intégrations,
ServiceSettings.EnableOAuthServiceProvider, activé par défaut). - Une personne ayant le droit de gérer les applications OAuth (les administrateurs système par défaut) ouvre son avatar, puis Intégrations › Applications OAuth 2.0, et ajoute l'application avec ses URL de rappel. Elle obtient un identifiant de client et un secret de client.
- Votre application redirige les utilisateurs vers
https://chat.example.com/oauth/authorizeavecresponse_type=code,client_id,redirect_urietstate. PKCE aveccode_challenge_method=S256est pris en charge. - Elle échange le code via
POST https://chat.example.com/oauth/access_token(grant_type=authorization_code, puisrefresh_tokenpour le renouveler), et appelle l'API avecAuthorization: Bearer <access token>.
Les utilisateurs voient les applications qu'ils ont autorisées dans Profil et paramètres › Sécurité › Applications autorisées.
Ressources principales
| Élément | Points d'accès |
|---|---|
| Vous et les autres utilisateurs | GET /users/me, GET /users/{user_id}, GET /users/username/{username}, POST /users/ids (une liste d'identifiants), POST /users/search, GET /users?in_team=…&in_channel=… |
| Communautés | 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 |
| Canaux | GET /users/me/teams/{team_id}/channels, GET /teams/name/{team}/channels/name/{channel}, POST /channels, POST /channels/direct (deux identifiants d'utilisateur), POST /channels/group, POST /channels/{channel_id}/members |
| Messages | 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 |
| Réactions | POST /reactions avec {"user_id", "post_id", "emoji_name"}, DELETE /users/{user_id}/posts/{post_id}/reactions/{emoji_name} |
| Fichiers | POST /files (multipart : channel_id et files), puis placez les identifiants renvoyés dans file_ids du message ; GET /files/{file_id} |
| Préférences | GET /users/me/preferences, PUT /users/me/preferences |
| Intégrations | /hooks/incoming, /hooks/outgoing, /commands, /bots, /oauth/apps (voir les pages suivantes) |
| Serveur | GET /system/ping (état de santé, aucun jeton requis), GET /config/client?format=old (les paramètres visibles par les clients) |
Publier un message
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"}'
Les messages sont au format Markdown. Ajoutez "root_id" (le premier message d'un fil de discussion) pour répondre dans un fil, "file_ids" pour les fichiers et "props" pour les pièces jointes et autres éléments supplémentaires (voir Pièces jointes).
Trouver l'identifiant d'un canal
curl -H "Authorization: Bearer $TOKEN" \
https://chat.example.com/api/v4/teams/name/lumen-labs/channels/name/ops-alerts
Les noms sont ceux présents dans le lien du canal : /lumen-labs/channels/ops-alerts.
Pagination
Les points d'accès de liste acceptent page (à partir de 0) et per_page (60 par défaut, 200 au maximum). Continuez à demander la page suivante jusqu'à ce qu'une page renvoyée soit plus courte que per_page.
Les messages d'un canal (GET /channels/{channel_id}/posts) acceptent également since (un horodatage : tout ce qui a changé depuis) ou before et after (un identifiant de message). Ils sont renvoyés sous forme de liste de messages : {"order": [IDs, newest first], "posts": {ID: post}, "next_post_id", "prev_post_id"}.
Erreurs
Les erreurs utilisent les codes d'état HTTP habituels (400 entrée invalide, 401 non authentifié, 403 non autorisé, 404 introuvable, 501 fonction désactivée) et un corps JSON :
{
"id": "api.context.permissions.app_error",
"message": "You do not have the appropriate permissions.",
"detailed_error": "",
"request_id": "jz8zm5nunpbt8f3gpqsz5dq6so",
"status_code": 403
}
Utilisez id dans votre code : message est traduit dans la langue de l'utilisateur. detailed_error est vide sauf si le serveur fonctionne en mode développeur (ServiceSettings.EnableDeveloper). Citez request_id à l'admin du serveur : il figure dans les journaux.
Limites de débit
La limitation de débit est désactivée par défaut. Lorsqu'un admin système l'active (Console système › Environnement › Limitation de débit), chaque client reçoit 10 requêtes par seconde avec des rafales de 100 par défaut, comptées par adresse IP ou par utilisateur. Les réponses contiennent X-RateLimit-Limit, X-RateLimit-Remaining et X-RateLimit-Reset ; au-delà de la limite, le serveur répond 429 avec un en-tête Retry-After en secondes. Certains points d'accès, comme l'authentification, ont leur propre limite quelle que soit la configuration.
Écrivez des scripts qui attendent et réessaient en cas de 429, et évitez le sondage : suivez plutôt le WebSocket.
Le flux d'événements WebSocket
Connectez-vous à wss://chat.example.com/api/v4/websocket. Authentifiez-vous soit avec l'en-tête Authorization: Bearer sur la requête de connexion, soit en envoyant ceci comme premier message :
{"seq": 1, "action": "authentication_challenge", "data": {"token": "…"}}
Le serveur envoie un événement hello, puis un événement pour tout ce que vous êtes autorisé à voir :
{
"event": "posted",
"data": {"channel_id": "…", "channel_type": "O", "post": "{\"id\":\"…\",\"message\":\"Hello\",…}"},
"broadcast": {"channel_id": "…", "team_id": "", "user_id": "", "omit_users": null},
"seq": 4
}
Notez que data.post est le message au format JSON. Événements courants : posted, post_edited, post_deleted, reaction_added, reaction_removed, typing, status_change, user_added, direct_added. Les applications émettent leurs propres événements, nommés custom_<app id>_<event>.
Vous pouvez également envoyer des actions, chacune avec un seq croissant : user_typing avec {"channel_id", "parent_id"}, ou get_statuses. Reconnectez-vous lorsque la connexion est interrompue, et récupérez ce que vous avez manqué avec since (voir Pagination).
Antimatter ajoute les événements suivants : community_attributes_updated, member_timeouts_updated, post_put_on_top, post_removed_from_top, server_categories_updated, channel_overrides_updated et category_overrides_updated.
Bibliothèques client
- Aller à :
model.Client4dansserver/public/model(importergithub.com/mattermost/mattermost/server/public/model).model.NewAPIv4Client(url), puisclient.SetToken(token);model.NewWebSocketClient4(wsURL, token)suit les événements. La copie d'Antimatter ajoute des méthodes pour ses propres points d'entrée, telles queUpdateMessageRequest,PutPostOnTopetExportChannel. - TypeScript : la classe
Client4de@mattermost/client, danswebapp/platform/client, avec ses types danswebapp/platform/types. La copie dans le dépôt d'Antimatter inclut les points de terminaison d'Antimatter ; le package publié sur npm par Mattermost ne les inclut pas.
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)
}
Ce qu'Antimatter ajoute à l'API
Ces points de terminaison et champs n'existent pas sur un serveur Mattermost. Tous nécessitent une session.
| Point de terminaison | Fonction |
|---|---|
GET /teams/{team_id}/user_attributes/fieldsPOST même cheminPATCH, DELETE …/fields/{field_id} | Attributs de la communauté : les champs de profil définis par les administrateurs d'une communauté pour ses membres (jusqu'à 20). Les membres peuvent les lire ; les administrateurs de la communauté les créent et les modifient. |
GET /teams/{team_id}/members/{user_id}/user_attributesPATCH même cheminPOST /teams/{team_id}/user_attributes/values/search | Les valeurs d'attributs d'un membre, sous la forme {field_id: value}. Les membres définissent les leurs (sauf ceux gérés par les administrateurs) ; les administrateurs définissent celles de n'importe qui. La recherche prend {"user_ids": [...]} (jusqu'à 200). |
GET /teams/{team_id}/timeoutsPUT /teams/{team_id}/members/{user_id}/timeoutGET /teams/{team_id}/members/{user_id}/moderation | Délais d'attente : {"until": time, "reason": "…"} empêche quelqu'un de publier, réagir et envoyer des fichiers dans la communauté jusqu'à cette date (au maximum 28 jours) ; "until": 0 lève la restriction. La vue de modération indique quand ils ont rejoint et combien ils ont publié récemment. |
GET /channels/{channel_id}/on_topPUT, DELETE /posts/{post_id}/on_top | Messages maintenus en haut d'un canal (jusqu'à 10). {"duration": ms}, au maximum 30 jours ; 0 les maintient jusqu'à leur suppression. Toute personne pouvant lire le canal peut les lister. Pour épingler un message en haut ou le retirer, il faut le droit de publier dans le canal et, dans un canal de communauté, d'être administrateur du canal ou de la communauté, ou d'avoir Gérer les messages (delete_others_posts) sur ce canal. Dans un message personnel ou de groupe, ses membres peuvent le faire. Refusé dans les canaux archivés. |
POST /channels/{channel_id}/message_request | Agit sur votre propre demande de message : {"action": "accept"}, "dismiss" ou "request" pour remettre une conversation parmi les demandes. Retourne votre membre de canal. |
GET, PUT /channels/{channel_id}/overridesGET /channels/{channel_id}/overrides/effectiveGET, PUT /channels/{channel_id}/role_access | Ce qu'un rôle ou une personne peut faire dans un canal, et les rôles qui voient un canal restreint par rôle. |
GET, PUT /teams/{team_id}/server_categoriesGET, PUT …/server_categories/overrides | Les catégories de canaux partagées par la communauté, ainsi que les modifications qui s'appliquent à tous les canaux d'une catégorie. |
GET /groups/{group_id}/team_rolePUT …/team_role/permissions | Les autorisations accordées par un rôle de la communauté. |
POST /teams/{team_id}/autolinks/preview | Teste les règles de liens automatiques de la communauté sur un texte. |
POST /channels/{channel_id}/export?format=csv&since=&until= | Télécharge les messages d'un canal au format CSV (jusqu'à 50 000), pour les personnes pouvant lire le canal. |
GET /posts/{post_id}/speech | Le message lu à voix haute, sous forme audio, lorsque la synthèse vocale est configurée. |
POST /posts/{post_id}/move_to_channel | Déplace un fil de discussion vers un autre canal de la même communauté : voir Déplacer un fil de discussion. |
GET, POST /ai/connectionsGET, PATCH, DELETE /ai/connections/{connection_id}GET /ai/connections/usable | Connexions de modèles, les fournisseurs d'IA utilisés par les fonctionnalités d'IA du serveur et les applications : voir Connexions de modèles. |
GET /channels/{channel_id}/message_actionsPOST /posts/{post_id}/message_actions/{hook_id}GET, POST /hooks/outgoing/{hook_id}/icon | Actions sur les messages : webhooks sortants que les utilisateurs déclenchent depuis le menu du message. Voir Actions sur les messages. |
Nouveaux champs
- Communautés (
Team, etPUT /teams/{team_id}/patch) :all_channels_membership(tout le monde est membre de chaque canal qu'il peut voir),default_channel_id(où atterrissent les nouveaux arrivants ; vide signifie Général),kind(communityouworkplace: dans un espace de travail, les administrateurs de canal peuvent aussi archiver leurs canaux ; les nouvelles communautés reçoivent leTeamSettings.DefaultCommunityKinddu serveur,communitypar défaut),member_list_view(comment la liste des membres regroupe les membres :choice, la valeur par défaut, permet à chaque membre de choisir ;rolesouteamsfixe le regroupement),hide_role_colors,require_team_badges,onboardingetautolinks(les deux sont des chaînes JSON). - Le canal par défaut d'une nouvelle communauté est
general(Général), et nontown-square. La mise à niveau 0.9.0 renomme le canaltown-squarede chaque communauté engeneral, en conservant son identifiant, à moins que la communauté possède déjà un canalgeneral. Les anciens noms continuent de fonctionner :GET /teams/{team_id}/channels/name/town-square,GET /teams/name/{team}/channels/name/town-squareet le paramètrechanneld'un webhook entrant renvoient le canal par défaut de la communauté lorsqu'aucun canal ne porte ce nom. Utilisezdefault_channel_id, ou le nomgeneral, dans le nouveau code. - Liaisons de canaux :
#channel-namelie un canal, tout comme~channel-name. La propchannel_mentionsde la publication liste les canaux liés de l'une ou l'autre façon ; un#wordqui ne nomme aucun canal reste un mot-dièse. L'interface web et l'application mobile d'Antimatter écrivent#name. - Les canaux archivés peuvent encore accueillir de nouveaux membres (
POST /channels/{channel_id}/members), qui peuvent consulter leur historique. Personne ne peut y publier, réagir, épingler, mettre un message en avant, renommer le canal ou modifier les rôles de ses membres. - Réponses en ligne : un message avec
"props": {"reply_to": "<post id>"}cite ce message du même canal. Ajoutez"reply_to_mention": falsepour ne pas notifier son auteur. Le serveur remplitmetadata.reply_toavec une brève description du message cité. - Spoilers :
"props": {"spoiler": true}masque le texte et les fichiers d'un message jusqu'à ce que le lecteur choisisse de les voir. - Ignorer et bloquer sont des préférences : catégorie
user_block, nommée d'après l'identifiant de l'autre personne, avec la valeurignoreoublock. Savoir si un message personnel attend en tant que demande se trouve dansnotify_props.dm_requestde votre membre de canal (pending,acceptedoudismissed). - Les pièces jointes de messages peuvent contenir des
stageset unchart: voir Cartes.
Déplacer un fil
POST /posts/{post_id}/move_to_channel déplace un fil de discussion, son premier message et toutes ses réponses, vers un autre canal de la même communauté. post_id peut être le premier message ou n'importe laquelle des réponses.
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(obligatoire) : le canal de destination du fil de discussion.flatten(valeur par défautfalse) : la valeurtruetransforme les réponses en messages du canal de destination, au lieu de former un fil de discussion. La fonction Make it a channel de Fusion l'utilise.
Les messages conservent leurs auteurs, horodatages, réactions et fichiers. Leurs copies portent la propriété silent_notification, de sorte qu'elles ne génèrent aucune notification. Les messages d'origine sont supprimés. La réponse est le premier message déplacé, avec son nouvel identifiant.
Qui peut déplacer un fil de discussion
- Vous devez pouvoir lire le fil de discussion et publier dans le canal de destination.
- Les administrateurs du canal, les administrateurs de la communauté, les personnes disposant de la permission Gérer les messages (
delete_others_posts) dans le canal, ainsi que les administrateurs système, peuvent déplacer n'importe quel fil de discussion. - L'auteur du fil de discussion peut le déplacer lorsque les deux canaux sont publics, ou lorsque tous les messages du fil sont les siens. Sinon, la réponse est
403avec l'identifiantapi.post.move_thread.private_needs_moderator.app_error. - Les deux canaux doivent appartenir à la même communauté (pas de messages personnels ou de groupe), être différents et non archivés. Les messages système et les messages effacés après lecture ne peuvent pas être déplacés.
- Un fil de discussion contenant plus de
WranglerSettings.MoveThreadMaxCountmessages (100 par défaut ; 0 pour aucune limite) est refusé.
Le pointeur et la note
Le déplacement laisse deux messages système de type system_wrangler : un pointeur dans l'ancien canal (« Un fil de discussion avec 13 messages a été déplacé vers #target ») et une note dans la cible (« Ce fil de discussion a été déplacé depuis #source »), sous le fil de discussion déplacé ou, avec flatten, après ses messages. Outre le texte du message, leurs propriétés permettent à un client d'afficher le nom du canal sous forme de lien :
- Le pointeur :
MovedThreadPermalink,NumMessages,MovedThreadChannelId,MovedThreadTeamName,MovedThreadPostIdet, pour une cible publique,MovedThreadChannelNameetMovedThreadChannelDisplayName. - La note :
MovedFromChannelId,MovedFromTeamName,MovedFromPostId(le pointeur),MovedFromPermalinket, pour une source publique,MovedFromChannelNameetMovedFromChannelDisplayName.
Les deux ont également un TranslationID. Le nom d'un canal privé est omis : les lecteurs voient « un autre canal ». L'endpoint POST /posts/{post_id}/move de Mattermost reste désactivé dans Antimatter ; utilisez cet endpoint.
Connexions aux modèles
Une connexion de modèle est l'adresse et la clé d'un fournisseur d'IA, configurées par un admin. Les fonctionnalités IA du serveur et les applications qui appellent le service IA les utilisent. Les admins système gèrent les connexions au niveau du serveur (manage_ai_connections) ; les admins d'une communauté gèrent celles de leur communauté (manage_team_ai_connections). Les clés sont en écriture seule : aucune réponse ne les contient, seulement api_key_set et api_key_last4.
| Point de terminaison | Fonction |
|---|---|
GET /ai/connections?scope= | Les connexions que vous gérez. scope est server ou l'identifiant d'une communauté ; sans cela, tous les scopes que vous gérez. |
POST /ai/connections | Ajoute une connexion (réponse 201). |
POST /ai/connections/test, POST /ai/connections/models | Teste une connexion, ou liste ses modèles, avant qu'elle ne soit enregistrée. Même corps que pour l'ajout ; rien n'est stocké. |
GET, PATCH (ou PUT), DELETE /ai/connections/{connection_id} | Lit, modifie ou supprime une connexion. Un patch ne contient que les champs à modifier ; omettez api_key pour conserver la clé. |
POST /ai/connections/{connection_id}/test | Teste une connexion enregistrée : {"ok", "error", "status_code", "latency_ms", "model_count"}. |
GET /ai/connections/{connection_id}/models | Les modèles proposés par le fournisseur. |
GET /ai/connections/{connection_id}/usage | Les requêtes et jetons de ce mois-ci. |
GET /ai/connections/usable?channel_id=&team_id= | Pour toute personne connectée : les connexions que vous pouvez y utiliser, avec leurs modèles et leurs capacités, mais jamais leurs clés ou leurs adresses. |
Le corps d'une nouvelle connexion :
{
"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 est openai_compatible ou anthropic. scope est server par défaut ; l'identifiant d'une communauté en fait une connexion propre à cette communauté. Dans limits, 0 signifie aucune limite ; les requêtes par minute sont comptées sur chaque serveur, et les budgets de jetons par mois civil (UTC) pour l'ensemble du cluster. sharing indique quelles communautés peuvent utiliser une connexion à l'échelle du serveur (les messages personnels et de groupe nécessitent all_teams), et audience qui peut l'utiliser ; les invités uniquement avec allow_guests. Les modifications sont inscrites dans le journal d'audit. Le guide d'administration explique les paramètres : voir IA.