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.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 exceeds 4096 bytes, the connection will be closed with a
4002close event code.
Receiving Events
Receiving a Gateway event from Discord is much more common than sending them. While some events are sent automatically, most require your app to define intents when Identifying. Intents are bitwise values that can be ORed (|) together to indicate which events (or groups of events) you want Discord to send your app.
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 as Dispatch events.
When your app is parsing a Dispatch event:
- The
tfield determines which Gateway event the payload represents. - The
sfield represents the sequence number of the event. Cache the most recent non-nullsvalue for heartbeats and when Resuming a connection.
Connections
Gateway connections are persistent WebSockets that introduce more complexity than sending HTTP requests. Your app must know how to open the initial connection, maintain it, and handle disconnects.Connection Lifecycle
At a high level, Gateway connections consist of the following cycle:- App establishes a connection after fetching a WSS URL using Get Gateway or Get Gateway Bot.
- Discord sends a Hello (opcode
10) event with aheartbeat_interval. - App starts sending Heartbeat (opcode
1) events everyheartbeat_intervalmilliseconds. - App sends an Identify (opcode
2) event for the initial handshake. - Discord sends a Ready (opcode
0) event with session details includingresume_gateway_urlandsession_id. - The connection may drop for various reasons. Whether the app can Resume is determined by the close opcode/code received.
- If resumable, open a new connection using
resume_gateway_urland send a Resume (opcode6) event. Otherwise, open a new connection using the cached URL and re-identify.
Connecting
Before establishing a Gateway connection, call Get Gateway or Get Gateway Bot to fetch the WSS URL. Cache theurl value and use it when reconnecting.
When connecting, explicitly pass the API version and encoding as query parameters.
wss://gateway.discord.gg/?v=10&encoding=json is an example WSS URL for connecting to the Gateway.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 | json or etf |
| compress? | string | The optional transport compression of gateway packets | zlib-stream or zstd-stream |
Hello Event
Once connected, your app receives a Hello (opcode10) event with a heartbeat_interval in milliseconds.
Sending Heartbeats
Heartbeats are pings used to keep an active Gateway connection alive. After connecting, your app should send heartbeats in a background process until the connection is closed.Heartbeat Interval
Upon receiving the Hello event, waitheartbeat_interval * jitter (where jitter is a random value between 0 and 1), then send the first Heartbeat (opcode 1) event. From that point, send a heartbeat every heartbeat_interval milliseconds.
The initial
jitter offset prevents mass client reconnection spikes at the same time.s field) from received events in the d field of the heartbeat. If no events have been received yet, pass null.
Discord responds to each heartbeat with a Heartbeat ACK (opcode 11) event:
1000 or 1001, then reconnect and attempt to Resume.
Heartbeat Requests
Discord may also request additional heartbeats by sending a Heartbeat (opcode1) event. Upon receiving it, immediately send back a heartbeat without waiting for the current interval to elapse.
Identifying
After the connection is open and heartbeats are being sent, send an Identify (opcode2) event. This is the initial handshake required before your app can send or receive most Gateway events.
After a valid Identify payload, Discord responds with a Ready event.
Example Identify Payload
Ready Event
The Ready event includes state your app needs to start interacting with the platform. Two fields are especially important to cache:resume_gateway_url— WebSocket URL to use when Resuming after a disconnect.session_id— ID for the Gateway session, required when Resuming.
Disconnecting
Handling a Disconnect
When your app encounters a disconnect, it receives a close code that determines whether you can reconnect and Resume, or must start over.- If your app can reconnect, use the
resume_gateway_urlandsession_idfrom the Ready event. See Resuming. - If your app cannot reconnect, open a new connection with the URL from Get Gateway or Get Gateway Bot and re-identify.
Initiating a Disconnect
Closing with code1000 or 1001 invalidates the session and shows the bot as offline. Closing with another code or dropping the TCP connection keeps the session alive and allows resuming within a timeout window.
Resuming
When disconnected, Discord supports reconnecting and replaying missed events starting from the last sequence number received. Unlike the initial connection, Resuming does not require a new Identify. Your app should attempt to resume when:- It receives a Reconnect (opcode
7) event. - It’s disconnected with a close code that permits reconnection.
- It’s disconnected without any close code.
- It receives an Invalid Session (opcode
9) withdset totrue.
Preparing to Resume
Before sending a Resume event, you need:session_idfrom the Ready eventresume_gateway_urlfrom the Ready event- The last sequence number (
s) from the final Dispatch event before disconnect
resume_gateway_url (not the original URL) with the same query parameters, then send:
9) with d: false and must re-identify.
When resuming, you must provide the same API version and encoding as the initial connection.
Gateway Intents
Intents are bitwise values passed in theintents parameter when Identifying that correlate to sets of related events. If you do not specify an intent, you will not receive any of its associated Gateway events.
Intents are optionally supported on the v6 gateway but required as of v8.
- Standard intents can be passed by default with no additional configuration.
- Privileged intents require you to toggle them in your app’s settings in the Developer Portal before use. Verified apps must also be approved during the verification process.
4013) or an unapproved privileged intent is used (4014).
List of Intents
Any events not listed below are not associated with an intent and are always sent to your app.GUILD_PRESENCES and GUILD_MEMBERS are turned off by default on all API versions.
*** MESSAGE_CONTENT does not represent individual events but affects what data is present for events that could contain message content fields.
Caveats
- Guild Member Update is sent for current-user updates regardless of whether the
GUILD_MEMBERSintent is set. - Thread Members Update by default only includes if the current user was added or removed. Request the
GUILD_MEMBERSintent to receive updates for other users.
Privileged Intents
Some intents are “privileged” due to the sensitive nature of their data:GUILD_PRESENCESGUILD_MEMBERSMESSAGE_CONTENT
Unverified apps can use privileged intents without approval but must still enable them in app settings. If the app’s verification status changes, it must apply for the privileged intent(s).
Enabling Privileged Intents
Enable privileged intents in the Developer Portal under your app’s Bot page in the “Privileged Gateway Intents” section. Only toggle intents your bot requires to function. Verified apps must request access to privileged intents during the verification process. If already verified and you need additional privileged intents, contact support.Gateway Restrictions
When using API v8 and above, all intents must be specified in theintents parameter when Identifying. Passing a privileged intent without it being configured or approved closes the connection with a 4014 close code.
HTTP Restrictions
Privileged intents also affect which HTTP API endpoints your app can call. For example, theGUILD_MEMBERS intent is required to use the List Guild Members endpoint. HTTP API restrictions are independent of which intents are passed during IDENTIFY.
Message Content Intent
MESSAGE_CONTENT (1 << 15) is a unique privileged intent not directly associated with Gateway events. Instead, it permits your app to receive message content data across the APIs.
Apps without this intent receive empty values in content fields with these exceptions:
- Content in messages the app sends
- Content in DMs with the app
- Content in which the app is mentioned
- Content of a 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
Use theencoding parameter when connecting to choose between plain-text JSON or binary ETF. JSON is generally recommended if you’re unsure.
Apps can also enable optional compression to receive zlib-compressed or zstd-compressed packets.
Using JSON Encoding
JSON encoding supports optional payload compression.Payload Compression
Payload compression enables optional per-packet compression for some events. Enable it by settingcompress: true in the Identify event. When enabled, your app must decompress payloads before parsing them.
Using ETF Encoding
When using ETF encoding:- Snowflake IDs are transmitted as 64-bit integers or strings.
- Your app cannot send compressed messages to the server.
- You must use string keys in payloads—atom keys cause a
4002decode error.
Transport Compression
Transport compression enables compression for all packets. Available options arezlib-stream and zstd-stream.
zlib-stream
When zlib transport compression is enabled, push received data to a buffer until you receive the 4-byteZ_SYNC_FLUSH suffix (00 00 ff ff), then decompress the buffer. Each Gateway connection should use its own unique zlib context.
zstd-stream
When zstd-stream is enabled, process all data through a zstd decompression context for the lifetime of the gateway connection. Each websocket message corresponds to a single gateway message but does not end a zstd frame—callZSTD_decompressStream repeatedly until all data is processed.
Tracking State
Most client state is provided during the initial Ready event and in subsequent Guild Create events. As resources change, Gateway events notify your app and provide associated data. Cache relevant resource states to avoid excessive API calls.For larger apps, only store data in memory that is needed for the app to operate. For example, you may not need to cache member information if events like
MESSAGE_CREATE already include the full member object.Guild Availability
When connecting as a bot, guilds start as unavailable. The gateway automatically attempts to reconnect on your behalf, and you will receive Guild Create events as guilds become available.Sharding
For apps in a large number of guilds, the Gateway supports user-controlled guild sharding, which splits events across multiple Gateway connections. Enable sharding by including theshard array in the Identify payload: [shard_id, num_shards] (zero-indexed shard ID and total shard count).
The Get Gateway Bot endpoint provides a recommended number of shards in the
shards field.guild_id (DMs, subscriptions, entitlements) are only sent to shard 0.
Max Concurrency
Start shards concurrently based on themax_concurrency value from the session start limit object. Shards are bucketed by:
Sharding for Large Bots
Bots in more than 150,000 guilds have additional sharding requirements. Discord will DM and email the bot owner when the bot is migrated to large bot sharding. The number of shards must be a multiple of the assigned shard number; invalid shard counts close the connection with a4010 close code.
The Get Gateway Bot endpoint always returns the correct shard count. Large bots also receive an increased session start limit: max(2000, (guild_count / 1000) * 5) per day.
Get Gateway
This endpoint does not require authentication.
Get Gateway Bot
| 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 |
Session Start Limit Object
| 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 |