Skip to content
Fluxer API

Client commands

Clients send commands over the Gateway WebSocket as JSON with an opcode in op and the data in d. Every command except Heartbeat, Identify and Resume needs an authenticated session, and sending one earlier closes with 4003 and reason Not authenticated.

OpcodeCommandResult
1HeartbeatOpcode 11 Heartbeat ACK
2IdentifyReady, a close frame, or no response while Fluxer holds a rate-limited Identify
3Presence UpdateNone
4Voice State UpdateVoice State Update and Voice Server Update
6ResumeReplayed Dispatches and Resumed, Invalid Session, a close frame, or no response while rate limited
8Request Guild MembersGuild Members Chunk
13Voice SignalVoice Signal for the target connection
14Lazy RequestGuild Sync and member list and thread list updates
15Request Guild CountsGuild Counts Update
16Request Channel Member CountsChannel Member Counts Update
28Request Forum UnreadsForum Unreads

A frame that does not decode to an object closes with 4002 and reason Decode failed, and an object with no op closes with 4002 and reason Invalid payload. Once the session is authenticated, an unknown opcode closes with 4001 and reason Unknown opcode. A payload with op but no d does the same, except Identify and Resume, which close with 4005 and reason Already authenticated. Every command counts against the payload budgets.

The bounded commands never close the connection, and they skip input they cannot parse.

Opcode 1 sends the last Dispatch sequence the client processed, or null before the first Dispatch. See Gateway overview for the timing.

FieldTypeDescription
d?integerThe last Dispatch sequence the client processed
{
"op": 1,
"d": 42
}

Once authenticated, a d that is neither null nor an integer closes with 4007 and reason Invalid sequence.

Opcode 2 authenticates and creates a new session.

FieldTypeDescription
tokenstringThe account or bot token, with no HTTP authentication prefix
propertiesidentify properties objectThe software and capabilities of the connecting client
presence?1?initial presence objectThe presence to publish when the session starts
ignored_events?2?array[string]The Dispatch event names this session does not want (at most 256)
flags?integerA non-negative session flags bitfield (default 0)
initial_guild_id?3?snowflakeThe snowflake of one guild the session joins as active
shard?4?array[integer]The [shard_id, shard_count] pair

1 Null and an omitted key both use the account's saved status and custom status

2 See Event filtering for the suppression rule

3 The session is active in that guild without a Lazy Request and gets no initial Guild Sync. An invalid value is ignored

4 shard_count is from 1 through 16,384, and shard_id is at least 0 and below shard_count

{
"op": 2,
"d": {
"token": "...",
"properties": {
"os": "Linux",
"browser": "Fluxer Client",
"device": "desktop"
},
"presence": {
"status": "online",
"afk": false,
"mobile": false
},
"ignored_events": ["TYPING_START"],
"flags": 2,
"initial_guild_id": "1189375284394692608"
}
}

Identify closes the connection on these faults.

FaultClose
A missing token or properties, or an invalid properties, ignored_events or flags4002 Invalid identify payload
Malformed shard4010 Invalid shard
A bot session with more than 2,500 guilds after the shard filter4011 Sharding required
The backend rejects the token4004 Invalid token
A non-bot account with 100 live sessions4008 Too many sessions
The socket already has a session4005 Already authenticated
ValueNameDescription
1 << 1DEBOUNCE_MESSAGE_REACTIONSMerges runs of DM and group DM reactions into Message Reaction Add Many
1 << 2CHANNEL_THREADSThe client can parse thread, forum and media channels
1 << 3GUILD_VISITSThe session receives the guilds the account is visiting

Undefined bits are ignored.

FieldTypeDescription
osstringThe operating system the client runs on
browserstringThe client library identifier
devicestringThe device or application identifier
e2ee_capable?1booleanWhether the client can take part in end-to-end encrypted voice
mobile?2booleanWhether the session is mobile (default false)
latitude?3stringThe client latitude as a decimal string (1-32 characters)
longitude?3stringThe client longitude as a decimal string (1-32 characters)

1 A session without it is refused from an end-to-end encrypted voice channel with VOICE_E2EE_REQUIRED

2 Used only when presence is absent or null. Otherwise the initial presence object decides

3 Send both as strings to order the Ready rtc_regions array by distance

FieldTypeDescription
status?1stringThe initial status, one of online, idle, dnd, invisible or offline
afk?booleanWhether the session is away (default false)
mobile?booleanWhether the presence is mobile (default false)
custom_status?2?custom status objectThe custom status this session publishes

1 Fluxer uses the account's saved status when status is missing, not a string or unknown, and when it is online but the saved status is something else

2 Used only when the account has no saved custom status, and stored as sent

A session whose status is offline or invisible shows as offline with no custom status to other users.

FieldTypeDescription
text??stringThe text of the custom status (1-128 characters)
expires_at?1?ISO8601 timestampThe time the custom status expires
emoji_id?2?snowflakeThe snowflake of the custom emoji
emoji_name?3?stringThe Unicode emoji (1-32 characters)

