ממשק REST

כל פעולה שיישומי Antimatter מבצעים עוברת דרך ממשק HTTP זהה, ולכן גם הסקריפטים שלכם יכולים לבצע אותה. עמוד זה מסביר כיצד לבצע אימות, אילו משאבים תשתמשו בהם ביותר, כיצד נראות תגובות ושגיאות, וכיצד לעקוב אחר אירועים בזמן אמת דרך WebSocket.

יסודות

  • כתובת URL בסיסית: https://chat.example.com/api/v4. כל נקודות התורן (endpoints) המפורטות להלן יחסיות אליה.
  • פורמט: JSON כקלט ויציאה, למעט העלאת קבצים (multipart). יש לשלוח Content-Type: application/json.
  • מזהים: לכל אובייקט יש id באורך 26 תווים. זמנים מוצגים במילי-שניות מאז תחילת Unix (create_at, update_at, delete_at; 0 מייצג "לא נמחק").
  • קהילות הן צוותים: הממשק מכנה אותם teams, עם team_id.
  • עצמך: בכל מקום שבו נתיב מקבל user_id, me מייצג את המשתמש המחובר, כפי שמופיע ב־GET /users/me.

הרשימה המלאה של נקודות הקצה נמצאת בקוד השרת: המסלולים מוגדרים ב-server/channels/api4/*.go והטיפוסים ב-server/public/model. תיאור OpenAPI בספריית api/v4/source במאגר מכסה את נקודות הקצה שנוצלו מ-Mattermost, וכן חלק מההוספות של Antimatter: העברת שרשורים, חיבורי מודלים ופעולות הודעות. השאר נמצא רק בקוד.

אימות

כל בקשה, למעט התחברות וכמה נקודות תורן ציבוריות, דורשת אישור (token) בכותרת 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. עבור כל אדם שיוכל ליצור טוקנים, מנהל מערכת פותח את קונסולת מערכת › ניהול משתמשים › משתמשים, בוחר ניהול תפקידים בתפריט של האדם, וסומן אפשרות לחשבון זה ליצור טוקני גישה אישיים. מנהלי מערכת תמיד יכולים ליצור אותם.
  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" עבור חשבון עם אימות דו-שלבי. סשנים פגים בהתאם להגדרות הסשן של השרת, ונקודת הכניסה מוגבלת בקצב (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, ומוסיף את האפליקציה עם כתובות ה-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. היא מחליפה את הקוד בכתובת 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 (רשימת מזהים), 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 (שני מזהי משתמשים), 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), ואז מוסיפים את המזהים שהוחזרו לשדה 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" לקבצים מצורפים ותוספות נוספות (ראו קבצים מצורפים).

מציאת מזהה ערוץ

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 (מזהה הודעה). הן חוזרות כרשימת הודעות: {"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 למנהל השרת: הוא מופיע ביומנים.

מגבלות קצב

הגבלת קצב כבויה כברירת מחדל. כאשר מנהל מערכת מפעיל אותה (קונסולת מערכת › סביבה › הגבלת קצב), כל לקוח מקבל 10 בקשות בשנייה עם פיצוצים של 100 כברירת מחדל, ומונה לפי כתובת IP או לפי משתמש. התגובות נושאות את X-RateLimit-Limit, X-RateLimit-Remaining ו־X-RateLimit-Reset; מעבר למגבלה, השרת עונה 429 עם כותרת Retry-After בשניות. לחלק מהנקודות, כגון התחברות, יש מגבלה משלהן ללא תלות בהגדרה.

כתבו סקריפטים שממתינים ומנסים שוב ב-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>.

ניתן גם לשלוח פעולות, כל אחת עם 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 (ייבוא github.com/mattermost/mattermost/server/public/model). model.NewAPIv4Client(url), ואז client.SetToken(token); model.NewWebSocketClient4(wsURL, token) עוקב אחר אירועים. העותק של Antimatter מוסיף שיטות לנקודות הגישה שלו, כגון UpdateMessageRequest, PutPostOnTop ו־ExportChannel.
  • TypeScript: מחלקת Client4 של @mattermost/client, ב-webapp/platform/client, עם סוגיה ב-webapp/platform/types. העותק במאגר של Antimatter כולל את נקודות הקצה של Antimatter; החבילה שפורסמה ב-npm על ידי Mattermost אינה כוללת אותן.
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
קטגוריות הערוצים המשותפות לקהילה, וההגדרות המותאמות (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ההודעה, כקובץ אודיו, כאשר מוגדר קריאת טקסט (text-to-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
פעולות הודעות: Webhooks יוצאים שמופעלים מתפריט ההודעה. ראו פעולות הודעות.

שדות חדשים

  • קהילות (Team, ו-PUT /teams/{team_id}/patch): all_channels_membership (כל אחד חבר בכל ערוץ שהוא יכול לראות), default_channel_id (אליו נוחתים חדשים; ריק פירושו General), kind (community או 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, תוך שמירה על המזהה, אלא אם הקהילה כבר מכילה ערוץ בשם 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 שאינו שם של ערוץ נשאר תג (hashtag). ממשק ה-Web של Antimatter ואפליקציית המובייל כותבים #name.
  • ערוצים בארכיון עדיין מקבלים חברים חדשים (POST /channels/{channel_id}/members), שיכולים לקרוא את ההיסטוריה. אף אחד אינו יכול לפרסם, להגיב, להצמיד, להעלות הודעה לראש, לשנות את שם הערוץ או לשנות את תפקידי החברים שבו.
  • תשובות מוטמעות: פוסט עם "props": {"reply_to": "<post id>"} מצטט את ההודעה הזו מאותו ערוץ. הוספת "reply_to_mention": false מונעת שליחת התראה למחבר ההודעה המקורית. השרת ממלא את metadata.reply_to עם תיאור קצר של ההודעה המצוטטת.
  • ספוילרים: "props": {"spoiler": true} מסתיר את הטקסט והקבצים של פוסט עד שהקורא בוחר להציג אותם.
  • התעלמות וחסימה הן העדפות: קטגוריה user_block, ששמה מבוסס על מזהה האדם האחר, עם הערך 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 הופך את התשובות להודעות של הערוץ היעד במקום לשרשור. Make it a channel של Fusion משתמש בזה.

ההודעות שומרות את המחברים, הזמנים, התגובות והקבצים. העותקים נושאים את שדה silent_notification, ולכן אינם מורים התראה לאף אחד. ההודעות המקוריות נמחקות. התשובה היא ההודעה הראשונה שהועברה, עם המזהה החדש שלה.

מי רשאי להעביר שרשור

  • יש להימצא ברשותך יכולת לקרוא את השרשור ולפרסם בערוץ היעד.
  • מנהלי הערוץ, מנהלי הקהילה, אנשים עם ניהול הודעות (delete_others_posts) בערוץ, ומנהלי מערכת רשאים להעביר כל שרשור.
  • יוצר השרשור רשאי להעבירו כאשר שני הערוצים ציבוריים, או כאשר כל ההודעות בשרשור הן שלו. אחרת, התשובה היא 403 עם המזהה api.post.move_thread.private_needs_moderator.app_error.
  • שני הערוצים חייבים להיות באותה קהילה (לא הודעות ישירות או הודעות קבוצה), שונים זה מזה, ולא בארכיון. לא ניתן להעביר הודעות מערכת והודעות שנמחקות לאחר הקריאה.
  • שרשור שאורכו עולה על WranglerSettings.MoveThreadMaxCount הודעות (100 כברירת מחדל; 0 ללא הגבלה) נדחה.

המחוון והפתק

ההעברה משאירה שתי הודעות מערכת מסוג 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; יש להשתמש בנקודת הקצה (endpoint) הזו.

חיבורי דגמים

חיבור מודל הוא כתובת ומפתח של ספק בינה מלאכותית, שמוגדרים על ידי מנהל. תכונות הבינה המלאכותית של השרת והאפליקציות שנוגעות לשירות הבינה המלאכותית משתמשות בהם. מנהלי מערכת מנהלים את החיבורים ברמת השרת (manage_ai_connections); מנהלי קהילה מנהלים את החיבורים של הקהילה שלהם (manage_team_ai_connections). מפתחות הם כתיבה בלבד: אף תשובה אינה מכילה מפתח, רק api_key_set ו-api_key_last4.

נקודת קצהמה היא עושה
GET /ai/connections?scope=החיבורים שאתה מנהל. scope הוא server או מזהה קהילה; ללא פרמטר זה, כל היקף (scope) שאתה מנהל.
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; מזהה של קהילה הופך אותו לחיבור של אותה קהילה. בlimits, 0 פירושו ללא הגבלה; הבקשות לדקה נספרות על כל שרת, ותקציבי הטוקנים לפי חודש לוח שנה (UTC) לכל הקלאסטר. sharing קובע אילו קהילות יכולות להשתמש בחיבור שרת-רחב (הודעות ישירות והודעות קבוצה דורשות all_teams), וaudience קובע מי יכול להשתמש בו; אורחים רק אם allow_guests מוגדר. השינויים נרשמים ביומן הביקורת. מדריך המנהלים מסביר את ההגדרות: ראו AI.