Gateways

Gateways are Discord's form of real-time communication over secure WebSockets. Clients will receive events and data over the gateway they are connected to and send data over the REST API. The API for interacting with Gateways is complex and fairly unforgiving, therefore it's highly recommended you read all of the following documentation before writing a custom implementation.

The Discord Gateway has a versioning system separate from the HTTP APIs. The documentation herein is only for the latest version in the following table, unless otherwise specified.

Important note: Not all event fields are documented, in particular, fields prefixed with an underscore are considered internal fields and should not be relied on. We may change the format at any time.

Gateway Versions
VersionStatus
9Available
8Available
7Doesn't look like anything to me
6Deprecated
5Discontinued
4Discontinued

Payloads

Gateway Payload Structure
FieldTypeDescription
opintegeropcode for the payload
d?mixed (any JSON value)event data
s?integer *sequence number, used for resuming sessions and heartbeats
t?string *the event name for this payload

* s and t are null when op is not 0 (Gateway Dispatch Opcode).

Sending Payloads

Packets sent from the client to the Gateway API are encapsulated within a gateway payload object and must have the proper opcode and data object set. The payload object can then be serialized in the format of choice (see ETF/JSON), and sent over the websocket. Payloads to the gateway are limited to a maximum of 4096 bytes sent, going over this will cause a connection termination with error code 4002.

Example Gateway Dispatch
json
{
"op": 0,
"d": {},
"s": 42,
"t": "GATEWAY_EVENT_NAME"
}

Receiving Payloads

Receiving payloads with the Gateway API is slightly more complex than sending. When using the JSON encoding with Payload Compression enabled, the Gateway has the option of sending payloads as compressed JSON binaries using zlib, meaning your library must detect (see RFC1950 2.2) and decompress these payloads before attempting to parse them. Otherwise the gateway does implement a shared compression context between messages sent, see Transport Compression.

Encoding and Compression

ETF/JSON

When initially creating and handshaking connections to the Gateway, a user can choose whether they wish to communicate over plain-text JSON or binary ETF.

Using ETF

While using ETF there are some additional constraints to note:

  • Snowflake IDs are transmitted as 64-bit integers over ETF.
  • The client must not send compressed messages to the server.
  • Payloads must use string keys, atom keys will lead to a 4002 decode error.

See erlpack for an ETF implementation example.

Payload Compression

When using JSON encoding with payload compression enabled (compress: true in identify), the Gateway may optionally send zlib-compressed payloads (see RFC1950 2.2). Your library must detect and decompress these payloads to plain-text JSON before attempting to parse them. If you are using payload compression, the gateway does not implement a shared compression context between messages sent. Payload compression will be disabled if you use transport compression (see below).

Transport Compression

Currently the only available transport compression option is zlib-stream. You will need to run all received packets through a shared zlib context, as seen in the example below. Every connection to the gateway should use its own unique zlib context.

Transport Compression Example
python
# Z_SYNC_FLUSH suffix
ZLIB_SUFFIX = b'\x00\x00\xff\xff'
# initialize a buffer to store chunks
buffer = bytearray()
# create a zlib inflation context to run chunks through
inflator = zlib.decompressobj()
# ...
def on_websocket_message(msg):
# always push the message data to your cache
buffer.extend(msg)
# check if the last four bytes are equal to ZLIB_SUFFIX
if len(msg) < 4 or msg[-4:] != ZLIB_SUFFIX:
return
# if the message *does* end with ZLIB_SUFFIX,
# get the full message by decompressing the buffers
# NOTE: the message is utf-8 encoded.
msg = inflator.decompress(buffer)
buffer = bytearray()
# here you can treat `msg` as either JSON or ETF encoded,
# depending on your `encoding` param

Connecting to the Gateway

Connecting

Gateway URL Query String Params
FieldTypeDescriptionAccepted Values
vintegerGateway Version to usesee Gateway versions
encodingstringThe encoding of received gateway packets'json' or 'etf'
compress?stringThe (optional) compression of gateway packets'zlib-stream'

The first step in establishing connectivity to the gateway is requesting a valid websocket endpoint from the API. This can be done through either the Get Gateway or the Get Gateway Bot endpoint.

With the resulting payload, you can now open a websocket connection to the "url" (or endpoint) specified. Generally, it is a good idea to explicitly pass the gateway version and encoding. For example, we may connect to wss://gateway.discord.gg/?v=9&encoding=json.

Once connected, the client should immediately receive an Opcode 10 Hello payload, with information on the connection's heartbeat interval:

Example Gateway Hello
json
{
"op": 10,
"d": {
"heartbeat_interval": 45000
}
}

Heartbeating

After receiving Opcode 10 Hello, the client may begin sending Opcode 1 Heartbeat payloads after heartbeat_interval * random.random() milliseconds, and every heartbeat_interval milliseconds thereafter. You may send heartbeats before this interval elapses, but you should avoid doing so unless necessary. There is already tolerance in the heartbeat_interval that will cover network latency, so you do not need to account for it in your own implementation - waiting the precise interval will suffice.

The gateway may request a heartbeat from the client in some situations by sending an Opcode 1 Heartbeat. When this occurs, the client should immediately send an Opcode 1 Heartbeat without waiting the remainder of the current interval.

Any time the client sends a heartbeat, the gateway will respond with Opcode 11 Heartbeat ACK, a successful acknowledgement of their last heartbeat:

Example Gateway Heartbeat ACK
json
{
"op": 11
}

If a client does not receive a heartbeat ack between its attempts at sending heartbeats, this may be due to a failed or "zombied" connection. The client should then immediately terminate the connection with a non-1000 close code, reconnect, and attempt to Resume.

Identifying

Next, the client is expected to send an Opcode 2 Identify:

Example Gateway Identify

This is a minimal IDENTIFY payload. IDENTIFY supports additional optional fields for other session properties, such as payload compression, or an initial presence state. See the Identify Structure for a more complete example of all options you can pass in.