1 Must be in the future

2 Must be an existing emoji. Fluxer drops the field when the account has no global expressions entitlement

3 A single Unicode emoji, ignored when emoji_id is sent

Presence Update events also include emoji_animated.

Opcode 6 restores a retained session. All fields are required, and a missing or mistyped field closes with 4002 and reason Invalid resume payload.

FieldTypeDescription
tokenstringThe token that owns the retained session
session_idstringThe session ID from Ready
seqintegerThe last Dispatch sequence the client processed

Send Resume on a new socket. Fluxer replays every retained Dispatch above seq in order and then sends Resumed. If another socket still has the session, that socket gets Opcode 7 and is closed.

ConditionResult
Unknown or expired sessionOpcode 9 with d: false
seq below the replay floorOpcode 9 with d: false
Token does not own the sessionClose 4004 Invalid token
seq above the session sequence or below the acknowledged oneClose 4007 Invalid sequence
Negative seq, or the session cannot be restored right nowClose 4000 Session unavailable
The socket already has a sessionClose 4005 Already authenticated

Opcode 3 replaces the current session presence. Updates over the Presence Update limit are dropped without a close.

FieldTypeDescription
statusstringThe status to publish, one of online, idle, dnd, invisible or offline
afk?booleanWhether the session is away (default false)
mobile?booleanWhether the session is mobile (default false)
custom_status?1?custom status objectThe custom status that replaces the current one

1 Omitting the key keeps the current custom status and null clears it. A rejected object, such as one from a limited account, leaves it unchanged

{
"op": 3,
"d": {
"status": "idle",
"afk": true,
"mobile": false,
"custom_status": {
"text": "away from keyboard"
}
}
}

A payload that is not an object, has no status, or has a string status outside the set closes with 4002 and reason Invalid presence payload. offline is stored as invisible.

Opcode 4 joins, moves, updates or leaves the voice membership of the current session. Every field is optional. A d that is not an object closes with 4002 and reason Invalid voice payload, and other invalid updates are dropped.

FieldTypeDescription
guild_id??snowflakeThe guild with the voice channel, where null selects the DM and group DM call context
channel_id??snowflakeThe channel to join or move to, where null leaves the membership
connection_id?1?stringThe existing voice connection this update applies to
self_mute?2booleanWhether the client has muted its microphone (default false)
self_deaf?2booleanWhether the client has deafened its output (default false)
self_video?2booleanWhether the client publishes camera video (default false)
self_stream?3booleanWhether this connection advertises a screenshare track (default false)
is_mobile?2booleanWhether this is a mobile voice client (default false)
viewer_stream_keys?4?array[string]The stream keys this connection watches, where an omitted key keeps the list and null clears it
latitude?number or stringThe client latitude, used to pick a voice region
longitude?number or stringThe client longitude, used to pick a voice region
p2p?5booleanWhether the client agrees to peer-to-peer media for a new connection, or leaves the mesh on an existing one

1 A channel_id with no connection_id opens a new connection and one with it updates or moves that connection. Leaving a guild with channel_id: null needs a connection_id, or the update is refused with VOICE_MISSING_CONNECTION_ID

2 Only true and the string "true" set the flag

3 Set like the other flags, and false is published when the member lacks STREAM in the channel. It sends no Voice Server Update

4 Each entry is a stream key matching this update's scope, guild and channel, or the update is refused with VOICE_INVALID_STATE. An entry with no connection is refused with VOICE_CONNECTION_NOT_FOUND

5 Only the JSON Boolean true agrees. On an existing connection, false moves the whole channel or call to LiveKit. A bot session never agrees. See Peer-to-peer voice

{
"op": 4,
"d": {
"guild_id": "1189375284394692608",
"channel_id": "1189375284394692610",
"self_mute": false,
"self_deaf": false,
"self_video": false,
"self_stream": false
}
}

guild_id: null with channel_id: null and a connection_id leaves that DM or group DM call connection. Without a connection_id it disconnects the session from every voice membership.

Joining or moving sends Voice Server Update to you and Voice State Update to every session that can see the channel. A refusal with VOICE_P2P_CONSENT_REQUIRED, VOICE_P2P_UNAVAILABLE or VOICE_CHANNEL_FULL comes back as a Gateway Error. Other refusals send nothing.

Updates over the Voice State Update limit are queued, and a newer one replaces a queued one.

Opcode 13 sends one signaling message to another connection in a peer-to-peer voice channel or call. Send it after a Voice Server Update with p2p: true.

FieldTypeDescription
guild_id??snowflakeThe guild with the voice channel, where null or omitted selects the DM and group DM call context
channel_idsnowflakeThe voice channel or call channel both connections are in
tostringThe connection_id of the voice state the signal is for
dataobjectThe signaling message, which Fluxer relays unread
{
"op": 13,
"d": {
"guild_id": "1189375284394692608",
"channel_id": "1189375284394692610",
"to": "b7f3c2a94e1d4c0f",
"data": {
"type": "offer",
"sdp": "v=0..."
}
}
}

