API-ul REST

Tot ce fac aplicațiile Antimatter trece prin același API HTTP, deci scripturile dumneavoastră pot face la fel. Această pagină explică cum să vă autentificați, resursele pe care le veți folosi cel mai des, cum arată răspunsurile și erorile și cum să urmăriți în timp real evenimente prin WebSocket.

Bazele

  • URL de bază: https://chat.example.com/api/v4. Toate punctele de acces de mai jos sunt relative la acesta.
  • Format: JSON la intrare și la ieșere, cu excepția încărcării fișierelor (multipart). Trimiteți Content-Type: application/json.
  • ID-uri: fiecare obiect are un id de 26 de caractere. Timpurile sunt în milisecunde de la epoca Unix (create_at, update_at, delete_at; 0 înseamnă „nu a fost șters”).
  • Comunitățile sunt echipe: API-ul le numește teams, cu un team_id.
  • tu însuți: oriunde un path acceptă un user_id, me se referă la utilizatorul autentificat, de exemplu în GET /users/me.

Lista completă de puncte de acces se găsește în codul serverului: rutele sunt declarate în server/channels/api4/*.go, iar tipurile în server/public/model. Descrierea OpenAPI din folderul api/v4/source din depozit acoperă punctele de acces moștenite de la Mattermost, precum și unele adăugiri din Antimatter: mutarea firelor de discuție, conexiunile la modele și acțiunile asupra mesajelor. Celelalte sunt disponibile doar în cod.

Autentificare

Fiecare cerere, cu excepția autentificării și a câtorva puncte de acces publice, necesită un token în antetul Authorization:

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

Acolo sunt acceptate trei tipuri de token: tokenuri de acces personale, tokenuri de sesiune și tokenuri de acces OAuth. Authorization: Token … este, de asemenea, acceptat. Tokenurile în șirul de interogare (?access_token=) sunt acceptate doar pentru tokenurile de acces OAuth.

Tokenuri de acces personale (recomandate pentru scripturi)

Un token de acces personal acționează în numele dumneavoastră, nu expiră, cu excepția cazului în care îi stabiliți o dată de expirare și poate fi revocat oricând. Tokenurile de acces personale sunt dezactivate implicit:

  1. Un administrator de sistem activează Activați jetoanele de acces personal în Consola de sistem › Integrări › Managementul integrării (ServiceSettings.EnableUserAccessTokens, AM_SERVICESETTINGS_ENABLEUSERACCESSTOKENS).
  2. Pentru fiecare persoană care poate crea jetoane, un administrator de sistem deschide Consola de sistem › Gestionarea utilizatorilor › Utilizatori, alege Gestionează rolurile din meniul persoanei și bifează Permite acestui cont să genereze jetoane de acces personal. Administratorii de sistem pot crea jetoane în orice moment.
  3. Persoana își deschide avatarul din colțul din dreapta sus, apoi Profil & setări › Securitate. În secțiunea Jetoane de acces personale, descrie scopul jetonului și alege Creați un nou jeton. Jetonul este afișat o singură dată: copiați-l.

Prin API: POST /users/{user_id}/tokens cu {"description": "backup script", "expires_at": 0} (expires_at în milisecunde; 0 pentru fără expirare). Câmpul token din răspuns este secretul; id-ul este cel pe care îl folosești pentru a-l revoca (POST /users/tokens/revoke cu {"token_id": "…"}). Din linia de comandă: amctl token generate <user> <description>.

Un administrator de sistem poate limita durata de viață a jetoanelor cu Durata maximă de validitate a tokenului de acces personal (zile) pe aceeași pagină din Consola de sistem.

Tokeni de sesiune

Autentificarea cu o parolă returnează un token de sesiune în antetul de răspuns Token, același tip de sesiune pe care îl folosesc aplicațiile:

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

Adaugă "token": "123456" pentru un cont cu autentificare în mai multe etape. Sesiunile expiră conform setărilor de sesiune ale serverului, iar punctul de autentificare este limitat în rată (5 cereri pe secundă). POST /users/logout încheie sesiunea.

Navigatoarele se autentifică cu un cookie. O cerere autentificată prin cookie trebuie să trimită și antetul X-CSRF-Token pentru orice operație care nu este GET; un token în antetul Authorization nu necesită un antet CSRF.

Aplicații OAuth 2.0

Pentru a permite utilizatorilor să se autentifice în aplicația ta cu contul lor Antimatter, înregistrează o aplicație OAuth 2.0. Antimatter devine apoi furnizorul OAuth:

  1. Activați furnizorul de servicii OAuth 2.0 trebuie să fie activat (Consola de sistem › Integrări › Managementul integrării, ServiceSettings.EnableOAuthServiceProvider, activat implicit).
  2. O persoană cu dreptul de a gestiona aplicațiile OAuth (administratorii de sistem, implicit) își deschide avatarul, apoi Integrări › Aplicații OAuth 2.0, și adaugă aplicația cu URL-urile de callback. Primește un client ID și un client secret.
  3. Aplicația dumneavoastră trimite utilizatorii la https://chat.example.com/oauth/authorize cu response_type=code, client_id, redirect_uri și state. Este suportat PKCE cu code_challenge_method=S256.
  4. Codul este schimbat la POST https://chat.example.com/oauth/access_token (cu grant_type=authorization_code, apoi refresh_token pentru reînnoire), iar apelurile către API se fac cu Authorization: Bearer <access token>.

Utilizatorii își pot vedea aplicațiile autorizate în Profil & setări › Securitate › Aplicații pe care le-ai autorizat.

Resurse principale

CeEndpoint-uri
Dumneavoastră și alți utilizatoriGET /users/me, GET /users/{user_id}, GET /users/username/{username}, POST /users/ids (o listă de ID-uri), POST /users/search, GET /users?in_team=…&in_channel=…
ComunitățiGET /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
CanaleGET /users/me/teams/{team_id}/channels, GET /teams/name/{team}/channels/name/{channel}, POST /channels, POST /channels/direct (două ID-uri de utilizator), POST /channels/group, POST /channels/{channel_id}/members
Mesaje (postări)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
ReacțiiPOST /reactions cu {"user_id", "post_id", "emoji_name"}, DELETE /users/{user_id}/posts/{post_id}/reactions/{emoji_name}
FișierePOST /files (multipart: channel_id și files), apoi introduceți ID-urile returnate în file_ids al postării; GET /files/{file_id}
PreferințeGET /users/me/preferences, PUT /users/me/preferences
Integrări/hooks/incoming, /hooks/outgoing, /commands, /bots, /oauth/apps (a se vedea paginile următoare)
ServerGET /system/ping (stare, nu necesită token), GET /config/client?format=old (setările vizibile de către clienți)

Publicare unui mesaj

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

Mesajele sunt în format Markdown. Adăugați "root_id" (prima postare dintr-un fir de discuție) pentru a răspunde într-un fir de discuție, "file_ids" pentru fișiere și "props" pentru atașamente și alte elemente suplimentare (a se vedea Atașamente).

Găsirea ID-ului unui canal

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

Numele sunt cele din linkul canalului: /lumen-labs/channels/ops-alerts.

Paginare

Endpoint-urile de listă acceptă page (de la 0) și per_page (60 implicit, maxim 200). Continuați să solicitați pagina următoare până când o pagină returnată este mai scurtă decât per_page.

Mesajele unui canal (GET /channels/{channel_id}/posts) acceptă și since (o dată: tot ce s-a modificat de atunci), sau before și after (un ID de mesaj). Răspunsul este o listă de mesaje: {"order": [IDs, newest first], "posts": {ID: post}, "next_post_id", "prev_post_id"}.

Erori

Erorile folosesc codurile de stare HTTP uzuale (400 intrare nevalidă, 401 neautentificat, 403 neautorizat, 404 nu a fost găsit, 501 funcție dezactivată) și un corp JSON:

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

Folosiți id în codul dumneavoastră: message este tradus în limba utilizatorului. detailed_error este gol, cu excepția cazului în care serverul rulează în mod de dezvoltare (ServiceSettings.EnableDeveloper). Citați request_id administratorului serverului: acesta se află în jurnale.

Limite de rată

Limitarea ratei este dezactivată implicit. Când un administrator de sistem o activează (Consola de sistem › Mediu › Evaluați setările de limită), fiecare client primește implicit 10 cereri pe secundă, cu rafale de 100, numărate după adresa IP sau după utilizator. Răspunsurile conțin X-RateLimit-Limit, X-RateLimit-Remaining și X-RateLimit-Reset; dacă se depășește limita, serverul răspunde cu 429 și un antet Retry-After în secunde. Unele endpoint-uri, cum ar fi autentificarea, au propria limită, indiferent de setare.

Scrieți scripturi care așteaptă și reîncearcă la 429, și evitați interogările repetate: folosiți în schimb WebSocket.

Fluxul de evenimente WebSocket

Conectați-vă la wss://chat.example.com/api/v4/websocket. Autentificați-vă fie cu antetul Authorization: Bearer în cererea de conexiune, fie trimițând acest lucru ca prim mesaj:

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

Serverul trimite un eveniment hello, apoi un eveniment pentru tot ce aveți voie să vedeți:

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

Rețineți că data.post este mesajul ca șir JSON. Evenimente comune: posted, post_edited, post_deleted, reaction_added, reaction_removed, typing, status_change, user_added, direct_added. Aplicațiile trimite propriile evenimente, numite custom_<app id>_<event>.

Puteți trimite și acțiuni, fiecare cu un seq crescător: user_typing cu {"channel_id", "parent_id"}, sau get_statuses. Reconectați-vă când conexiunea se întrerupe și preluați ce ați ratat cu since (a se vedea Paginarea).

Antimatter adaugă aceste evenimente: community_attributes_updated, member_timeouts_updated, post_put_on_top, post_removed_from_top, server_categories_updated, channel_overrides_updated și category_overrides_updated.

Biblioteci client

  • Mergi: model.Client4 în server/public/model (import github.com/mattermost/mattermost/server/public/model). model.NewAPIv4Client(url), apoi client.SetToken(token); model.NewWebSocketClient4(wsURL, token) urmărește evenimentele. Copia Antimatter adaugă metode pentru propriile sale puncte de acces, cum ar fi UpdateMessageRequest, PutPostOnTop și ExportChannel.
  • TypeScript: clasa Client4 din @mattermost/client, în webapp/platform/client, cu tipurile sale în webapp/platform/types. Copia din depozitul Antimatter include punctele de acces ale Antimatter; pachetul publicat pe npm de Mattermost nu le 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)
}

Ce adaugă Antimatter la API

Aceste puncte de acces și câmpuri nu există pe un server Mattermost. Toate necesită o sesiune.

Punct de accesCe face
GET /teams/{team_id}/user_attributes/fields
POST aceeași cale
PATCH, DELETE …/fields/{field_id}
Atributele comunității: câmpurile de profil definite de administratorii unei comunități pentru membrii săi (maxim 20). Membrii le pot citi; administratorii comunității le creează și le modifică.
GET /teams/{team_id}/members/{user_id}/user_attributes
PATCH aceeași cale
POST /teams/{team_id}/user_attributes/values/search
Valorile atributelor unui membru, sub forma {field_id: value}. Membrii își setează propriile valori (cu excepția celor administrate de administratori); administratorii pot seta valorile oricui. Căutarea primește {"user_ids": [...]} (maxim 200).
GET /teams/{team_id}/timeouts
PUT /teams/{team_id}/members/{user_id}/timeout
GET /teams/{team_id}/members/{user_id}/moderation
Timpul de așteptare: {"until": time, "reason": "…"} împiedică o persoană să posteze, să reacționeze și să încarce fișiere în comunitate până la acel moment (maxim 28 de zile); "until": 0 ridică restricția. Vederile de moderare indică când s-a alăturat și cât de mult a postat recent.
GET /channels/{channel_id}/on_top
PUT, DELETE /posts/{post_id}/on_top
Mesajele fixate în partea de sus a unui canal (maximum 10). {"duration": ms}, cel mult 30 de zile; 0 le păstrează până la eliminarea manuală. Oricine poate citi canalul le vede în listă. Fixarea unui mesaj sau eliminarea sa necesită dreptul de a posta în canal și, într-un canal de comunitate, să fii administrator al canalului sau al comunității, sau să ai Gestionează mesajele (delete_others_posts) acolo. Într-un mesaj direct sau de grup, membrii săi pot face acest lucru. Este refuzat în canalele arhivate.
POST /channels/{channel_id}/message_requestAcționează asupra cererii de mesaj proprii: {"action": "accept"}, "dismiss" sau "request" pentru a readuce o conversație printre cereri. Returnează membrul canalului.
GET, PUT /channels/{channel_id}/overrides
GET /channels/{channel_id}/overrides/effective
GET, PUT /channels/{channel_id}/role_access
Ce poate face un rol sau o persoană într-un canal, și ce roluri pot vedea un canal restricționat prin rol.
GET, PUT /teams/{team_id}/server_categories
GET, PUT …/server_categories/overrides
Categoriile de canale partajate de comunitate, și suprascrierile care se aplică tuturor canalelor dintr-o categorie.
GET /groups/{group_id}/team_role
PUT …/team_role/permissions
Permisiunile acordate de un rol de comunitate.
POST /teams/{team_id}/autolinks/previewTestează regulile de autolink ale comunității pe un text.
POST /channels/{channel_id}/export?format=csv&since=&until=Descarcă mesajele unui canal în format CSV (până la 50.000), pentru persoanele care pot citi canalul.
GET /posts/{post_id}/speechMesajul citit cu voce, în format audio, atunci când este configurată conversia text în vorbire.
POST /posts/{post_id}/move_to_channelMută un fir de discuție în alt canal din aceeași comunitate: vezi Mutarea unui fir de discuție.
GET, POST /ai/connections
GET, PATCH, DELETE /ai/connections/{connection_id}
GET /ai/connections/usable
Conexiunile la modele, furnizorii de inteligență artificială folosiți de funcțiile și aplicațiile AI ale serverului: vezi Conexiuni la modele.
GET /channels/{channel_id}/message_actions
POST /posts/{post_id}/message_actions/{hook_id}
GET, POST /hooks/outgoing/{hook_id}/icon
Acțiuni asupra mesajelor: webhooks de ieșire pe care utilizatorii le rulează din meniul mesajului. Vezi Acțiuni asupra mesajelor.

Câmpuri noi

  • Comunități (Team, și PUT /teams/{team_id}/patch): all_channels_membership (toată lumea este în fiecare canal pe care îl poate vedea), default_channel_id (unde ajung noii veniți; gol înseamnă General), kind (community sau workplace: într-un workplace, administratorii canalelor pot arhiva și canalele lor; comunitățile noi primesc TeamSettings.DefaultCommunityKind al serverului, implicit community), member_list_view (cum grupează lista de membri membrii: choice, implicit, le permite fiecărui membru să aleagă; roles sau teams fixează gruparea), hide_role_colors, require_team_badges, onboarding și autolinks (ambele sunt șiruri JSON).
  • Canalul implicit al unei comunități noi este general (General), nu town-square. Actualizarea la versiunea 0.9.0 redenumeste town-square al fiecărei comunități în general, păstrându-i ID-ul, cu excepția cazului în care comunitatea are deja un canal general. Numele vechi continuă să funcționeze: GET /teams/{team_id}/channels/name/town-square, GET /teams/name/{team}/channels/name/town-square și câmpul channel al unui webhook primit returnează canalul implicit al comunității atunci când niciun canal nu are acel nume. Folosiți default_channel_id sau numele general în codul nou.
  • Linkuri de canal: #channel-name leagă un canal, la fel cum face ~channel-name. Proprietatea channel_mentions a mesajului listează canalele legate în oricare dintre aceste moduri; un #word care nu numește niciun canal rămâne un hashtag. Interfața web și aplicația mobilă Antimatter scriu #name.
  • Canalele arhivate pot încă primi membri noi (POST /channels/{channel_id}/members), care își pot citi istoricul. Nimeni nu poate posta, reacționa, fixa, pune un mesaj în evidență, redenumi canalul sau modifica rolurile membrilor acolo.
  • Răspunsuri inline: un mesaj cu "props": {"reply_to": "<post id>"} citează acel mesaj din același canal. Adăugați "reply_to_mention": false pentru a nu notifica autorul. Serverul completează metadata.reply_to cu o descriere scurtă a mesajului citat.
  • Spoilere: "props": {"spoiler": true} ascunde textul și fișierele unui mesaj până când cititorul alege să le vadă.
  • Ignorarea și blocarea sunt preferințe: categoria user_block, numită după ID-ul celeilalte persoane, cu valoarea ignore sau block. Dacă un mesaj direct așteaptă ca cerere, se află în notify_props.dm_request al membrului canalului dvs. (pending, accepted sau dismissed).
  • Atașamentele mesajelor pot conține stages și un chart: consultați Carduri.

Mutarea unui fir de discuție

POST /posts/{post_id}/move_to_channel mută un fir de discuție, mesajul său inițial și toate răspunsurile, într-un alt canal din aceeași comunitate. post_id poate fi mesajul inițial sau oricare dintre răspunsuri.

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 (obligatoriu): canalul în care se mută firul de discuție.
  • flatten (implicit false): true transformă răspunsurile în mesaje ale canalului țintă, în loc să rămână un fir de discuție. Opțiunea Make it a channel din Fusion o utilizează.

Mesajele își păstrează autorii, orele, reacțiile și fișierele. Copiile lor au proprietatea silent_notification, deci nu notifică pe nimeni. Mesajele originale sunt șterse. Răspunsul este mesajul inițial mutat, cu noul său ID.

Cine poate muta un fir de discuție

  • Trebuie să puteți citi firul de discuție și să puteți posta în canalul țintă.
  • Administratorii canalului, administratorii comunității, persoanele cu dreptul Gestionează mesajele (delete_others_posts) în canal și administratorii de sistem pot muta orice fir de discuție.
  • Autorul firului de discuție îl poate muta atunci când ambele canale sunt publice, sau atunci când toate mesajele din fir sunt ale acestuia. În caz contrar, răspunsul este 403 cu ID-ul api.post.move_thread.private_needs_moderator.app_error.
  • Ambele canale trebuie să fie în aceeași comunitate (fără mesaje directe sau de grup), să fie diferite și să nu fie arhivate. Mesajele de sistem și mesajele care se șterg la citire nu pot fi mutate.
  • Un fir de discuție cu mai mult de WranglerSettings.MoveThreadMaxCount mesaje (100 implicit; 0 pentru fără limită) este refuzat.

Indicatorul și nota

Mutarea lasă două mesaje de sistem de tip system_wrangler: un indicator în canalul vechi („Un fir de discuție cu 13 mesaje a fost mutat în #target”) și o notă în canalul de destinație („Acest fir de discuție a fost mutat din #source”), sub firul mutat sau, cu flatten, după mesajele acestuia. Pe lângă textul mesajului, proprietățile lor permit unui client să afișeze numele canalului ca link:

  • Indicatorul: MovedThreadPermalink, NumMessages, MovedThreadChannelId, MovedThreadTeamName, MovedThreadPostId și, pentru o destinație publică, MovedThreadChannelName și MovedThreadChannelDisplayName.
  • Nota: MovedFromChannelId, MovedFromTeamName, MovedFromPostId (indicatorul), MovedFromPermalink și, pentru o sursă publică, MovedFromChannelName și MovedFromChannelDisplayName.

Ambele au și un TranslationID. Numele unui canal privat este omis: cititorii văd „alt canal”. Endpoint-ul propriu al Mattermost, POST /posts/{post_id}/move, este dezactivat în Antimatter; folosiți acest endpoint.

Conexiuni la modele

O conexiune la model este adresa și cheia unui furnizor de IA, configurate de un administrator. Funcțiile de IA ale serverului și aplicațiile care apelează serviciul de IA le folosesc. Administratorii de sistem gestionează conexiunile la nivel de server (manage_ai_connections); administratorii unei comunități își gestionează propriile conexiuni (manage_team_ai_connections). Cheile sunt doar de scriere: niciun răspuns nu conține o cheie, doar api_key_set și api_key_last4.

Punct de accesCe face
GET /ai/connections?scope=Conexiunile pe care le gestionați. scope este server sau ID-ul unei comunități; fără acesta, toate domeniile pe care le gestionați.
POST /ai/connectionsAdaugă o conexiune (răspunde cu 201).
POST /ai/connections/test, POST /ai/connections/modelsTestează o conexiune sau listează modelele acesteia înainte de a fi salvată. Același corp ca la adăugare; nimic nu este stocat.
GET, PATCH (sau PUT), DELETE /ai/connections/{connection_id}Citește, modifică sau șterge o conexiune. Un patch conține doar câmpurile de modificat; lăsați api_key gol pentru a păstra cheia.
POST /ai/connections/{connection_id}/testTestează o conexiune salvată: {"ok", "error", "status_code", "latency_ms", "model_count"}.
GET /ai/connections/{connection_id}/modelsModelele oferite de furnizor.
GET /ai/connections/{connection_id}/usageSolicitările și tokenii din acest lună.
GET /ai/connections/usable?channel_id=&team_id=Pentru oricine este autentificat: conexiunile pe care le puteți utiliza acolo, cu modelele și capacitățile lor, dar niciodată cheile sau adresele lor.

Corpul unei noi conexiuni:

{
  "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 este openai_compatible sau anthropic. scope are valoarea implicită server; un ID de comunitate îl face o conexiune a acelei comunități. În limits, 0 înseamnă fără limită; solicitările pe minut sunt numărate pe fiecare server, iar bugetele de tokeni pe lună calendaristică (UTC) pentru întregul cluster. sharing indică ce comunități pot utiliza o conexiune la nivel de server (mesajele directe și de grup necesită all_teams), iar audience cine o poate utiliza; oaspeții doar cu allow_guests. Modificările sunt scrise în jurnalul de audit. Ghidul administratorului explică setările: consultați AI.