json
{
"op": 2,
"d": {
"token": "my_token",
"intents": 513,
"properties": {
"$os": "linux",
"$browser": "my_library",
"$device": "my_library"
}
}
}

If the payload is valid, the gateway will respond with a Ready event. Your client is now considered in a "connected" state. Clients are limited by maximum concurrency when Identifying; if they exceed this limit, the gateway will respond with an Opcode 9 Invalid Session. It is important to note that although the ready event contains a large portion of the required initial state, some information (such as guilds and their members) is sent asynchronously (see Guild Create event).

Resuming

The Internet is a scary place. Disconnections happen, especially with persistent connections. Due to Discord's architecture, this is a semi-regular event and should be expected and handled. Discord has a process for "resuming" (or reconnecting) a connection that allows the client to replay any lost events from the last sequence number they received in the exact same way they would receive them normally.

Your client should store the session_id from the Ready, and the sequence number of the last event it received. When your client detects that it has been disconnected, it should completely close the connection and open a new one (following the same strategy as Connecting). Once the new connection has been opened, the client should send a Gateway Resume:

Example Gateway Resume
json
{
"op": 6,
"d": {
"token": "my_token",
"session_id": "session_id_i_stored",
"seq": 1337
}
}

If successful, the gateway will respond by replaying all missed events in order, finishing with a Resumed event to signal replay has finished, and all subsequent events are new. It's also possible that your client cannot reconnect in time to resume, in which case the client will receive a Opcode 9 Invalid Session and is expected to wait a random amount of time—between 1 and 5 seconds—then send a fresh Opcode 2 Identify.

Disconnections

If the gateway ever issues a disconnect to your client, it will provide a close event code that you can use to properly handle the disconnection. A full list of these close codes can be found in the Response Codes documentation.

When you close the connection to the gateway with the close code 1000 or 1001, your session will be invalidated and your bot will appear offline. If you simply close the TCP connection, or use a different close code, the bot session will remain active and timeout after a few minutes. This can be useful for a reconnect, which will resume the previous session.

Gateway Intents

Maintaining a stateful application can be difficult when it comes to the amount of data you're expected to process, especially at scale. Gateway Intents are a system to help you lower that computational burden.

When identifying to the gateway, you can specify an intents parameter which allows you to conditionally subscribe to pre-defined "intents", groups of events defined by Discord. If you do not specify a certain intent, you will not receive any of the gateway events that are batched into that group. The valid intents are:

List of Intents

GUILDS (1 << 0)
- GUILD_CREATE
- GUILD_UPDATE
- GUILD_DELETE
- GUILD_ROLE_CREATE
- GUILD_ROLE_UPDATE
- GUILD_ROLE_DELETE
- CHANNEL_CREATE
- CHANNEL_UPDATE
- CHANNEL_DELETE
- CHANNEL_PINS_UPDATE
- THREAD_CREATE
- THREAD_UPDATE
- THREAD_DELETE
- THREAD_LIST_SYNC
- THREAD_MEMBER_UPDATE
- THREAD_MEMBERS_UPDATE *
- STAGE_INSTANCE_CREATE
- STAGE_INSTANCE_UPDATE
- STAGE_INSTANCE_DELETE
GUILD_MEMBERS (1 << 1)
- GUILD_MEMBER_ADD
- GUILD_MEMBER_UPDATE
- GUILD_MEMBER_REMOVE
- THREAD_MEMBERS_UPDATE *
GUILD_BANS (1 << 2)
- GUILD_BAN_ADD
- GUILD_BAN_REMOVE
GUILD_EMOJIS_AND_STICKERS (1 << 3)
- GUILD_EMOJIS_UPDATE
- GUILD_STICKERS_UPDATE
GUILD_INTEGRATIONS (1 << 4)
- GUILD_INTEGRATIONS_UPDATE
- INTEGRATION_CREATE
- INTEGRATION_UPDATE
- INTEGRATION_DELETE
GUILD_WEBHOOKS (1 << 5)
- WEBHOOKS_UPDATE
GUILD_INVITES (1 << 6)
- INVITE_CREATE
- INVITE_DELETE
GUILD_VOICE_STATES (1 << 7)
- VOICE_STATE_UPDATE
GUILD_PRESENCES (1 << 8)
- PRESENCE_UPDATE
GUILD_MESSAGES (1 << 9)
- MESSAGE_CREATE
- MESSAGE_UPDATE
- MESSAGE_DELETE
- MESSAGE_DELETE_BULK
GUILD_MESSAGE_REACTIONS (1 << 10)
- MESSAGE_REACTION_ADD
- MESSAGE_REACTION_REMOVE
- MESSAGE_REACTION_REMOVE_ALL
- MESSAGE_REACTION_REMOVE_EMOJI
GUILD_MESSAGE_TYPING (1 << 11)
- TYPING_START
DIRECT_MESSAGES (1 << 12)
- MESSAGE_CREATE
- MESSAGE_UPDATE
- MESSAGE_DELETE
- CHANNEL_PINS_UPDATE
DIRECT_MESSAGE_REACTIONS (1 << 13)
- MESSAGE_REACTION_ADD
- MESSAGE_REACTION_REMOVE
- MESSAGE_REACTION_REMOVE_ALL
- MESSAGE_REACTION_REMOVE_EMOJI
DIRECT_MESSAGE_TYPING (1 << 14)
- TYPING_START

* Thread Members Update contains different data depending on which intents are used.

Caveats

Any events not defined in an intent are considered "passthrough" and will always be sent to you.

Guild Member Update is sent for current-user updates regardless of whether the GUILD_MEMBERS intent is set.

Guild Create and Request Guild Members are uniquely affected by intents. See these sections for more information.

Thread Members Update by default only includes if the current user was added to or removed from a thread. To receive these updates for other users, request the GUILD_MEMBERS Gateway Intent.

If you specify an intent value in your IDENTIFY payload that is invalid, the socket will close with a 4013 close code. An invalid intent is one that is not meaningful and not documented above.

If you specify an intent value in your IDENTIFY payload that is disallowed, the socket will close with a 4014 close code. A disallowed intent is a privileged intent that has not been approved for your bot.