Fluxer relays the signal when both the sender and the to connection have a voice state with p2p: true in that channel. Only the target connection's session gets the Voice Signal. Any other signal is dropped with no event and no close.

Opcode 8 requests member chunks for one or more guilds.

FieldTypeDescription
guild_id?1snowflakeThe ID of the single guild to query
guild_ids?1array[snowflake]A non-empty array of the guild IDs to query
query?2stringThe display name prefix to match (default empty string)
limit?3integerThe result limit (0-100, default 0)
user_ids?4array[snowflake]The explicit user IDs to select (at most 100, default empty)
presences?5booleanWhether results include presences (default false)
nonce?stringA value of at most 32 bytes echoed in each chunk

1 guild_id is used only when guild_ids is absent or empty. The nonce is echoed only when the request has one guild

2 Matched case-insensitively against the guild nickname, then the global name, then the username

3 0 with a non-empty query gives 25 results. 0 with an empty query requests the full member list, up to 100,000 entries

4 A non-empty array selects those members and ignores query and limit. More than 100 entries abandons the request

5 Offline and invisible presences are omitted

{
"op": 8,
"d": {
"guild_id": "1189375284394692608",
"query": "ann",
"limit": 50,
"presences": true,
"nonce": "a1b2c3"
}
}

Guilds the session is not connected to are skipped, and a request with no connected guild gets no chunk. A full member list needs MANAGE_ROLES, KICK_MEMBERS and BAN_MEMBERS together, and the owner and ADMINISTRATOR satisfy that. Without them the request is dropped silently.

A bot can request one guild at a time. A bot asking for the full list gets one accepted request per guild every 30 seconds, and another inside that window gets Rate Limited and no chunk.

Results arrive as Guild Members Chunk pages of at most 1,000 members with chunk_index and chunk_count. Chunks are not replayed on Resume. If you send a new request while one is running, it replaces any request still waiting.

Opcode 14 sets the per-guild subscriptions that decide member list, typing, sync and thread traffic.

FieldTypeDescription
subscriptions1map[snowflake, guild subscription object]The subscription options for each guild, keyed by guild ID

1 Fluxer applies each guild's options again when the session connects to that guild later

{
"op": 14,
"d": {
"subscriptions": {
"1189375284394692608": {
"active": true,
"typing": true,
"member_list_channels": {
"1189375284394692610": [[0, 99]]
}
}
}
}
}
FieldTypeDescription
active?1booleanWhether the guild is active for this session
sync?1booleanWhether the session requests a Guild Sync for the guild
typing?booleanWhether the guild delivers Typing Start, overriding the active flag
member_list_channels?2map[snowflake, array[array[integer]]]The member list windows to subscribe to, keyed by channel ID
members?array[snowflake]The explicit member IDs to subscribe to (at most 1,000)
focused_channel_id?3?snowflakeThe channel or public thread a visiting session has open

1 A non-Boolean value stops Fluxer applying the remaining options for that guild and the guilds after it

2 Each range is [start, end] with start at least 0, end at least start and at most 100,000, and end - start at most 99. Invalid ranges are dropped and each channel keeps its first 10

3 Used only for a guild the session is visiting, where it is the only option applied. Null or an unreadable channel clears it. A visiting session gets messages and reactions only for this channel

Event filtering describes what active changes.

Switching a guild between passive and active sends a Guild Sync unless the session already has one for that guild. Going passive also clears the threads subscription, and the next switch to active syncs again.

A channel gets Guild Member List Update only when you have VIEW_CHANNEL and VIEW_CHANNEL_MEMBERS in it. Thread IDs here subscribe to nothing, so use thread_member_lists. Subscribing a channel to a range drops the session's other member list in that guild.

Opcode 15 requests the member and online counts for guilds.

FieldTypeDescription
guild_idsarray[snowflake]The guild IDs to query, deduplicated and truncated to 100
nonce?stringA value of 1-64 bytes echoed in the result
{
"op": 15,
"d": {
"guild_ids": ["1189375284394692608"],
"nonce": "counts-1"
}
}

Guilds the session is not connected to are skipped. Results arrive in one Guild Counts Update, and a guild that does not answer within 2,000 ms is omitted.

Opcode 16 requests the member and online counts for channels in one guild.

FieldTypeDescription
guild_idsnowflakeThe ID of the guild whose channels are queried
channel_idsarray[snowflake]The channel IDs to query, deduplicated and truncated to 25
channel_id?1snowflakeThe ID of the single channel to query
nonce?stringA value of 1-64 bytes echoed in the result

1 Used only when channel_ids is absent or not an array

{
"op": 16,
"d": {
"guild_id": "1189375284394692608",
"channel_ids": ["1189375284394692610"],
"nonce": "channel-counts-1"
}
}

An invalid or unconnected guild gives an empty result. Results arrive in one Channel Member Counts Update, and a channel is counted only when you have VIEW_CHANNEL and VIEW_CHANNEL_MEMBERS in it.

A command sent while four bounded commands are running is dropped with no close and no result.