Overview
The Fluxer Gateway is a WebSocket-based connection that provides real-time event delivery for your bot. It enables your bot to receive messages, member updates, voice state changes, and other events as they happen.
Before connecting, retrieve the Gateway URL and connection parameters:
curl -H "Authorization: Bot {bot_token}" \
https://api.fluxer.app/v1/gateway/bot
Response:
{
"url" : "wss://gateway.fluxer.app" ,
"shards" : 1 ,
"session_start_limit" : {
"total" : 1000 ,
"remaining" : 999 ,
"reset_after" : 14400000 ,
"max_concurrency" : 1
}
}
WebSocket URL to connect to
Recommended number of shards for your bot (always 1 for most bots)
Connection rate limit information
The session_start_limit prevents abuse by limiting how many Gateway connections you can establish within a time window.
Connection Flow
Establishing Connection
1. Connect to WebSocket
Node.js (ws)
Python (websockets)
Go (gorilla/websocket)
import WebSocket from 'ws' ;
const ws = new WebSocket ( 'wss://gateway.fluxer.app' );
ws . on ( 'open' , () => {
console . log ( 'Connected to Gateway' );
});
ws . on ( 'message' , ( data ) => {
const payload = JSON . parse ( data . toString ());
handleGatewayPayload ( payload );
});
ws . on ( 'close' , ( code , reason ) => {
console . log ( `Disconnected: ${ code } - ${ reason } ` );
});
ws . on ( 'error' , ( error ) => {
console . error ( 'WebSocket error:' , error );
});
2. Receive Hello Event
The Gateway sends a Hello event immediately after connection:
{
"op" : 10 ,
"d" : {
"heartbeat_interval" : 41250
}
}
Opcode 10 indicates a Hello event
Milliseconds between heartbeat messages (typically 41250ms)
3. Send Identify
Authenticate your bot by sending an Identify payload:
{
"op" : 2 ,
"d" : {
"token" : "Bot 123456789012345678.dGhpcyBpcyBhIHNlY3JldCB0b2tlbiBleGFtcGxl" ,
"properties" : {
"os" : "linux" ,
"browser" : "my-bot" ,
"device" : "my-bot"
},
"intents" : 513 ,
"presence" : {
"status" : "online" ,
"afk" : false
}
}
}
Your bot token with “Bot ” prefix
Connection properties for identification
Gateway intents bitfield (see Intents section)
Include the “Bot ” prefix before your token, or the connection will be rejected.
4. Receive Ready Event
Upon successful authentication, the Gateway sends a Ready event:
{
"op" : 0 ,
"t" : "READY" ,
"d" : {
"v" : 1 ,
"user" : {
"id" : "123456789012345678" ,
"username" : "my_awesome_bot" ,
"discriminator" : "0001" ,
"avatar" : null ,
"bot" : true
},
"guilds" : [
{ "id" : "987654321098765432" , "unavailable" : false }
],
"session_id" : "abc123def456" ,
"application_id" : "123456789012345678"
}
}
The Ready event contains your bot’s user information and a list of guilds it’s a member of.
Heartbeat
Maintain the connection by sending heartbeat messages at the specified interval:
let heartbeatInterval : NodeJS . Timeout ;
let lastSequence : number | null = null ;
function handleHello ( payload : any ) {
const interval = payload . d . heartbeat_interval ;
heartbeatInterval = setInterval (() => {
ws . send ( JSON . stringify ({
op: 1 ,
d: lastSequence
}));
}, interval );
}
function handleDispatch ( payload : any ) {
lastSequence = payload . s ;
}
Failure to send heartbeats will cause the Gateway to close your connection with code 4000.
Heartbeat ACK
The Gateway acknowledges each heartbeat:
If you don’t receive a heartbeat ACK before sending the next heartbeat, consider the connection zombie and reconnect.
Gateway Intents
Intents control which events your bot receives. Calculate the bitfield:
// Gateway Intents
const Intents = {
GUILDS: 1 << 0 , // 1
GUILD_MEMBERS: 1 << 1 , // 2
GUILD_BANS: 1 << 2 , // 4
GUILD_EMOJIS: 1 << 3 , // 8
GUILD_INTEGRATIONS: 1 << 4 , // 16
GUILD_WEBHOOKS: 1 << 5 , // 32
GUILD_INVITES: 1 << 6 , // 64
GUILD_VOICE_STATES: 1 << 7 , // 128
GUILD_PRESENCES: 1 << 8 , // 256
GUILD_MESSAGES: 1 << 9 , // 512
GUILD_MESSAGE_REACTIONS: 1 << 10 , // 1024
GUILD_MESSAGE_TYPING: 1 << 11 , // 2048
DIRECT_MESSAGES: 1 << 12 , // 4096
DIRECT_MESSAGE_REACTIONS: 1 << 13 , // 8192
DIRECT_MESSAGE_TYPING: 1 << 14 , // 16384
};
// Example: Guilds + Guild Messages
const intents = Intents . GUILDS | Intents . GUILD_MESSAGES ;
// Result: 513
Common Intent Combinations
Basic Bot
Moderation Bot
Support Bot
const intents =
Intents . GUILDS |
Intents . GUILD_MESSAGES ;
// 513
Receives guild events and messages const intents =
Intents . GUILDS |
Intents . GUILD_MEMBERS |
Intents . GUILD_MESSAGES |
Intents . GUILD_MESSAGE_REACTIONS ;
// 1539
Includes member events for moderation const intents =
Intents . GUILDS |
Intents . GUILD_MESSAGES |
Intents . DIRECT_MESSAGES ;
// 4609
Handles both guild and DM messages
Privileged intents (GUILD_PRESENCES, GUILD_MEMBERS) may require approval for verified bots with 100+ guilds.
Receiving Events
All events use opcode 0 (Dispatch) with an event type:
{
"op" : 0 ,
"s" : 42 ,
"t" : "MESSAGE_CREATE" ,
"d" : {
"id" : "234567890123456789" ,
"channel_id" : "345678901234567890" ,
"author" : {
"id" : "456789012345678901" ,
"username" : "user123" ,
"discriminator" : "0001"
},
"content" : "Hello, bot!" ,
"timestamp" : "2026-03-04T12:00:00.000Z"
}
}
Always 0 for dispatch events
Sequence number (use for heartbeats)
Event type name (e.g., MESSAGE_CREATE)
Event data (structure varies by event type)
Event Handler Example
function handleGatewayPayload ( payload : any ) {
const { op , t , d , s } = payload ;
if ( s !== null ) {
lastSequence = s ;
}
switch ( op ) {
case 10 : // Hello
handleHello ( payload );
sendIdentify ();
break ;
case 11 : // Heartbeat ACK
console . log ( 'Heartbeat acknowledged' );
break ;
case 0 : // Dispatch
handleEvent ( t , d );
break ;
default :
console . log ( 'Unknown opcode:' , op );
}
}
function handleEvent ( type : string , data : any ) {
switch ( type ) {
case 'READY' :
console . log ( `Logged in as ${ data . user . username } ` );
break ;
case 'MESSAGE_CREATE' :
handleMessage ( data );
break ;
case 'GUILD_MEMBER_ADD' :
handleMemberJoin ( data );
break ;
// ... handle other events
}
}
Common Gateway Events
MESSAGE_CREATE
Received when a message is sent in a channel your bot can see:
{
"op" : 0 ,
"t" : "MESSAGE_CREATE" ,
"d" : {
"id" : "234567890123456789" ,
"channel_id" : "345678901234567890" ,
"guild_id" : "456789012345678901" ,
"author" : { ... },
"content" : "!help" ,
"timestamp" : "2026-03-04T12:00:00.000Z" ,
"mention_everyone" : false ,
"mentions" : [],
"attachments" : [],
"embeds" : []
}
}
GUILD_MEMBER_ADD
Received when a user joins a guild:
{
"op" : 0 ,
"t" : "GUILD_MEMBER_ADD" ,
"d" : {
"user" : {
"id" : "567890123456789012" ,
"username" : "newuser" ,
"discriminator" : "0001"
},
"guild_id" : "456789012345678901" ,
"joined_at" : "2026-03-04T12:00:00.000Z" ,
"roles" : []
}
}
VOICE_STATE_UPDATE
Received when a user’s voice state changes:
{
"op" : 0 ,
"t" : "VOICE_STATE_UPDATE" ,
"d" : {
"guild_id" : "456789012345678901" ,
"channel_id" : "678901234567890123" ,
"user_id" : "567890123456789012" ,
"session_id" : "xyz789" ,
"mute" : false ,
"deaf" : false ,
"self_mute" : false ,
"self_deaf" : false
}
}
All Gateway Events Complete reference of Gateway events
Event Filtering Control which events you receive
Resuming Sessions
If your connection drops, resume instead of re-identifying:
{
"op" : 6 ,
"d" : {
"token" : "Bot {bot_token}" ,
"session_id" : "abc123def456" ,
"seq" : 42
}
}
Your bot token with “Bot ” prefix
Session ID from the Ready event
Last sequence number received
Resume vs Identify
When to Resume
When to Identify
Connection was closed unexpectedly
Close code is 4000-4999 (except 4004, 4010, 4011, 4014)
You have a valid session_id and sequence number
Less than 5 minutes since disconnection
First connection
Session invalidated (close code 4004, 4010, 4011, 4014)
More than 5 minutes since disconnection
Resume attempt failed
Close Codes
Code Description Reconnect 4000 Unknown error Yes (resume) 4001 Unknown opcode Yes (resume) 4002 Decode error Yes (resume) 4003 Not authenticated No 4004 Authentication failed No 4005 Already authenticated Yes (resume) 4007 Invalid sequence Yes (identify) 4008 Rate limited Yes (identify) 4009 Session timeout Yes (identify) 4010 Invalid shard No 4011 Sharding required No 4014 Disallowed intents No
Do not attempt to reconnect if the close code is 4003, 4004, 4010, 4011, or 4014.
Rate Limits
Gateway Rate Limits
Identify : 1 per 5 seconds
Presence Updates : 5 per 60 seconds
Gateway Commands : 120 per 60 seconds
Handling Rate Limits
let commandCount = 0 ;
let resetTime = Date . now () + 60000 ;
function canSendCommand () : boolean {
const now = Date . now ();
if ( now >= resetTime ) {
commandCount = 0 ;
resetTime = now + 60000 ;
}
if ( commandCount >= 120 ) {
console . warn ( 'Gateway rate limit reached' );
return false ;
}
commandCount ++ ;
return true ;
}
Best Practices
Implement Reconnection Logic
Always handle disconnections gracefully with exponential backoff: let reconnectAttempts = 0 ;
const maxReconnectDelay = 60000 ; // 60 seconds
function reconnect () {
const delay = Math . min (
1000 * Math . pow ( 2 , reconnectAttempts ),
maxReconnectDelay
);
setTimeout (() => {
reconnectAttempts ++ ;
connect ();
}, delay );
}
Store Session Information
Persist session_id and sequence number for resumption: let sessionId : string | null = null ;
let lastSequence : number | null = null ;
function handleReady ( data : any ) {
sessionId = data . session_id ;
// Save to file or database
}
Monitor Heartbeat ACKs
Detect zombie connections by tracking heartbeat acknowledgments: let lastHeartbeatAck = Date . now ();
let heartbeatAckReceived = true ;
function sendHeartbeat () {
if ( ! heartbeatAckReceived ) {
console . warn ( 'Heartbeat not acknowledged, reconnecting' );
reconnect ();
return ;
}
heartbeatAckReceived = false ;
ws . send ( JSON . stringify ({ op: 1 , d: lastSequence }));
}
function handleHeartbeatAck () {
heartbeatAckReceived = true ;
lastHeartbeatAck = Date . now ();
}
Handle Large Payloads
Some events can be very large (e.g., READY with many guilds). Use streaming JSON parsers for memory efficiency.
Request Minimal Intents
Only request the intents your bot actually needs to reduce bandwidth and processing.
Troubleshooting
Connection immediately closes with 4004
Not receiving MESSAGE_CREATE events
Ensure you’ve requested the GUILD_MESSAGES intent (512) in your Identify payload.
Connection closes with 4000 after a few minutes
You’re not sending heartbeats at the correct interval. Check that your heartbeat timer is working.
Session cannot be resumed
Sessions expire after 5 minutes or when invalidated. Fall back to sending a new Identify payload.
Next Steps
Handle Commands Process user commands from MESSAGE_CREATE events
Gateway Events Reference Complete list of all Gateway events
Presence & Status Update your bot’s online status
Voice Connections Connect to voice channels (advanced)