Bots in under 100 guilds can enable these intents in the bot tab of the developer dashboard. Verified bots can get access to privileged intents when getting verified, or by writing into support after getting verified.

Privileged Intents

Some intents are defined as "Privileged" due to the sensitive nature of the data. Those intents are:

  • GUILD_PRESENCES
  • GUILD_MEMBERS

To specify these intents in your IDENTIFY payload, you must visit your application page in the Developer Portal and enable the toggle for each Privileged Intent that you wish to use. If your bot qualifies for verification, you must first verify your bot and request access to these intents during the verification process. If your bot is already verified and you need to request additional privileged intents, contact support.

Events under the GUILD_PRESENCES and GUILD_MEMBERS intents are turned off by default on all gateway versions. If you are using Gateway v6, you will receive those events if you are authorized to receive them and have enabled the intents in the Developer Portal. You do not need to use Intents on Gateway v6 to receive these events; you just need to enable the flags.

If you are using Gateway v8 or above, Intents are mandatory and must be specified when identifying.

In addition to the gateway restrictions described here, Discord's REST API is also affected by Privileged Intents. Specifically, to use the List Guild Members endpoint, you must have the GUILD_MEMBERS intent enabled for your application. This behavior is independent of whether the intent is set during IDENTIFY.

Rate Limiting

Clients are allowed to send 120 gateway commands every 60 seconds, meaning you can send an average of 2 commands per second. Clients who surpass this limit are immediately disconnected from the Gateway, and similarly to the HTTP API, repeat offenders will have their API access revoked. Clients also have a limit of concurrent Identify requests allowed per 5 seconds. If you hit this limit, the Gateway will respond with an Opcode 9 Invalid Session.

Tracking State

Most of a client's state is provided during the initial Ready event and the Guild Create events that immediately follow. As objects are further created/updated/deleted, other events are sent to notify the client of these changes and to provide the new or updated data. To avoid excessive API calls, Discord expects clients to locally cache as many relevant object states as possible, and to update them as gateway events are received.

An example of state tracking can be found with member status caching. When initially connecting to the gateway, the client receives information regarding the online status of guild members (online, idle, dnd, offline). To keep this state updated, a client must track and parse Presence Update events as they are received, and apply the provided data to the cached member objects.

For larger bots, client state can grow to be quite large. We recommend only storing objects in memory that are needed for a bot's operation. Many bots, for example, just respond to user input through chat commands. These bots may only need to keep guild information (like guild/channel roles and permissions) in memory, since MESSAGE_CREATE and MESSAGE_UPDATE events have the full member object available.

Guild Availability

When connecting to the gateway as a bot user, guilds that the bot is a part of will start out as unavailable. Don't fret! The gateway will automatically attempt to reconnect on your behalf. As guilds become available to you, you will receive Guild Create events.

Sharding

As bots grow and are added to an increasing number of guilds, some developers may find it necessary to break or split portions of their bots operations into separate logical processes. As such, Discord gateways implement a method of user-controlled guild sharding which allows for splitting events across a number of gateway connections. Guild sharding is entirely user controlled, and requires no state-sharing between separate connections to operate.

To enable sharding on a connection, the user should send the shard array in the Identify payload. The first item in this array should be the zero-based integer value of the current shard, while the second represents the total number of shards. DMs will only be sent to shard 0. To calculate what events will be sent to what shard, the following formula can be used:

Sharding Formula
python
shard_id = (guild_id >> 22) % num_shards

As an example, if you wanted to split the connection between three shards, you'd use the following values for shard for each connection: [0, 3], [1, 3], and [2, 3]. Note that only the first shard ([0, 3]) would receive DMs.

Note that num_shards does not relate to, or limit, the total number of potential sessions—it is only used for routing traffic. As such, sessions do not have to be identified in an evenly distributed manner when sharding. You can establish multiple sessions with the same [shard_id, num_shards], or sessions with different num_shards values. This allows you to create sessions that will handle more or less traffic than others for more fine-tuned load balancing, or orchestrate "zero-downtime" scaling/updating by handing off traffic to a new deployment of sessions with a higher or lower num_shards count that are prepared in parallel.

Max Concurrency

If you have multiple shards, you may start them concurrently based on the max_concurrency value returned to you on session start. Which shards you can start concurrently are assigned based on a key for each shard. The rate limit key for a given shard can be computed with

rate_limit_key = shard_id % max_concurrency

This puts your shards into "buckets" of max_concurrency size. When you start your bot, you may start up to max_concurrency shards at a time, and you must start them by "bucket" in order. To explain another way, let's say you have 16 shards, and your max_concurrency is 16:

shard_id: 0, rate limit key (0 % 16): 0
shard_id: 1, rate limit key (1 % 16): 1
shard_id: 2, rate limit key (2 % 16): 2
shard_id: 3, rate limit key (3 % 16): 3
shard_id: 4, rate limit key (4 % 16): 4
shard_id: 5, rate limit key (5 % 16): 5
shard_id: 6, rate limit key (6 % 16): 6
shard_id: 7, rate limit key (7 % 16): 7
shard_id: 8, rate limit key (8 % 16): 8
shard_id: 9, rate limit key (9 % 16): 9
shard_id: 10, rate limit key (10 % 16): 10
shard_id: 11, rate limit key (11 % 16): 11
shard_id: 12, rate limit key (12 % 16): 12
shard_id: 13, rate limit key (13 % 16): 13
shard_id: 14, rate limit key (14 % 16): 14
shard_id: 15, rate limit key (15 % 16): 15

You may start all 16 of your shards at once, because each has a rate_limit_key which fills the bucket of 16 shards. However, let's say you had 32 shards:

