REST API

ทุกสิ่งที่แอป Antimatter ทำจะผ่าน HTTP API เดียวกัน ดังนั้นสคริปต์ของคุณก็สามารถทำได้เช่นกัน หน้านี้จะอธิบายวิธีการยืนยันตัวตน ทรัพยากรที่คุณจะใช้งานบ่อยที่สุด รูปแบบของคำตอบและข้อผิดพลาด และวิธีการติดตามเหตุการณ์แบบเรียลไทม์ผ่าน WebSocket

พื้นฐาน

  • URL ฐาน: https://chat.example.com/api/v4 ปลายทางทั้งหมดด้านล่างนี้จะเป็นค่าสัมพัทธ์จาก URL นี้
  • ฟอร์แมต: รับและส่งออกข้อมูลเป็น JSON ยกเว้นการอัปโหลดไฟล์ (multipart) ส่ง Content-Type: application/json
  • ID: ทุกออบเจกต์จะมี id ยาว 26 ตัวอักษร เวลาจะเป็นมิลลิวินาทีนับตั้งแต่ Unix epoch (create_at, update_at, delete_at; 0 หมายถึง "ไม่ถูกลบ")
  • ชุมชนคือทีม: API เรียกสิ่งเหล่านี้ว่า teams พร้อม team_id
  • ตัวคุณเอง: ในทุกเส้นทางที่รับ user_id คำว่า me หมายถึงผู้ใช้ที่เข้าสู่ระบบ เช่น GET /users/me

