Connection Lifecycle
From the first WebSocket handshake to steady-state traffic, a client moves through several phases. This page is a reference for writing a resilient client that recovers from disconnects on its own.
Full cycle
Section titled “Full cycle” ┌──────────────────┐ │ connect(ws://...)│ └────────┬─────────┘ │ ▼ ┌──────────────────┐ HELLO (op 10) │ server → HELLO │◀─────────────── │ heartbeat_ │ │ interval │ └────────┬─────────┘ │ ├─── start heartbeat timer │ ▼ ┌──────────────────┐ IDENTIFY (op 2) or RESUME (op 6) │ client → IDENTIFY│───────────────▶ └────────┬─────────┘ │ ▼ ┌──────────────────┐ READY (op 0, t=READY) │ server → READY │◀─────────────── │ session_id, │ │ user, guilds │ └────────┬─────────┘ │ ▼ ┌──────────────────┐ │ steady state │ ← dispatch events, heartbeat every N ms │ │ └────────┬─────────┘ │ ┌──────────┼──────────┬──────────────┐ │ │ │ │ ▼ ▼ ▼ ▼ close INVALID_ RECONNECT heartbeat code SESSION (op 7) ACK missed (op 9) │ │ │ │ └────┬─────┴──────────┴──────────────┘ │ ▼ reconnect → RESUME if session_id still valid, else IDENTIFYPhase 1: HELLO
Section titled “Phase 1: HELLO”Right after connecting, the server sends opcode 10 (HELLO):
{ "op": 10, "d": { "heartbeat_interval": 41250 }}heartbeat_interval is in milliseconds. The client starts a timer that sends a heartbeat every N ms (see below).
Phase 2: IDENTIFY
Section titled “Phase 2: IDENTIFY”The client sends opcode 2 with the token and client info:
{ "op": 2, "d": { "token": "Bot MTIzNDU2...", "properties": { "os": "linux", "browser": "mybot", "device": "mybot" }, "presence": null, "ignored_events": [], "initial_guild_id": null, "flags": 0 }}| Field | Required | Description |
|---|---|---|
token | Yes | Bot <token> string for bots, or raw user token for first-party |
properties.os | Yes | Arbitrary string, e.g. linux |
properties.browser | Yes | Your app name, e.g. mybot |
properties.device | Yes | Device/instance name |
presence | No | Initial presence — see PRESENCE_UPDATE |
ignored_events | No | Array of event type names the client does not want. Default: receive everything |
initial_guild_id | No | Which guild to sync first when the client has many |
flags | No | Feature bitfield. Default 0 |
If the token is invalid the server closes the connection with 4004 AUTHENTICATION_FAILED. You must not reconnect in that case — it will escalate to a ban.
Phase 3: READY
Section titled “Phase 3: READY”On a successful IDENTIFY the server sends the READY event (op: 0, t: "READY"):
{ "op": 0, "s": 1, "t": "READY", "d": { "v": 1, "user": { "id": "149...", "username": "my_bot", "bot": true, "flags": 0 }, "session_id": "a1b2c3d4...", "resume_gateway_url": "wss://gateway.floodilka.com", "guilds": [ { "id": "142...", "unavailable": true } ], "user_settings": { ... } }}Fields you must persist:
session_id— needed for RESUMEresume_gateway_url— use this instead of the default URL when RESUMingsfrom the envelope (1here) — the latest sequence number
unavailable: true on a guild means full data hasn’t loaded yet. Expect GUILD_CREATE dispatches within seconds.
Phase 4: Heartbeat loop
Section titled “Phase 4: Heartbeat loop”The client must send opcode 1 every heartbeat_interval ms with the latest known s:
{ "op": 1, "d": 42 }Before any s has been seen (right after HELLO) send d: null.
The server replies with 11 (HEARTBEAT_ACK):
{ "op": 11 }The server may itself send opcode 1 asking the client to heartbeat immediately — reply right away, don’t wait for the timer.
Phase 5: Handling events
Section titled “Phase 5: Handling events”After READY, dispatch messages start arriving:
{ "op": 0, "s": 43, "t": "MESSAGE_CREATE", "d": { "id": "...", "channel_id": "...", "content": "hi", "author": { ... } }}Update s from every such message — you’ll need it for heartbeats and RESUME.
Full event list: Events.
Phase 6: Disconnect and recovery
Section titled “Phase 6: Disconnect and recovery”A connection can break in three ways:
RECONNECT (op 7)
Section titled “RECONNECT (op 7)”The server sends opcode 7 with no d — it wants the client to reconnect and resume:
{ "op": 7, "d": null }Algorithm:
- Close the WebSocket with code
4000(so the server keeps the session) - Reconnect to
resume_gateway_url(from READY) - Wait for HELLO, restart the heartbeat timer
- Send RESUME (op 6) instead of IDENTIFY
INVALID_SESSION (op 9)
Section titled “INVALID_SESSION (op 9)”The server sends opcode 9:
{ "op": 9, "d": true }d: true— the session is still alive, RESUME is allowedd: false— the session is dead, you must do a new IDENTIFY (not RESUME)
In either case wait 1–5 seconds with random jitter before retrying — don’t hammer.
Close code
Section titled “Close code”The WebSocket closed with a close code. See Close codes. The key rule:
1000,1001,4000-4003(except4004) — safe to reconnect4004 AUTHENTICATION_FAILED,4010 INVALID_SHARD,4011 SHARDING_REQUIRED,4012 INVALID_API_VERSION— reconnecting won’t help. Fix the client config
Phase 7: RESUME
Section titled “Phase 7: RESUME”RESUME is an IDENTIFY with the previous session’s context:
{ "op": 6, "d": { "token": "Bot MTIzNDU2...", "session_id": "a1b2c3d4...", "seq": 42 }}seq is the last observed s. The server catches the client up, replaying events from seq + 1 onward, then sends RESUMED (op: 0, t: "RESUMED").
If seq is too old for the server to replay, you’ll get op: 9 (INVALID_SESSION with d: false) and have to IDENTIFY fresh. Any state you’ve accumulated in memory must be discarded.
Resilient reconnect template
Section titled “Resilient reconnect template”- Connect, wait for HELLO, start the heartbeat timer
- If you have stored
session_idandseq— send RESUME. Otherwise — IDENTIFY - Wait for READY or RESUMED. Persist
session_idandresume_gateway_url - Process events, update
seqon every dispatch - On any disconnect:
- Exponential backoff with jitter (1s, 2s, 4s, …, max 30s)
- If the current attempt was a RESUME and it failed with
op: 9→ clear state and fall back to IDENTIFY - If the close code is
4004/4010/4011/4012— stop the bot, log the error, do not retry
What’s next
Section titled “What’s next”- Opcodes — every
opvalue - Close codes — the full close-code table
- Events — full list of dispatch events