shard_id: 0, rate limit key (0 % 16): 0
shard_id: 1, rate limit key (1 % 16): 1
shard_id: 2, rate limit key (2 % 16): 2
shard_id: 3, rate limit key (3 % 16): 3
shard_id: 4, rate limit key (4 % 16): 4
shard_id: 5, rate limit key (5 % 16): 5
shard_id: 6, rate limit key (6 % 16): 6
shard_id: 7, rate limit key (7 % 16): 7
shard_id: 8, rate limit key (8 % 16): 8
shard_id: 9, rate limit key (9 % 16): 9
shard_id: 10, rate limit key (10 % 16): 10
shard_id: 11, rate limit key (11 % 16): 11
shard_id: 12, rate limit key (12 % 16): 12
shard_id: 13, rate limit key (13 % 16): 13
shard_id: 14, rate limit key (14 % 16): 14
shard_id: 15, rate limit key (15 % 16): 15
shard_id: 16, rate limit key (16 % 16): 0
shard_id: 17, rate limit key (17 % 16): 1
shard_id: 18, rate limit key (18 % 16): 2
shard_id: 19, rate limit key (19 % 16): 3
shard_id: 20, rate limit key (20 % 16): 4
shard_id: 21, rate limit key (21 % 16): 5
shard_id: 22, rate limit key (22 % 16): 6
shard_id: 23, rate limit key (23 % 16): 7
shard_id: 24, rate limit key (24 % 16): 8
shard_id: 25, rate limit key (25 % 16): 9
shard_id: 26, rate limit key (26 % 16): 10
shard_id: 27, rate limit key (27 % 16): 11
shard_id: 28, rate limit key (28 % 16): 12
shard_id: 29, rate limit key (29 % 16): 13
shard_id: 30, rate limit key (30 % 16): 14
shard_id: 31, rate limit key (31 % 16): 15

In this case, you must start the shard buckets in "order". That means that you can start shard 0 -> shard 15 concurrently, and then you can start shard 16 -> shard 31.

Sharding for Very Large Bots

If you own a bot that is near or in over 150,000 guilds, there are some additional considerations you must take around sharding. Please file a support-ticket to get moved to the sharding for big bots, when you reach near this amount of servers. You can contact the discord support using https://dis.gd/contact.

The number of shards you run must be a multiple of a fixed number we will determine when reaching out to you. If you attempt to start your bot with an invalid number of shards, your websocket connection will close with a 4010 Invalid Shard opcode. The gateway bot bootstrap endpoint will return the correct amount of shards, so if you're already using this endpoint to determine your number of shards, you shouldn't require any further changes.

The session start limit for these bots will also be increased from 1000 to max(2000, (guild_count / 1000) * 3) per day. You also receive an increased max_concurrency, the number of shards you can concurrently start.

Finally, the Get Current User Guilds endpoint will no longer return results for your bot. We will be creating a new endpoint that is more shard-aware to iterate through your bot's guilds if needed.

Commands and Events

Commands are requests made to the gateway socket by a client.

Gateway Commands
namedescription
Identifytriggers the initial handshake with the gateway
Resumeresumes a dropped gateway connection
Heartbeatmaintains an active gateway connection
Request Guild Membersrequests members for a guild
Update Voice Statejoins, moves, or disconnects the client from a voice channel
Update Presenceupdates a client's presence

Events are payloads sent over the socket to a client that correspond to events in Discord.

Gateway Events
namedescription
Hellodefines the heartbeat interval
Readycontains the initial state information
Resumedresponse to Resume
Reconnectserver is going away, client should reconnect to gateway and resume
Invalid Sessionfailure response to Identify or Resume or invalid active session
Channel Createnew guild channel created
Channel Updatechannel was updated
Channel Deletechannel was deleted
Channel Pins Updatemessage was pinned or unpinned
Thread Createthread created, also sent when being added to a private thread
Thread Updatethread was updated
Thread Deletethread was deleted
Thread List Syncsent when gaining access to a channel, contains all active threads in that channel
Thread Member Updatethread member for the current user was updated
Thread Members Updatesome user(s) were added to or removed from a thread
Guild Createlazy-load for unavailable guild, guild became available, or user joined a new guild
Guild Updateguild was updated
Guild Deleteguild became unavailable, or user left/was removed from a guild
Guild Ban Adduser was banned from a guild
Guild Ban Removeuser was unbanned from a guild
Guild Emojis Updateguild emojis were updated
Guild Stickers Updateguild stickers were updated
Guild Integrations Updateguild integration was updated
Guild Member Addnew user joined a guild
Guild Member Removeuser was removed from a guild
Guild Member Updateguild member was updated
Guild Members Chunkresponse to Request Guild Members
Guild Role Createguild role was created
Guild Role Updateguild role was updated
Guild Role Deleteguild role was deleted
Integration Createguild integration was created
Integration Updateguild integration was updated
Integration Deleteguild integration was deleted
Interaction Createuser used an interaction, such as an Application Command
Invite Createinvite to a channel was created
Invite Deleteinvite to a channel was deleted
Message Createmessage was created
Message Updatemessage was edited
Message Deletemessage was deleted
Message Delete Bulkmultiple messages were deleted at once
Message Reaction Adduser reacted to a message
Message Reaction Removeuser removed a reaction from a message
Message Reaction Remove Allall reactions were explicitly removed from a message
Message Reaction Remove Emojiall reactions for a given emoji were explicitly removed from a message
Presence Updateuser was updated
Stage Instance Createstage instance was created
Stage Instance Deletestage instance was deleted or closed
Stage Instance Updatestage instance was updated
Typing Startuser started typing in a channel
User Updateproperties about the user changed
Voice State Updatesomeone joined, left, or moved a voice channel
Voice Server Updateguild's voice server was updated
Webhooks Updateguild channel webhook was created, update, or deleted

Event Names

Event names are in standard constant form, fully upper-cased and replacing all spaces with underscores. For instance, Channel Create would be CHANNEL_CREATE and Voice State Update would be VOICE_STATE_UPDATE. Within the following documentation, they have been left in standard English form to aid in readability.

Identify

Used to trigger the initial handshake with the gateway.

