L'API REST
Tutto ciò che le app Antimatter fanno passa attraverso la stessa API HTTP, quindi anche i tuoi script possono farlo. Questa pagina spiega come autenticarsi, le risorse che userai di più, come appaiono le risposte e gli errori, e come seguire gli eventi in tempo reale tramite WebSocket.
Fondamenti
- URL di base:
https://chat.example.com/api/v4. Tutti gli endpoint seguenti sono relativi a questo. - Formato: JSON in input e in output, ad eccezione dei caricamenti di file (multipart). Invia
Content-Type: application/json. - ID: ogni oggetto ha un
iddi 26 caratteri. I tempi sono in millisecondi dall'epoca Unix (create_at,update_at,delete_at; 0 significa "non eliminato"). - Le community sono team: l'API li chiama
teams, con unteam_id. - Te stesso: ovunque un percorso accetti un
user_id,meindica l'utente autenticato, come inGET /users/me.
L'elenco completo degli endpoint è nel codice del server: le rotte sono dichiarate in server/channels/api4/*.go e i tipi in server/public/model. La descrizione OpenAPI nella cartella api/v4/source del repository copre gli endpoint ereditati da Mattermost e alcune delle aggiunte di Antimatter: spostamento dei thread, connessioni al modello e azioni sui messaggi. Gli altri sono presenti solo nel codice.
Autenticazione
Ogni richiesta, ad eccezione dell'accesso e di alcuni endpoint pubblici, richiede un token nell'intestazione Authorization:
curl -H "Authorization: Bearer $TOKEN" https://chat.example.com/api/v4/users/me
Sono accettati tre tipi di token: token di accesso personale, token di sessione e token di accesso OAuth. È accettato anche Authorization: Token …. I token nella stringa di query (?access_token=) sono accettati solo per i token di accesso OAuth.
Token di accesso personale (consigliati per gli script)
Un token di accesso personale agisce come te, non scade a meno che non gli si assegni una data di scadenza e può essere revocato in qualsiasi momento. I token di accesso personale sono disabilitati di default:
- Un amministratore di sistema attiva Attiva Token di Accesso in Console di Sistema › Integrazioni › Gestione integrazioni (
ServiceSettings.EnableUserAccessTokens,AM_SERVICESETTINGS_ENABLEUSERACCESSTOKENS). - Per ogni persona che potrebbe creare token, un amministratore di sistema apre Console di Sistema › Gestione utenti › Utenti, seleziona Gestisci ruoli nel menu della persona e spunta Consenti a questo account di generare token di accesso personale. Gli amministratori di sistema possono sempre crearli.
- L'utente apre il proprio avatar in alto a destra, quindi Profilo e impostazioni › Sicurezza. Sotto Gestisci Token di Accesso personali, descrive lo scopo del token e sceglie Crea Token. Il token viene mostrato una sola volta: copialo.
Con l'API: POST /users/{user_id}/tokens con {"description": "backup script", "expires_at": 0} (expires_at in millisecondi; 0 per nessuna scadenza). Il campo token della risposta è il segreto; il suo id è quello che si usa per revocarlo (POST /users/tokens/revoke con {"token_id": "…"}). Dalla riga di comando: amctl token generate <user> <description>.
Un amministratore di sistema può impostare un limite alla durata dei token con Durata massima token di accesso personale (giorni) nella stessa pagina della Console di Sistema.
Token di sessione
L'accesso con una password restituisce un token di sessione nell'intestazione di risposta Token, lo stesso tipo di sessione usato dalle app:
curl -i -X POST https://chat.example.com/api/v4/users/login \
-H 'Content-Type: application/json' \
-d '{"login_id": "maya", "password": "…"}'
Aggiungi "token": "123456" per un account con autenticazione a più fattori. Le sessioni scadono come specificato dalle impostazioni di sessione del server, e l'endpoint di accesso è soggetto a limitazione di frequenza (5 richieste al secondo). POST /users/logout termina la sessione.
X-CSRF-Token per qualsiasi operazione diversa da GET; un token nell'intestazione Authorization non richiede un'intestazione CSRF.App OAuth 2.0
Per consentire alle persone di accedere alla tua applicazione con il proprio account Antimatter, registra un'app OAuth 2.0. Antimatter diventa quindi il provider OAuth:
- Attiva fornitore servizio OAuth 2.0 deve essere attivo (Console di Sistema › Integrazioni › Gestione integrazioni,
ServiceSettings.EnableOAuthServiceProvider, attivo per impostazione predefinita). - Chi ha il diritto di gestire le app OAuth (di default gli amministratori di sistema) apre il proprio avatar, quindi Integrazioni › App OAuth 2.0, e aggiunge l'app con i suoi URL di callback. Riceve un client ID e un client secret.
- La tua applicazione reindirizza gli utenti a
https://chat.example.com/oauth/authorizeconresponse_type=code,client_id,redirect_uriestate. È supportato PKCE concode_challenge_method=S256. - Effettua lo scambio del codice tramite
POST https://chat.example.com/oauth/access_token(congrant_type=authorization_code, poirefresh_tokenper il rinnovo) e chiama l'API conAuthorization: Bearer <access token>.
Gli utenti possono visualizzare le app che hanno autorizzato in Profilo e impostazioni › Sicurezza › App autorizzate.
Risorse principali
| Elemento | Endpoint |
|---|---|
| Tu e gli altri utenti | GET /users/me, GET /users/{user_id}, GET /users/username/{username}, POST /users/ids (una lista di ID), POST /users/search, GET /users?in_team=…&in_channel=… |
| Comunità | 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 |
| Canali | GET /users/me/teams/{team_id}/channels, GET /teams/name/{team}/channels/name/{channel}, POST /channels, POST /channels/direct (due ID utente), POST /channels/group, POST /channels/{channel_id}/members |
| Messaggi (post) | 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 |
| Reazioni | POST /reactions con {"user_id", "post_id", "emoji_name"}, DELETE /users/{user_id}/posts/{post_id}/reactions/{emoji_name} |
| File | POST /files (multipart: channel_id e files), quindi inserisci gli ID restituiti in file_ids del messaggio; GET /files/{file_id} |
| Preferenze | GET /users/me/preferences, PUT /users/me/preferences |
| Integrazioni | /hooks/incoming, /hooks/outgoing, /commands, /bots, /oauth/apps (vedi le pagine successive) |
| Server | GET /system/ping (stato di salute, non richiede token), GET /config/client?format=old (le impostazioni visibili ai client) |
Pubblica un messaggio
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"}'
I messaggi sono in Markdown. Aggiungi "root_id" (il primo post di un thread) per rispondere in un thread, "file_ids" per i file e "props" per gli allegati e altre proprietà (vedi Allegati).
Trova l'ID di un canale
curl -H "Authorization: Bearer $TOKEN" \
https://chat.example.com/api/v4/teams/name/lumen-labs/channels/name/ops-alerts
I nomi sono quelli presenti nel link del canale: /lumen-labs/channels/ops-alerts.
Paginazione
Gli endpoint di elenco accettano page (da 0) e per_page (60 di default, massimo 200). Continua a richiedere la pagina successiva finché una pagina non restituisce meno elementi di per_page.
I messaggi di un canale (GET /channels/{channel_id}/posts) accettano anche since (un tempo: tutto ciò che è cambiato da allora), oppure before e after (un ID di post). Vengono restituiti come un elenco di post: {"order": [IDs, newest first], "posts": {ID: post}, "next_post_id", "prev_post_id"}.
Errori
Gli errori utilizzano i codici di stato HTTP standard (400 input non valido, 401 non autenticato, 403 non autorizzato, 404 non trovato, 501 funzionalità disabilitata) e un corpo JSON:
{
"id": "api.context.permissions.app_error",
"message": "You do not have the appropriate permissions.",
"detailed_error": "",
"request_id": "jz8zm5nunpbt8f3gpqsz5dq6so",
"status_code": 403
}
Utilizza id nel tuo codice: message viene tradotto nella lingua dell'utente. detailed_error è vuoto a meno che il server non sia in modalità sviluppatore (ServiceSettings.EnableDeveloper). Cita request_id all'amministratore del server: è presente nei log.
Limiti di frequenza
Il limite di velocità è disattivato per impostazione predefinita. Quando un amministratore di sistema lo attiva (Console di Sistema › Ambiente › Limite di velocità), ogni client riceve 10 richieste al secondo con burst di 100 per impostazione predefinita, conteggiate per indirizzo IP o per utente. Le risposte includono X-RateLimit-Limit, X-RateLimit-Remaining e X-RateLimit-Reset; se si supera il limite, il server risponde con 429 e un header Retry-After in secondi. Alcuni endpoint, come l'accesso, hanno un limite proprio indipendentemente dalle impostazioni.
Scrivi script che attendono e riprovano in caso di 429, ed evita il polling: usa invece il WebSocket.
Il flusso di eventi WebSocket
Connettiti a wss://chat.example.com/api/v4/websocket. Autenticati con l'header Authorization: Bearer nella richiesta di connessione, oppure inviando questo come primo messaggio:
{"seq": 1, "action": "authentication_challenge", "data": {"token": "…"}}
Il server invia un evento hello, seguito da un evento per tutto ciò a cui hai accesso:
{
"event": "posted",
"data": {"channel_id": "…", "channel_type": "O", "post": "{\"id\":\"…\",\"message\":\"Hello\",…}"},
"broadcast": {"channel_id": "…", "team_id": "", "user_id": "", "omit_users": null},
"seq": 4
}
Nota che data.post è il post come stringa JSON. Eventi comuni: posted, post_edited, post_deleted, reaction_added, reaction_removed, typing, status_change, user_added, direct_added. Le app inviano i propri eventi, denominati custom_<app id>_<event>.
Puoi anche inviare azioni, ciascuna con un seq crescente: user_typing con {"channel_id", "parent_id"}, oppure get_statuses. Riconnettiti quando la connessione si interrompe e recupera ciò che hai perso con since (vedi Paginazione).
Antimatter aggiunge questi eventi: community_attributes_updated, member_timeouts_updated, post_put_on_top, post_removed_from_top, server_categories_updated, channel_overrides_updated e category_overrides_updated.
Librerie client
- Vai:
model.Client4inserver/public/model(importagithub.com/mattermost/mattermost/server/public/model).model.NewAPIv4Client(url), poiclient.SetToken(token);model.NewWebSocketClient4(wsURL, token)segue gli eventi. La copia di Antimatter aggiunge metodi per i propri endpoint, comeUpdateMessageRequest,PutPostOnTopeExportChannel. - TypeScript: la classe
Client4di@mattermost/client, inwebapp/platform/client, con i relativi tipi inwebapp/platform/types. La copia nel repository di Antimatter include gli endpoint di Antimatter; il pacchetto pubblicato su npm da Mattermost non li include.
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)
}
Cosa Antimatter aggiunge all'API
Questi endpoint e campi non esistono su un server Mattermost. Tutti richiedono una sessione.
| Endpoint | Funzione |
|---|---|
GET /teams/{team_id}/user_attributes/fieldsPOST stesso percorsoPATCH, DELETE …/fields/{field_id} | Attributi della community: i campi del profilo definiti dagli amministratori della community per i suoi membri (fino a 20). I membri possono leggerli; gli amministratori della community li creano e modificano. |
GET /teams/{team_id}/members/{user_id}/user_attributesPATCH stesso percorsoPOST /teams/{team_id}/user_attributes/values/search | I valori degli attributi di un membro, come {field_id: value}. I membri impostano i propri (tranne quelli gestiti dagli amministratori); gli amministratori impostano quelli di chiunque. La ricerca accetta {"user_ids": [...]} (fino a 200). |
GET /teams/{team_id}/timeoutsPUT /teams/{team_id}/members/{user_id}/timeoutGET /teams/{team_id}/members/{user_id}/moderation | Timeout: {"until": time, "reason": "…"} impedisce a qualcuno di pubblicare, reagire e caricare nella community fino a quel momento (al massimo 28 giorni); "until": 0 lo rimuove. La vista di moderazione mostra quando si sono uniti e quanto hanno pubblicato di recente. |
GET /channels/{channel_id}/on_topPUT, DELETE /posts/{post_id}/on_top | Messaggi mantenuti in cima a un canale (fino a 10). {"duration": ms}, al massimo 30 giorni; 0 li mantiene finché non vengono rimossi. Chiunque possa leggere il canale li elenca. Per mettere un messaggio in cima o rimuoverlo è necessario il diritto di pubblicare nel canale e, in un canale di una community, essere amministratore del canale o della community, oppure disporre di Gestisci messaggi (delete_others_posts) lì. In un messaggio diretto o di gruppo, possono farlo i suoi membri. Rifiutato nei canali archiviati. |
POST /channels/{channel_id}/message_request | Agisce sulla richiesta di messaggio personale: {"action": "accept"}, "dismiss" o "request" per rimettere una conversazione tra le richieste. Restituisce il tuo membro del canale. |
GET, PUT /channels/{channel_id}/overridesGET /channels/{channel_id}/overrides/effectiveGET, PUT /channels/{channel_id}/role_access | Cosa può fare un ruolo o una persona in un canale, e quali ruoli visualizzano un canale protetto da ruolo. |
GET, PUT /teams/{team_id}/server_categoriesGET, PUT …/server_categories/overrides | Le categorie di canali condivise della community, e le sovrascritture che si applicano a ogni canale in una categoria. |
GET /groups/{group_id}/team_rolePUT …/team_role/permissions | Le autorizzazioni concesse da un ruolo della community. |
POST /teams/{team_id}/autolinks/preview | Prova le regole di autolink della community su un testo. |
POST /channels/{channel_id}/export?format=csv&since=&until= | Scarica i messaggi di un canale in formato CSV (fino a 50.000), per le persone che possono leggere il canale. |
GET /posts/{post_id}/speech | Il messaggio letto ad alta voce, in formato audio, quando la sintesi vocale è configurata. |
POST /posts/{post_id}/move_to_channel | Sposta un thread in un altro canale della stessa community: vedi Sposta un thread. |
GET, POST /ai/connectionsGET, PATCH, DELETE /ai/connections/{connection_id}GET /ai/connections/usable | Connessioni ai modelli, i provider AI utilizzati dalle funzioni AI del server e dalle app: vedi Connessioni ai modelli. |
GET /channels/{channel_id}/message_actionsPOST /posts/{post_id}/message_actions/{hook_id}GET, POST /hooks/outgoing/{hook_id}/icon | Azioni sui messaggi: webhook in uscita che le persone eseguono dal menu del messaggio. Vedi Azioni sui messaggi. |
Nuovi campi
- Community (
Team, ePUT /teams/{team_id}/patch):all_channels_membership(tutti sono in ogni canale che possono vedere),default_channel_id(dove arrivano i nuovi arrivati; vuoto significa General),kind(communityoworkplace: in un workplace, gli amministratori dei canali possono archiviare anche i propri canali; le nuove community ottengono ilTeamSettings.DefaultCommunityKinddel server,communitydi default),member_list_view(come l'elenco dei membri raggruppa i membri:choice, il default, permette a ciascun membro di scegliere;rolesoteamslo fissa),hide_role_colors,require_team_badges,onboardingeautolinks(entrambi stringhe JSON). - Il canale predefinito di una nuova community è
general(General), nontown-square. L'aggiornamento alla versione 0.9.0 rinomina iltown-squaredi ogni community ingeneral, mantenendone l'ID, a meno che la community non disponga già di un canalegeneral. I nomi precedenti continuano a funzionare:GET /teams/{team_id}/channels/name/town-square,GET /teams/name/{team}/channels/name/town-squaree il campochanneldi un webhook in ingresso restituiscono il canale predefinito della community quando non esiste un canale con quel nome. Utilizzadefault_channel_ido il nomegeneralnel nuovo codice. - Link ai canali:
#channel-namecollega a un canale, proprio come~channel-name. La proprietàchannel_mentionsdel post elenca i canali collegati in uno dei due modi; un#wordche non corrisponde a un canale resta un hashtag. L'interfaccia web e l'app mobile di Antimatter scrivono#name. - I canali archiviati accettano ancora nuovi membri (
POST /channels/{channel_id}/members), che possono leggerne la cronologia. Nessuno può pubblicare, reagire, fissare, mettere un messaggio in cima, rinominare il canale o modificare i ruoli dei suoi membri. - Risposte inline: un post con
"props": {"reply_to": "<post id>"}cita quel messaggio dello stesso canale. Aggiungi"reply_to_mention": falseper non notificare l'autore. Il server compilametadata.reply_tocon una breve descrizione del messaggio citato. - Spoiler:
"props": {"spoiler": true}nasconde il testo e i file di un post finché il lettore non sceglie di visualizzarli. - Ignorare e bloccare sono preferenze: categoria
user_block, denominata in base all'ID dell'altra persona, con il valoreignoreoblock. Se un messaggio diretto attende come richiesta è definito innotify_props.dm_requestdel tuo membro del canale (pending,acceptedodismissed). - Allegati dei messaggi possono contenere
stagese unchart: vedi Cards.
Spostare un thread
POST /posts/{post_id}/move_to_channel sposta un thread, il suo primo messaggio e tutte le sue risposte, in un altro canale della stessa community. post_id può essere il primo messaggio o qualsiasi risposta.
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(obbligatorio): il canale in cui viene spostato il thread.flatten(valore predefinitofalse): se impostato sutrue, le risposte diventano messaggi del canale di destinazione anziché un thread. La funzione Make it a channel di Fusion la utilizza.
I messaggi mantengono i loro autori, i tempi, le reazioni e i file. Le copie hanno la proprietà silent_notification, quindi non notificano nessuno. I messaggi originali vengono eliminati. La risposta è il primo messaggio spostato, con il suo nuovo ID.
Chi può spostare un thread
- Devi poter leggere il thread e pubblicare nel canale di destinazione.
- Gli amministratori del canale, gli amministratori della community, le persone con Gestisci messaggi (
delete_others_posts) nel canale e gli amministratori di sistema possono spostare qualsiasi thread. - L'autore del thread può spostarlo quando entrambi i canali sono pubblici, o quando tutti i messaggi del thread sono suoi. In caso contrario, la risposta è
403con l'IDapi.post.move_thread.private_needs_moderator.app_error. - Entrambi i canali devono appartenere alla stessa community (non sono ammessi messaggi diretti o di gruppo), essere diversi e non archiviati. Non è possibile spostare i messaggi di sistema né i messaggi che si autodistruggono alla lettura.
- Un thread con più di
WranglerSettings.MoveThreadMaxCountmessaggi (100 di default; 0 per nessun limite) viene rifiutato.
Il puntatore e la nota
Lo spostamento genera due messaggi di sistema di tipo system_wrangler: un puntatore nel canale di origine ("Un thread con 13 messaggi è stato spostato in #target") e una nota nel canale di destinazione ("Questo thread è stato spostato da #source"), posizionati sotto il thread spostato o, con flatten, dopo i suoi messaggi. Oltre al testo del messaggio, le proprietà (props) permettono al client di visualizzare il nome del canale come un collegamento:
- Il puntatore:
MovedThreadPermalink,NumMessages,MovedThreadChannelId,MovedThreadTeamName,MovedThreadPostIde, per una destinazione pubblica,MovedThreadChannelNameeMovedThreadChannelDisplayName. - La nota:
MovedFromChannelId,MovedFromTeamName,MovedFromPostId(il puntatore),MovedFromPermalinke, per un'origine pubblica,MovedFromChannelNameeMovedFromChannelDisplayName.
Entrambi hanno anche un TranslationID. Il nome di un canale privato viene omesso: i lettori vedranno "un altro canale". L'endpoint POST /posts/{post_id}/move di Mattermost è disabilitato in Antimatter; usa questo endpoint.
Connessioni ai modelli
Una connessione al modello è l'indirizzo e la chiave di un provider di IA, configurati da un amministratore. Le funzionalità di IA del server e le app che chiamano il servizio di IA li utilizzano. Gli amministratori di sistema gestiscono le connessioni a livello di server (manage_ai_connections); gli amministratori di una community gestiscono le connessioni della propria community (manage_team_ai_connections). Le chiavi sono solo in scrittura: nessuna risposta le contiene, solo api_key_set e api_key_last4.
| Endpoint | Funzione |
|---|---|
GET /ai/connections?scope= | Le connessioni che gestisci. scope è server o l'ID di una community; se omesso, restituisce tutti gli scope che gestisci. |
POST /ai/connections | Aggiunge una connessione (risponde con 201). |
POST /ai/connections/test, POST /ai/connections/models | Testa una connessione o ne elenca i modelli prima di salvarla. Stesso corpo della richiesta di aggiunta; nulla viene memorizzato. |
GET, PATCH (o PUT), DELETE /ai/connections/{connection_id} | Legge, modifica o elimina una connessione. Una patch contiene solo i campi da modificare; ometti api_key per mantenere la chiave esistente. |
POST /ai/connections/{connection_id}/test | Testa una connessione salvata: {"ok", "error", "status_code", "latency_ms", "model_count"}. |
GET /ai/connections/{connection_id}/models | I modelli offerti dal provider. |
GET /ai/connections/{connection_id}/usage | Richieste e token di questo mese. |
GET /ai/connections/usable?channel_id=&team_id= | Per chiunque sia autenticato: le connessioni che puoi utilizzare, con i relativi modelli e funzionalità, mai le chiavi o gli indirizzi. |
Il corpo di una nuova connessione:
{
"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 o anthropic. scope ha come valore predefinito server; l'ID di una community la rende una connessione di quella community. In limits, 0 significa nessun limite; le richieste al minuto vengono conteggiate su ogni server, i budget di token per mese solare (UTC) per l'intero cluster. sharing indica quali community possono utilizzare una connessione a livello di server (i messaggi diretti e di gruppo richiedono all_teams), e audience chi può utilizzarla; gli ospiti solo con allow_guests. Le modifiche vengono registrate nel registro di controllo. La guida per gli amministratori spiega le impostazioni: vedi AI.