---
# SPDX-License-Identifier: AGPL-3.0-or-later
title: Gateway threads
description: Thread Dispatch events, thread subscriptions, forum unread counts, and the thread session flag.
draft: true
---
A session receives [threads](/http-api/threads/) through the Dispatch events below. A guild ready object in [Ready](/gateway/events/#ready), [Guild Create](/gateway/events/#guild-create), and [Guild Sync](/gateway/events/#guild-sync) has `threads` only when the session can view threads in that guild. A client treats the presence of that key as the signal that threads, forums, and media channels exist in the guild.
:::note[Threads need the `CHANNEL_THREADS` capability]
A user session receives thread data only when it sets `CHANNEL_THREADS` in Identify. A bot session needs no flag.
:::
## Session flag
| Value | Name | Description |
| --- | --- | --- |
| 1 << 2 | CHANNEL_THREADS | The client can parse thread, forum, and media channels |
The flag joins the [session flags](/gateway/commands/#session-flags) of Identify. A user session without it sees no channel of type 11, 12, 15, or 16, and no thread event.
## Guild threads
`threads` on a guild ready object is an array of [thread objects](/http-api/threads/#thread-object). A user session receives the active threads it joined, each with `member`. A bot session receives every active thread it can view.
The `member` of each entry has no `id`, `user_id`, or `member`.
## Dispatch events
| Event | Description | Scope |
| --- | --- | --- |
| [Thread Create](#thread-create) | A thread was created or became visible | Thread |
| [Thread Update](#thread-update) | A thread changed | Thread |
| [Thread Delete](#thread-delete) | A thread was deleted | Thread |
| [Thread List Sync](#thread-list-sync) | The session's active thread set was replaced | Guild |
| [Thread Member Update](#thread-member-update) | The session's own membership changed | Current user |
| [Thread Members Update](#thread-members-update) | Users joined or left a thread | Thread |
| [Thread Member List Update](#thread-member-list-update) | A subscribed thread member list resynced | Command response |
| [Forum Unreads](#forum-unreads) | Unread counts for forum posts | Command response |
A session receives a thread event only when it can view the thread. Messages, reactions, typing, and pins in a thread reach a session that is a member of the thread, a bot session, or an active session that subscribed through `threads`. A message in a thread has `channel_type` set to the thread type.
### THREAD_CREATE
A thread was created, or the session was added to one. The payload is the [thread object](/http-api/threads/#thread-object) with the fields below.
| Field | Type | Description |
| --- | --- | --- |
| newly_created? | boolean | Whether the thread was just created, present only then |
| member? | [thread member](/http-api/thread-members/#thread-member-object) object | The session's own membership, present only for a member |
A user session receives it for a thread it joined, a thread it was added to, or any thread while subscribed through `threads`. A passive session receives it only when it was added.
### THREAD_UPDATE
A thread changed. The payload is the [thread object](/http-api/threads/#thread-object).
A new message and a changed counter emit no Thread Update. A passive session receives it only for a thread it joined.
### THREAD_DELETE
A thread was deleted.
| Field | Type | Description |
| --- | --- | --- |
| id | snowflake | The ID of the thread |
| guild_id | snowflake | The ID of the guild |
| parent_id | snowflake | The ID of the parent channel |
| type | integer | The [thread type](/http-api/threads/#thread-types) |
Recipients are the sessions that could view the thread before the deletion.
### THREAD_LIST_SYNC
The session's active threads were replaced for a guild or for some of its channels.
| Field | Type | Description |
| --- | --- | --- |
| guild_id | snowflake | The ID of the guild |
| channel_ids?1 | array[snowflake] | The parent channels whose threads are replaced |
| threads | array[[thread](/http-api/threads/#thread-object) object] | The active threads the session can view |
| members | array[[thread member](/http-api/thread-members/#thread-member-object) object] | The session's memberships in those threads |
1 Absent when the event replaces every thread in the guild
Fluxer sends it after `threads` is set to true in [Lazy Request](#lazy-request-thread-options), within 5,000 ms, and when the session gains access to a channel that has threads.
### THREAD_MEMBER_UPDATE
The session's own membership in a thread changed. The payload is the [thread member object](/http-api/thread-members/#thread-member-object) with `guild_id`.
### THREAD_MEMBERS_UPDATE
Users joined or left a thread.
| Field | Type | Description |
| --- | --- | --- |
| id | snowflake | The ID of the thread |
| guild_id | snowflake | The ID of the guild |
| member_count | integer | The number of thread members, capped at 50 |
| added_members?1 | array[[thread member](/http-api/thread-members/#thread-member-object) object] | The users who joined |
| removed_member_ids? | array[snowflake] | The IDs of the users who left |
1 Each entry adds `member`, the guild member, and `presence`, the [presence object](/gateway/events/#presence-object). Either is null when Fluxer has none
A bot session receives every Thread Members Update it can view. A user session receives it when it was added or removed, is a member, or subscribed through `threads`. A passive session receives it only when it was added or removed.
### THREAD_MEMBER_LIST_UPDATE
A thread member list the session subscribed to through `thread_member_lists` resynced.
| Field | Type | Description |
| --- | --- | --- |
| guild_id | snowflake | The ID of the guild |
| thread_id | snowflake | The ID of the thread |
| members1 | array[thread member list item object] | The members of the thread, at most 1,000 |
1 Each item is `user_id`, `join_timestamp`, `flags`, `member`, and `presence`, where `member` is the guild member or null
The event is delivered live and never retained for Resume.
### FORUM_UNREADS
The answer to [Request Forum Unreads](#request-forum-unreads).
| Field | Type | Description |
| --- | --- | --- |
| guild_id | snowflake | The ID of the guild |
| channel_id | snowflake | The ID of the forum or media channel |
| threads | array[forum unread object] | One entry for each requested post the session can view |
Each forum unread object is `thread_id` with either `count` or `missing`. `count` is the number of unread messages after the sent `ack_message_id`, capped at 25. `missing` is true when the request sent no `ack_message_id` for that post.
## Lazy Request thread options
The [guild subscription object](/gateway/commands/#guild-subscription-object) of [Lazy Request](/gateway/commands/#lazy-request) takes two more options.
| Field | Type | Description |
| --- | --- | --- |
| threads? | boolean | Whether the session receives every thread event and thread message in the guild |
| thread_member_lists? | array[snowflake] | The threads whose member lists the session subscribes to, at most 10 |
Fluxer ignores both options for a user session that did not set `CHANNEL_THREADS`. A thread the session cannot view is dropped from `thread_member_lists`. Each newly listed thread produces a [Thread Member List Update](#thread-member-list-update), and a membership change in it produces another.
## Request Forum Unreads
Opcode `28` requests unread counts for posts in one forum or media channel.
| Field | Type | Description |
| --- | --- | --- |
| guild_id | snowflake | The ID of the guild |
| channel_id | snowflake | The ID of the forum or media channel |
| threads | array[forum unread request object] | The posts to count, deduplicated and truncated to 40 |
Each forum unread request object is `thread_id` and an optional `ack_message_id`, the newest message the client has read in that post.
```json
{
"op": 28,
"d": {
"guild_id": "1189375284394692608",
"channel_id": "1189375284394692700",
"threads": [{"thread_id": "1189375284394692800", "ack_message_id": "1189375284394692900"}]
}
}
```
Results arrive in one [Forum Unreads](#forum-unreads), where a post outside the channel has no entry. A channel the session cannot view, and a request with no valid `thread_id`, produce no Dispatch. A session that cannot view threads closes with `4001` and reason `Unknown opcode`.
A session sends at most five Request Forum Unreads commands in a rolling 5-second window. A further command is discarded without closing the connection.