Identify Structure
FieldTypeDescriptionDefault
tokenstringauthentication token-
propertiesobjectconnection properties-
compress?booleanwhether this connection supports compression of packetsfalse
large_threshold?integervalue between 50 and 250, total number of members where the gateway will stop sending offline members in the guild member list50
shard?array of two integers (shard_id, num_shards)used for Guild Sharding-
presence?update presence objectpresence structure for initial presence information-
intentsintegerthe Gateway Intents you wish to receive-
Identify Connection Properties
FieldTypeDescription
\$osstringyour operating system
\$browserstringyour library name
\$devicestringyour library name
Example Identify
json
{
"op": 2,
"d": {
"token": "my_token",
"properties": {
"$os": "linux",
"$browser": "disco",
"$device": "disco"
},
"compress": true,
"large_threshold": 250,
"shard": [0, 1],
"presence": {
"activities": [
{
"name": "Cards Against Humanity",
"type": 0
}
],
"status": "dnd",
"since": 91879201,
"afk": false
},
// This intent represents 1 << 0 for GUILDS, 1 << 1 for GUILD_MEMBERS, and 1 << 2 for GUILD_BANS
// This connection will only receive the events defined in those three intents
"intents": 7
}
}

Resume

Used to replay missed events when a disconnected client resumes.

Resume Structure
FieldTypeDescription
tokenstringsession token
session_idstringsession id
seqintegerlast sequence number received
Example Resume
json
{
"op": 6,
"d": {
"token": "randomstring",
"session_id": "evenmorerandomstring",
"seq": 1337
}
}

Heartbeat

Used to maintain an active gateway connection. Must be sent every heartbeat_interval milliseconds after the Opcode 10 Hello payload is received. The inner d key is the last sequence number—s—received by the client. If you have not yet received one, send null.

Example Heartbeat
{
"op": 1,
"d": 251
}

Request Guild Members

Used to request all members for a guild or a list of guilds. When initially connecting, if you don't have the GUILD_PRESENCES Gateway Intent, or if the guild is over 75k members, it will only send members who are in voice, plus the member for you (the connecting user). Otherwise, if a guild has over large_threshold members (value in the Gateway Identify), it will only send members who are online, have a role, have a nickname, or are in a voice channel, and if it has under large_threshold members, it will send all members. If a client wishes to receive additional members, they need to explicitly request them via this operation. The server will send Guild Members Chunk events in response with up to 1000 members per chunk until all members that match the request have been sent.

Due to our privacy and infrastructural concerns with this feature, there are some limitations that apply:

  • GUILD_PRESENCES intent is required to set presences = true. Otherwise, it will always be false
  • GUILD_MEMBERS intent is required to request the entire member list—(query=‘’, limit=0<=n)
  • You will be limited to requesting 1 guild_id per request
  • Requesting a prefix (query parameter) will return a maximum of 100 members
  • Requesting user_ids will continue to be limited to returning 100 members
Guild Request Members Structure
FieldTypeDescriptionRequired
guild_idsnowflakeid of the guild to get members fortrue
query?stringstring that username starts with, or an empty string to return all membersone of query or user_ids
limitintegermaximum number of members to send matching the query; a limit of 0 can be used with an empty string query to return all memberstrue when specifying query
presences?booleanused to specify if we want the presences of the matched membersfalse
user_ids?snowflake or array of snowflakesused to specify which users you wish to fetchone of query or user_ids
nonce?stringnonce to identify the Guild Members Chunk responsefalse
Guild Request Members
json
{
"op": 8,
"d": {
"guild_id": "41771983444115456",
"query": "",
"limit": 0
}
}

Update Voice State

Sent when a client wants to join, move, or disconnect from a voice channel.

Gateway Voice State Update Structure
FieldTypeDescription
guild_idsnowflakeid of the guild
channel_id?snowflakeid of the voice channel client wants to join (null if disconnecting)
self_mutebooleanis the client muted
self_deafbooleanis the client deafened
Example Gateway Voice State Update
json
{
"op": 4,
"d": {
"guild_id": "41771983423143937",
"channel_id": "127121515262115840",
"self_mute": false,
"self_deaf": false
}
}

Update Presence

Sent by the client to indicate a presence or status update.

Gateway Presence Update Structure
FieldTypeDescription
since?integerunix time (in milliseconds) of when the client went idle, or null if the client is not idle
activitiesarray of activity objectsthe user's activities
statusstringthe user's new status
afkbooleanwhether or not the client is afk
Status Types
StatusDescription
onlineOnline
dndDo Not Disturb
idleAFK
invisibleInvisible and shown as offline
offlineOffline
Example Gateway Presence Update
json
{
"op": 3,
"d": {
"since": 91879201,
"activities": [
{
"name": "Save the Oxford Comma",
"type": 0
}
],
"status": "online",
"afk": false
}
}

Connecting and Resuming

Hello

Sent on connection to the websocket. Defines the heartbeat interval that the client should heartbeat to.

Hello Structure
FieldTypeDescription
heartbeat_intervalintegerthe interval (in milliseconds) the client should heartbeat with
Example Hello
json
{
"op": 10,
"d": {
"heartbeat_interval": 45000
}
}

Ready

The ready event is dispatched when a client has completed the initial handshake with the gateway (for new sessions). The ready event can be the largest and most complex event the gateway will send, as it contains all the state required for a client to begin interacting with the rest of the platform.

guilds are the guilds of which your bot is a member. They start out as unavailable when you connect to the gateway. As they become available, your bot will be notified via Guild Create events.

Ready Event Fields
FieldTypeDescription
vintegergateway version
useruser objectinformation about the user including email
guildsarray of Unavailable Guild objectsthe guilds the user is in
session_idstringused for resuming connections
shard?array of two integers (shard_id, num_shards)the shard information associated with this session, if sent when identifying
applicationpartial application objectcontains id and flags

Resumed

The resumed event is dispatched when a client has sent a resume payload to the gateway (for resuming existing sessions).

Reconnect

The reconnect event is dispatched when a client should reconnect to the gateway (and resume their existing session, if they have one). This event usually occurs during deploys to migrate sessions gracefully off old hosts.

Example Gateway Reconnect
json
{
"op": 7,
"d": null
}

Invalid Session

