REST API

Antimatterアプリが実行するすべての処理は同じHTTP APIを経由するため、スクリプトでも同じことができます。このページでは、認証方法、よく使用するリソース、レスポンスとエラーの形式、WebSocket経由でイベントをリアルタイムに追跡する方法について説明します。

基本

  • ベースURL: https://chat.example.com/api/v4。以下のすべてのエンドポイントはこれに対する相対パスです。
  • 形式: JSONの送受信(ファイルアップロードはmultipart形式)。Content-Type: application/json を送信してください。
  • ID: すべてのオブジェクトには26文字の id があります。時刻はUnix epochからのミリ秒単位で表されます(create_at、update_at、delete_at;0は「削除されていない」ことを意味します)。
  • コミュニティはチームです: APIでは teams と呼ばれ、team_id を持ちます。
  • あなた自身: パスに user_id を受け取る場所では、me はログイン中のユーザーを指します。例: GET /users/me。

エンドポイントの完全なリストはサーバーのコードにあります。ルートは server/channels/api4/*.go に、型は server/public/model に宣言されています。リポジトリの api/v4/source フォルダーにある OpenAPI 記述は、Mattermost から継承されたエンドポイントと、Antimatter の追加機能(スレッドの移動、モデル接続、メッセージアクション)をカバーしています。それ以外はコードにのみ存在します。

認証

サインインと一部の公開エンドポイントを除くすべてのリクエストには、Authorization ヘッダーにトークンが必要です:

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

ここで受け入れられるトークンは3種類あります:パーソナルアクセストークン、セッショントークン、OAuthアクセストークン。Authorization: Token … も受け入れられます。クエリ文字列(?access_token=)でのトークンは、OAuthアクセストークンのみ受け入れられます。

パーソナルアクセストークン(スクリプトに推奨)

パーソナルアクセストークンはあなたとして動作し、有効期限を設定しない限り期限切れになりません。いつでも失効させることができます。パーソナルアクセストークンはデフォルトで無効です:

  1. システム管理者は、システムコンソール › 統合機能 › 統合機能管理 で パーソナルアクセストークンを有効にする をオンにします (ServiceSettings.EnableUserAccessTokens, AM_SERVICESETTINGS_ENABLEUSERACCESSTOKENS)。
  2. トークンを生成できる各ユーザーについて、システム管理者は システムコンソール › ユーザー管理 › ユーザー を開き、対象ユーザーのメニューから ロールの管理 を選択し、このアカウントがパーソナルアクセストークンを生成できるようにする にチェックします。システム管理者は常にトークンを生成できます。
  3. ユーザーは右上のアバターを開き、プロフィール & 設定 › セキュリティー に移動します。パーソナルアクセストークン の下で、トークンの用途を説明し、トークンを生成する を選択します。トークンは一度のみ表示されるため、コピーしてください。

API を使用する場合: POST /users/{user_id}/tokens に {"description": "backup script", "expires_at": 0} を送信します (expires_at はミリ秒単位で、0 は期限なしを意味します)。レスポンスの token フィールドがシークレットです。その id を使用してトークンを失効させることができます (POST /users/tokens/revoke に {"token_id": "…"} を送信)。コマンドラインから: amctl token generate <user> <description>。

システム管理者は、同じシステムコンソールページ上の 個人アクセストークンの最大有効期間 (日) を使用して、トークンの有効期間に上限を設けることができます。

セッショントークン

パスワードでサインインすると、Token レスポンスヘッダーにセッショントークンが返されます。これはアプリケーションが使用するのと同じ種類のセッションです:

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

多要素認証が有効なアカウントの場合、"token": "123456" を追加します。セッションの有効期限はサーバーのセッション設定に従い、ログインエンドポイントはレート制限 (1秒あたり5リクエスト) が適用されます。POST /users/logout でセッションを終了できます。

ブラウザはCookieを使用して認証します。Cookieによる認証のリクエストは、GET以外のリクエストに対して X-CSRF-Token ヘッダーも送信する必要があります。Authorization ヘッダーにトークンを含む場合は、CSRFヘッダーは不要です。

OAuth 2.0 アプリケーション

ユーザーが Antimatter アカウントを使用してあなたのアプリケーションにサインインできるようにするには、OAuth 2.0 アプリケーションを登録します。Antimatter は OAuth プロバイダーとして機能します:

  1. OAuth 2.0サービスプロバイダーを有効にする がオンになっている必要があります (システムコンソール › 統合機能 › 統合機能管理, ServiceSettings.EnableOAuthServiceProvider, デフォルトでオン)。
  2. OAuth アプリの管理権限を持つユーザー (デフォルトではシステム管理者) は、アバターを開き、統合機能 › OAuth 2.0 アプリ に移動して、コールバックURLを指定してアプリを追加します。これにより、クライアントIDとクライアントシークレットが取得できます。
  3. アプリケーションは、https://chat.example.com/oauth/authorize に response_type=code、client_id、redirect_uri、state を付けてユーザーをリダイレクトします。code_challenge_method=S256 を使用した PKCE がサポートされています。
  4. POST https://chat.example.com/oauth/access_token でコードを交換します(grant_type=authorization_code、更新には refresh_token を使用)。API の呼び出しには Authorization: Bearer <access token> を使用します。

ユーザーは、プロフィール & 設定 › セキュリティー › 承認したアプリ で、自分が承認したアプリを確認できます。

主なリソース

対象エンドポイント
自分と他のユーザーGET /users/me、GET /users/{user_id}、GET /users/username/{username}、POST /users/ids(ID のリスト)、POST /users/search、GET /users?in_team=…&in_channel=…
コミュニティ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
チャンネルGET /users/me/teams/{team_id}/channels、GET /teams/name/{team}/channels/name/{channel}、POST /channels、POST /channels/direct(2 つのユーザー ID)、POST /channels/group、POST /channels/{channel_id}/members
メッセージ(投稿)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
リアクションPOST /reactions に {"user_id", "post_id", "emoji_name"} を指定、DELETE /users/{user_id}/posts/{post_id}/reactions/{emoji_name}
ファイルPOST /files(multipart: channel_id と files)、返された ID を投稿の file_ids に設定します。GET /files/{file_id}
環境設定GET /users/me/preferences, PUT /users/me/preferences
統合/hooks/incoming、/hooks/outgoing、/commands、/bots、/oauth/apps(次のページを参照)
サーバーGET /system/ping(ヘルスチェック、トークン不要)、GET /config/client?format=old(クライアントが参照する設定)

メッセージの投稿

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

メッセージは Markdown です。スレッドに返信するには "root_id"(スレッドの最初の投稿)、ファイルには "file_ids"、添付ファイルやその他の追加情報には "props" を指定します(添付ファイルを参照)。

チャンネル ID の特定

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

名前はチャンネルのリンクに示されているものです:/lumen-labs/channels/ops-alerts。

ページネーション

リスト系エンドポイントは page(0 から)と per_page(デフォルト 60、最大 200)を受け取ります。per_page より少ない件数が返ってくるまで、次のページを要求し続けます。

チャンネルのメッセージ(GET /channels/{channel_id}/posts)も、since(時間:それ以降に変更されたものすべて)または before と after(投稿 ID)を受け取ります。返却されるのは投稿リストで、{"order": [IDs, newest first], "posts": {ID: post}, "next_post_id", "prev_post_id"} という形式です。

エラー

エラーは一般的な HTTP ステータスコード(400 不正な入力、401 未ログイン、403 許可されていません、404 見つかりません、501 機能が無効)と JSON ボディを使用します:

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

コードでは id を使用してください:message はユーザーの言語に翻訳されます。detailed_error はサーバーが開発者モード(ServiceSettings.EnableDeveloper)で実行されていない限り空です。request_id をサーバーの管理者に引用してください:ログにあります。

レート制限

投稿頻度制限はデフォルトでオフです。システム管理者がこれをオンにすると (システムコンソール › 環境 › 投稿頻度制限)、デフォルトでは各クライアントに対して1秒あたり10リクエスト、バースト100リクエストが許可され、IPアドレスまたはユーザー単位でカウントされます。レスポンスには X-RateLimit-Limit、X-RateLimit-Remaining、X-RateLimit-Reset が含まれます。制限を超えると、サーバーは 429 を返し、Retry-After ヘッダーに秒数を指定します。ログインなどの一部のエンドポイントは、設定に関わらず独自の制限があります。

429 を受信した際に待機して再試行するスクリプトを作成し、ポーリングを避けてください。代わりに WebSocket を追跡してください。

WebSocket イベントストリーム

wss://chat.example.com/api/v4/websocket に接続します。認証は、接続リクエストに Authorization: Bearer ヘッダーを付けるか、最初のメッセージとして以下を送信することで行います:

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

サーバーは hello イベントを送信し、その後、閲覧が許可されているすべてのイベントを送信します:

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

data.post は JSON 文字列としての投稿であることに注意してください。一般的なイベント:posted、post_edited、post_deleted、reaction_added、reaction_removed、typing、status_change、user_added、direct_added。アプリは custom_<app id>_<event> という名前の独自のイベントを送信します。

アクションも送信できます。各アクションには増加する seq が付与されます:user_typing は {"channel_id", "parent_id"} を、または get_statuses を送信します。接続が切断された場合は再接続し、since を使用して取りこぼしたものを取得してください(ページネーションを参照)。

Antimatterはこれらのイベントを追加します: community_attributes_updated、member_timeouts_updated、post_put_on_top、post_removed_from_top、server_categories_updated、channel_overrides_updated、category_overrides_updated。

クライアントライブラリ

  • 開始: server/public/model 内の model.Client4 (インポート: github.com/mattermost/mattermost/server/public/model)。 model.NewAPIv4Client(url) を呼び出し、次に client.SetToken(token) を実行します。 model.NewWebSocketClient4(wsURL, token) を使用するとイベントを追跡できます。Antimatterのコピーには、UpdateMessageRequest、PutPostOnTop、ExportChannel など、独自のエンドポイント用のメソッドが追加されています。
  • TypeScript: webapp/platform/client内の@mattermost/clientのClient4クラスで、型はwebapp/platform/typesにあります。 AntimatterのリポジトリにあるコピーにはAntimatterのエンドポイントが含まれていますが、Mattermostがnpmに公開しているパッケージには含まれていません。
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)
}

AntimatterがAPIに追加するもの

これらのエンドポイントとフィールドはMattermostサーバーには存在しません。 すべてセッションが必要です。

エンドポイント機能
GET /teams/{team_id}/user_attributes/fields
POST 同じパス
PATCH、DELETE …/fields/{field_id}
コミュニティ属性: コミュニティの管理者がメンバー用に定義するプロフィールフィールド(最大20個)。 メンバーはこれらを読み取ることができます。コミュニティの管理者が作成・変更します。
GET /teams/{team_id}/members/{user_id}/user_attributes
PATCH 同じパス
POST /teams/{team_id}/user_attributes/values/search
メンバーの属性値は{field_id: value}として保持されます。 メンバーは自分の値を設定できます(管理者管理の項目を除く)。管理者は誰でも設定できます。 検索には{"user_ids": [...]}(最大200件)を使用します。
GET /teams/{team_id}/timeouts
PUT /teams/{team_id}/members/{user_id}/timeout
GET /teams/{team_id}/members/{user_id}/moderation
タイムアウト: {"until": time, "reason": "…"}は、その時点まで(最大28日間)コミュニティでの投稿、リアクション、アップロードを禁止します。 "until": 0で解除します。 モデレーションビューでは、参加日時と最近の投稿量を確認できます。
GET /channels/{channel_id}/on_top
PUT, DELETE /posts/{post_id}/on_top
チャンネルの上部に保持されるメッセージ(最大10件)。{"duration": ms}、最大30日。0の場合は削除されるまで保持されます。チャンネルの読み取り権限を持つユーザーはこれらをリストに表示できます。メッセージを上部に固定したり解除したりするには、チャンネルへの投稿権限が必要です。また、コミュニティのチャンネルでは、そのチャンネルまたはコミュニティの管理者であるか、そこに メッセージの管理(delete_others_posts)権限を持つ必要があります。ダイレクトメッセージまたはグループメッセージでは、そのメンバーが実行できます。アーカイブされたチャンネルでは拒否されます。
POST /channels/{channel_id}/message_request自分のメッセージリクエストに対して操作します: {"action": "accept"}、"dismiss"、または"request"で会話をリクエストリストに戻します。 自分のチャンネルメンバー情報を返します。
GET, PUT /channels/{channel_id}/overrides
GET /channels/{channel_id}/overrides/effective
GET, PUT /channels/{channel_id}/role_access
チャンネル内でロールまたはユーザーが実行できる操作、およびロール制限付きチャンネルを表示できるロール。
GET, PUT /teams/{team_id}/server_categories
GET, PUT …/server_categories/overrides
コミュニティの共有チャンネルカテゴリ、およびそのカテゴリ内のすべてのチャンネルに適用されるオーバーライド。
GET /groups/{group_id}/team_role
PUT …/team_role/permissions
コミュニティロールが付与する権限。
POST /teams/{team_id}/autolinks/previewテキストに対してコミュニティのオートリンクルールを試す。
POST /channels/{channel_id}/export?format=csv&since=&until=チャンネルのメッセージをCSVとしてダウンロード(最大50,000件)。チャンネルの読み取り権限を持つユーザー向け。
GET /posts/{post_id}/speechテキスト読み上げが設定されている場合、メッセージを音声として読み上げる。
POST /posts/{post_id}/move_to_channelスレッドを同じコミュニティ内の別のチャンネルに移動します:スレッドの移動を参照してください。
GET, POST /ai/connections
GET, PATCH, DELETE /ai/connections/{connection_id}
GET /ai/connections/usable
モデル接続は、サーバーのAI機能やアプリが使用するAIプロバイダーです:モデル接続を参照してください。
GET /channels/{channel_id}/message_actions
POST /posts/{post_id}/message_actions/{hook_id}
GET, POST /hooks/outgoing/{hook_id}/icon
メッセージアクション:ユーザーがメッセージメニューから実行する送信Webhookです。メッセージアクションを参照してください。

新しいフィールド

  • コミュニティ(Team、および PUT /teams/{team_id}/patch):all_channels_membership(全員が閲覧可能なすべてのチャンネルに参加する)、default_channel_id(新規参加者が最初に表示される場所。空の場合は General)、kind(community または workplace:workplace では、チャンネル管理者が自分のチャンネルをアーカイブできます。新しいコミュニティにはサーバーの TeamSettings.DefaultCommunityKind が設定され、デフォルトは community です)、member_list_view(メンバーリストがメンバーをグループ化する方式:choice(デフォルト)は各メンバーが選択可能、roles または teams は固定)、hide_role_colors、require_team_badges、onboarding および autolinks(いずれも JSON 文字列)。
  • 新しいコミュニティのデフォルトチャンネルは general(General)であり、town-square ではありません。0.9.0 のアップグレードでは、コミュニティの town-square が general に名前変更されますが、ID は保持されます。ただし、コミュニティにすでに general チャンネルが存在する場合は例外です。旧名称は引き続き機能します:GET /teams/{team_id}/channels/name/town-square、GET /teams/name/{team}/channels/name/town-square、および受信 Webhook の channel は、その名称のチャンネルが存在しない場合、コミュニティのデフォルトチャンネルを返します。新しいコードでは default_channel_id または名称 general を使用してください。
  • チャンネルリンク: #channel-name は ~channel-name と同様にチャンネルをリンクします。投稿の channel_mentions プロパティには、どちらの方法でリンクされたチャンネルもリストされます。チャンネル名に対応しない #word はハッシュタグのままです。Antimatter の Web インターフェースとモバイルアプリは #name を使用します。
  • アーカイブされたチャンネルは引き続き新しいメンバーを受け入れることができます(POST /channels/{channel_id}/members)。メンバーは履歴を読み取ることができます。ただし、誰も投稿、リアクション、ピン留め、メッセージの最上部への配置、チャンネルの名前変更、メンバーのロール変更を行うことはできません。
  • インライン返信:"props": {"reply_to": "<post id>"} を持つ投稿は、同じチャンネル内のそのメッセージを引用します。"reply_to_mention": false を追加すると、投稿者に通知しません。サーバーは metadata.reply_to に、引用されたメッセージの短い説明を設定します。
  • ネタバレ:"props": {"spoiler": true} を設定すると、投稿のテキストとファイルが、閲覧者が表示を選択するまで非表示になります。
  • 無視とブロックは設定項目です。カテゴリは user_block で、他の人のIDを名前に使用し、値は ignore または block です。ダイレクトメッセージがリクエストとして待機するかどうかは、あなたのチャンネルメンバーの notify_props.dm_request(pending、accepted または dismissed)で管理されます。
  • メッセージ添付は stages と chart を保持できます:カードを参照してください。

スレッドを移動する

POST /posts/{post_id}/move_to_channel は、スレッド、その最初のメッセージ、およびすべての返信を、同じコミュニティ内の別のチャンネルに移動します。post_id は最初のメッセージまたは任意の返信であっても構いません。

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(必須): スレッドを移動先のチャンネル。
  • flatten(デフォルト false): true にすると、返信がスレッドではなく、ターゲットチャンネルのメッセージになります。Fusion の Make it a channel はこれを使用します。

メッセージは、作成者、時間、リアクション、ファイルを保持します。コピーには silent_notification プロパティが付与されるため、誰も通知を受け取りません。元のメッセージは削除されます。応答は、新しい ID を持つ移動後の最初のメッセージです。

スレッドを移動できるユーザー

  • スレッドを読み取り、ターゲットチャンネルに投稿できる必要があります。
  • チャンネルの管理者、コミュニティの管理者、チャンネル内で メッセージの管理(delete_others_posts)権限を持つユーザー、およびシステム管理者は、任意のスレッドを移動できます。
  • スレッドの作成者は、両方のチャンネルが公開されている場合、またはスレッドのすべてのメッセージが自分自身のものの場合に、スレッドを移動できます。それ以外の場合は、ID api.post.move_thread.private_needs_moderator.app_error を伴う 403 が返されます。
  • 移動元のチャンネルと移動先のチャンネルは、同じコミュニティに属している必要があります(ダイレクトメッセージやグループメッセージは対象外です)。また、両者は異なるものであり、アーカイブされていない必要があります。システムメッセージと、読み取り後に削除されるメッセージは移動できません。
  • WranglerSettings.MoveThreadMaxCount(デフォルトは100、0の場合は無制限)を超えるメッセージ数を持つスレッドは、移動が拒否されます。

ポインターとノート

移動操作により、system_wrangler タイプのシステムメッセージが2つ生成されます。元のチャンネルにはポインター(例:「13件のメッセージのスレッドが #target に移動されました」)、移動先のチャンネルにはノート(例:「このスレッドは #source から移動されました」)が作成されます。これらは、移動されたスレッドの下に、または flatten オプションを使用した場合、そのメッセージ群の後に配置されます。メッセージ本文に加え、これらのプロパティにより、クライアントはチャンネル名をリンクとして表示できます。

  • ポインター: MovedThreadPermalink、NumMessages、MovedThreadChannelId、MovedThreadTeamName、MovedThreadPostId、および公開チャンネルが移動先の場合は MovedThreadChannelName と MovedThreadChannelDisplayName。
  • ノート: MovedFromChannelId、MovedFromTeamName、MovedFromPostId(ポインター)、MovedFromPermalink、および公開チャンネルが移動元の場合は MovedFromChannelName と MovedFromChannelDisplayName。

両者には TranslationID も含まれます。非公開チャンネルの名前は省略され、閲覧者には「別のチャンネル」と表示されます。Antimatter では、Mattermost 独自の POST /posts/{post_id}/move は無効化されています。このエンドポイントを使用してください。

モデル接続

モデル接続とは、AIプロバイダーのアドレスとキーであり、管理者によって設定されます。サーバーのAI機能やAIサービスを利用するアプリがこれを使用します。システム管理者はサーバー全体の接続(manage_ai_connections)を管理し、コミュニティの管理者は各自のコミュニティの接続(manage_team_ai_connections)を管理します。キーは書き込み専用であり、応答にはキー自体は含まれず、api_key_set と api_key_last4 のみが返されます。

エンドポイント機能
GET /ai/connections?scope=あなたが管理している接続の一覧。scope は server またはコミュニティのIDです。指定しない場合、あなたが管理できるすべてのスコープの接続が返されます。
POST /ai/connections接続を追加します(201 を返します)。
POST /ai/connections/test, POST /ai/connections/models接続を保存する前に、接続テストまたはモデルの一覧取得を行います。追加時と同じボディを使用し、データは保存されません。
GET、PATCH(または PUT)、DELETE /ai/connections/{connection_id}接続の読み取り、変更、削除を行います。PATCH リクエストでは変更するフィールドのみを含め、api_key を省略すると既存のキーが保持されます。
POST /ai/connections/{connection_id}/test保存済みの接続をテストします:{"ok", "error", "status_code", "latency_ms", "model_count"}。
GET /ai/connections/{connection_id}/modelsプロバイダーが提供するモデル。
GET /ai/connections/{connection_id}/usage今月のリクエスト数とトークン数。
GET /ai/connections/usable?channel_id=&team_id=サインインしたユーザー全員に対して: その場所で使用可能な接続、そのモデルと機能を表示します。キーやアドレスは表示されません。

新しい接続の本体:

{
  "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 または anthropic です。scope のデフォルト値は server です。コミュニティのIDを指定すると、そのコミュニティの接続になります。limits では、0は無制限を意味します。毎分のリクエスト数は各サーバーでカウントされ、トークン予算はUTCのカレンダー月ごとにクラスタ全体で管理されます。sharing はサーバー全体の接続をどのコミュニティが使用できるかを指定し(ダイレクトメッセージとグループメッセージには all_teams が必要です)、audience は使用可能なユーザーを指定します。ゲストは allow_guests が設定されている場合のみ使用できます。変更は監査ログに記録されます。設定の詳細は管理者ガイドを参照してください: AI。