Mattermost Common Operations
Plain-language playbooks for everyday Mattermost work. Each one drives the REST API. For exact endpoint signatures and every field, open the api-reference skill's matching references/*.md file (named in each workflow).
Before anything: ensure a token
If MATTERMOST_TOKEN is not already set this session, run the setup skill's login first (it reads the token from the login Token response header). Every call below assumes MATTERMOST_TOKEN and MATTERMOST_API_URL are set and uses Authorization: Bearer ${MATTERMOST_TOKEN}.
The golden rules (why workflows look the way they do)
- Resolve names to IDs once. Users say "the Engineering team, #general"; the API wants 26-char IDs. Resolve with the
by_name/by_username/by_email endpoints first and keep the IDs. A 404 usually means a name slipped through where an ID was needed.
- Patch, don't replace. Prefer
PUT /…/{id}/patch so you change only what was asked. There is no version field to send — Mattermost has no optimistic locking.
- Mind the channel type.
O public, P private, D direct, G group. DMs/GMs are created (or fetched) by POSTing user-id arrays, not by name.
- Confirm before destructive or system-wide actions.
DELETE, user deactivation, and any /config, /license, /data_retention, /plugins write is high-impact — show the user what will change first.
Workflow: resolve a team & channel by name
TEAM_ID=$(curl -s -H "Authorization: Bearer ${MATTERMOST_TOKEN}" \
"${MATTERMOST_API_URL%/}/api/v4/teams/name/engineering" | jq -r .id)
CHANNEL_ID=$(curl -s -H "Authorization: Bearer ${MATTERMOST_TOKEN}" \
"${MATTERMOST_API_URL%/}/api/v4/teams/${TEAM_ID}/channels/name/general" | jq -r .id)
(→ teams.md, channels.md)
Workflow: post a message
curl -s -X POST -H "Authorization: Bearer ${MATTERMOST_TOKEN}" -H "Content-Type: application/json" \
-d "{\"channel_id\":\"${CHANNEL_ID}\",\"message\":\"Hello team :wave:\"}" \
"${MATTERMOST_API_URL%/}/api/v4/posts" | jq '{id, message}'
- Reply in a thread: add
"root_id":"<root_post_id>".
- Attach a file: upload first (
POST /files), then pass "file_ids":["<id>"] (→ files-emoji.md).
- React:
POST /reactions with {"user_id","post_id","emoji_name"}. (→ posts.md)
Workflow: send a direct message
# DM = a channel between two user ids
ME=$(curl -s -H "Authorization: Bearer ${MATTERMOST_TOKEN}" "${MATTERMOST_API_URL%/}/api/v4/users/me" | jq -r .id)
OTHER=$(curl -s -H "Authorization: Bearer ${MATTERMOST_TOKEN}" "${MATTERMOST_API_URL%/}/api/v4/users/username/alice" | jq -r .id)
DM=$(curl -s -X POST -H "Authorization: Bearer ${MATTERMOST_TOKEN}" -H "Content-Type: application/json" \
-d "[\"${ME}\",\"${OTHER}\"]" "${MATTERMOST_API_URL%/}/api/v4/channels/direct" | jq -r .id)
curl -s -X POST -H "Authorization: Bearer ${MATTERMOST_TOKEN}" -H "Content-Type: application/json" \
-d "{\"channel_id\":\"${DM}\",\"message\":\"ping\"}" "${MATTERMOST_API_URL%/}/api/v4/posts" >/dev/null
For a group message, POST an array of 3–8 ids to /channels/group. (→ channels.md)
Workflow: create a channel and add members
- Create —
POST /channels with {"team_id","name","display_name","type":"O"} (P for private). (→ channels.md)
- Add a user —
POST /channels/{channel_id}/members with {"user_id"}.
- Set header/purpose —
PUT /channels/{channel_id}/patch with {"header":"...","purpose":"..."}.
- Make someone a channel admin —
PUT /channels/{channel_id}/members/{user_id}/roles with {"roles":"channel_user channel_admin"}.
Workflow: create a team and invite people
POST /teams with {"name","display_name","type":"O"}. (→ teams.md)
- Add existing users:
POST /teams/{team_id}/members (one) or /members/batch (many).
- Email-invite new people:
POST /teams/{team_id}/invite/email with an array of emails.
Workflow: manage users
- Find —
GET /users/username/{username} or POST /users/search with {"term"}. (→ users.md)
- Create —
POST /users with {"email","username","password"}.
- Deactivate (reversible) —
PUT /users/{user_id}/active with {"active":false}. Confirm first.
- Grant admin —
PUT /users/{user_id}/roles with {"roles":"system_user system_admin"}.
Workflow: wire an incoming webhook
HOOK=$(curl -s -X POST -H "Authorization: Bearer ${MATTERMOST_TOKEN}" -H "Content-Type: application/json" \
-d "{\"channel_id\":\"${CHANNEL_ID}\",\"display_name\":\"CI\"}" \
"${MATTERMOST_API_URL%/}/api/v4/hooks/incoming" | jq -r .id)
echo "Post to: ${MATTERMOST_API_URL%/}/hooks/${HOOK}"
(→ integrations.md)
Workflow: report & audit
- Counts:
GET /users/stats, GET /teams/{team_id}/stats, GET /channels/{channel_id}/stats.
- Analytics:
GET /analytics/old?name=standard (admin). (→ system-admin.md)
- Search messages:
POST /teams/{team_id}/posts/search with {"terms":"outage from:alice after:2026-01-01"}. (→ posts.md)
- List with pagination: walk
?page=0&per_page=200, incrementing page until a short page returns.
When a call fails (401, 403, 404, 429), switch to the troubleshoot skill.
1---2name: common-operations-33description: This skill should be used when the user wants to do collaboration work in Mattermost — "post a message to a channel", "send a DM in Mattermost", "create a channel", "add users to a team/channel", "deactivate a user", "create a team", "set up a webhook", "react to a post", or any everyday Mattermost operation. Provides plain-language workflows that drive the REST API and route to the exact endpoints.4---56# Mattermost Common Operations78Plain-language playbooks for everyday Mattermost work. Each one drives the REST API. For exact endpoint signatures and every field, open the `api-reference` skill's matching `references/*.md` file (named in each workflow).910## Before anything: ensure a token1112If `MATTERMOST_TOKEN` is not already set this session, run the `setup` skill's login first (it reads the token from the login **`Token` response header**). Every call below assumes `MATTERMOST_TOKEN` and `MATTERMOST_API_URL` are set and uses `Authorization: Bearer ${MATTERMOST_TOKEN}`.1314## The golden rules (why workflows look the way they do)15161. **Resolve names to IDs once.** Users say "the Engineering team, #general"; the API wants 26-char IDs. Resolve with the `by_name`/`by_username`/`by_email` endpoints first and keep the IDs. A `404` usually means a name slipped through where an ID was needed.172. **Patch, don't replace.** Prefer `PUT /…/{id}/patch` so you change only what was asked. There is **no `version` field** to send — Mattermost has no optimistic locking.183. **Mind the channel type.** `O` public, `P` private, `D` direct, `G` group. DMs/GMs are created (or fetched) by POSTing user-id arrays, not by name.194. **Confirm before destructive or system-wide actions.** `DELETE`, user deactivation, and any `/config`, `/license`, `/data_retention`, `/plugins` write is high-impact — show the user what will change first.2021## Workflow: resolve a team & channel by name2223```bash24TEAM_ID=$(curl -s -H "Authorization: Bearer ${MATTERMOST_TOKEN}" \25 "${MATTERMOST_API_URL%/}/api/v4/teams/name/engineering" | jq -r .id)26CHANNEL_ID=$(curl -s -H "Authorization: Bearer ${MATTERMOST_TOKEN}" \27 "${MATTERMOST_API_URL%/}/api/v4/teams/${TEAM_ID}/channels/name/general" | jq -r .id)28```29(→ `teams.md`, `channels.md`)3031## Workflow: post a message3233```bash34curl -s -X POST -H "Authorization: Bearer ${MATTERMOST_TOKEN}" -H "Content-Type: application/json" \35 -d "{\"channel_id\":\"${CHANNEL_ID}\",\"message\":\"Hello team :wave:\"}" \36 "${MATTERMOST_API_URL%/}/api/v4/posts" | jq '{id, message}'37```38- **Reply in a thread**: add `"root_id":"<root_post_id>"`.39- **Attach a file**: upload first (`POST /files`), then pass `"file_ids":["<id>"]` (→ `files-emoji.md`).40- **React**: `POST /reactions` with `{"user_id","post_id","emoji_name"}`. (→ `posts.md`)4142## Workflow: send a direct message4344```bash45# DM = a channel between two user ids46ME=$(curl -s -H "Authorization: Bearer ${MATTERMOST_TOKEN}" "${MATTERMOST_API_URL%/}/api/v4/users/me" | jq -r .id)47OTHER=$(curl -s -H "Authorization: Bearer ${MATTERMOST_TOKEN}" "${MATTERMOST_API_URL%/}/api/v4/users/username/alice" | jq -r .id)48DM=$(curl -s -X POST -H "Authorization: Bearer ${MATTERMOST_TOKEN}" -H "Content-Type: application/json" \49 -d "[\"${ME}\",\"${OTHER}\"]" "${MATTERMOST_API_URL%/}/api/v4/channels/direct" | jq -r .id)50curl -s -X POST -H "Authorization: Bearer ${MATTERMOST_TOKEN}" -H "Content-Type: application/json" \51 -d "{\"channel_id\":\"${DM}\",\"message\":\"ping\"}" "${MATTERMOST_API_URL%/}/api/v4/posts" >/dev/null52```53For a group message, POST an array of 3–8 ids to `/channels/group`. (→ `channels.md`)5455## Workflow: create a channel and add members56571. **Create** — `POST /channels` with `{"team_id","name","display_name","type":"O"}` (`P` for private). (→ `channels.md`)582. **Add a user** — `POST /channels/{channel_id}/members` with `{"user_id"}`.593. **Set header/purpose** — `PUT /channels/{channel_id}/patch` with `{"header":"...","purpose":"..."}`.604. **Make someone a channel admin** — `PUT /channels/{channel_id}/members/{user_id}/roles` with `{"roles":"channel_user channel_admin"}`.6162## Workflow: create a team and invite people63641. `POST /teams` with `{"name","display_name","type":"O"}`. (→ `teams.md`)652. Add existing users: `POST /teams/{team_id}/members` (one) or `/members/batch` (many).663. Email-invite new people: `POST /teams/{team_id}/invite/email` with an array of emails.6768## Workflow: manage users69701. **Find** — `GET /users/username/{username}` or `POST /users/search` with `{"term"}`. (→ `users.md`)712. **Create** — `POST /users` with `{"email","username","password"}`.723. **Deactivate** (reversible) — `PUT /users/{user_id}/active` with `{"active":false}`. Confirm first.734. **Grant admin** — `PUT /users/{user_id}/roles` with `{"roles":"system_user system_admin"}`.7475## Workflow: wire an incoming webhook7677```bash78HOOK=$(curl -s -X POST -H "Authorization: Bearer ${MATTERMOST_TOKEN}" -H "Content-Type: application/json" \79 -d "{\"channel_id\":\"${CHANNEL_ID}\",\"display_name\":\"CI\"}" \80 "${MATTERMOST_API_URL%/}/api/v4/hooks/incoming" | jq -r .id)81echo "Post to: ${MATTERMOST_API_URL%/}/hooks/${HOOK}"82```83(→ `integrations.md`)8485## Workflow: report & audit86871. Counts: `GET /users/stats`, `GET /teams/{team_id}/stats`, `GET /channels/{channel_id}/stats`.882. Analytics: `GET /analytics/old?name=standard` (admin). (→ `system-admin.md`)893. Search messages: `POST /teams/{team_id}/posts/search` with `{"terms":"outage from:alice after:2026-01-01"}`. (→ `posts.md`)904. List with pagination: walk `?page=0&per_page=200`, incrementing `page` until a short page returns.9192When a call fails (401, 403, 404, 429), switch to the `troubleshoot` skill.