Sent to indicate one of at least three different situations:

  • the gateway could not initialize a session after receiving an Opcode 2 Identify
  • the gateway could not resume a previous session after receiving an Opcode 6 Resume
  • the gateway has invalidated an active session and is requesting client action

The inner d key is a boolean that indicates whether the session may be resumable. See Connecting and Resuming for more information.

Example Gateway Invalid Session
json
{
"op": 9,
"d": false
}

Channels

Channel Create

Sent when a new guild channel is created, relevant to the current user. The inner payload is a channel object.

Channel Update

Sent when a channel is updated. The inner payload is a channel object. This is not sent when the field last_message_id is altered. To keep track of the last_message_id changes, you must listen for Message Create events.

Channel Delete

Sent when a channel relevant to the current user is deleted. The inner payload is a channel object.

Thread Create

Sent when a thread is created, relevant to the current user, or when the current user is added to a thread. The inner payload is a channel object. When being added to an existing private thread, includes a thread member object.

Thread Update

Sent when a thread is updated. The inner payload is a channel object. This is not sent when the field last_message_id is altered. To keep track of the last_message_id changes, you must listen for Message Create events.

Thread Delete

Sent when a thread relevant to the current user is deleted. The inner payload is a subset of the channel object, containing just the id, guild_id, parent_id, and type fields.

Thread List Sync

Sent when the current user gains access to a channel.

Thread List Sync Event Fields
FieldTypeDescription
guild_idsnowflakethe id of the guild
channel_ids?array of snowflakesthe parent channel ids whose threads are being synced. If omitted, then threads were synced for the entire guild. This array may contain channel_ids that have no active threads as well, so you know to clear that data.
threadsarray of channel objectsall active threads in the given channels that the current user can access
membersarray of thread member objectsall thread member objects from the synced threads for the current user, indicating which threads the current user has been added to

Thread Member Update

Sent when the thread member object for the current user is updated. The inner payload is a thread member object. This event is documented for completeness, but unlikely to be used by most bots. For bots, this event largely is just a signal that you are a member of the thread. See the threads docs for more details.

Thread Members Update

Sent when anyone is added to or removed from a thread. If the current user does not have the GUILD_MEMBERS Gateway Intent, then this event will only be sent if the current user was added to or removed from the thread.

Thread Members Update Event Fields
FieldTypeDescription
idsnowflakethe id of the thread
guild_idsnowflakethe id of the guild
member_countintegerthe approximate number of members in the thread, capped at 50
added_members?*array of thread member objectsthe users who were added to the thread
removed_member_ids?array of snowflakesthe id of the users who were removed from the thread

* In this gateway event, the thread member objects will also include the guild member and nullable presence objects for each added thread member.

Channel Pins Update

Sent when a message is pinned or unpinned in a text channel. This is not sent when a pinned message is deleted.

Channel Pins Update Event Fields
FieldTypeDescription
guild_id?snowflakethe id of the guild
channel_idsnowflakethe id of the channel
last_pin_timestamp??ISO8601 timestampthe time at which the most recent pinned message was pinned

Guilds

Guild Create

This event can be sent in three different scenarios:

  1. When a user is initially connecting, to lazily load and backfill information for all unavailable guilds sent in the Ready event. Guilds that are unavailable due to an outage will send a Guild Delete event.
  2. When a Guild becomes available again to the client.
  3. When the current user joins a new Guild.

The inner payload is a guild object, with all the extra fields specified.

Guild Update

Sent when a guild is updated. The inner payload is a guild object.

Guild Delete

Sent when a guild becomes or was already unavailable due to an outage, or when the user leaves or is removed from a guild. The inner payload is an unavailable guild object. If the unavailable field is not set, the user was removed from the guild.

Guild Ban Add

Sent when a user is banned from a guild.

Guild Ban Add Event Fields
FieldTypeDescription
guild_idsnowflakeid of the guild
usera user objectthe banned user

Guild Ban Remove

Sent when a user is unbanned from a guild.

Guild Ban Remove Event Fields
FieldTypeDescription
guild_idsnowflakeid of the guild
usera user objectthe unbanned user

Guild Emojis Update

Sent when a guild's emojis have been updated.

Guild Emojis Update Event Fields
FieldTypeDescription
guild_idsnowflakeid of the guild
emojisarrayarray of emojis

Guild Stickers Update

Sent when a guild's stickers have been updated.

Guild Stickers Update Event Fields
FieldTypeDescription
guild_idsnowflakeid of the guild
stickersarrayarray of stickers

Guild Integrations Update

Sent when a guild integration is updated.

Guild Integrations Update Event Fields
FieldTypeDescription
guild_idsnowflakeid of the guild whose integrations were updated

Guild Member Add

Sent when a new user joins a guild. The inner payload is a guild member object with an extra guild_id key:

Guild Member Add Extra Fields
FieldTypeDescription
guild_idsnowflakeid of the guild

Guild Member Remove

Sent when a user is removed from a guild (leave/kick/ban).

Guild Member Remove Event Fields
FieldTypeDescription
guild_idsnowflakethe id of the guild
usera user objectthe user who was removed

Guild Member Update

Sent when a guild member is updated. This will also fire when the user object of a guild member changes.

Guild Member Update Event Fields
FieldTypeDescription
guild_idsnowflakethe id of the guild
rolesarray of snowflakesuser role ids
usera user objectthe user
nick??stringnickname of the user in the guild
joined_at?ISO8601 timestampwhen the user joined the guild
premium_since??ISO8601 timestampwhen the user starting boosting the guild
deaf?booleanwhether the user is deafened in voice channels
mute?booleanwhether the user is muted in voice channels
pending?booleanwhether the user has not yet passed the guild's Membership Screening requirements

Guild Members Chunk

Sent in response to Guild Request Members. You can use the chunk_index and chunk_count to calculate how many chunks are left for your request.

