A API REST

Tudo o que os aplicativos do Antimatter fazem passa pela mesma API HTTP, então seus scripts também podem. Esta página explica como autenticar, os recursos que você mais usará, como as respostas e os erros se parecem e como acompanhar eventos em tempo real via WebSocket.

Fundamentos

  • URL base: https://chat.example.com/api/v4. Todos os endpoints abaixo são relativos a ela.
  • Formato: JSON na entrada e na saída, exceto para envio de arquivos (multipart). Envie Content-Type: application/json.
  • IDs: 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 excluído").
  • Comunidades são equipes: a API as chama de teams, com um team_id.
  • Você mesmo: sempre que um caminho aceita um user_id, me significa o usuário conectado, como em GET /users/me.

A lista completa de endpoints está 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, conexões de modelos e ações de mensagem. Os demais estão apenas no código.

Autenticação

Cada solicitação, exceto o login e alguns endpoints públicos, requer um token no cabeçalho Authorization:

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

Três tipos de token são aceitos lá: tokens de acesso pessoal, tokens de sessão e tokens de acesso OAuth. Authorization: Token … também é aceito. Tokens na string de consulta (?access_token=) são aceitos apenas para tokens de acesso OAuth.

Tokens de acesso pessoal (recomendados para scripts)

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

  1. Um administrador do sistema ativa Ativar Tokens de Acesso Individual em Console do Sistema › Integrações › Gerenciamento de Integração (ServiceSettings.EnableUserAccessTokens, AM_SERVICESETTINGS_ENABLEUSERACCESSTOKENS).
  2. Para cada pessoa que pode criar tokens, um administrador do sistema abre Console do Sistema › Gestão de Usuários › Usuários, escolhe Gerenciar funções no menu da pessoa e marca Allow this account to generate personal access tokens. Os administradores do sistema sempre podem criá-los.
  3. A pessoa abre seu avatar no canto superior direito, depois Perfil & configurações › Segurança. Em Tokens de Acesso Individual, descreve para que o token será usado e escolhe Criar Token. O token é exibido apenas uma vez: copie-o.

Pela 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; seu id é o que você usa para revogá-lo (POST /users/tokens/revoke com {"token_id": "…"}). Da linha de comando: amctl token generate <user> <description>.

Um administrador do sistema pode limitar a duração dos tokens com Tempo de vida máximo do token de acesso pessoal (dias) na mesma página do Console do Sistema.

Tokens de sessão

Fazer login com uma senha retorna um token de sessão no cabeçalho de resposta Token, o mesmo tipo de sessão usado pelos aplicativos:

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 de múltiplos fatores. As sessões expiram conforme as configurações de sessão do servidor, e o endpoint de login tem limite de taxa (5 requisições por segundo). POST /users/logout encerra a sessão.

Os navegadores autenticam com um cookie. Uma requisição autenticada pelo cookie também deve 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.

Aplicativos OAuth 2.0

Para permitir que as pessoas façam login no seu aplicativo com sua conta do Antimatter, registre um aplicativo OAuth 2.0. O Antimatter será então o provedor OAuth:

  1. Ativar Provedor de Serviço OAuth 2.0 deve estar ativado (Console do Sistema › Integrações › Gerenciamento de Integração, ServiceSettings.EnableOAuthServiceProvider, ativado por padrão).
  2. Alguém com o direito de gerenciar aplicativos OAuth (administradores do sistema por padrão) abre seu avatar, depois Integrações › Aplicativos OAuth 2.0, e adiciona o aplicativo com suas URLs de callback. Eles recebem um ID de cliente e um segredo de cliente.
  3. Seu aplicativo 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. Ele 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 os aplicativos que autorizaram em Perfil e configurações › Segurança › Aplicativos autorizados.

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 usuário), 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}
ArquivosPOST /files (multipart: channel_id e files), depois coloque os IDs retornados em 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 (saúde, não requer token), GET /config/client?format=old (as configuraçõ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 em um tópico, "file_ids" para arquivos 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 aqueles no link do canal: /lumen-labs/channels/ops-alerts.

Paginação

Os endpoints de lista aceitam page (a partir de 0) e per_page (60 por padrão, no máximo 200). Continue pedindo a próxima página até que uma página volte mais curta que per_page.

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

Erros

Os erros usam os códigos de status HTTP habituais (400 entrada inválida, 401 não autenticado, 403 não permitido, 404 não encontrado, 501 recurso desativado) 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
}

