In most cases, performing REST operations on Discord resources can be done using the HTTP API rather than the Gateway API.
Gateway Events
Gateway events are payloads sent over a Gateway connection—either from an app to Discord, or from Discord to an app. An app typically sends events when connecting and managing its connection to the Gateway, and receives events when listening to actions taking place in a server. All Gateway events are encapsulated in a Gateway event payload. A full list of Gateway events and their details are in the Gateway events documentation.Example Gateway Event
Sending Events
When sending a Gateway event (like when performing an initial handshake or updating presence), your app must send an event payload object with a valid opcode (op) and inner data object (d).
Specific rate limits are applied when sending events, which you can read about in the Rate Limiting section.
- Must be serialized in plain-text JSON or binary ETF.
- Must not exceed 4096 bytes. If an event payload does exceed 4096 bytes, the connection will be closed with a 4002close event code.
Receiving Events
Receiving a Gateway event from Discord (like when a reaction is added to a message) is much more common (and slightly more complex) than sending them. While some events are sent to your app automatically, most events require your app to define intents when Identifying. Intents are bitwise values that can be ORed (|) to indicate which events (or groups of events) you want Discord to send your app. A list of intents and their corresponding events are listed in the intents section.
When receiving events, you can also configure how events will be sent to your app, like the encoding and compression, or whether sharding should be enabled).
All events that your app can receive via a connection are in the Gateway event documentation.
Dispatch Events
Dispatch (opcode0) events are the most common type of event your app will receive. Most Gateway events which represent actions taking place in a guild will be sent to your app as Dispatch events.
When your app is parsing a Dispatch event:
- The tfield can be used to determine which Gateway event the payload represents the data you can expect in thedfield.
- The sfield represents the sequence number of the event, which is the relative order in which it occurred. You need to cache the most recent non-nullsvalue for heartbeats, and to pass when Resuming a connection.
Connections
Gateway connections are persistent WebSockets which introduce more complexity than sending HTTP requests or responding to interactions (like Slash Commands). When interacting with the Gateway, your app must know how to open the initial connection, as well as maintain it and handle any disconnects.Connection Lifecycle
There are nuances that aren’t included in the overview below. More details about each step and event can be found in the individual sections below.
- App establishes a connection with the Gateway after fetching and caching a WSS URL using the Get Gateway or Get Gateway Bot endpoint.
- Discord sends the app a Hello (opcode 10) event containing a heartbeat interval in milliseconds. Read the section on Connecting
- Start the Heartbeat interval. App must send a Heartbeat (opcode 1) event, then continue to send them every heartbeat interval until the connection is closed. Read the section on Sending Heartbeats- Discord will respond to each Heartbeat event with a Heartbeat ACK (opcode 11) event to confirm it was received. If an app doesn’t receive a Heartbeat ACK, it should close the connection and reconnect.
- Discord may send the app a Heartbeat (opcode 1) event, in which case the app should send a Heartbeat event immediately.
 