Guild Members Chunk Event Fields
FieldTypeDescription
guild_idsnowflakethe id of the guild
membersarray of guild member objectsset of guild members
chunk_indexintegerthe chunk index in the expected chunks for this response (0 <= chunk_index < chunk_count)
chunk_countintegerthe total number of expected chunks for this response
not_found?arrayif passing an invalid id to REQUEST_GUILD_MEMBERS, it will be returned here
presences?array of presence objectsif passing true to REQUEST_GUILD_MEMBERS, presences of the returned members will be here
nonce?stringthe nonce used in the Guild Members Request

Guild Role Create

Sent when a guild role is created.

Guild Role Create Event Fields
FieldTypeDescription
guild_idsnowflakethe id of the guild
rolea role objectthe role created

Guild Role Update

Sent when a guild role is updated.

Guild Role Update Event Fields
FieldTypeDescription
guild_idsnowflakethe id of the guild
rolea role objectthe role updated

Guild Role Delete

Sent when a guild role is deleted.

Guild Role Delete Event Fields
FieldTypeDescription
guild_idsnowflakeid of the guild
role_idsnowflakeid of the role

Integrations

Integration Create

Sent when an integration is created. The inner payload is a integration object with an additional guild_id key:

Integration Create Event Additional Fields
FieldTypeDescription
guild_idsnowflakeid of the guild

Integration Update

Sent when an integration is updated. The inner payload is a integration object with an additional guild_id key:

Integration Update Event Additional Fields
FieldTypeDescription
guild_idsnowflakeid of the guild

Integration Delete

Sent when an integration is deleted.

Integration Delete Event Fields
FieldTypeDescription
idsnowflakeintegration id
guild_idsnowflakeid of the guild
application_id?snowflakeid of the bot/OAuth2 application for this discord integration

Invites

Invite Create

Sent when a new invite to a channel is created.