Use id no seu código: message é traduzido para o idioma do usuário. detailed_error fica vazio, a menos que o servidor esteja em modo de desenvolvedor (ServiceSettings.EnableDeveloper). Informe o request_id ao administrador do servidor: ele está nos logs.

Limites de taxa

O limite de velocidade está desativado por padrão. Quando um administrador do sistema o ativa (Console do Sistema › Ambiente › Limite de Velocidade), cada cliente recebe 10 requisições por segundo com picos de 100 por padrão, contado por endereço IP ou por usuário. As respostas incluem X-RateLimit-Limit, X-RateLimit-Remaining e X-RateLimit-Reset; acima do limite, o servidor responde 429 com um cabeçalho Retry-After em segundos. Alguns endpoints, como o de login, têm seu próprio limite independentemente da configuração.

Escreva scripts que aguardam e tentam novamente em caso de 429, e evite consultas repetidas: use o WebSocket em vez disso.

O fluxo de eventos do WebSocket

Conecte-se a wss://chat.example.com/api/v4/websocket. Autentique-se com o cabeçalho Authorization: Bearer na requisição de conexão, ou enviando isto como a primeira mensagem:

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

O servidor envia um evento hello, seguido por um evento para tudo que você tem permissão para 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
}

Observe que data.post é a mensagem como uma string JSON. Eventos comuns: posted, post_edited, post_deleted, reaction_added, reaction_removed, typing, status_change, user_added, direct_added. Os aplicativos enviam seus próprios eventos, nomeados custom_<app id>_<event>.

Você 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 conexão cair e recupere o que perdeu com since (veja Paginação).

O Antimatter adiciona os seguintes 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 seus próprios endpoints, como UpdateMessageRequest, PutPostOnTop e ExportChannel.
  • TypeScript: a classe Client4 do @mattermost/client, em webapp/platform/client, com 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 em um servidor Mattermost. Todos eles exigem uma sessão.

EndpointO que faz
GET /teams/{team_id}/user_attributes/fields
POST mesmo caminho
PATCH, DELETE …/fields/{field_id}
Atributos da comunidade: os campos de perfil definidos pelos administradores da comunidade para seus membros (até 20). Os membros podem lê-los; os administradores da comunidade os criam e modificam.
GET /teams/{team_id}/members/{user_id}/user_attributes
PATCH 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 próprios (exceto os gerenciados 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 que alguém publique, reaja ou envie arquivos na comunidade até o horário especificado (no máximo 28 dias); "until": 0 remove a suspensão. A visão de moderação mostra quando o membro entrou e quanto publicou 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 as lista. Colocar uma mensagem no topo ou removê-la exige o direito de publicar no canal e, em um canal de uma comunidade, ser administrador do canal ou da comunidade, ou ter Gerenciar mensagens (delete_others_posts) lá. Em uma mensagem direta ou de grupo, seus membros podem. Recusado em canais arquivados.
POST /channels/{channel_id}/message_requestAge sobre a solicitação de mensagem própria: {"action": "accept"}, "dismiss" ou "request" para colocar uma conversa novamente entre as solicitações. Retorna 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 em um canal, e quais papéis veem um canal restrito por papel.
GET, PUT /teams/{team_id}/server_categories
GET, PUT …/server_categories/overrides
As categorias de canais compartilhadas 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 autolinks da comunidade em um texto.
POST /channels/{channel_id}/export?format=csv&since=&until=Baixa 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: veja Mover um tópico.
GET, POST /ai/connections
GET, PATCH, DELETE /ai/connections/{connection_id}
GET /ai/connections/usable
Conexões de modelos, os provedores de IA usados pelos recursos de IA do servidor e pelos aplicativos: veja Conexõ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. Veja 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 novatos chegam; vazio significa Geral), kind (community ou workplace: em um workplace, os administradores de canal também podem arquivar seus canais; novas comunidades recebem o TeamSettings.DefaultCommunityKind do servidor, community por padrão), member_list_view (como a lista de membros agrupa os membros: choice, o padrão, permite que cada membro escolha; roles ou teams fixa isso), hide_role_colors, require_team_badges, onboarding e autolinks (ambos strings JSON).
  • O Canal padrão 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 seu ID, a menos que a comunidade já tenha um canal general. Os nomes antigos continuam funcionando: GET /teams/{team_id}/channels/name/town-square, GET /teams/name/{team}/channels/name/town-square e o campo channel de um webhook recebido retornam o canal padrão da comunidade quando nenhum canal tem esse nome. Use default_channel_id ou o nome general em novo código.
  • Links de canais: #channel-name vincula um canal, assim como ~channel-name. A prop channel_mentions da publicação lista os canais vinculados de qualquer forma; um #word que não nomeia nenhum canal permanece uma hashtag. A interface web e o aplicativo móvel do Antimatter escrevem #name.
  • Canais Arquivados ainda aceitam novos membros (POST /channels/{channel_id}/members), que podem ler seu histórico. Ninguém pode publicar, reagir, fixar, colocar uma mensagem no topo, renomear o canal ou alterar as funções de seus membros ali.
  • Respostas inline: uma publicação com "props": {"reply_to": "<post id>"} cita aquela mensagem do mesmo canal. Adicione "reply_to_mention": false para não notificar seu autor. O servidor preenche metadata.reply_to com uma breve descrição da mensagem citada.
  • Spoilers: "props": {"spoiler": true} oculta o texto e os arquivos de uma publicação até que o leitor escolha 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 espera como uma solicitação está no notify_props.dm_request do seu membro de canal (pending, accepted ou dismissed).
  • Anexos de mensagem podem carregar stages e um chart: veja Cartões.

