Building bots
Gateway
One WebSocket that tells your bot what's happening, as it happens.
Connect to wss://bafflux.com/api/gateway with your token in the Authorization header. While at least one connection is open, your bot shows as online.
const ws = new WebSocket('wss://bafflux.com/api/gateway', { headers: { Authorization: `Bot ${process.env.BOT_TOKEN}` } });
ws.onmessage = (event) => {
const { t, d } = JSON.parse(event.data);
console.log(t, d);
};In Python, the websockets package takes the header as additional_headers={"Authorization": f"Bot {token}"}.
Messages
Every message from the gateway is JSON with two fields:
| Field | Meaning |
|---|---|
t | The event name, like MESSAGE_CREATE |
d | The event's data |
The gateway only talks: you never need to send anything on it. The server sends a WebSocket ping every 25 seconds, which WebSocket libraries answer on their own.
Staying connected
- The first event is always
READY, with your bot's account ind.user. - Connections can drop (server restarts, network trouble). Reconnect with a growing delay: 1 s, 2 s, 4 s... up to 30 s.
- Events that happened while you were disconnected aren't replayed. After reconnecting, fetch whatever you need to catch up on (for example the newest messages of a channel).
- A bot that stops reading falls behind: after 256 unread events, new ones are dropped for that connection.
Events
| Event | When | d |
|---|---|---|
READY | You connected | { user } |
SERVER_CREATE | Your bot was added to a server | The server, with channels, roles and myRoles |
SERVER_UPDATE | A server's name or icon changed | { id, name, iconUrl } |
SERVER_REMOVE | Your bot was kicked or banned, or the server was deleted | { serverId, reason } |
SERVER_CHANNELS_UPDATE | Channels were added, changed, moved or deleted | { serverId, channels } (the whole list you can see) |
SERVER_ROLES_UPDATE | Roles changed | { serverId, roles } |
THREAD_UPDATE | A thread got a message, was renamed, hidden or shown | { serverId, channel } |
MESSAGE_CREATE | A new message | A message, plus serverId |
MESSAGE_UPDATE | A message was edited, or its link previews or embed image sizes arrived | A message |
MESSAGE_DELETE | A message was deleted | { id, channelId } |
MESSAGE_REACTION_ADD / MESSAGE_REACTION_REMOVE | Someone reacted or took it back | { channelId, messageId, userId, emoji } |
MESSAGE_PIN | A message was pinned or unpinned | { channelId, messageId, pinned } |
TYPING_START | Someone started typing | { channelId, userId } |
MENTION | A message mentions your bot (directly, a role it has, or @everyone) | { channelId, messageId, serverId } |
MEMBER_ADD | Someone joined a server | { serverId, member } |
MEMBER_REMOVE | Someone left or was removed | { serverId, userId } |
MEMBER_UPDATE | Someone's roles changed | { serverId, userId, roles } |
PRESENCE_UPDATE | Someone's status changed | { userId, status, customStatus } |
USER_UPDATE | Someone changed their name or pictures | { id, username, displayName, avatarUrl, bannerUrl } |
DM_OPEN | A DM with your bot opened | The DM channel |
INTERACTION_CREATE | Someone used one of your slash commands | An interaction |
You only get events for servers your bot is in and channels it can see.
Example: a prefix command
Prefix commands (like !help) are ordinary messages. Watch MESSAGE_CREATE, skip your own messages, and reply:
if (t === 'MESSAGE_CREATE' && d.content === '!help' && d.author.id !== myId) {
await fetch(`https://bafflux.com/api/channels/${d.channelId}/messages`, {
method: 'POST',
headers: { Authorization: `Bot ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ content: 'Try /ping or /say', replyTo: d.id })
});
}Take myId from the READY event (d.user.id). Register prefix commands too (see Commands), so they're listed in the command picker.