A API REST

Tudo o que as aplicações do Antimatter fazem passa pela mesma API HTTP, pelo que os seus scripts também o podem fazer. Esta página explica como autenticar, os recursos que mais vai usar, como são as respostas e os erros, e como seguir eventos em tempo real através do WebSocket.

Fundamentos

  • URL base: https://chat.example.com/api/v4. Todos os pontos de acesso abaixo são relativos a este.
  • Formato: JSON na entrada e na saída, exceto para carregamentos de ficheiros (multipart). Envie Content-Type: application/json.
  • ID: cada objeto tem um id de 26 caracteres. Os tempos são em milissegundos desde a época Unix (create_at, update_at, delete_at; 0 significa "não eliminado").
  • As comunidades são equipas: a API chama-lhes teams, com um team_id.
  • si próprio: sempre que um caminho requer um user_id, me significa o utilizador autenticado, como em GET /users/me.

A lista completa de endpoints encontra-se no código do servidor: as rotas são declaradas em server/channels/api4/*.go e os tipos em server/public/model. A descrição OpenAPI na pasta api/v4/source do repositório cobre os endpoints herdados do Mattermost, bem como algumas das adições do Antimatter: mover tópicos, ligações de modelos e ações de mensagem. Os restantes existem apenas no código.

Autenticação

Cada pedido, exceto o de iniciar sessão e alguns pontos de acesso públicos, necessita de um token no cabeçalho Authorization:

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

São aceites três tipos de token: tokens de acesso pessoal, tokens de sessão e tokens de acesso OAuth. Authorization: Token … também é aceite. Tokens na cadeia de consulta (?access_token=) só são aceites para tokens de acesso OAuth.

Tokens de acesso pessoal (recomendados para scripts)

Um token de acesso pessoal atua em seu nome, não expira, a menos que lhe defina uma data de expiração, e pode ser revogado a qualquer momento. Os tokens de acesso pessoal estão desativados por omissão:

  1. Um administrador do sistema ativa Ativar fichas de acesso pessoal em Consola do sistema › Integrações › Gestão de integrações (ServiceSettings.EnableUserAccessTokens, AM_SERVICESETTINGS_ENABLEUSERACCESSTOKENS).
  2. Para cada pessoa que pode criar fichas, um administrador do sistema abre Consola do sistema › Gestão de utilizadores › Utilizadores, escolhe Gerir funções no menu da pessoa e marca Permitir que esta conta gere fichas de acesso pessoal. Os administradores do sistema podem sempre criá-las.
  3. A pessoa abre o seu avatar no canto superior direito, depois Perfil & definições › Segurança. Em Tokens de acesso pessoal, descreve para que serve o token e escolhe Criar token. O token é mostrado apenas uma vez: copie-o.

Com a API: POST /users/{user_id}/tokens com {"description": "backup script", "expires_at": 0} (expires_at em milissegundos; 0 para nenhum). O campo token da resposta é o segredo; o seu id é o que usa para o revogar (POST /users/tokens/revoke com {"token_id": "…"}). A partir da linha de comandos: amctl token generate <user> <description>.

Um administrador do sistema pode limitar a duração de validade das fichas com Duração máxima de validade do token de acesso pessoal (dias) na mesma página da Consola do sistema.

Tokens de sessão

Iniciar sessão com uma palavra-passe devolve um token de sessão no cabeçalho de resposta Token, o mesmo tipo de sessão que as aplicações usam:

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

Adicione "token": "123456" para uma conta com autenticação multifator. As sessões expiram conforme as definições de sessão do servidor, e o ponto de entrada de login tem limite de taxa (5 pedidos por segundo). POST /users/logout termina a sessão.

Os navegadores autenticam com um cookie. Um pedido autenticado pelo cookie deve também enviar o cabeçalho X-CSRF-Token para qualquer coisa que não seja GET; um token no cabeçalho Authorization não precisa de cabeçalho CSRF.

Aplicações OAuth 2.0

Para permitir que as pessoas iniciem sessão na sua aplicação com a sua conta Antimatter, registe uma aplicação OAuth 2.0. O Antimatter passa então a ser o provedor OAuth:

  1. Ativar Provedor de Serviços OAuth 2.0 tem de estar ativado (Consola do sistema › Integrações › Gestão de integrações, ServiceSettings.EnableOAuthServiceProvider, ativado por omissão).
  2. Alguém com o direito de gerir aplicações OAuth (administradores do sistema por omissão) abre o seu avatar, depois Integrações › Aplicações OAuth 2.0, e adiciona a aplicação com as suas URLs de callback. Recebe um ID de cliente e um segredo de cliente.
  3. A sua aplicação envia as pessoas para https://chat.example.com/oauth/authorize com response_type=code, client_id, redirect_uri e state. O PKCE com code_challenge_method=S256 é suportado.
  4. Troca o código em POST https://chat.example.com/oauth/access_token (grant_type=authorization_code, depois refresh_token para renovar) e chama a API com Authorization: Bearer <access token>.

As pessoas veem as aplicações que autorizaram em Perfil e definições › Segurança › Aplicações autorizadas.

Recursos principais

O quêEndpoints
Você e outras pessoasGET /users/me, GET /users/{user_id}, GET /users/username/{username}, POST /users/ids (uma lista de IDs), POST /users/search, GET /users?in_team=…&in_channel=…
ComunidadesGET /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
CanaisGET /users/me/teams/{team_id}/channels, GET /teams/name/{team}/channels/name/{channel}, POST /channels, POST /channels/direct (dois IDs de utilizador), POST /channels/group, POST /channels/{channel_id}/members
Mensagens (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
ReaçõesPOST /reactions com {"user_id", "post_id", "emoji_name"}, DELETE /users/{user_id}/posts/{post_id}/reactions/{emoji_name}
FicheirosPOST /files (multipart: channel_id e files), depois coloque os IDs devolvidos no campo file_ids da mensagem; GET /files/{file_id}
PreferênciasGET /users/me/preferences, PUT /users/me/preferences
Integrações/hooks/incoming, /hooks/outgoing, /commands, /bots, /oauth/apps (veja as páginas seguintes)
ServidorGET /system/ping (estado, não requer token), GET /config/client?format=old (as definições que os clientes veem)

Publicar uma mensagem

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

As mensagens são em Markdown. Adicione "root_id" (a primeira mensagem de um tópico) para responder num tópico, "file_ids" para ficheiros e "props" para anexos e outros extras (veja Anexos).

Encontrar o ID de um canal

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

Os nomes são os que aparecem no link do canal: /lumen-labs/channels/ops-alerts.

Paginação

Os endpoints de listas aceitam page (a partir de 0) e per_page (60 por omissão, no máximo 200). Continue a pedir a página seguinte até uma página vir mais curta do que per_page.

As mensagens de um canal (GET /channels/{channel_id}/posts) também aceitam since (um tempo: tudo o que foi alterado desde então) ou before e after (um ID de publicação). São devolvidas como uma lista de publicações: {"order": [IDs, newest first], "posts": {ID: post}, "next_post_id", "prev_post_id"}.

Erros

Os erros utilizam os códigos de estado HTTP habituais (400 entrada inválida, 401 não autenticado, 403 não autorizado, 404 não encontrado, 501 funcionalidade desativada) e um corpo JSON:

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

Utilize id no seu código: message é traduzido para a língua do utilizador. detailed_error fica vazio, exceto se o servidor estiver em modo de desenvolvimento (ServiceSettings.EnableDeveloper). Indique request_id ao administrador do servidor: ele está nos registos.

Limites de taxa

A limitação de taxa está desativada por omissão. Quando um administrador do sistema a ativa (Consola do sistema › Ambiente › Limitação de taxa), cada cliente recebe 10 pedidos por segundo, com rajadas de 100 por omissão, contados por endereço IP ou por utilizador. As respostas incluem X-RateLimit-Limit, X-RateLimit-Remaining e X-RateLimit-Reset; quando o limite é excedido, o servidor responde com 429 e um cabeçalho Retry-After em segundos. Alguns pontos de acesso, como a autenticação, têm o seu próprio limite, independentemente da configuração.

Escreva scripts que esperem e repitam em caso de 429, e evite a consulta periódica: siga o WebSocket em vez disso.

O fluxo de eventos do WebSocket

Ligue-se a wss://chat.example.com/api/v4/websocket. Autentique-se com o cabeçalho Authorization: Bearer no pedido de ligação, ou enviando isto como a primeira mensagem:

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

O servidor envia um evento hello, seguido de um evento para tudo o que lhe é permitido ver:

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

Note que data.post é a publicação como uma string JSON. Eventos comuns: posted, post_edited, post_deleted, reaction_added, reaction_removed, typing, status_change, user_added, direct_added. As aplicações enviam os seus próprios eventos, nomeados custom_<app id>_<event>.

Também pode enviar ações, cada uma com um seq crescente: user_typing com {"channel_id", "parent_id"}, ou get_statuses. Reconecte-se quando a ligação cair e obtenha o que perdeu com since (ver Paginação).

O Antimatter adiciona estes eventos: community_attributes_updated, member_timeouts_updated, post_put_on_top, post_removed_from_top, server_categories_updated, channel_overrides_updated e category_overrides_updated.

Bibliotecas de cliente

  • Ir: model.Client4 em server/public/model (importar github.com/mattermost/mattermost/server/public/model). model.NewAPIv4Client(url), depois client.SetToken(token); model.NewWebSocketClient4(wsURL, token) segue os eventos. A cópia do Antimatter adiciona métodos para os seus próprios pontos de entrada, como UpdateMessageRequest, PutPostOnTop e ExportChannel.
  • TypeScript: a classe Client4 de @mattermost/client, em webapp/platform/client, com os seus tipos em webapp/platform/types. A cópia no repositório do Antimatter inclui os endpoints do Antimatter; o pacote publicado no npm pela Mattermost não.
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)
}

O que o Antimatter adiciona à API

Estes endpoints e campos não existem num servidor Mattermost. Todos eles exigem uma sessão.

EndpointO que faz
GET /teams/{team_id}/user_attributes/fields
POST no mesmo caminho
PATCH, DELETE …/fields/{field_id}
Atributos da comunidade: os campos de perfil definidos pelos administradores de uma comunidade para os seus membros (até 20). Os membros podem lê-los; os administradores da comunidade criam-nos e modificam-nos.
GET /teams/{team_id}/members/{user_id}/user_attributes
PATCH no mesmo caminho
POST /teams/{team_id}/user_attributes/values/search
Os valores dos atributos de um membro, como {field_id: value}. Os membros definem os seus próprios (exceto os geridos por administradores); os administradores definem os de qualquer pessoa. A pesquisa aceita {"user_ids": [...]} (até 200).
GET /teams/{team_id}/timeouts
PUT /teams/{team_id}/members/{user_id}/timeout
GET /teams/{team_id}/members/{user_id}/moderation
Suspensões: {"until": time, "reason": "…"} impede alguém de publicar, reagir e carregar ficheiros na comunidade até à data indicada (no máximo 28 dias); "until": 0 remove a suspensão. A vista de moderação mostra quando entraram e quanto publicaram recentemente.
GET /channels/{channel_id}/on_top
PUT, DELETE /posts/{post_id}/on_top
Mensagens mantidas no topo de um canal (até 10). {"duration": ms}, no máximo 30 dias; 0 mantém até ser removida. Qualquer pessoa que possa ler o canal vê-as. Colocar uma mensagem no topo ou removê-la exige o direito de publicar no canal e, num canal de uma comunidade, ser administrador do canal ou da comunidade, ou ter Gerir mensagens (delete_others_posts) aí. Numa mensagem direta ou de grupo, os seus membros podem fazê-lo. Recusado em canais arquivados.
POST /channels/{channel_id}/message_requestAge sobre o seu próprio pedido de mensagem: {"action": "accept"}, "dismiss" ou "request" para colocar uma conversa novamente entre os pedidos. Devolve o seu membro do canal.
GET, PUT /channels/{channel_id}/overrides
GET /channels/{channel_id}/overrides/effective
GET, PUT /channels/{channel_id}/role_access
O que um papel ou uma pessoa pode fazer num canal, e que papéis veem um canal com acesso restrito por papel.
GET, PUT /teams/{team_id}/server_categories
GET, PUT …/server_categories/overrides
As categorias de canais partilhadas pela comunidade, e as substituições que se aplicam a todos os canais de uma categoria.
GET /groups/{group_id}/team_role
PUT …/team_role/permissions
As permissões que um papel da comunidade concede.
POST /teams/{team_id}/autolinks/previewTesta as regras de ligações automáticas da comunidade num texto.
POST /channels/{channel_id}/export?format=csv&since=&until=Descarrega as mensagens de um canal como CSV (até 50.000), para pessoas que podem ler o canal.
GET /posts/{post_id}/speechA mensagem lida em voz alta, como áudio, quando a conversão de texto em fala estiver configurada.
POST /posts/{post_id}/move_to_channelMove um tópico para outro canal da mesma comunidade: ver Mover um tópico.
GET, POST /ai/connections
GET, PATCH, DELETE /ai/connections/{connection_id}
GET /ai/connections/usable
Ligações de modelos, os fornecedores de IA que as funcionalidades de IA do servidor e as aplicações utilizam: ver Ligações de modelos.
GET /channels/{channel_id}/message_actions
POST /posts/{post_id}/message_actions/{hook_id}
GET, POST /hooks/outgoing/{hook_id}/icon
Ações de mensagem: webhooks de saída que as pessoas executam a partir do menu da mensagem. Ver Ações de mensagem.

Novos campos

  • Comunidades (Team, e PUT /teams/{team_id}/patch): all_channels_membership (todos estão em todos os canais que podem ver), default_channel_id (onde os novos membros chegam; vazio significa Geral), kind (community ou workplace: num workplace, os administradores de canal também podem arquivar os seus canais; novas comunidades recebem o TeamSettings.DefaultCommunityKind do servidor, community por omissão), member_list_view (como a lista de membros agrupa os membros: choice, a omissão, permite a cada membro escolher; roles ou teams fixa-a), hide_role_colors, require_team_badges, onboarding e autolinks (ambas cadeias JSON).
  • O Canal predefinido de uma nova comunidade é general (General), não town-square. A atualização para a versão 0.9.0 renomeia o town-square de cada comunidade para general, mantendo o respetivo ID, a menos que a comunidade já tenha um canal general. Os nomes antigos continuam a funcionar: GET /teams/{team_id}/channels/name/town-square, GET /teams/name/{team}/channels/name/town-square e o parâmetro channel de um webhook recebido devolvem o canal predefinido da comunidade quando não existe nenhum canal com esse nome. Utilize default_channel_id, ou o nome general, em novo código.
  • Links de canais: #channel-name liga um canal, tal como ~channel-name. A propriedade channel_mentions da publicação lista os canais ligados de qualquer forma; um #word que não nomeia nenhum canal permanece uma etiqueta. A interface web e a aplicação móvel do Antimatter escrevem #name.
  • Os canais arquivados continuam a aceitar novos membros (POST /channels/{channel_id}/members), que podem ler o respetivo histórico. Ninguém pode publicar, reagir, fixar, colocar uma mensagem no topo, renomear o canal ou alterar as funções dos seus membros.
  • Respostas em linha: uma publicação com "props": {"reply_to": "<post id>"} cita essa mensagem do mesmo canal. Adicione "reply_to_mention": false para não notificar o autor. O servidor preenche metadata.reply_to com uma breve descrição da mensagem citada.
  • Alertas de conteúdo: "props": {"spoiler": true} oculta o texto e os ficheiros de uma publicação até o leitor escolher vê-los.
  • Ignorar e bloquear são preferências: categoria user_block, nomeada com o ID da outra pessoa, com o valor ignore ou block. Se uma mensagem direta fica pendente como pedido, isso está nos notify_props.dm_request do seu membro do canal (pending, accepted ou dismissed).
  • Anexos de mensagem podem ter stages e um chart: veja Cartões.

Mover um tópico

POST /posts/{post_id}/move_to_channel move um tópico, a sua primeira mensagem e todas as suas respostas, para outro canal da mesma comunidade. post_id pode ser a primeira mensagem ou qualquer resposta.

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 (obrigatório): o canal para onde o tópico é movido.
  • flatten (predefinição false): true faz com que as respostas se tornem mensagens do canal de destino em vez de um tópico. A opção Tornar num canal do Fusion utiliza-a.

As mensagens mantêm os respetivos autores, horários, reações e ficheiros. As suas cópias transportam a propriedade silent_notification, pelo que não notificam ninguém. As mensagens originais são eliminadas. A resposta é a primeira mensagem movida, com o seu novo ID.

Quem pode mover um tópico

  • Tem de ser capaz de ler o tópico e de publicar no canal de destino.
  • Os administradores do canal, os administradores da comunidade, pessoas com Gerir mensagens (delete_others_posts) no canal, e os administradores do sistema podem mover qualquer tópico.
  • O autor do tópico pode movê-lo quando ambos os canais são públicos, ou quando todas as mensagens do tópico são suas. Caso contrário, a resposta é 403 com o ID api.post.move_thread.private_needs_moderator.app_error.
  • Ambos os canais devem pertencer à mesma comunidade (sem mensagens diretas ou de grupo), ser diferentes e não estarem arquivados. As mensagens do sistema e as mensagens que se eliminam após a leitura não podem ser movidas.
  • Um tópico com mais de WranglerSettings.MoveThreadMaxCount mensagens (100 por omissão; 0 para sem limite) é recusado.

O ponteiro e a nota

A operação de mover deixa duas mensagens do sistema do tipo system_wrangler: um ponteiro no canal de origem ("Um tópico com 13 mensagens foi movido para #target") e uma nota no canal de destino ("Este tópico foi movido de #source"), por baixo do tópico movido ou, com flatten, após as suas mensagens. Além do texto da mensagem, as suas propriedades permitem a um cliente apresentar o nome do canal como um hiperligação:

  • O ponteiro: MovedThreadPermalink, NumMessages, MovedThreadChannelId, MovedThreadTeamName, MovedThreadPostId e, para um destino público, MovedThreadChannelName e MovedThreadChannelDisplayName.
  • A nota: MovedFromChannelId, MovedFromTeamName, MovedFromPostId (o ponteiro), MovedFromPermalink e, para uma origem pública, MovedFromChannelName e MovedFromChannelDisplayName.

Ambas têm também um TranslationID. O nome de um canal privado é omitido: os leitores veem "outro canal". O próprio POST /posts/{post_id}/move do Mattermost permanece desativado no Antimatter; use este endpoint.

Ligações de modelos

Uma ligação de modelo é o endereço e a chave de um provedor de IA, configurados por um administrador. As funcionalidades de IA do servidor e as aplicações que chamam o serviço de IA utilizam-nas. Os administradores do sistema gerem as ligações de âmbito global do servidor (manage_ai_connections); os administradores de uma comunidade gerem as ligações da sua própria comunidade (manage_team_ai_connections). As chaves são apenas de gravação: nenhuma resposta as inclui, apenas api_key_set e api_key_last4.

EndpointO que faz
GET /ai/connections?scope=As ligações que gerem. scope é server ou o ID de uma comunidade; sem ele, todos os âmbitos que gerem.
POST /ai/connectionsAdiciona uma ligação (responde 201).
POST /ai/connections/test, POST /ai/connections/modelsTesta uma ligação, ou lista os seus modelos, antes de esta ser guardada. O mesmo corpo que para adicionar uma; nada é armazenado.
GET, PATCH (ou PUT), DELETE /ai/connections/{connection_id}Lê, altera ou elimina uma ligação. Um patch inclui apenas os campos a alterar; omita api_key para manter a chave.
POST /ai/connections/{connection_id}/testTesta uma ligação guardada: {"ok", "error", "status_code", "latency_ms", "model_count"}.
GET /ai/connections/{connection_id}/modelsOs modelos que o prestador de serviços disponibiliza.
GET /ai/connections/{connection_id}/usageAs solicitações e os tokens deste mês.
GET /ai/connections/usable?channel_id=&team_id=Para qualquer pessoa iniciada na sessão: as ligações que pode utilizar, com os respetivos modelos e capacidades, nunca as chaves ou endereços.

O corpo de uma nova ligação:

{
  "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 ou anthropic. scope tem por omissão server; o ID de uma comunidade torna-a a ligação dessa comunidade. Em limits, 0 significa sem limite; as solicitações por minuto são contadas em cada servidor, e os orçamentos de tokens por mês civil (UTC) para todo o cluster. sharing indica que comunidades podem utilizar uma ligação de âmbito de servidor (as mensagens diretas e de grupo necessitam de all_teams), e audience quem a pode utilizar; convidados apenas com allow_guests. As alterações são registadas no registo de auditoria. O guia de administração explica as definições: ver IA.