Mover um tópico

POST /posts/{post_id}/move_to_channel move um tópico, 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 o qual o tópico será movido.
  • flatten (padrão false): true faz com que as respostas se tornem mensagens do canal de destino, em vez de um tópico. O recurso Make it a channel do Fusion usa isso.

As mensagens mantêm seus autores, horários, reações e arquivos. Suas cópias carregam a propriedade silent_notification, de modo que não notificam ninguém. As mensagens originais são excluídas. A resposta é a primeira mensagem movida, com seu novo ID.

Quem pode mover um tópico

  • Você deve ser capaz de ler o tópico e de publicar no canal de destino.
  • Os administradores do canal, os administradores da comunidade, pessoas com Gerenciar mensagens (delete_others_posts) no canal e 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 dele. Caso contrário, a resposta é 403 com o ID api.post.move_thread.private_needs_moderator.app_error.
  • Ambos os canais devem estar na mesma comunidade (sem mensagens diretas ou de grupo), ser diferentes e não estar arquivados. Mensagens do sistema e mensagens que se autodestroem após a leitura não podem ser movidas.
  • Um tópico com mais de WranglerSettings.MoveThreadMaxCount mensagens (100 por padrão; 0 para sem limite) é recusado.

O ponteiro e a nota

A movimentação 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"), abaixo do tópico movido ou, com flatten, após as suas mensagens. Além do texto da mensagem, as propriedades permitem que um cliente desenhe o nome do canal como um link:

  • 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 também tê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.

Conexões de modelos

Uma conexão de modelo é o endereço e a chave de um provedor de IA, configurados por um administrador. Os recursos de IA do servidor e os aplicativos que chamam o serviço de IA os utilizam. Os administradores do sistema gerenciam as conexões em nível de servidor (manage_ai_connections); os administradores de uma comunidade gerenciam as conexões da própria comunidade (manage_team_ai_connections). As chaves são somente para gravação: nenhuma resposta as contém, apenas api_key_set e api_key_last4.

EndpointO que faz
GET /ai/connections?scope=As conexões que você gerencia. scope é server ou o ID de uma comunidade; sem ele, todos os escopos que você gerencia.
POST /ai/connectionsAdiciona uma conexão (responde 201).
POST /ai/connections/test, POST /ai/connections/modelsTesta uma conexão ou lista seus modelos antes de ela ser salva. Mesmo corpo que para adicionar uma; nada é armazenado.
GET, PATCH (ou PUT), DELETE /ai/connections/{connection_id}Lê, altera ou exclui uma conexão. Um patch contém apenas os campos a alterar; omita api_key para manter a chave.
POST /ai/connections/{connection_id}/testTesta uma conexão salva: {"ok", "error", "status_code", "latency_ms", "model_count"}.
GET /ai/connections/{connection_id}/modelsOs modelos oferecidos pelo provedor.
GET /ai/connections/{connection_id}/usageAs solicitações e tokens deste mês.
GET /ai/connections/usable?channel_id=&team_id=Para qualquer pessoa conectada: as conexões que você pode usar lá, com seus modelos e capacidades, nunca suas chaves ou endereços.

O corpo de uma nova conexã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 como padrão server; o ID de uma comunidade torna-a a conexão daquela 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 quais comunidades podem usar uma conexão em nível de servidor (mensagens diretas e de grupo exigem all_teams), e audience quem pode usá-la; convidados apenas com allow_guests. As alterações são gravadas no log de auditoria. O guia do administrador explica as configurações: veja IA.