Invite Create Event Fields
FieldTypeDescription
channel_idsnowflakethe channel the invite is for
codestringthe unique invite code
created_atISO8601 timestampthe time at which the invite was created
guild_id?snowflakethe guild of the invite
inviter?user objectthe user that created the invite
max_ageintegerhow long the invite is valid for (in seconds)
max_usesintegerthe maximum number of times the invite can be used
target_type?integerthe type of target for this voice channel invite
target_user?user objectthe user whose stream to display for this voice channel stream invite
target_application?partial application objectthe embedded application to open for this voice channel embedded application invite
temporarybooleanwhether or not the invite is temporary (invited users will be kicked on disconnect unless they're assigned a role)
usesintegerhow many times the invite has been used (always will be 0)

Invite Delete

Sent when an invite is deleted.

Invite Delete Event Fields
FieldTypeDescription
channel_idsnowflakethe channel of the invite
guild_id?snowflakethe guild of the invite
codestringthe unique invite code

Messages

Message Create

Sent when a message is created. The inner payload is a message object.

Message Update

Sent when a message is updated. The inner payload is a message object.

Message Delete

Sent when a message is deleted.

Message Delete Event Fields
FieldTypeDescription
idsnowflakethe id of the message
channel_idsnowflakethe id of the channel
guild_id?snowflakethe id of the guild

Message Delete Bulk

Sent when multiple messages are deleted at once.

Message Delete Bulk Event Fields
FieldTypeDescription
idsarray of snowflakesthe ids of the messages
channel_idsnowflakethe id of the channel
guild_id?snowflakethe id of the guild

Message Reaction Add

Sent when a user adds a reaction to a message.

Message Reaction Add Event Fields
FieldTypeDescription
user_idsnowflakethe id of the user
channel_idsnowflakethe id of the channel
message_idsnowflakethe id of the message
guild_id?snowflakethe id of the guild
member?member objectthe member who reacted if this happened in a guild
emojia partial emoji objectthe emoji used to react - example

Message Reaction Remove

Sent when a user removes a reaction from a message.

Message Reaction Remove Event Fields
FieldTypeDescription
user_idsnowflakethe id of the user
channel_idsnowflakethe id of the channel
message_idsnowflakethe id of the message
guild_id?snowflakethe id of the guild
emojia partial emoji objectthe emoji used to react - example

Message Reaction Remove All

Sent when a user explicitly removes all reactions from a message.

Message Reaction Remove All Event Fields
FieldTypeDescription
channel_idsnowflakethe id of the channel
message_idsnowflakethe id of the message
guild_id?snowflakethe id of the guild

Message Reaction Remove Emoji

Sent when a bot removes all instances of a given emoji from the reactions of a message.

Message Reaction Remove Emoji
FieldTypeDescription
channel_idsnowflakethe id of the channel
guild_id?snowflakethe id of the guild
message_idsnowflakethe id of the message
emojipartial emoji objectthe emoji that was removed

Presence

Presence Update

A user's presence is their current state on a guild. This event is sent when a user's presence or info, such as name or avatar, is updated.

Presence Update Event Fields
FieldTypeDescription
useruser objectthe user presence is being updated for
guild_idsnowflakeid of the guild
statusstringeither "idle", "dnd", "online", or "offline"
activitiesarray of activity objectsuser's current activities
client_statusclient_status objectuser's platform-dependent status

Client Status Object

Active sessions are indicated with an "online", "idle", or "dnd" string per platform. If a user is offline or invisible, the corresponding field is not present.

FieldTypeDescription
desktop?stringthe user's status set for an active desktop (Windows, Linux, Mac) application session
mobile?stringthe user's status set for an active mobile (iOS, Android) application session
web?stringthe user's status set for an active web (browser, bot account) application session

Activity Object

Activity Structure
FieldTypeDescription
namestringthe activity's name
typeintegeractivity type
url??stringstream url, is validated when type is 1
created_atintegerunix timestamp (in milliseconds) of when the activity was added to the user's session
timestamps?timestamps objectunix timestamps for start and/or end of the game
application_id?snowflakeapplication id for the game
details??stringwhat the player is currently doing
state??stringthe user's current party status
emoji??emoji objectthe emoji used for a custom status
party?party objectinformation for the current party of the player
assets?assets objectimages for the presence and their hover texts
secrets?secrets objectsecrets for Rich Presence joining and spectating
instance?booleanwhether or not the activity is an instanced game session
flags?integeractivity flags ORd together, describes what the payload includes
buttons?array of buttonsthe custom buttons shown in the Rich Presence (max 2)
Activity Types
IDNameFormatExample
0GamePlaying {name}"Playing Rocket League"
1StreamingStreaming {details}"Streaming Rocket League"
2ListeningListening to {name}"Listening to Spotify"
3WatchingWatching {name}"Watching YouTube Together"
4Custom{emoji} {name}":smiley: I am cool"
5CompetingCompeting in {name}"Competing in Arena World Champions"
Activity Timestamps
FieldTypeDescription
start?integerunix time (in milliseconds) of when the activity started
end?integerunix time (in milliseconds) of when the activity ends
Activity Emoji
FieldTypeDescription
namestringthe name of the emoji
id?snowflakethe id of the emoji
animated?booleanwhether this emoji is animated
Activity Party
FieldTypeDescription
id?stringthe id of the party
size?array of two integers (current_size, max_size)used to show the party's current and maximum size
Activity Assets
FieldTypeDescription
large_image?stringthe id for a large asset of the activity, usually a snowflake
large_text?stringtext displayed when hovering over the large image of the activity
small_image?stringthe id for a small asset of the activity, usually a snowflake
small_text?stringtext displayed when hovering over the small image of the activity
Activity Secrets
FieldTypeDescription
join?stringthe secret for joining a party
spectate?stringthe secret for spectating a game
match?stringthe secret for a specific instanced match
Activity Flags
NameValue
INSTANCE1 << 0
JOIN1 << 1
SPECTATE1 << 2
JOIN_REQUEST1 << 3
SYNC1 << 4
PLAY1 << 5
Activity Buttons

When received over the gateway, the buttons field is an array of strings, which are the button labels. Bots cannot access a user's activity button URLs. When sending, the buttons field must be an array of the below object:

FieldTypeDescription
labelstringthe text shown on the button (1-32 characters)
urlstringthe url opened when clicking the button (1-512 characters)
Example Activity
json
{
"details": "24H RL Stream for Charity",
"state": "Rocket League",
"name": "Twitch",
"type": 1,
"url": "https://www.twitch.tv/discord"
}
Example Activity with Rich Presence
json
{
"name": "Rocket League",
"type": 0,
"application_id": "379286085710381999",
"state": "In a Match",
"details": "Ranked Duos: 2-1",
"timestamps": {
"start": 15112000660000
},
"party": {
"id": "9dd6594e-81b3-49f6-a6b5-a679e6a060d3",
"size": [2, 2]
},
"assets": {
"large_image": "351371005538729000",
"large_text": "DFH Stadium",
"small_image": "351371005538729111",
"small_text": "Silver III"
},
"secrets": {
"join": "025ed05c71f639de8bfaa0d679d7c94b2fdce12f",
"spectate": "e7eb30d2ee025ed05c71ea495f770b76454ee4e0",
"match": "4b2fdce12f639de8bfa7e3591b71a0d679d7c93f"
}
}

Typing Start

Sent when a user starts typing in a channel.

Typing Start Event Fields
FieldTypeDescription
channel_idsnowflakeid of the channel
guild_id?snowflakeid of the guild
user_idsnowflakeid of the user
timestampintegerunix time (in seconds) of when the user started typing
member?member objectthe member who started typing if this happened in a guild

User Update

Sent when properties about the user change. Inner payload is a user object.

Voice

Voice State Update

Sent when someone joins/leaves/moves voice channels. Inner payload is a voice state object.

Voice Server Update

Sent when a guild's voice server is updated. This is sent when initially connecting to voice, and when the current voice instance fails over to a new server.

Voice Server Update Event Fields
FieldTypeDescription
tokenstringvoice connection token
guild_idsnowflakethe guild this voice server update is for
endpoint?stringthe voice server host
Example Voice Server Update Payload
json
{
"token": "my_token",
"guild_id": "41771983423143937",
"endpoint": "smart.loyal.discord.gg"
}

Webhooks

Webhooks Update

Sent when a guild channel's webhook is created, updated, or deleted.

Webhook Update Event Fields
FieldTypeDescription
guild_idsnowflakeid of the guild
channel_idsnowflakeid of the channel

Interactions

Interaction Create

Sent when a user in a guild uses an Application Command. Inner payload is an Interaction.

Stage Instances

Stage Instance Create

Sent when a Stage instance is created (i.e. the stage is now "live"). inner payload is a stage instance

Stage Instance Update

Sent when a Stage instance has been updated. inner payload is a stage instance

Stage Instance Delete

Sent when a Stage instance has been deleted (i.e. the stage has been closed). inner payload is a stage instance

Get Gateway

GET/gateway

Returns an object with a single valid WSS URL, which the client can use for Connecting. Clients should cache this value and only call this endpoint to retrieve a new URL if they are unable to properly establish a connection using the cached version of the URL.

Example Response
json
{
"url": "wss://gateway.discord.gg/"
}

Get Gateway Bot

GET/gateway/bot

Returns an object based on the information in Get Gateway, plus additional metadata that can help during the operation of large or sharded bots. Unlike the Get Gateway, this route should not be cached for extended periods of time as the value is not guaranteed to be the same per-call, and changes as the bot joins/leaves guilds.

JSON Response
FieldTypeDescription
urlstringThe WSS URL that can be used for connecting to the gateway
shardsintegerThe recommended number of shards to use when connecting
session_start_limitsession_start_limit objectInformation on the current session start limit
Example Response
json
{
"url": "wss://gateway.discord.gg/",
"shards": 9,
"session_start_limit": {
"total": 1000,
"remaining": 999,
"reset_after": 14400000,
"max_concurrency": 1
}
}

Session Start Limit Object

Session Start Limit Structure
FieldTypeDescription
totalintegerThe total number of session starts the current user is allowed
remainingintegerThe remaining number of session starts the current user is allowed
reset_afterintegerThe number of milliseconds after which the limit resets
max_concurrencyintegerThe number of identify requests allowed per 5 seconds