Gateway events¶
A Dispatch reports a change or a command result through the Gateway. It has opcode 0, an event name, and a payload.
Dispatch envelope¶
| Field | Type | Description |
|---|---|---|
| op | integer | Value 0 |
| t | string | Upper-case event name |
| s | integer | Non-negative session sequence |
| d | any | Payload defined for the named event |
Ready establishes sequence 1. Live Dispatches advance it by one. Replayed Dispatches keep their original sequence and can have gaps. Resumed carries the session's current sequence without advancing it. The sequence is local to one Gateway session and orders nothing across shards or HTTP operations.
Dispatch delivery¶
Event filtering defines delivery by guild availability, channel visibility, permissions, and session settings. Account-scoped Dispatches go only through the session-level filters, which are the shard filter and the ignored_events list.
Most guild-scoped Dispatches carry a guild_id string, which the Gateway adds to every event it fans out to a guild. Guild Create and Guild Sync identify the guild as id. Guild Counts Update and Channel Member Counts Update have no top-level guild_id, and each entry in their counts array has its own.
The originating session is excluded from a Dispatch only for Message Reaction Add and Message Reaction Remove in a guild channel, and only when the HTTP request supplied a session_id query parameter. That field is removed from the payload. The same field on a direct message reaction is forwarded to every recipient unchanged and excludes nobody. Every other mutation delivers its Dispatch to the acting session like any other eligible session.
A Dispatch is buffered for Resume replay unless it is Guild Sync, Guild Member List Update, or Guild Members Chunk. Those are delivered live and never retained. A single oversized Dispatch is delivered but not retained, as Limits and rate limits describes. Ready is also sent outside the replay buffer.
Extra keys are normal
Many TEBHOS payloads carry a few additional keys next to the documented ones, kept for older TEBHOS clients (for example user_id and member_id on member events, or relation_type on relationship events). Ignore keys you do not recognise.
Dispatch events¶
| Event | Description | Scope |
|---|---|---|
| READY | The initial session state after a successful Identify | Session lifecycle |
| RESUMED | Retained replay completes after a successful Resume | Session lifecycle |
| SESSIONS_REPLACE | The account's live session presence set is replaced | Current user |
| AUTH_SESSION_CHANGE | The account's login sessions were revoked or the password changed | Current user |
| RATE_LIMITED | A member request is refused by its budget | Command response |
| USER_UPDATE | The current user's account record changes | Current user |
| USER_SETTINGS_UPDATE | The current user's account-wide settings change | Current user |
| USER_GUILD_SETTINGS_UPDATE | One guild notification record changes | Current user |
| USER_NOTE_UPDATE | The current user writes or clears a private note | Current user |
| USER_PINNED_DMS_UPDATE | The current user's pinned private channel set is replaced | Current user |
| USER_CONNECTIONS_UPDATE | The current user's external connection set is replaced | Current user |
| WEBAUTHN_CREDENTIALS_UPDATE | The current user's passkey set is replaced | Current user |
| RELATIONSHIP_ADD | The current user gains a relationship | Current user |
| RELATIONSHIP_UPDATE | One of the current user's relationships changes | Current user |
| RELATIONSHIP_REMOVE | The current user loses a relationship | Current user |
| SAVED_MESSAGE_CREATE | The current user saves a message | Current user |
| SAVED_MESSAGE_DELETE | The current user unsaves a message | Current user |
| RECENT_MENTION_DELETE | The current user removes a recent mention | Current user |
| FAVORITE_MEME_UPDATE | One of the current user's saved memes changes | Current user |
| FAVORITE_MEME_DELETE | The current user deletes a saved meme | Current user |
| GUILD_CREATE | A guild becomes available to the session | Guild connection |
| GUILD_SYNC | A subscribed session receives the guild's full current state again | Guild connection |
| GUILD_UPDATE | A guild's configuration changes | Guild connection |
| GUILD_DELETE | A guild leaves the session's visibility or becomes unavailable | Guild connection |
| GUILD_ROLE_CREATE | A role is created in a guild | Guild connection |
| GUILD_ROLE_UPDATE | Exactly one role record changes | Guild connection |
| GUILD_ROLE_UPDATE_BULK | One operation changes several role records together | Guild connection |
| GUILD_ROLE_DELETE | A role is deleted from a guild | Guild connection |
| GUILD_EMOJIS_UPDATE | A guild's emojis change | Guild connection |
| GUILD_STICKERS_UPDATE | A guild's stickers change | Guild connection |
| CHANNEL_CREATE | A channel becomes visible to the session | Channel visibility |
| CHANNEL_UPDATE | A visible channel changes | Channel visibility |
| CHANNEL_UPDATE_BULK | One operation changes several channels together | Channel visibility |
| CHANNEL_DELETE | A channel leaves the session's visibility | Channel visibility |
| CHANNEL_RECIPIENT_ADD | A user joins a group direct message the session belongs to | Private channel |
| CHANNEL_RECIPIENT_REMOVE | A user leaves a group direct message the session belongs to | Private channel |
| WEBHOOKS_UPDATE | The webhook set of a guild channel changes | Guild connection |
| INVITE_CREATE | An invite is created | Invite audience |
| INVITE_DELETE | An invite is deleted | Invite audience |
| GUILD_MEMBER_ADD | A user becomes a member of a connected guild | Guild connection |
| GUILD_MEMBER_UPDATE | A member's guild state or public user representation changes | Guild connection |
| GUILD_MEMBER_REMOVE | A user stops being a member of a connected guild | Guild connection |
| GUILD_MEMBERS_CHUNK | A bounded member result answers Request Guild Members | Command response |
| GUILD_MEMBER_LIST_UPDATE | A subscribed member list resyncs the subscriber's ranges | Member list subscription |
| GUILD_AUDIT_LOG_ENTRY_CREATE | An audit log entry is written in a guild | Holders of VIEW_AUDIT_LOG |
| GUILD_BAN_ADD | A guild ban is created | Guild connection |
| GUILD_BAN_REMOVE | A guild ban is removed | Guild connection |
| PRESENCE_UPDATE | One visible presence changes | Presence subscription |
| PRESENCE_UPDATE_BULK | A recovering guild delivers its visible presences together | Guild connection |
| PASSIVE_UPDATES | Channel last_message_id values or voice states changed for one passive session |
Passive session |
| MESSAGE_CREATE | A visible message is created | Channel visibility |
| MESSAGE_UPDATE | A visible message changes and is republished in full | Message access |
| MESSAGE_DELETE | One visible message is deleted | Message access |
| MESSAGE_DELETE_BULK | Several messages in one channel are deleted together | Channel visibility |
| MESSAGE_ACK | The current user's read state advances for a channel | Current user |
| MESSAGE_REACTION_ADD | A user adds a reaction to a message | Message access |
| MESSAGE_REACTION_ADD_MANY | A debouncing session receives several reaction additions as one event | Message access |
| MESSAGE_REACTION_REMOVE | One user's reaction is removed from a message | Message access |
| MESSAGE_REACTION_REMOVE_ALL | Every reaction is removed from a message at once | Message access |
| MESSAGE_REACTION_REMOVE_EMOJI | Every reaction using one emoji is removed from a message | Message access |
| TYPING_START | A visible user begins typing in a channel | Channel visibility |
| CHANNEL_PINS_UPDATE | A channel's pins change | Channel visibility |
| CHANNEL_PINS_ACK | The current user acknowledges a channel's pins | Current user |
| VOICE_STATE_UPDATE | A guild or call participant's voice state changes | Channel visibility |
| VOICE_SERVER_UPDATE | The session receives or replaces its own voice grant | Current session |
| ENTRANCE_SOUND_PLAY | A participant's entrance sound plays in a voice channel | Voice channel |
| CALL_CREATE | A private channel call begins or becomes visible | Call recipient |
| CALL_UPDATE | The ringing set, participant roster, or region of a call changes | Call recipient |
| CALL_DELETE | A call ends or becomes unavailable | Call recipient |
| GUILD_COUNTS_UPDATE | Member and online counts are returned for connected guilds | Command response |
| CHANNEL_MEMBER_COUNTS_UPDATE | Per-channel member and online counts are returned for one guild | Command response |
TEBHOS also sends a set of product-specific events for its own clients. They are listed under TEBHOS client events.
TEBHOS never sends FAVORITE_MEME_CREATE: no route creates a saved meme.
Session and current user¶
READY¶
The initial session state. Sent once after a successful Identify, always with sequence 1.
| Field | Type | Description |
|---|---|---|
| session_id | string | Identifier for Resume |
| version | integer | Gateway API version, always 1 |
| user | user object | The authenticated account in its private representation |
| guilds | array[guild ready object] | The session's guilds. Always empty on a bot session: its guilds arrive afterwards as described below |
| private_channels | array[channel object] | Direct message and group direct message channels |
| relationships | array[relationship object] | The account's relationships. Each entry has its user removed, and the accounts appear in users instead |
| presences | array[presence object] | Visible presences at connection time. Always empty for a bot |
| users | array[partial user object] | Users referenced by the payload, collected from relationships, private channel recipients, and guild members. Always empty for a bot |
| sessions | array[session presence object] | The account's live sessions |
| read_states | array[read state object] | Per-channel read state |
| user_settings | ?user settings object | Account-wide settings |
| user_guild_settings | array[user guild settings object] | Per-guild notification settings |
| notes | map[snowflake, string] | Private notes keyed by user ID |
| pinned_dms | array[snowflake] | Pinned private channel IDs |
| favorite_memes | array[meme object] | Saved memes |
| webauthn_credentials | array[WebAuthn credential object] | Registered passkeys |
| rtc_regions | array[RTC region object] | Voice regions, ordered nearest first |
| country_code | string | Country resolved from the connecting address, US when the address resolves to none |
| latitude? | string | Latitude resolved from the connecting address |
| longitude? | string | Longitude resolved from the connecting address |
| auth_session_id_hash? | string | Base64url hash identifying the login session. Absent on a bot session |
| shard? | array[integer] | The accepted [shard_id, shard_count] pair, present only when Identify supplied one |
| _timings? | object | Timing breakdown, only meaningful for staff accounts |
The payload can also carry channels and read_state_proto, which the TEBHOS clients use to seed their read-state cache. Treat them as internal.
Ready is sent outside the replay buffer, so a Resume never replays it.
A bot session receives Ready as soon as it is identified, with an empty guilds array. Each of its guilds then arrives separately as the session connects to it: one Guild Create per available guild, and one Guild Delete with unavailable: true per unavailable guild. These are ordinary Dispatches, kept in the replay buffer like any other.
Shortly after Ready, every session receives one Call Create for each of its private channels that has an active call.
Guild ready object¶
The same structure appears in Ready, Guild Create, and Guild Sync.
| Field | Type | Description |
|---|---|---|
| id | snowflake | Guild ID |
| properties | guild object | Guild record without its roles, channels, emojis, stickers, or members |
| roles | array[guild role object] | Every role in the guild |
| channels | array[channel object] | Channels the session can view |
| emojis | array[guild emoji object] | Every emoji in the guild |
| stickers | array[guild sticker object] | Every sticker in the guild |
| members | array[guild member object] | The session's own member object plus the member object of every participant named by voice_states |
| member_count | integer | Total member count |
| online_count | integer | Online member count, the same guild-wide figure for every recipient |
| presences | array[presence object] | Always an empty array. Guild presences arrive as separate Presence Update and Presence Update Bulk Dispatches |
| voice_states | array[voice state object] | Voice states in channels the session can view |
| joined_at | ?ISO8601 timestamp | When the account joined the guild |
| unavailable? | boolean | Whether the guild is unavailable |
| unavailable_hidden? | boolean | Whether an unavailable guild is hidden from the client |
A client that needs the rest of the roster asks for it with Request Guild Members or subscribes to a member list through Lazy Request.
An unavailable guild is reduced to id and unavailable: true, plus unavailable_hidden: true when the guild is hidden.
Inside Ready, each entry in members has its user replaced by {"id": "..."}, and the removed accounts appear in the Ready users array. A Guild Create sent after Ready, including those a bot receives for its guilds, and every Guild Sync have the members with user intact.
Session presence object¶
| Field | Type | Description |
|---|---|---|
| session_id | string | Session identifier, or the literal all for the aggregate entry |
| status | string | online, idle, dnd, invisible, or offline |
| afk | boolean | Whether the session is away |
| mobile | boolean | Whether the session is mobile |
The first entry always has session_id: "all" and the account's combined status.
WebAuthn credential object¶
| Field | Type | Description |
|---|---|---|
| id | string | Credential ID |
| name | string | Credential name |
| created_at | ISO8601 timestamp | When the passkey was registered |
| last_used_at | ?ISO8601 timestamp | When the passkey was last used |
RTC region object¶
| Field | Type | Description |
|---|---|---|
| id | string | Region ID |
| name | string | Human-readable region name |
| emoji | string | Region emoji |
The array always begins with a synthetic entry whose id is automatic and name is Automatic. Choosing it leaves the region to the server. Every other entry is a region the account can use, ordered by distance from the latitude and longitude in the Identify properties when both parse as numbers, and otherwise by region ID.
RESUMED¶
Sent after a successful Resume has replayed every retained Dispatch above the supplied sequence. The payload is empty apart from an optional timing object for staff accounts. Resumed carries the session's current sequence in s without advancing it.
SESSIONS_REPLACE¶
The account's set of live sessions changed. The payload is a bare JSON array of session presence objects and is always the complete set. Ready sends the initial set as sessions.
AUTH_SESSION_CHANGE¶
The account's login sessions changed in a way other devices must react to.
| Field | Type | Description |
|---|---|---|
| reason | string | password_change, all_sessions_revoked, or other_sessions_revoked |
| user_id | snowflake | The account |
| keep_session_hashes? | array[string] | Present on password_change: the hex hashes of the login session that stays signed in |
No token rotation
TEBHOS does not deliver a replacement token in this event. A client whose login session was revoked receives 401 on its next HTTP request and must sign in again. The Gateway sessions of revoked login sessions are closed separately.
RATE_LIMITED¶
A Request Guild Members command was refused by the bot full-member-list budget. Delivered to the requesting session alone.
| Field | Type | Description |
|---|---|---|
| opcode | integer | The refused opcode, always 8 |
| retry_after | number | Seconds until the request can be retried |
| meta | object | guild_id, plus nonce when the request named exactly one guild and supplied a valid nonce |
The budget admits one unfiltered member request per bot account and guild every 30,000 ms. Every other command refusal is silent.
USER_UPDATE¶
The current user's account record changed. The payload is the complete user object in its private representation.
USER_SETTINGS_UPDATE¶
The current user's account-wide settings changed. The payload is the complete user settings object.
USER_GUILD_SETTINGS_UPDATE¶
One guild's notification settings changed. The payload is that guild's complete user guild settings object, with user_id added.
USER_NOTE_UPDATE¶
The current user wrote or cleared a private note.
| Field | Type | Description |
|---|---|---|
| id | snowflake | User the note is about |
| note | string | Note text, empty when cleared |
USER_PINNED_DMS_UPDATE¶
The current user's pinned private channel set changed.
| Field | Type | Description |
|---|---|---|
| channels | array[snowflake] | Every pinned channel ID, in pinned order |
channels is always the complete set. Ready sends the initial set as pinned_dms.
USER_CONNECTIONS_UPDATE¶
The current user's external connection set changed.
| Field | Type | Description |
|---|---|---|
| connections | array[connection object] | Every connection the account holds |
WEBAUTHN_CREDENTIALS_UPDATE¶
The current user's passkey set changed. The payload is a bare JSON array of WebAuthn credential objects and is always the complete set.
RELATIONSHIP_ADD¶
The current user gained a relationship.
| Field | Type | Description |
|---|---|---|
| id | snowflake | The other user's ID |
| type | integer | Relationship type |
| user | partial user object | The other user |
| since | ?ISO8601 timestamp | When the relationship was created |
| nickname | ?string | Private nickname for the other user |
| share_voice_activity | boolean | Whether the current user shares voice activity with this friend |
RELATIONSHIP_UPDATE¶
An existing relationship changed. The payload has the same structure as Relationship Add.
RELATIONSHIP_REMOVE¶
A relationship ended.
| Field | Type | Description |
|---|---|---|
| id | snowflake | The other user's ID |
SAVED_MESSAGE_CREATE¶
The current user saved a message. The payload is the complete message object as that user sees it, with message_id added.
SAVED_MESSAGE_DELETE¶
The current user unsaved a message.
| Field | Type | Description |
|---|---|---|
| message_id | snowflake | The message that is no longer saved |
RECENT_MENTION_DELETE¶
The current user removed a message from the recent mention feed.
| Field | Type | Description |
|---|---|---|
| message_id | snowflake | The message removed from the feed |
FAVORITE_MEME_UPDATE¶
One of the current user's saved memes changed. The payload is the complete meme object.
FAVORITE_MEME_DELETE¶
The current user deleted a saved meme.
| Field | Type | Description |
|---|---|---|
| meme_id | snowflake | The deleted meme |
Guilds and channels¶
GUILD_CREATE¶
A guild became available to the session. The payload is a guild ready object.
roles, channels, emojis, stickers, and voice_states are always complete, and a client replaces its stored lists with them. members is a partial list: add or update those members and keep the rest.
Every session receives Guild Create when a guild becomes available after Ready, for example after joining one or after an unavailable guild recovers. A bot session also receives one for each of its available guilds after Ready, because its Ready carries no guilds.
A second, short Guild Create on create and join
When the current user creates a guild or joins one over HTTP, the API also sends that user a Guild Create whose payload is { "guild": { "id", "name", "image_url", ... } }, a short summary for the TEBHOS clients. The full guild ready object follows from the Gateway once the session connects to the guild. Tell them apart by the top-level guild key.
GUILD_SYNC¶
A session that asked for a sync through Lazy Request receives the guild's full current state again. The payload is a guild ready object, and a client handles it like Guild Create.
TEBHOS sends a sync when a Lazy Request switches the guild between active and passive, and when sync: true names the guild.
GUILD_UPDATE¶
A guild's configuration changed. The payload is the complete guild object with guild_id added.
Guild Update is the only Dispatch an unavailable guild sends.
GUILD_DELETE¶
A guild left the session's visibility, or became unavailable.
| Field | Type | Description |
|---|---|---|
| id? | snowflake | Guild ID, present on the Gateway's own Guild Delete |
| guild_id? | snowflake | Guild ID, present on the API's Guild Delete |
| reason? | string | Present on the API's Guild Delete: deleted, kicked, or user_left |
| unavailable? | boolean | True when the guild is temporarily unavailable |
| unavailable_hidden? | boolean | True when an unavailable guild is hidden from the client |
Two sources send this event. The Gateway sends {id} when the session leaves the guild, and {id, unavailable: true} when the guild becomes temporarily unreachable. The API additionally sends {guild_id, reason} to the affected user when the guild is deleted, when the user is kicked, and when the user leaves. A client reads the guild from id or guild_id, whichever is present.
Without unavailable, the account is no longer a member, and a client deletes everything it stores for that guild. With unavailable: true, a client keeps the guild as an unavailable entry until a later Guild Create.
GUILD_ROLE_CREATE¶
A role was created in a guild.
| Field | Type | Description |
|---|---|---|
| guild_id | snowflake | Guild the role belongs to |
| role | guild role object | The created role |
GUILD_ROLE_UPDATE¶
Exactly one role record changed.
| Field | Type | Description |
|---|---|---|
| guild_id | snowflake | Guild the role belongs to |
| role | guild role object | The role's complete updated representation |
GUILD_ROLE_UPDATE_BULK¶
One operation changed several roles together, most often a reorder.
| Field | Type | Description |
|---|---|---|
| guild_id | snowflake | Guild the roles belong to |
| roles | array[guild role object] | Every changed role in its complete updated representation |
GUILD_ROLE_DELETE¶
A role was deleted from a guild.
| Field | Type | Description |
|---|---|---|
| guild_id | snowflake | Guild the role belonged to |
| role_id | snowflake | The deleted role |
GUILD_EMOJIS_UPDATE¶
A guild's emojis changed.
| Field | Type | Description |
|---|---|---|
| guild_id | snowflake | Guild the emojis belong to |
| emojis | array[guild emoji object] | Every emoji in the guild |
A client replaces its stored emojis with this array. TEBHOS sends no per-emoji events.
GUILD_STICKERS_UPDATE¶
A guild's stickers changed.
| Field | Type | Description |
|---|---|---|
| guild_id | snowflake | Guild the stickers belong to |
| stickers | array[guild sticker object] | Every sticker in the guild |
A client replaces its stored stickers with this array. TEBHOS sends no per-sticker events.
CHANNEL_CREATE¶
A channel became visible to the session, whether newly created or newly permitted. The payload is the complete channel object, with guild_id present for a guild channel.
CHANNEL_UPDATE¶
A visible channel changed. The payload is the complete channel object.
CHANNEL_UPDATE_BULK¶
One operation changed several channels together, most often a reorder.
| Field | Type | Description |
|---|---|---|
| guild_id | snowflake | Guild the channels belong to |
| channels | array[channel object] | The guild's channels in their updated representation |
Each recipient sees only channels it can view. An empty result produces no Dispatch and consumes no sequence number.
CHANNEL_DELETE¶
A channel left the session's visibility, whether deleted or newly hidden. For a guild channel the payload is the channel object as it was before the change, and recipients are the sessions that could see it. When the current user closes or leaves a private channel, the payload is {id, channel_id, type}.
CHANNEL_RECIPIENT_ADD¶
A user joined a group direct message the session belongs to.
| Field | Type | Description |
|---|---|---|
| channel_id | snowflake | Group direct message channel |
| user | partial user object | The user that joined |
CHANNEL_RECIPIENT_REMOVE¶
A user left a group direct message the session belongs to.
| Field | Type | Description |
|---|---|---|
| channel_id | snowflake | Group direct message channel |
| user | partial user object | The user that left |
WEBHOOKS_UPDATE¶
The webhook set of a guild channel changed. The event carries no webhook data, so a client that needs the new set reads it over the HTTP API.
| Field | Type | Description |
|---|---|---|
| guild_id | snowflake | Guild the channel belongs to |
| channel_id | snowflake | Channel whose webhooks changed |
INVITE_CREATE¶
A guild invite was created. The payload is the complete invite object, the same body GET /invites/{code} returns. It reaches the sessions holding MANAGE_CHANNELS on the invite's channel.
INVITE_DELETE¶
A guild invite was deleted.
| Field | Type | Description |
|---|---|---|
| code | string | The deleted invite code |
| channel_id? | snowflake | Channel the invite pointed at |
| guild_id | snowflake | Guild the invite belonged to |
Recipients are chosen the same way as for Invite Create.
Members and moderation¶
GUILD_MEMBER_ADD¶
A user became a member of a guild the session is connected to. The payload is the complete guild member object with guild_id added.
GUILD_MEMBER_UPDATE¶
A member's guild state or public user representation changed. The payload is the complete guild member object with guild_id added.
In a guild with more than 250 members, a passive session receives this event only when the subject is its own user.
GUILD_MEMBER_REMOVE¶
A user stopped being a member of a guild the session is connected to.
| Field | Type | Description |
|---|---|---|
| guild_id | snowflake | Guild the user left |
| user | object | The user that is no longer a member. The object has id alone |
| reason? | string | Present when the API knows why: for example kicked or temporary_membership_ended |
In a guild with more than 250 members, a passive session receives this event only when the subject is its own user.
GUILD_MEMBERS_CHUNK¶
Answers Request Guild Members for the requesting session.
| Field | Type | Description |
|---|---|---|
| guild_id | snowflake | Guild the members belong to |
| members | array[guild member object] | Up to 1,000 members |
| chunk_index | integer | Zero-based index of this chunk |
| chunk_count | integer | Total chunks in this response |
| presences? | array[presence object] | Present only when the request set presences and at least one member has a visible presence |
| nonce? | string | Echoed only when the request named exactly one guild and supplied a valid nonce |
A request that matches no member still produces one chunk with an empty members array, chunk_index 0, and chunk_count 1. This event is never retained for Resume.
GUILD_MEMBER_LIST_UPDATE¶
A member list the session subscribed to through Lazy Request resyncs the subscriber's ranges.
| Field | Type | Description |
|---|---|---|
| guild_id | snowflake | Guild the list belongs to |
| id | string | List identifier, which is the channel ID as a string |
| channel_id? | snowflake | Channel the list is scoped to |
| member_count | integer | Total members in the list |
| online_count | integer | Online members in the list |
| groups | array[member list group object] | Group headers in list order |
| ops | array[member list operation object] | Operations to apply |
Member list group object¶
| Field | Type | Description |
|---|---|---|
| id | string | Group identifier: a hoisted role ID, online, or offline. Hoisted role groups come first in role order, then online, then offline |
| count | integer | Members in the group |
A group whose count is 0 is omitted. The offline group is also omitted once it holds more than 1,000 members, together with its items.
Member list operation object¶
| Field | Type | Description |
|---|---|---|
| op | string | Operation kind, always SYNC |
| range | array[integer] | Inclusive [start, end] range this operation replaces |
| items | array[member list item object] | Replacement items for the range |
SYNC is the only operation TEBHOS sends. A client MUST ignore an operation it does not recognise.
Member list item object¶
Each item has exactly one of the fields.
| Field | Type | Description |
|---|---|---|
| group? | member list group object | A group header occupying one list position |
| member? | guild member object | A member of the list, extended with a presence field. The value is the member's presence object, or {"status": "offline", "mobile": false, "afk": false} |
GUILD_AUDIT_LOG_ENTRY_CREATE¶
An audit log entry was written. The payload is the audit log entry with guild_id added. Recipients are every session in the guild that holds VIEW_AUDIT_LOG, including the acting session.
GUILD_BAN_ADD¶
A guild ban was created.
| Field | Type | Description |
|---|---|---|
| guild_id | snowflake | Guild the ban was created in |
| user | object | The banned user, with id alone |
| reason | ?string | The ban reason supplied with the request |
GUILD_BAN_REMOVE¶
A guild ban was removed.
| Field | Type | Description |
|---|---|---|
| guild_id | snowflake | Guild the ban was removed from |
| user | object | The unbanned user, with id alone |
PRESENCE_UPDATE¶
One visible presence changed. The payload is a presence object.
A session receives a presence for a friend, for a recipient of a group direct message it belongs to, and for a guild member it subscribed to through the members array of a Lazy Request. A bot session holds no friend or group direct message subscription, so the guild path is the only one that reaches it.
Presence object¶
| Field | Type | Description |
|---|---|---|
| user | partial user object | The user the presence belongs to |
| status | string | online, idle, dnd, or offline |
| mobile | boolean | Whether the user's active status comes from a mobile session |
| afk | boolean | Whether every one of the user's sessions is away |
| custom_status | ?custom status object | The user's custom status |
| guild_id? | snowflake | Guild context, present when the presence arrived through a guild |
An account's published status is the highest-precedence status across its live sessions, in the order dnd, online, idle, invisible, and offline when no session is live. A session that selected invisible, and an account with no live session, both publish status: "offline". A session that lost its transport is published as offline 5,000 ms later, even though it stays resumable for 60,000 ms. custom_status is null whenever the published status is offline.
Custom status object¶
| Field | Type | Description |
|---|---|---|
| text | ?string | Custom status text |
| expires_at | ?ISO8601 timestamp | When the custom status expires |
| emoji_id | ?snowflake | Custom emoji ID |
| emoji_name | ?string | Unicode emoji, or the custom emoji's name |
| emoji_animated | boolean | Whether the custom emoji is animated |
PRESENCE_UPDATE_BULK¶
Several visible presences delivered in one Dispatch. A guild sends this only when it leaves the unavailable state, immediately after the Guild Create that restores it.
| Field | Type | Description |
|---|---|---|
| guild_id | snowflake | Guild context applied to every entry |
| presences | array[presence object] | Visibly online presences, excluding the recipient's own |
PASSIVE_UPDATES¶
A passive session in a guild with more than 250 members receives missed changes every 30,000 ms. No event is sent when nothing changed.
| Field | Type | Description |
|---|---|---|
| guild_id | snowflake | Guild the update covers |
| channels | map[snowflake, snowflake] | Changed last_message_id per viewable channel |
| voice_states? | array[voice state object] | Changed voice states in channels the session can view. A participant that left appears with channel_id null |
Messages and reactions¶
MESSAGE_CREATE¶
A visible message was created. The payload is the complete message object with the fields below added.
| Field | Type | Description |
|---|---|---|
| channel_type | integer | Channel type of the channel |
| nicks? | map[snowflake, string] | Group direct message nicknames, present only when the group stores at least one |
| mention_here? | boolean | Present and true only when the message has a here mention |
| guild_id? | snowflake | Guild the channel belongs to |
| member? | guild member object | The author's guild member object without its user, present in a guild channel |
Message Create overrides both the passive filter and the ignored_events list when the message mentions the session's user. See Event filtering.
MESSAGE_UPDATE¶
A visible message changed. The payload is the complete current message object. In a guild channel it is extended with guild_id and member.
MESSAGE_DELETE¶
One visible message was deleted.
| Field | Type | Description |
|---|---|---|
| id | snowflake | The deleted message |
| channel_id | snowflake | Channel the message was in |
| content? | ?string | Content the message held before it was deleted |
| author_id? | snowflake | Account that wrote the message |
| guild_id? | snowflake | Guild the channel belongs to |
| member? | guild member object | The author's guild member object without its user, present in a guild channel while the author is a member |
MESSAGE_DELETE_BULK¶
Several messages in one channel were deleted together.
| Field | Type | Description |
|---|---|---|
| ids | array[snowflake] | The deleted messages |
| channel_id | snowflake | Channel the messages were in |
| guild_id? | snowflake | Guild the channel belongs to |
MESSAGE_ACK¶
The current user's read state advanced for a channel, usually because another of the account's sessions read it.
| Field | Type | Description |
|---|---|---|
| channel_id | snowflake | Channel whose read state advanced |
| message_id | ?snowflake | Message the read state now points at |
| mention_count | integer | Remaining mention count for the channel |
| manual | boolean | Whether the acknowledgement was explicit |
| last_pin_timestamp | ?ISO8601 timestamp | Last pin time recorded in the read state |
| version | string | Read state version as a decimal string |
MESSAGE_REACTION_ADD¶
A user added a reaction to a message.
| Field | Type | Description |
|---|---|---|
| user_id | snowflake | User that reacted |
| channel_id | snowflake | Channel the message is in |
| message_id | snowflake | Message that was reacted to |
| emoji | reaction emoji object | The emoji |
| guild_id? | snowflake | Guild the channel belongs to |
| member? | guild member object | The reacting user's guild member object, present in a guild channel |
In a guild channel the session named by the request's session_id is excluded and the field is removed. In a private channel the field is delivered and excludes nobody, so a client MUST tolerate receiving its own reaction back.
Reaction emoji object¶
| Field | Type | Description |
|---|---|---|
| id | ?string | Custom emoji ID, null for a Unicode emoji |
| name | string | Unicode emoji, or the custom emoji's name |
| animated? | boolean | Whether the custom emoji is animated, absent for a Unicode emoji |
MESSAGE_REACTION_ADD_MANY¶
With the DEBOUNCE_MESSAGE_REACTIONS session flag, private-channel additions are grouped over 650 ms and delivered together. Each window keeps the latest 512 additions. Guild-channel additions always arrive as individual Message Reaction Add events.
| Field | Type | Description |
|---|---|---|
| channel_id | snowflake | Channel the message is in |
| message_id | snowflake | Message that was reacted to |
| guild_id? | snowflake | Guild the channel belongs to |
| reactions | array[object] | The merged additions in arrival order, each with user_id, emoji, and member? |
A window covering several messages produces a separate Dispatch for each. When the window closes holding exactly one addition, the session receives a plain Message Reaction Add.
MESSAGE_REACTION_REMOVE¶
One user's reaction was removed from a message. The payload has the same fields as Message Reaction Add, and exclusion works the same way.
MESSAGE_REACTION_REMOVE_ALL¶
Every reaction was removed from a message at once.
| Field | Type | Description |
|---|---|---|
| channel_id | snowflake | Channel the message is in |
| message_id | snowflake | Message whose reactions were cleared |
| guild_id? | snowflake | Guild the channel belongs to |
MESSAGE_REACTION_REMOVE_EMOJI¶
Every reaction using one emoji was removed from a message.
| Field | Type | Description |
|---|---|---|
| channel_id | snowflake | Channel the message is in |
| message_id | snowflake | Message the reactions were on |
| emoji | reaction emoji object | The emoji whose reactions were removed |
| guild_id? | snowflake | Guild the channel belongs to |
TYPING_START¶
A visible user began typing in a channel.
| Field | Type | Description |
|---|---|---|
| channel_id | snowflake | Channel the user is typing in |
| user_id | snowflake | User that started typing |
| timestamp | integer | Unix seconds when typing started |
| guild_id? | snowflake | Guild the channel belongs to |
| member? | guild member object | The typing user's guild member object, present in a guild channel |
In a guild, the typing override set through Lazy Request decides delivery. With no override, a session receives the event when it is active in the guild or when the guild has 250 members or fewer.
CHANNEL_PINS_UPDATE¶
A message was pinned or unpinned.
| Field | Type | Description |
|---|---|---|
| channel_id | snowflake | Channel whose pins changed |
| message_id | snowflake | The message that was pinned or unpinned |
| last_pin_timestamp | ?ISO8601 timestamp | Time of the most recent pin, null when nothing is pinned |
| guild_id? | snowflake | Guild the channel belongs to |
CHANNEL_PINS_ACK¶
The current user acknowledged a channel's pins. Every session of the account receives it.
| Field | Type | Description |
|---|---|---|
| channel_id | snowflake | Channel whose pins were acknowledged |
| last_pin_timestamp | ISO8601 timestamp | The pin time recorded for the channel |
Voice and calls¶
VOICE_STATE_UPDATE¶
A participant's voice state changed. The payload is a voice state object. Recipients are the sessions that can view the voice channel, passive sessions included. A channel_id of null means the participant left.
Voice state object¶
| Field | Type | Description |
|---|---|---|
| guild_id | ?snowflake | Guild the voice channel belongs to, null in a call |
| channel_id | ?snowflake | Voice channel, null when the participant left |
| user_id | snowflake | Participant |
| connection_id | ?string | Voice connection identity |
| session_id | ?string | Gateway session that owns the connection |
| member | ?guild member object | The participant's guild member object, null in a call |
| mute | boolean | Server mute |
| deaf | boolean | Server deafen |
| self_mute | boolean | Local microphone mute |
| self_deaf | boolean | Local output deafen |
| self_video | boolean | Whether the participant publishes camera video |
| self_stream | boolean | Whether the connection advertises a screen share track. False when the participant lacks STREAM in a guild channel |
| is_mobile | boolean | Whether the participant is on a mobile client |
| suppress | boolean | Whether the participant is suppressed |
| viewer_stream_keys | array[string] | Streams this connection is watching |
| e2ee_capable | boolean | Whether the participant's client supports end-to-end encrypted voice |
| version | integer | Monotonic version of this participant's voice state |
VOICE_SERVER_UPDATE¶
The session received or replaced its own voice grant. Delivered to the requesting session alone.
| Field | Type | Description |
|---|---|---|
| token | string | The LiveKit access token this connection presents |
| endpoint | string | The LiveKit signalling URL to connect to, a ws:// or wss:// address |
| connection_id | string | The voice connection the grant covers |
| channel_id | snowflake | The channel the grant covers |
| guild_id? | snowflake | Present for a guild voice channel, absent for a call |
| e2ee_key? | string | Key material for an end-to-end encrypted channel |
TEBHOS uses LiveKit for voice media. There is no second voice WebSocket, no voice opcode set, and no UDP discovery step. See Voice.
A grant is issued when a connection opens, when it moves to another channel, and when its region changes. Toggling self_mute, self_video, or self_stream produces no new grant.
ENTRANCE_SOUND_PLAY¶
A participant played their entrance sound in a voice channel they are connected to. See Entrance sounds.
| Field | Type | Description |
|---|---|---|
| user_id | snowflake | Participant whose sound plays |
| channel_id | snowflake | Voice channel |
| guild_id | ?snowflake | Guild the channel belongs to, null for a call |
| sound_id | snowflake | Entrance sound |
| hash | string | Content hash of the sound file |
| url | string | URL to fetch the sound from |
| duration_ms | integer | Sound duration in milliseconds |
| content_type | string | MIME type of the sound file |
Recipients are every other account with a voice state in that channel, once per account. The event reaches all of an account's sessions, so a client filters on channel_id.
CALL_CREATE¶
A private channel call began, or became visible in the session's initial state.
| Field | Type | Description |
|---|---|---|
| channel_id | snowflake | Channel the call is in |
| message_id | snowflake | Call message that opened the call |
| region | ?string | Voice region serving the call, auto or null for automatic routing |
| ringing | array[snowflake] | Recipients being rung |
| voice_states | array[voice state object] | Participants |
| recipients? | array[snowflake] | Every recipient of the channel, present on initial or recovered call state |
| created_at? | integer | Unix milliseconds when the call was opened, present on initial or recovered call state |
Recipients are every recipient of the channel, whether or not they joined the call. The same set receives Call Update and Call Delete.
API form
When the API creates the call (the first ring), it also sends a Call Create in its own form: call_id, channel_id, initiator_id, livekit_room_name, started_at, message_id, region, empty ringing and voice_states, unavailable, and unavailable_recipients. The Gateway's form follows once the call process starts. Handle both by channel_id.
CALL_UPDATE¶
The ringing set, participant roster, or region of an active call changed. The Gateway form has the same structure as Call Create without recipients and created_at, and is sent only when the call state visibly changed. A region change made over HTTP also sends an API form with id, call_id, channel_id, initiator_id, livekit_room_name, started_at, region, voice_states, ringing, and message_id.
CALL_DELETE¶
A call ended, or became unavailable.
| Field | Type | Description |
|---|---|---|
| channel_id | snowflake | Channel the call was in |
| unavailable? | boolean | True when the call became unavailable |
| call_id? | string | Present on the API form |
| ended_by? | snowflake | Present on the API form when a user ended the call |
| reason? | string | empty on the API form sent when stopping the ring left the call empty |
With unavailable: true, the client keeps the call as an unavailable entry. If it becomes available again, a fresh Call Create includes recipients and created_at.
Count response events¶
GUILD_COUNTS_UPDATE¶
Answers Request Guild Counts for the requesting session.
| Field | Type | Description |
|---|---|---|
| counts | array[guild count entry object] | One entry per guild that answered in time |
| nonce? | string | Echoed when the request supplied a valid nonce |
Guild count entry object¶
| Field | Type | Description |
|---|---|---|
| guild_id | snowflake | Guild the counts describe |
| member_count | integer | Total members |
| online_count | integer | Online members that share at least one channel the requesting account can view. An account with ADMINISTRATOR receives the guild's whole online count |
CHANNEL_MEMBER_COUNTS_UPDATE¶
Answers Request Channel Member Counts for the requesting session.
| Field | Type | Description |
|---|---|---|
| counts | array[channel count entry object] | One entry per channel that answered |
| nonce? | string | Echoed when the request supplied a valid nonce |
Channel count entry object¶
| Field | Type | Description |
|---|---|---|
| guild_id | snowflake | Guild the channel belongs to |
| channel_id | snowflake | Channel the counts describe |
| member_count | integer | Members that can view the channel |
| online_count | integer | Online members that can view the channel |
TEBHOS client events¶
The TEBHOS web, desktop, and mobile clients also receive the events below. They drive product features that have no standard event (live rooms, Pro, boosts, categories, cosmetics) or give the clients a faster, smaller signal next to a standard event. Their payloads are shaped for the TEBHOS clients and can change without notice, so a bot SHOULD rely on the standard events above and ignore these. Each is subject to ignored_events.
| Event | Sent when | Main fields |
|---|---|---|
SERVER_UPDATED |
Next to every Guild Update | id, server_id, name, image_url, vanity_url |
SERVER_DELETED |
A guild is about to be deleted, to its members | server_id |
SERVER_OWNERSHIP_TRANSFERRED |
Guild ownership moved (a Guild Update follows) | server_id, new_owner_profile_id, previous_owner_profile_id |
CATEGORY_CREATED, CATEGORY_UPDATED, CATEGORY_DELETED |
A channel category changed through the category routes | server_id, id, plus name/position, or orphaned_channel_ids on delete |
PERMISSION_UPDATED |
A channel or category permission overwrite changed, to each user who can view it | server_id, parent, parent_id, override, deleted |
MEMBER_PERMISSION_RESYNC |
Next to Permission Updated, to the whole guild | server_id |
GUILD_MEMBER_ROLES_UPDATE |
A role was assigned to or removed from a member | guild_id, member_id, role_id, action |
MEMBER_KICKED |
A member was kicked | server_id, member_id, profile_id, kicked_name, kicker_name |
MEMBER_YOU_WERE_BANNED |
To the banned user | serverId, serverName, reason, expiresAt |
MEMBER_YOU_WERE_TIMED_OUT |
To the timed-out user | serverId, timeoutUntil |
MEMBER_TIMEOUT_UPDATED |
A member's timeout changed, to the guild | serverId, profileId, timeoutUntil |
PROFILE_UPDATE |
A user edited their profile, to their guilds and friends | profile_id, name, image_url, bio, and other profile fields |
USER_EQUIPPED_CHANGED |
The user changed an equipped cosmetic | profile_id, equipped |
NOTIFICATION_UPDATE |
Unread or mention totals changed | user_id, server_id, channel_id, server_total_unread, server_total_mention |
DM_SIDEBAR_UPDATE |
A private channel should move in the sidebar | channel_id |
DM_CHANNEL_UPDATED |
A group direct message's name or icon changed, to its recipients | The channel object |
AUTH_SESSION_CREATE |
A new login session was created for the account | user_id |
AUTH_SESSION_REVOKE |
One login session was revoked | session_id (hex hash) |
PREMIUM_UPDATE |
The account's TEBHOS Pro state changed after a payment | user_id, reason |
BUSINESS_ACTIVATED |
A guild's business plan became active, to its owner | guild_id, plan, until |
GUILD_BOOST_ADD |
A guild received a boost | guild_id, user_id, name |
CALL_RING |
The user is being rung for a private call | channel_id, call_id, initiator (id, name, image_url) |
CALL_STOP_RING |
Ringing stopped for a private call | channel_id, call_id, stopped_by, recipients |
GUILD_VOICE_STATE_UPDATE |
A voice state written through the older voice-state routes | user_id, server_id, channel_id, mute, deafen, and stream flags |
GUILD_VOICE_SERVER_MODERATE |
A moderator muted or deafened the user through the older voice-state routes | server_id, server_mute, server_deaf |
LIVE_ROOM_CHANGED |
A public live room opened, changed, or closed, to every connected user | action, room_id |
LIVE_ROOM_FRIEND_STARTED |
A friend opened a live room | Room summary with host details |
LIVE_ROOM_SPEAKER_PROMOTED, LIVE_ROOM_SPEAKER_DEMOTED |
A live room speaker changed | Room and speaker IDs |
LIVE_ROOM_POLL_CREATED, LIVE_ROOM_POLL_VOTE_UPDATED, LIVE_ROOM_POLL_ENDED |
A live room poll changed | Poll payload |
Resource representation¶
Every resource object named on this page has the representation defined by the HTTP API. A Dispatch payload with a resource object has the same fields, with the guild-scoped events adding guild_id and the message and reaction events adding member.
These reductions are specific to the Gateway. Ready strips user from each relationship and from each guild member and moves those accounts into its users array. The member added to a message event has its own user removed, and the account is in the message's author.