Gateway
Connecting
GET /gateway/bot says where the gateway is (GET /gateway too,
without a token):
{ "url": "wss://api.voicaw.com/api/gateway", "shards": 1,
"session_start_limit": { "total": 1000, "remaining": 1000, "reset_after": 86400000, "max_concurrency": 1 } }
Connect to it with the version and encoding, as on Discord:
wss://api.voicaw.com/api/gateway?v=10&encoding=json&compress=zlib-stream
encoding: onlyjson. Anything else (etf) is closed with4002.compress: leave it out for plain text frames, orzlib-streamfor one zlib stream across the connection, flushed after every payload (binary frames ending in00 00 ff ff). What you send is never compressed.
The gateway then sends Hello with the heartbeat interval (41.25 seconds). Send a heartbeat
that often (Voicaw closes a connection that hasn't sent one in about 67 seconds with
4009), and Identify within 30 seconds (or 4003).
Opcodes
| Op | Name | Direction | Notes |
|---|---|---|---|
| 0 | Dispatch | Receive | An event, with its name t and sequence number s. |
| 1 | Heartbeat | Send | Answered with Heartbeat ACK. |
| 2 | Identify | Send | token, intents (required), properties, and optionally shard and presence. compress and large_threshold are ignored. |
| 3 | Presence Update | Send | status: online, idle, dnd (shown as online) or invisible (shown as offline). Activities aren't shown. |
| 4 | Voice State Update | Send | Ignored: bots can't join voice channels. |
| 6 | Resume | Send | token, session_id, seq. |
| 8 | Request Guild Members | Send | guild_id (or a list), query and limit, or user_ids (up to 100); presences, nonce. Answered with Guild Members Chunk events of up to 1000 members. |
| 9 | Invalid Session | Receive | The session can't be resumed (always false): Identify again. |
| 10 | Hello | Receive | heartbeat_interval. |
| 11 | Heartbeat ACK | Receive |
The gateway never sends Reconnect (7) or asks for a heartbeat (1).
Ready and guilds
After Identify comes READY (the bot's user, its guilds as unavailable, the
session_id and resume_gateway_url), then one
GUILD_CREATE per guild (with the Guilds intent). A guild comes whole: its
roles, emoji, the channels and active threads the bot can see, and every member
(large is always false), with presences if you asked for the Guild Presences
intent. voice_states is always empty.
Resuming
If the connection drops, the session waits two minutes for a Resume, keeping the last 1000
events. Resume on a new connection (at resume_gateway_url, the same address)
and you get everything after seq, then RESUMED. Closing the
connection yourself with 1000 or 1001 ends the session at once, as on Discord.
Intents and events
Intents choose which events you get. None is privileged: no approval is needed for any of them. Message content is included whether or not you ask for Message Content.
| Intent | Bit | Events |
|---|---|---|
| Guilds | 1 << 0 | GUILD_CREATE, GUILD_UPDATE, GUILD_DELETE, GUILD_ROLE_CREATE, GUILD_ROLE_UPDATE, GUILD_ROLE_DELETE, CHANNEL_CREATE, CHANNEL_UPDATE, CHANNEL_DELETE, CHANNEL_PINS_UPDATE, THREAD_CREATE, THREAD_UPDATE, THREAD_DELETE |
| Guild Members | 1 << 1 | GUILD_MEMBER_ADD, GUILD_MEMBER_UPDATE, GUILD_MEMBER_REMOVE |
| Guild Expressions | 1 << 3 | GUILD_EMOJIS_UPDATE |
| Guild Voice States | 1 << 7 | VOICE_STATE_UPDATE (people joining, leaving, muting in voice channels) |
| Guild Presences | 1 << 8 | PRESENCE_UPDATE, and presences in GUILD_CREATE |
| Guild Messages | 1 << 9 | MESSAGE_CREATE, MESSAGE_UPDATE, MESSAGE_DELETE |
| Guild Message Reactions | 1 << 10 | MESSAGE_REACTION_ADD, MESSAGE_REACTION_REMOVE |
| Guild Message Typing | 1 << 11 | TYPING_START |
| Guild Scheduled Events | 1 << 16 | GUILD_SCHEDULED_EVENT_CREATE, GUILD_SCHEDULED_EVENT_UPDATE (also when one starts, ends with status 3, or moves on to its next occurrence), GUILD_SCHEDULED_EVENT_DELETE, GUILD_SCHEDULED_EVENT_USER_ADD, GUILD_SCHEDULED_EVENT_USER_REMOVE; with Guilds, guild_scheduled_events in GUILD_CREATE |
Always, whatever the intents: READY, RESUMED,
INTERACTION_CREATE (to one of the bot's sessions; see
Commands and components),
GUILD_MEMBERS_CHUNK, USER_UPDATE (for the bot itself) and
GUILD_MEMBER_UPDATE for the bot's own member. Discord's other intents are
accepted but bring nothing: Moderation, Integrations, Webhooks, Invites, Direct Message
Reactions and Typing, Auto Moderation and Polls. Direct Messages
(1 << 12) brings MESSAGE_CREATE, _UPDATE and
_DELETE for the bot's DMs (no guild_id; to shard 0 only, as on
Discord). See DMs.
Not sent: bulk deletes come as one MESSAGE_DELETE per message, and removing every reaction as one MESSAGE_REACTION_REMOVE per reaction. Bans have no event of their own (the member's GUILD_MEMBER_REMOVE comes).
Events only come for what the bot can see: messages in channels it has View Channel in,
and presences and members of guilds it's in. A channel that becomes visible or hidden to
the bot (a permission change) comes as CHANNEL_CREATE or
CHANNEL_DELETE.
Limits and sharding
- Up to 16 sessions at once per bot (more are closed with
4008). - Up to 120 payloads a minute sent by the bot, as on Discord (more:
4008). shard: [id, count]is accepted, and guilds are split with Discord's formula,(guild_id >> 22) % count. Voicaw's ids are small numbers, not snowflakes, so in practice every guild lands on shard 0: one shard is all a bot needs.
Close codes
| Code | Meaning | Reconnect? |
|---|---|---|
4000 | Unknown error, or the session was resumed on another connection | Yes |
4001 | Unknown opcode | Yes |
4002 | Payload not valid JSON, or an encoding/compression Voicaw doesn't support | Yes (fix the URL) |
4003 | Not authenticated (no Identify in time, or a payload before it) | Yes |
4004 | Authentication failed: a wrong token, or it was reset or the application deleted | No |
4005 | Already authenticated | Yes |
4008 | Rate limited, or too many sessions | Yes, later |
4009 | Session timed out (no heartbeat) | Yes |
4010 | Invalid shard | No |
4013 | Invalid intents | No |