รายการ endpoint ทั้งหมดอยู่ในโค้ดของเซิร์ฟเวอร์: routes ถูกประกาศใน server/channels/api4/*.go และ types อยู่ใน server/public/model คำอธิบาย OpenAPI ในโฟลเดอร์ api/v4/source ของ repository ครอบคลุม endpoint ที่สืบทอดมาจาก Mattermost และส่วนเพิ่มเติมบางส่วนของ Antimatter: การย้ายเธรด, การเชื่อมต่อโมเดล และการดำเนินการกับข้อความ ส่วนที่เหลือมีอยู่ในโค้ดเท่านั้น

การยืนยันตัวตน

ทุกคำขอ ยกเว้นการเข้าสู่ระบบและปลายทางสาธารณะบางรายการ ต้องมีโทเคนในหัว Authorization:

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

ยอมรับโทเคนสามประเภท: โทเคนการเข้าถึงส่วนบุคคล, โทเคนเซสชัน และโทเคนการเข้าถึง OAuth Authorization: Token … ก็ถูกยอมรับเช่นกัน โทเคนในสตริงคำขอ (?access_token=) จะถูกยอมรับเฉพาะสำหรับโทเคนการเข้าถึง OAuth เท่านั้น

โทเคนการเข้าถึงส่วนบุคคล (แนะนำสำหรับสคริปต์)

โทเคนการเข้าถึงส่วนบุคคลจะทำงานในนามของคุณ ไม่หมดอายุเว้นแต่คุณกำหนดวันหมดอายุ และสามารถเพิกถอนได้ตลอดเวลา โทเคนการเข้าถึงส่วนบุคคลจะปิดอยู่เป็นค่าเริ่มต้น:

  1. ผู้ดูแลระบบเปิดใช้งาน เปิดใช้งานโทเคนการเข้าถึงส่วนตัว ใน คอนโซลระบบ › อินทิเกรชัน › การจัดการอินทิเกรชัน (ServiceSettings.EnableUserAccessTokens, AM_SERVICESETTINGS_ENABLEUSERACCESSTOKENS)
  2. สำหรับแต่ละบุคคลที่อาจสร้างโทเคน ผู้ดูแลระบบเปิด คอนโซลระบบ › การจัดการผ้้ใช้ › ผู้ใช้งาน เลือก จัดการบทบาท ในเมนูของบุคคลนั้น และทำเครื่องหมาย Allow this account to generate personal access tokens ผู้ดูแลระบบสามารถสร้างโทเคนได้เสมอ
  3. บุคคลนั้นเปิดอวตารที่มุมขวาบน จากนั้นไปที่ Profile & settings › ความปลอดภัย ภายใต้ โทเคนการเข้าถึงส่วนตัว ระบุวัตถุประสงค์ของโทเคนและเลือก สร้างโทเคน โทเคนจะแสดงเพียงครั้งเดียว: คัดลอกไว้

ผ่าน 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" สำหรับบัญชีที่มีการยืนยันตัวตนหลายปัจจัย เซสชันจะหมดอายุตามที่การตั้งค่าเซสชันของเซิร์ฟเวอร์ระบุ และจุดสิ้นสุดการเข้าสู่ระบบมีการจำกัดอัตรา (5 คำขอต่อวินาที) POST /users/logout สิ้นสุดเซสชัน

เบราว์เซอร์ยืนยันตัวตนด้วยคุกกี้แทน คำขอที่ยืนยันตัวตนด้วยคุกกี้ต้องส่งหัว X-CSRF-Token ด้วยสำหรับทุกสิ่งที่ไม่ใช่ GET; โทเคนในหัว Authorization ไม่ต้องการหัว CSRF

แอปพลิเคชัน OAuth 2.0

เพื่อให้ผู้คนสามารถเข้าสู่ระบบแอปพลิเคชันของคุณด้วยบัญชี Antimatter ของพวกเขา จดทะเบียนแอปพลิเคชัน OAuth 2.0 Antimatter จะเป็นผู้ให้บริการ OAuth:

  1. ต้องเปิดใช้งาน เปิดใช้งานผู้ให้บริการ OAuth 2.0 (คอนโซลระบบ › อินทิเกรชัน › การจัดการอินทิเกรชัน, ServiceSettings.EnableOAuthServiceProvider, เปิดใช้งานโดยค่าเริ่มต้น)
  2. บุคคลที่มีสิทธิ์จัดการแอป OAuth (ผู้ดูแลระบบโดยค่าเริ่มต้น) เปิดอวตาร จากนั้นไปที่ อินทิเกรชัน › แอป OAuth 2.0 และเพิ่มแอปพร้อม URL สำหรับ callback พวกเขาจะได้รับ client ID และ client secret
  3. แอปพลิเคชันของคุณจะส่งผู้ใช้ไปยัง https://chat.example.com/oauth/authorize พร้อม response_type=code, client_id, redirect_uri และ state ระบบรองรับ PKCE โดยใช้ code_challenge_method=S256
  4. จากนั้นจะแลกเปลี่ยน code ที่ POST https://chat.example.com/oauth/access_token (ใช้ grant_type=authorization_code และใช้ refresh_token เพื่อต่ออายุ) และเรียกใช้ API ด้วย Authorization: Bearer <access token>

ผู้ใช้สามารถดูแอปที่พวกเขาอนุญาตใน Profile & settings › ความปลอดภัย › แอปที่คุณให้สิทธิ์

ทรัพยากรหลัก

รายการEndpoints
คุณและผู้ใช้คนอื่น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 (ID ของผู้ใช้สองคน), POST /channels/group, POST /channels/{channel_id}/members
ข้อความ (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
รีแอคชัน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 (ตรวจสอบสถานะระบบ ไม่ต้องใช้ token), 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

การแบ่งหน้า

Endpoints แบบรายการจะรับ 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 ให้แก่ผู้ดูแลระบบของเซิร์ฟเวอร์: มันอยู่ในบันทึกเหตุการณ์ (logs).

การจำกัดอัตรา

การจำกัดอัตรามีค่าเริ่มต้นเป็นปิด เมื่อผู้ดูแลระบบเปิดใช้งาน (คอนโซลระบบ › สภาพแวดล้อม › การจำกัดอัตร) แต่ละไคลเอนต์จะได้รับ 10 คำขอต่อวินาทีพร้อมการกระแทก (bursts) 100 ครั้งโดยค่าเริ่มต้น นับตามที่อยู่ IP หรือตามผู้ใช้ คำตอบจะประกอบด้วย X-RateLimit-Limit, X-RateLimit-Remaining และ X-RateLimit-Reset; เมื่อเกินขีดจำกัด เซิร์ฟเวอร์จะตอบกลับด้วย 429 พร้อม header Retry-After ในหน่วยวินาที บาง endpoint เช่น การเข้าสู่ระบบ มีขีดจำกัดของตัวเองไม่ว่าการตั้งค่าจะเป็นอย่างไร

เขียนสคริปต์ที่รอและลองใหม่เมื่อได้รับ 429 และหลีกเลี่ยงการโพล (polling): ใช้การติดตาม 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>.

คุณยังสามารถส่งการกระทำ (actions) ได้ด้วย แต่ละอย่างมี 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.

ไลบรารีไคลเอนต์

  • ไป: model.Client4 ใน server/public/model (import github.com/mattermost/mattermost/server/public/model). model.NewAPIv4Client(url), แล้ว client.SetToken(token); model.NewWebSocketClient4(wsURL, token) ติดตามเหตุการณ์ Antimatter เพิ่มเมธอดสำหรับ endpoint ของตัวเอง เช่น UpdateMessageRequest, PutPostOnTop และ ExportChannel.
  • TypeScript: คลาส Client4 ของ @mattermost/client ใน webapp/platform/client พร้อม type ใน webapp/platform/types คัดลอกในคลัง Antimatter รวม endpoint ของ 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

endpoint และฟิลด์เหล่านี้ไม่มีในเซิร์ฟเวอร์ Mattermost ทุกตัวต้องมีการเซสชัน

Endpointสิ่งที่ทำ
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
Timeout: {"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ทดสอบกฎการเชื่อมโยงอัตโนมัติ (autolink) ของชุมชนกวยข้อความ
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
การดำเนินการกับข้อความ: outgoing webhooks ที่ผู้ใช้เรียกใช้จากเมนูข้อความ ดู การดำเนินการกับข้อความ

ฟิลด์ใหม่

  • ชุมชน (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 string)
  • ช่องเริ่มต้นของชุมชนใหม่คือ 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 และ channel ของ webhook ที่เข้ามายังชี้ไปยังช่องเริ่มต้นของชุมชนเมื่อไม่มีช่องที่มีชื่อนั้น ใช้ default_channel_id หรือชื่อ general ในโค้ดใหม่
  • ลิงก์ช่อง: #channel-name ใช้ลิงก์ไปยังช่อง เช่นเดียวกับ ~channel-name ฟิลด์ channel_mentions ของโพสต์จะระบุช่องที่ถูกลิงก์ด้วยวิธีใดวิธีหนึ่ง; #word ที่ไม่ตรงกับช่องใดจะยังคงเป็นแฮชแท็ก อินเทอร์เฟซเว็บและแอปมือถือของ Antimatter ใช้รูปแบบ #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 ได้: ดู Cards.

ย้ายเธรด

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 ทำให้ข้อความตอบกลับกลายเป็นข้อความของช่องปลายทางแทนที่จะเป็นเธรด Make it a channel ของ Fusion ใช้ค่านี้

ข้อความยังคงผู้เขียน, เวลา, รีแอคชัน และไฟล์แนบไว้ สำเนาของข้อความเหล่านี้จะมีฟิลด์ silent_notification ทำให้ไม่มีการแจ้งเตือนให้ใคร ข้อความเดิมจะถูกลบไป คำตอบคือข้อความแรกที่ถูกย้าย พร้อม ID ใหม่

ใครสามารถย้ายเธรดได้

  • คุณต้องสามารถอ่านเธรดนั้นได้ และสามารถโพสต์ในช่องปลายทางได้
  • ผู้ดูแลระบบของช่อง, ผู้ดูแลระบบของชุมชน, ผู้ที่มีสิทธิ์ จัดการข้อความ (delete_others_posts) ในช่อง และผู้ดูแลระบบระดับระบบ สามารถย้ายเธรดใดก็ได้
  • ผู้เขียนเธรดสามารถย้ายได้เมื่อช่องทั้งสองเป็นช่องสาธารณะ หรือเมื่อข้อความทุกข้อในเธรดเป็นของผู้เขียนนั้น หากไม่เป็นไปตามเงื่อนไข คำตอบจะเป็น 403 พร้อม ID api.post.move_thread.private_needs_moderator.app_error
  • ช่องทั้งสองต้องอยู่ในชุมชนเดียวกัน (ไม่รวมข้อความส่วนตัวหรือข้อความกลุ่ม) ต้องเป็นคนละช่อง และต้องไม่ได่เก็บถาวรแล้ว ไม่สามารถเคลื่อนข้อความระบบหรือข้อความที่หายหลังหว่้อ่านแล้วได้
  • เธรดที่ยาวกว่่า WranglerSettings.MoveThreadMaxCount ข้อความ (ค่าเริ่มต้น 100; 0 หมายถิงไม่มีขั้่น) จะถูกปัดถอย

พอย์เตอร์และโน้ต

การเคลื่อนข้่าจะทิ้่งข้อความระบบ 2 ข้อความประเภท system_wrangler: พอย์เตอร์ในช่องเดิม ("เธรดที่มี 13 ข้อความได่ถูกเคลื่อนไป #target") และโน้ตในช่องปลายทาง ("เธรดนี้ได่ถูกเคลื่อนมาจาก #source") ท่ีอย่ใตเธรดท่ีถูกเคลื่อน หรือ, เม่อใช flatten, ท่ีอย่หลั่้งข้อความของเธรด นอ่กจากเนื้่อความของข้อความแล้ว, props ของข้อความเหล่านี้ยอมให้ไคลเอนต์วาดเนื้่อความของช่องเป็นลิงก์ได้:

  • พอย์เตอร์: MovedThreadPermalink, NumMessages, MovedThreadChannelId, MovedThreadTeamName, MovedThreadPostId และ, สำหรับช่องปลายทางสาธารณะ, MovedThreadChannelName และ MovedThreadChannelDisplayName.
  • โน้ต: MovedFromChannelId, MovedFromTeamName, MovedFromPostId (พอย์เตอร์), MovedFromPermalink และ, สำหรับช่องต้นตอสวนสาธารณะ, MovedFromChannelName และ MovedFromChannelDisplayName.

ทั้งสองย้งมี TranslationID ด้วย เนื้่อความของช่องส่วนตัวจะไม่ถูกแสดง: ผู้อ่านจะเห็น "ช่องอื่่น" POST /posts/{post_id}/move ของ Mattermost เองจะปิดอย่ใน Antimatter; ให่ใชเอนดพอยต์นี้

การเชื่อมต่อโมเดล

การเชื่อมต่อโมเดลคือที่อยู่และคีย์ของผู้ใหบริการ AI ท่ีผู้ดูลแลระบบตั้้งค่าไว้ ฟีเจอร์ AI ของเซิร์ฟเวอร์และแอปท่ีเรียกใช้บริการ AI ใชสิ่งเหล่านี้ ผู้ดูลแลระบบจัดการการเชื่อมต่อท่ีใชทั้้งเซิร์ฟเวอร์ (manage_ai_connections); ผู้ดูลแลของชุมชนจัดการการเชื่อมต่อของชุมชนตนเอง (manage_team_ai_connections). คีย์เขียนเท่านั้้น: คำตอบไม่มีคีย์, มีเพี่่ง api_key_set และ api_key_last4 เท่านั้้น

Endpointสิ่งที่ทำ
GET /ai/connections?scope=การเชื่อมต่อท่ีคุณจัดการ scope คือ server หรือ ID ของชุมชน; เม่อไม่มี, ทุ่ก scope ท่ีคุณจัดการ
POST /ai/connectionsเพิ่่มการเชื่อมต่อ (ตอบ 201).
POST /ai/connections/test, POST /ai/connections/modelsทดสอบการเชื่อมต่อ หรือลิสต์โมเดลของมัน, ก่อนท่ีจะบันทึกลง. ใช body เดียวกับการเพิ่่ม; ไม่มีสิ่่งใดถูกบันทึก
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 การเปลยี่ นแปลงจะถกู บันทึกลงในบันทึกการตรวจสอบ (audit log) คู่มือผ้ดู แลระบบอธิบายการตัง้ ค่า: ดู AI