- Discord will respond to each Heartbeat event with a Heartbeat ACK (opcode 
- App sends an Identify (opcode 2) event to perform the initial handshake with the Gateway. Read the section on Identifying
- Discord sends the app a Ready (opcode 0) event which indicates the handshake was successful and the connection is established. The Ready event contains aresume_gateway_urlthat the app should keep track of to determine the WebSocket URL an app should use to Resume. Read the section on the Ready event
- The connection may be dropped for a variety of reasons at any time. Whether the app can Resume the connection or whether it must re-identify is determined by a variety of factors like the opcode and close code that it receives. Read the section on Disconnecting
- If an app can resume/reconnect, it should open a new connection using resume_gateway_urlwith the same version and encoding, then send a Resume (opcode6) event. If an app cannot resume/reconnect, it should open a new connection using the cached URL from step #1, then repeat the whole Gateway cycle. Yipee! Read the section on Resuming
Connecting
Before your app can establish a connection to the Gateway, it should call the Get Gateway or the Get Gateway Bot endpoint. Either endpoint will return a payload with aurl field whose value is the WSS URL you can use to open a WebSocket connection. In addition to the URL, Get Gateway Bot contains additional information about the recommended number of shards and the session start limits for your app.
When initially calling either Get Gateway or Get Gateway Bot, you should cache the value of the url field and use that when re-connecting to the Gateway.
When connecting to the URL, it’s a good idea to explicitly pass the API version and encoding as query parameters. You can also optionally include whether Discord should compress data that it sends your app.
wss://gateway.discord.gg/?v=10&encoding=json is an example of a WSS URL an app may use to connect to the Gateway.For security reasons, the Gateway cannot be accessed directly from a Cloudflare Worker. Attempts will result in a 401 Unauthorized status code.
Gateway URL Query String Params
| Field | Type | Description | Accepted Values | 
|---|---|---|---|
| v | integer | API Version to use | API version | 
| encoding | string | The encoding of received gateway packets | jsonoretf | 
| compress? | string | The optional transport compression of gateway packets | zlib-streamorzstd-stream | 
Hello Event
Once connected to the Gateway, your app will receive a Hello (opcode10) event that contains your connection’s heartbeat interval (heartbeat_interval).
The heartbeat interval indicates a length of time in milliseconds that you should use to determine how often your app needs to send a Heartbeat event in order to maintain the active connection. Heartbeating is detailed in the Sending Heartbeats section.
Example Hello Event
Sending Heartbeats
Heartbeats are pings used to let Discord know that your app is still actively using a Gateway connection. After connecting to the Gateway, your app should send heartbeats (as described below) in a background process until the Gateway connection is closed.Heartbeat Interval
When your app opens a Gateway connection, it will receive a Hello (opcode10) event which includes a heartbeat_interval field that has a value representing a length of time in milliseconds.
Upon receiving the Hello event, your app should wait heartbeat_interval * jitter where jitter is any random value between 0 and 1, then send its first Heartbeat (opcode 1) event. From that point until the connection is closed, your app must continually send Discord a heartbeat every heartbeat_interval milliseconds. If your app fails to send a heartbeat event in time, your connection will be closed and you will be forced to Resume.
When sending a heartbeat, your app will need to include the last sequence number your app received in the d field. The sequence number is sent to your app in the event payload in the s field. If your app hasn’t received any events yet, you can just pass null in the d field.
In the first heartbeat, 
jitter is an offset value between 0 and heartbeat_interval that is meant to prevent too many clients (both desktop and apps) from reconnecting their sessions at the exact same time (which could cause an influx of traffic).heartbeat_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 don’t need to account for it in your implementation.
When you send a Heartbeat event, Discord will respond with a Heartbeat ACK (opcode 11) event, which is an acknowledgement that the heartbeat was received:
Example Heartbeat ACK
In the event of a service outage where you stay connected to the Gateway, you should continue to send heartbeats and receive heartbeat ACKs. The Gateway will eventually respond and issue a session once it’s able to.
1000 or 1001, then reconnect and attempt to Resume.
Heartbeat Requests
In addition to the Heartbeat interval, Discord may request additional heartbeats from your app by sending a Heartbeat (opcode1) event. Upon receiving the event, your app should immediately send back another Heartbeat event without waiting the remainder of the current interval.
Just like with the interval, Discord will respond with an Heartbeat ACK (opcode 11) event.
Identifying
After the connection is open and your app is sending heartbeats, you should send an Identify (opcode2) event. The Identify event is an initial handshake with the Gateway that’s required before your app can begin sending or receiving most Gateway events.
Apps are limited by maximum concurrency (max_concurrency in the session start limit object) when identifying. If your app exceeds this limit, Discord will respond with a Invalid Session (opcode 9) event.
After your app sends a valid Identify payload, Discord will respond with a Ready event which indicates that your app is in a successfully-connected state with the Gateway. The Ready event is sent as a standard Dispatch (opcode 0).
Clients are limited to 1000 
IDENTIFY calls to the websocket in a 24-hour period. This limit is global and across all shards, but does not include RESUME calls. Upon hitting this limit, all active sessions for the app will be terminated, the bot token will be reset, and the owner will receive an email notification. It’s up to the owner to update their application with the new token.Example Identify Payload
Below is a minimalIDENTIFY payload. IDENTIFY supports additional fields for other session properties like payload compression and an initial presence state.
See the Identify Structure for details about the event.
Ready event
As mentioned above, the Ready event is sent to your app after it sends a valid Identify payload. The Ready event includes state, like the guilds your app is in, that it needs to start interacting with the rest of the platform. The Ready event also includes fields that you’ll need to cache in order to eventually Resume your connection after disconnects. Two fields in particular are important to call out:- resume_gateway_urlis a WebSocket URL that your app should use when it Resumes after a disconnect. The- resume_gateway_urlshould be used instead of the URL used when connecting.
- session_idis the ID for the Gateway session for the new connection. It’s required to know which stream of events were associated with your disconnection connection.
Disconnecting
Gateway disconnects happen for a variety of reasons, and may be initiated by Discord or by your app.Handling a Disconnect
Due to Discord’s architecture, disconnects are a semi-regular event and should be expected and handled. When your app encounters a disconnect, it will typically be sent a close code which can be used to determine whether you can reconnect and Resume the session, or whether you have to start over and re-Identify. After you determine whether or not your app can reconnect, you will do one of the following:- If you determine that your app can reconnect and resume the previous session, then you should reconnect using the resume_gateway_urlandsession_idfrom the Ready event. Details about when and how to resume can be found in the Resuming section.
- If you cannot reconnect or the reconnect fails, you should open a new connection using the URL from the initial call to Get Gateway or Get Gateway Bot. In the case you cannot reconnect, you’ll have to re-identify after opening a new connection.
Initiating a Disconnect
When you close the connection to the gateway with close code1000 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 session will remain active and timeout after a few minutes. This can be useful when you’re Resuming the previous session.
Resuming
When your app is disconnected, Discord has a process for reconnecting and resuming, which allows your app to replay any lost events starting from the last sequence number it received. After Resuming, your app will receive the missed events in the same way it would have had the connection had stayed active. Unlike the initial connection, your app does not need to re-Identify when Resuming. There are a handful of scenarios when your app should attempt to resume:- It receives a Reconnect (opcode 7) event
- It’s disconnected with a close code that indicates it can reconnect. A list of close codes is in the Opcodes and Status Codes documentation.
- It’s disconnected but doesn’t receive any close code.
- It receives an Invalid Session (opcode 9) event with thedfield set totrue. This is an unlikely scenario, but it is possible.
Preparing to Resume
Before your app can send a Resume (opcode6) event, it will need three values: the session_id and the resume_gateway_url from the Ready event, and the sequence number (s) from the last Dispatch (opcode 0) event it received before the disconnect.
After the connection is closed, your app should open a new connection using resume_gateway_url rather than the URL used to initially connect, with the same query parameters from the initial Connection. If your app doesn’t use the resume_gateway_url when reconnecting, it will experience disconnects at a higher rate than normal.
Once the new connection is opened, your app should send a Gateway Resume event using the session_id and sequence number mentioned above. When sending the event, session_id will have the same field name, but the last sequence number will be passed as seq in the data object (d).
When Resuming, you do not need to send an Identify event after opening the connection.
If successful, the Gateway will send the missed events in order, finishing with a Resumed event to signal event replay has finished and that all subsequent events will be new.
When resuming with the 
resume_gateway_url you need to provide the same version and encoding as the initial connection.9) event. If the d field is set to false (which is most of the time), your app should disconnect. After disconnect, your app should create a new connection with your cached URL from the Get Gateway or the Get Gateway Bot endpoint, then send an Identify (opcode 2) event.
Example Gateway Resume Event
Gateway Intents
Maintaining a stateful application can be difficult when it comes to the amount of data your app is expected to process over a Gateway connection, especially at scale. Gateway intents are a system to help you lower the computational burden. Intents are bitwise values passed in theintents parameter when Identifying which correlate to a set of related events. For example, the event sent when a guild is created (GUILD_CREATE) and when a channel is updated (CHANNEL_UPDATE) both require the same GUILDS (1 << 0) intent (as listed in the table below). If you do not specify an intent when identifying, you will not receive any of the Gateway events associated with that intent.
Intents are optionally supported on the v6 gateway but required as of v8
- Standard intents can be passed by default. You don’t need any additional permissions or configurations.
- Privileged intents require you to toggle the intent for your app in your app’s settings within the Developer Portal before passing said intent. For verified apps (required for apps in 100+ guilds), the intent must also be approved after the verification process to use the intent. More information about privileged intents can be found in the section below.
4013 close code), or a privileged intent that hasn’t been configured or approved for your app (4014 close code).
List of Intents
Below is a list of all intents and the Gateway events associated with them. Any events not listed means it’s not associated with an intent and will always be sent to your app. All events, including those that aren’t associated with an intent, are in the Gateway events documentation.GUILD_PRESENCES and GUILD_MEMBERS intents are turned off by default on all API versions. If you are using API 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 API v6 to receive these events; you just need to enable the flags. If you are using API v8 or above, intents are mandatory and must be specified when identifying.
*** MESSAGE_CONTENT does not represent individual events, but rather affects what data is present for events that could contain message content fields. More information is in the message content intent section.
Caveats
Guild Member Update is sent for current-user updates regardless of whether theGUILD_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.
Privileged Intents
Some intents are defined as “privileged” due to the sensitive nature of the data. Currently, those intents include:- GUILD_PRESENCES
- GUILD_MEMBERS
- MESSAGE_CONTENT
IDENTIFY payload, you must enable the privileged intents your app requires. Verified apps can only use privileged intents after they’ve been approved for them.
Unverified apps can use privileged intents without approval, but still must enable them in their app’s settings. If the app’s verification status changes, it will then have to apply for the privileged intent(s).
GUILD_MEMBERS intent enabled for your application. This behavior is independent of whether the intent is set during IDENTIFY.
Enabling Privileged Intents
Before using privileged intents, you must enable them in your app’s settings. In the Developer Portal, you can navigate to your app’s settings then toggle the privileged intents on the Bots page under the “Privileged Gateway Intents” section. You should only toggle privileged intents that your bot requires to function. If your app qualifies for verification, you must first verify your app and request access to these intents during the verification process. If your app is already verified and you need to request additional privileged intents, you can contact support.Gateway Restrictions
Privileged intents affect which Gateway events your app is permitted to receive. When using API v8 and above, all intents (privileged and not) must be specified in theintents parameter when Identifying. If you pass a privileged intent in the intents parameter without configuring it in your app’s settings, or being approved for it during verification, your Gateway connection will be closed with a (4014 close code).
For API v6, you will receive events associated with the privileged intents your app has configured and is authorized to receive without passing those intents into the 
intents parameter when Identifying.GUILD_PRESENCES and GUILD_MEMBERS intents are turned off by default regardless of the API version.
HTTP Restrictions
In addition to Gateway restrictions, privileged intents also affect the HTTP API endpoints your app is permitted to call, and the data it can receive. For example, to use the List Guild Members endpoint, your app must enable theGUILD_MEMBERS intent (and be approved for it if eligible for verification).
HTTP API restrictions are independent of Gateway restrictions, and are unaffected by which intents your app passes in the intents parameter when Identifying.
Message Content Intent
MESSAGE_CONTENT (1 << 15) is a unique privileged intent that isn’t directly associated with any Gateway events. Instead, access to MESSAGE_CONTENT permits your app to receive message content data across the APIs.
Any fields affected by the message content intent are noted in the relevant documentation. For example, the content, embeds, attachments, components, and poll fields in message objects all contain message content and therefore require the intent.
Like other privileged intents, 
MESSAGE_CONTENT must be approved for your app. After your app is verified, you can apply for the intent from your app’s settings within the Developer Portal. You can read more about the message content intent review policy in the Help Center.- Content in messages that an app sends
- Content in DMs with the app
- Content in which the app is mentioned
- Content of the message a message context menu command is used on
Rate Limiting
This section refers to Gateway rate limits, not HTTP API rate limits
9).
Encoding and Compression
When establishing a connection to the Gateway, apps can use theencoding parameter to choose whether to communicate with Discord using a plain-text JSON or binary ETF encoding. You can pick whichever encoding type you’re more comfortable with, but both have their own quirks. If you aren’t sure which encoding to use, JSON is generally recommended.
Apps can also optionally enable compression to receive zlib-compressed or zstd-compressed packets. Payload compression can only be enabled when using a JSON encoding, but transport compression can be used regardless of encoding type.
Using JSON Encoding
When using the plain-text JSON encoding, apps have the option to enable payload compression.Payload Compression
If an app is using payload compression, it cannot use transport compression.
compress to true when sending an Identify (opcode 2) event. Note that even when payload compression is enabled, not all payloads will be compressed.
When payload compression is enabled, your app (or 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 events sent.
Payload compression will be disabled if you use transport compression.
Using ETF Encoding
When using ETF (External Term Format) encoding, there are some specific behaviors you should know:- Snowflake IDs are transmitted as 64-bit integers or strings.
- Your app can’t send compressed messages to the server.
- When sending payloads, you must use string keys. Using atom keys will result in a 4002decode error.
Transport Compression
Transport compression enables optional compression for all packets when Discord is sending events over the connection. The currently-available transport compression options arezlib-stream and zstd-stream.
zlib-stream
When zlib transport compression is enabled, your app needs to process received data through a single Gateway connection using a shared zlib context. However, each Gateway connection should use its own unique zlib context. When processing transport-compressed data, you should push received data to a buffer until you receive the 4-byteZ_SYNC_FLUSH suffix (00 00 ff ff). After you receive the Z_SYNC_FLUSH suffix, you can then decompress the buffer.
Transport Compression Example
zstd-stream
When zstd-stream transport compression is enabled, all data needs to be processed through a zstd decompression context that stays alive for the lifetime of the gateway connection. When processing data, each websocket message corresponds to a single gateway message, but does not end a zstd frame. You will need to repeatedly call ZSTD_decompressStream until all data in the frame has been processed (ZSTD_decompressStream will not necessarily return 0, though). Take a look at this Erlang + C++ implementation for inspiration.Tracking State
Most of a client’s state is provided during the initial Ready event and in the Guild Create events that follow. As resources continue to be created, updated, and deleted, Gateway events are sent to notify the app of these changes and to provide associated data. To avoid excessive API calls, apps should cache as many relevant resource states as possible, and update them as new events are received.For larger apps, client state can grow to be very large. Therefore, we recommend only storing data in memory that are needed for the app to operate. In some cases, there isn’t a need to cache member information (like roles or permissions) since some events like MESSAGE_CREATE have the full member object included.
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 apps grow and are added to an increasing number of guilds, some developers may find it necessary to divide portions of their app’s operations across multiple processes. As such, the Gateway implements a method of user-controlled guild sharding which allows apps to split events across a number of Gateway connections. Guild sharding is entirely controlled by an app, and requires no state-sharing between separate connections to operate. While all apps can enable sharding, it’s not necessary for apps in a smaller number of guilds.Each shard can only support a maximum of 2500 guilds, and apps that are in 2500+ guilds must enable sharding.
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.
The Get Gateway Bot endpoint provides a recommended number of shards for your app in the 
shards fieldSharding Formula
shard for each connection: [0, 3], [1, 3], and [2, 3].
Gateway events that do not contain a 
guild_id will only be sent to the first shard (shard_id: 0). This includes Direct Message (DM), subscription and entitlement events.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 for more fine-tuned load balancing, or to 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 themax_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
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:
rate_limit_key which fills the bucket of 16 shards. However, let’s say you had 32 shards:
Sharding for Large Bots
If your bot is in more than 150,000 guilds, there are some additional considerations you must take around sharding. Discord will migrate your bot to large bot sharding when it starts to get near the large bot sharding threshold. The bot owner(s) will receive a system DM and email confirming this move has completed as well as what shard number has been assigned. The number of shards you run must be a multiple of the shard number provided when reaching out to you. If you attempt to start your bot with an invalid number of shards, your Gateway connection will close with a4010 Invalid Shard close code.
The Get Gateway Bot endpoint will always 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 changes.
The session start limit for these bots will also be increased from 1000 to max(2000, (guild_count / 1000) * 5) per day. You also receive an increased max_concurrency, the number of shards you can concurrently start.
Get Gateway
GET/gateway
This endpoint does not require authentication.
Example Response
Get Gateway Bot
GET/gateway/bot
This endpoint requires authentication using a valid bot token.
JSON Response
| Field | Type | Description | 
|---|---|---|
| url | string | WSS URL that can be used for connecting to the Gateway | 
| shards | integer | Recommended number of shards to use when connecting | 
| session_start_limit | session_start_limit object | Information on the current session start limit | 
Example Response
Session Start Limit Object
Session Start Limit Structure
| Field | Type | Description | 
|---|---|---|
| total | integer | Total number of session starts the current user is allowed | 
| remaining | integer | Remaining number of session starts the current user is allowed | 
| reset_after | integer | Number of milliseconds after which the limit resets | 
| max_concurrency | integer | Number of identify requests allowed per 5 seconds |