Files
fluxer/fluxer_docs/src/content/docs/http-api/thread-members.mdx
T

332 lines
17 KiB
Plaintext

---
# SPDX-License-Identifier: AGPL-3.0-or-later
title: Thread members
description: Thread member objects, joining and leaving threads, member lists, and thread notification settings.
---
import RouteHeader from '@/components/RouteHeader.astro';
A thread member records that a user joined a [thread](/http-api/threads/). A thread holds at most 1,000 members, and adding one more returns 400 `MAX_THREAD_MEMBERS`.
:::note[User requests need the `channel_threads` client capability]
A request from a user without the [`channel_threads` client capability](/http-api/threads/#client-capability) returns 404 `NOT_FOUND`. [Get thread member](#get-thread-member) and [List thread members](#list-thread-members) return 404 `NOT_FOUND` to every user. A `channel_id` that does not exist or names a channel outside a guild returns the same 404.
:::
A route on this page returns 403 `MISSING_PERMISSIONS` when the caller is not a member of the guild, unless its own entry states an earlier result. A guild channel that is not a thread and that the caller cannot view also returns 403 `MISSING_PERMISSIONS`. A thread whose parent channel no longer exists returns 404 `UNKNOWN_CHANNEL`.
## Thread member object
### Structure
| Field | Type | Description |
| --- | --- | --- |
| id?<sup>1</sup> | snowflake | The ID of the thread |
| user_id?<sup>1</sup> | snowflake | The ID of the user |
| join_timestamp | ISO8601 timestamp | The time the user last joined the thread |
| flags | integer | The [thread member flags](#thread-member-flags) |
| muted?<sup>2</sup> | boolean | Whether the user muted the thread |
| mute_config?<sup>2</sup> | ?[guild mute configuration](/http-api/users/settings/#guild-mute-configuration-object) object | The mute expiry of the thread, or null when none is stored |
| member?<sup>3</sup> | [guild member](/http-api/guild-members/#guild-member-object) object | The guild member of the user |
<sup>1</sup> Omitted on the `member` of a thread in [Ready](/gateway/events/#ready), [Guild Create](/gateway/events/#guild-create), and [Guild Sync](/gateway/events/#guild-sync)
<sup>2</sup> Present only on the caller's own membership
<sup>3</sup> In an HTTP response, present only when the request sets `with_member` and the user is still a guild member. [Thread Members Update](/gateway/threads/#thread-members-update) defines it on each `added_members` entry
### Example
```json
{
"id": "1501320100000000000",
"user_id": "1501314428688992222",
"join_timestamp": "2026-05-05T20:30:05.018Z",
"flags": 3,
"muted": false,
"mute_config": null
}
```
## Thread member flags
| Value | Name | Description |
| --- | --- | --- |
| 1 &lt;&lt; 0 | HAS_INTERACTED<sup>1</sup> | The user sent a message in the thread or created it |
| 1 &lt;&lt; 1 | ALL_MESSAGES | Notify the user of every message in the thread |
| 1 &lt;&lt; 2 | ONLY_MENTIONS | Notify the user only of mentions in the thread |
| 1 &lt;&lt; 3 | NO_MESSAGES | Notify the user of nothing in the thread |
<sup>1</sup> Set only by Fluxer. A bot that creates a thread starts without it
At most one of the three notification flags is set. With none set, the thread follows the notification level of its parent.
A member keeps the membership after losing access to the parent. Removal from the guild removes every membership in its threads. Fluxer emits a [Thread Members Update](/gateway/threads/#thread-members-update) for each of them.
## Join thread
<RouteHeader method="PUT" path="/v1/channels/{channel_id}/thread-members/@me" bot />
Adds the caller to a thread. Returns 204 with no body. Emits a [Thread Members Update](/gateway/threads/#thread-members-update) Gateway event.
### Limitations
- The caller must be able to view the thread.
- The thread must not be archived.
- A locked thread requires a thread moderator.
Joining a thread the caller already belongs to runs the checks above, then returns 204 and changes nothing. Each session of a newly added user receives [Thread Create](/gateway/threads/#thread-create) when it has [thread access](/gateway/threads/#session-flag) and can view the thread. A session still connecting to the guild receives none.
Joining a locked thread needs an enrolled authenticator while the guild [MFA level](/http-api/guilds/#mfa-levels) is elevated, unless the caller owns the guild.
### Path parameters
| Field | Type | Description |
| --- | --- | --- |
| channel_id | snowflake | The ID of the thread |
### Response
| Status | Body | Condition |
| --- | --- | --- |
| 204 | empty | Caller is a member |
| 400 | [error response](/http-api/#error-response) | Channel is not a thread and the request returns `INVALID_CHANNEL_TYPE` |
| 400 | [error response](/http-api/#error-response) | Thread is archived and the request returns `THREAD_ARCHIVED` |
| 400 | [error response](/http-api/#error-response) | Thread is locked and the caller is not a thread moderator, returning `THREAD_LOCKED` |
| 400 | [error response](/http-api/#error-response) | Thread has 1,000 members and the request returns `MAX_THREAD_MEMBERS` |
| 400 | [error response](/http-api/#error-response) | Caller needs an authenticator and the request returns `TWO_FACTOR_REQUIRED` |
| 403 | [error response](/http-api/#error-response) | Caller cannot view the thread and the request returns `MISSING_ACCESS` |
### Rate limit
10 requests per 10 seconds for each authenticated user and channel ID, on the `channel:thread:member:put::channel_id` bucket.
## Add thread member
<RouteHeader method="PUT" path="/v1/channels/{channel_id}/thread-members/{user_id}" bot />
Adds another guild member to a thread. Requires `SEND_MESSAGES_IN_THREADS`. Returns 204 with no body. Emits a [Thread Members Update](/gateway/threads/#thread-members-update) Gateway event.
### Limitations
- The caller must be able to view the thread.
- The thread must not be archived.
- A locked thread requires a thread moderator.
- A private thread with `invitable` false requires the caller or the target to be a thread moderator.
- The target must be a guild member who can view the parent.
`user_id` of `@me` behaves as [Join thread](#join-thread). A request that names the caller's own ID runs the checks above, and Fluxer posts no message for it. Adding a user who is already a member runs the checks above, then returns 204 and changes nothing. Each session of a newly added user receives [Thread Create](/gateway/threads/#thread-create) when it has [thread access](/gateway/threads/#session-flag) and can view the thread. A session still connecting to the guild receives none.
Adding to a locked thread needs an enrolled authenticator while the guild [MFA level](/http-api/guilds/#mfa-levels) is elevated, unless the caller owns the guild. Adding a target who is not a thread moderator to a private thread with `invitable` false needs one too.
### Path parameters
| Field | Type | Description |
| --- | --- | --- |
| channel_id | snowflake | The ID of the thread |
| user_id | snowflake | The ID of the user to add |
### Response
| Status | Body | Condition |
| --- | --- | --- |
| 204 | empty | Target is a member |
| 400 | [error response](/http-api/#error-response) | Channel is not a thread and the request returns `INVALID_CHANNEL_TYPE` |
| 400 | [error response](/http-api/#error-response) | Thread is archived and the request returns `THREAD_ARCHIVED` |
| 400 | [error response](/http-api/#error-response) | Thread is locked and the caller is not a thread moderator, returning `THREAD_LOCKED` |
| 400 | [error response](/http-api/#error-response) | Thread has 1,000 members and the request returns `MAX_THREAD_MEMBERS` |
| 400 | [error response](/http-api/#error-response) | Caller needs an authenticator and the request returns `TWO_FACTOR_REQUIRED` |
| 403 | [error response](/http-api/#error-response) | Caller cannot view the thread and the request returns `MISSING_ACCESS` |
| 403 | [error response](/http-api/#error-response) | Caller lacks `SEND_MESSAGES_IN_THREADS` and the request returns `MISSING_PERMISSIONS` |
| 403 | [error response](/http-api/#error-response) | Neither user is a thread moderator in a private thread that is not `invitable`, returning `MISSING_PERMISSIONS` |
| 403 | [error response](/http-api/#error-response) | Target cannot view the parent and the request returns `MISSING_ACCESS` |
| 403 | [error response](/http-api/#error-response) | Caller is timed out and the request returns `COMMUNICATION_DISABLED` |
| 404 | [error response](/http-api/#error-response) | Target is not a guild member and the request returns `UNKNOWN_MEMBER` |
### Side effects
Adding another user posts a `RECIPIENT_ADD` message in the thread that mentions the target. Fluxer emits [Message Create](/gateway/events/#message-create) for it.
### Rate limit
10 requests per 10 seconds for each authenticated user and channel ID, on the `channel:thread:member:put::channel_id` bucket.
## Leave thread
<RouteHeader method="DELETE" path="/v1/channels/{channel_id}/thread-members/@me" bot />
Removes the caller from a thread. Returns 204 with no body. Emits a [Thread Members Update](/gateway/threads/#thread-members-update) Gateway event.
A timed-out member can leave a thread. A member who can no longer view the thread receives 403 `MISSING_ACCESS`.
### Path parameters
| Field | Type | Description |
| --- | --- | --- |
| channel_id | snowflake | The ID of the thread |
### Response
| Status | Body | Condition |
| --- | --- | --- |
| 204 | empty | Caller left the thread |
| 400 | [error response](/http-api/#error-response) | Channel is not a thread and the request returns `INVALID_CHANNEL_TYPE` |
| 400 | [error response](/http-api/#error-response) | Thread is archived and the request returns `THREAD_ARCHIVED` |
| 403 | [error response](/http-api/#error-response) | Caller cannot view the thread and the request returns `MISSING_ACCESS` |
| 404 | [error response](/http-api/#error-response) | Caller is not a member and the request returns `UNKNOWN_THREAD_MEMBER` |
### Rate limit
10 requests per 10 seconds for each authenticated user and channel ID, on the `channel:thread:member:delete::channel_id` bucket.
## Remove thread member
<RouteHeader method="DELETE" path="/v1/channels/{channel_id}/thread-members/{user_id}" bot />
Removes a member from a thread. Requires `MANAGE_THREADS`, or ownership of a private thread. Returns 204 with no body. Emits a [Thread Members Update](/gateway/threads/#thread-members-update) Gateway event.
### Limitations
- The caller must be able to view the thread.
- The thread must not be archived.
- The caller must be a [thread moderator](/http-api/threads/#thread-moderators) or the owner of the private thread.
`user_id` of `@me` or of the caller behaves as [Leave thread](#leave-thread).
Removing a member needs an enrolled authenticator while the guild [MFA level](/http-api/guilds/#mfa-levels) is elevated, unless the caller owns the guild or the private thread.
### Path parameters
| Field | Type | Description |
| --- | --- | --- |
| channel_id | snowflake | The ID of the thread |
| user_id | snowflake | The ID of the user to remove |
### Response
| Status | Body | Condition |
| --- | --- | --- |
| 204 | empty | Member was removed |
| 400 | [error response](/http-api/#error-response) | Channel is not a thread and the request returns `INVALID_CHANNEL_TYPE` |
| 400 | [error response](/http-api/#error-response) | Thread is archived and the request returns `THREAD_ARCHIVED` |
| 400 | [error response](/http-api/#error-response) | Caller needs an authenticator and the request returns `TWO_FACTOR_REQUIRED` |
| 403 | [error response](/http-api/#error-response) | Caller cannot view the thread and the request returns `MISSING_ACCESS` |
| 403 | [error response](/http-api/#error-response) | Caller is neither a thread moderator nor the owner of the private thread and the request returns `MISSING_PERMISSIONS` |
| 403 | [error response](/http-api/#error-response) | Caller is timed out and the request returns `COMMUNICATION_DISABLED` |
| 404 | [error response](/http-api/#error-response) | Target is not a member and the request returns `UNKNOWN_THREAD_MEMBER` |
### Side effects
Removing another user posts a `RECIPIENT_REMOVE` message in the thread that mentions the target. Fluxer emits [Message Create](/gateway/events/#message-create) for it.
### Rate limit
10 requests per 10 seconds for each authenticated user and channel ID, on the `channel:thread:member:delete::channel_id` bucket.
## Get thread member
<RouteHeader method="GET" path="/v1/channels/{channel_id}/thread-members/{user_id}" bot />
Returns the [thread member object](#thread-member-object) of a user. Requires a bot token.
### Path parameters
| Field | Type | Description |
| --- | --- | --- |
| channel_id | snowflake | The ID of the thread |
| user_id | snowflake | The ID of the user |
### Query parameters
| Field | Type | Description |
| --- | --- | --- |
| with_member? | boolean | Whether to include the guild member of the user (default false) |
### Response
| Status | Body | Condition |
| --- | --- | --- |
| 200 | [thread member](#thread-member-object) object | Member was returned |
| 400 | [error response](/http-api/#error-response) | Channel is not a thread and the request returns `INVALID_CHANNEL_TYPE` |
| 403 | [error response](/http-api/#error-response) | Caller cannot view the thread and the request returns `MISSING_ACCESS` |
| 404 | [error response](/http-api/#error-response) | User is not a member and the request returns `UNKNOWN_THREAD_MEMBER` |
| 404 | [error response](/http-api/#error-response) | Caller is a user and the request returns `NOT_FOUND` |
### Rate limit
40 requests per 10 seconds for each authenticated user and channel ID, on the `channel:thread:member:get::channel_id` bucket.
## List thread members
<RouteHeader method="GET" path="/v1/channels/{channel_id}/thread-members" bot />
Returns the [thread member objects](#thread-member-object) of a thread in ascending user ID order. Requires a bot token.
A user client reads member lists through the `thread_member_lists` option of [Lazy Request](/gateway/commands/#lazy-request).
### Path parameters
| Field | Type | Description |
| --- | --- | --- |
| channel_id | snowflake | The ID of the thread |
### Query parameters
| Field | Type | Description |
| --- | --- | --- |
| with_member? | boolean | Whether to include the guild member of each thread member (default false) |
| after? | snowflake | Return members with a user ID above this one |
| limit? | integer | The maximum number of members to return (1-100, default 100) |
### Response
| Status | Body | Condition |
| --- | --- | --- |
| 200 | array[[thread member](#thread-member-object) object] | Members were returned |
| 400 | [error response](/http-api/#error-response) | Channel is not a thread and the request returns `INVALID_CHANNEL_TYPE` |
| 403 | [error response](/http-api/#error-response) | Caller cannot view the thread and the request returns `MISSING_ACCESS` |
| 404 | [error response](/http-api/#error-response) | Caller is a user and the request returns `NOT_FOUND` |
### Rate limit
20 requests per 10 seconds for each authenticated user and channel ID, on the `channel:thread:members:list::channel_id` bucket.
## Modify thread member settings
<RouteHeader method="PATCH" path="/v1/channels/{channel_id}/thread-members/@me/settings" />
Changes the caller's notification settings for a thread they joined. User-only. Returns the updated [thread member object](#thread-member-object), or 204 when nothing changed. Emits a [Thread Member Update](/gateway/threads/#thread-member-update) Gateway event.
### Path parameters
| Field | Type | Description |
| --- | --- | --- |
| channel_id | snowflake | The ID of the thread |
### JSON body
| Field | Type | Description |
| --- | --- | --- |
| flags?<sup>1</sup> | integer | The notification [thread member flags](#thread-member-flags) |
| muted? | boolean | Whether the thread is muted |
| mute_config? | ?[guild mute configuration input](/http-api/users/settings/#guild-mute-configuration-input-object) object | The mute expiry of the thread, or null to clear it |
<sup>1</sup> Replaces the three notification flags and keeps `HAS_INTERACTED`. A value of 0 clears them
While `muted` is true, the member receives no push notification from the thread, including for a mention. A mute with an `end_time` stops when that time passes.
### Response
| Status | Body | Condition |
| --- | --- | --- |
| 200 | [thread member](#thread-member-object) object | Settings changed |
| 204 | empty | The body matched the stored settings |
| 400 | [error response](/http-api/#error-response) | `flags` sets more than one notification flag or any other bit and the request returns `INVALID_THREAD_NOTIFICATION_SETTINGS` |
| 400 | [error response](/http-api/#error-response) | Channel is not a thread and the request returns `INVALID_CHANNEL_TYPE` |
| 403 | [error response](/http-api/#error-response) | Caller is a bot and the request returns `ACCESS_DENIED` |
| 403 | [error response](/http-api/#error-response) | Caller cannot view the thread and the request returns `MISSING_ACCESS` |
| 404 | [error response](/http-api/#error-response) | Caller is not a member and the request returns `UNKNOWN_THREAD_MEMBER` |
### Rate limit
10 requests per 10 seconds for each authenticated user and channel ID, on the `channel:thread:member:settings::channel_id` bucket.