Realtime
Chat WebSocket
One Socket.IO namespace — wss://api.velora.tv/chat — carries every chat message, moderation action and viewer-count tick on Velora. Connect with a token and you can read and send as that user; connect without one and you read only. Chatbots, moderation tools and third-party chat clients all live on this one socket.
The namespace is not optional
Connect to wss://api.velora.tv/chat. If you connect to the root URL (wss://api.velora.tv/socket.io/) with no namespace, the server accepts your handshake and then disconnects you within seconds, because nothing is listening there. This is the first thing to check when a connection dies immediately.
Connect
Velora’s chat runs on Socket.IO. Both the websocket and polling transports work; websocket is the one to use for bots.
You can connect as a guest — read-only, you receive messages but cannot send — or as an authenticated user, which gives full chat permissions scoped by your account’s role and by channel-specific roles such as moderator or VIP.
If you’re building a bot, you want the authenticated path. Bots authenticate with either:
- A user JWT — the same kind a logged-in browser uses. Fastest path to ship.
- An OAuth 2.0 access token from a registered developer app. The proper choice for distributed or published bots.
wss://api.velora.tv/chat
Authenticate
Pass your JWT or OAuth access token using any of three methods. The gateway checks all three on connection and the first one present wins.
import { io } from 'socket.io-client';
const socket = io('wss://api.velora.tv/chat', {
auth: { token: 'YOUR_JWT_OR_OAUTH_TOKEN' },
transports: ['websocket'],
});const socket = io('wss://api.velora.tv/chat', {
extraHeaders: { Authorization: 'Bearer YOUR_TOKEN' },
transports: ['websocket'],
});const socket = io('wss://api.velora.tv/chat?token=YOUR_TOKEN', {
transports: ['websocket'],
});If no token is sent you connect as a guest (read-only). Authenticated connections receive your role, account-wide permissions and channel-specific roles automatically — there is no separate login event to emit.
Join a channel
Authenticating connects you to the gateway; it does not subscribe you to anything. To start receiving messages and events for a specific channel, emit joinChannel.
socket.emit('joinChannel', { channelId: 'streamer_user_id_or_username' });channelId can be either the broadcaster’s user ID (UUID) or their username — the server resolves both. You can join multiple channels concurrently on the same socket. To leave: socket.emit('leaveChannel', { channelId }).
Send a message
socket.emit('sendMessage', {
channelId: 'streamer_user_id_or_username',
message: 'Hello from my bot!',
// Optional fields:
platform: 'velora', // 'velora' (default), 'twitch', 'kick', 'youtube'
effect: 'rainbow', // optional message effect
effectColor: '#ff00ff', // optional color override
replyTo: { // optional reply context
messageId: 'parent_msg_id',
username: 'parent_author',
snippet: 'Parent message preview',
},
});The server enforces a 500-character maximum, per-channel slow-mode / follower-only / sub-only / emote-only checks, blacklist filtering, and email-verification gating. If your message is rejected you receive a commandResult event back saying why.
Events to listen for
The gateway emits a wide variety of events. These are the ones bots and chat clients actually use.
newMessageA new chat message arrived. Payload includes id, sender, content, badges, channelRole, replyTo.
userJoinedA user joined a channel you’re subscribed to.
userLeftA user left.
userBannedA user was banned from a channel — clients should purge their visible messages.
userTimedOutIncludes durationSeconds + expiresAt.
bannedViewerJoined / bannedViewerLeftMod-only — channel-banned-but-still-watching viewers (broadcaster + moderators only receive these, regular viewers don’t).
messagePinnedA pinned message went up; payload has the message and TTL.
raidSessionStarted / raidControlResultOutbound raid lifecycle.
viewer_count_updateLive viewer count for the channel.
moderationNoticeTargeted notice (ban, timeout, etc.) sent to the affected user.
commandResultResult of a sendMessage / slash command — check success and message fields.
chatClearedA moderator cleared chat history; clients should clear their local message buffer.
Reconnection & heartbeats
Socket.IO clients reconnect automatically. The gateway accepts a heartbeat emit at any cadence to keep your session warm and responds with the current channel members. If you don’t emit anything for a long stretch you may be dropped — emit a heartbeat or a ping every 60–120s if your client is otherwise quiet.
After a reconnect your joinChannel subscriptions must be re-emitted: they are scoped to the socket lifetime, not to the user. A reconnect handler that re-joins your channels is one of the first things to write.
Building a bot
For published or multi-user bots, register a developer app first — see Getting Started and Authentication. Your bot then uses an OAuth access token per streamer to connect on their behalf.
There is no separate “bot token” to generate.
The gateway accepts a normal access token — the same kind the OAuth flow returns. Pass it as auth.token on the socket handshake, or as an Authorization: Bearer header.
Client ID + client secret alone will not work.
Velora has no client-credentials grant. A bot always acts on behalf of a streamer, so it needs a token issued through the OAuth authorize flow with that streamer’s consent — even when the bot only ever serves one channel, and even when you are that streamer.
Long-running bots must refresh.
Access tokens are short-lived by design, so a bot that runs longer than a few minutes has to refresh using the refresh token from the same OAuth exchange. A token pasted into a config file by hand will stop working and is not a supported setup.
Bot accounts are flagged in the payload.
User IDs starting with bot:, streamerbot:, or devapp: carry isBot: true in their newMessage payloads, so chat clients can render bot messages differently if they want.
Need non-chat events too — subscriptions, raids, channel-points redemptions, donations? Use the Events API alongside the chat WebSocket. They complement each other.
Streamer.bot integration
Velora ships a first-class Streamer.bot bridge. If you’re writing a Streamer.bot action that needs to send a Velora chat message, use the bridge rather than speaking Socket.IO directly.
POST https://api.velora.tv/streamerbot/messages
Authorization: Bearer <streamerbot-config-token>
Content-Type: application/json
{
"channelId": "your_user_id",
"message": "Hello from Streamer.bot!"
}Configure the bridge token in your dashboard under Settings → Integrations → Streamer.bot. The bridge handles the WebSocket connection, retries and rate-limit backoff for you.
Slash commands in Streamer.bot: the bridge automatically recognises slash commands (messages starting with /) and executes them with the channel owner’s permissions. Sending "/announceblue Stream starting soon!" through the bridge executes the announcement command as if the streamer had typed it.
Slash commands
Velora supports slash commands for channel moderation and announcements. Sent via the Streamer.bot bridge or from a channel-owned bot, they execute with the channel owner’s permissions.
Announcement commands
Post styled announcements in chat that are instantly recognisable and attention-grabbing — stream start/end notices, important updates, calls to action.
Base command (channel accent colour)
/announce <message>alias: /ann/announceblue <message>alias: /annblue/announcegold <message>alias: /anngold/announcegreen <message>alias: /anngreen/announcered <message>alias: /annred/announceorange <message>alias: /annorange/announcecoral <message>alias: /anncoralRequirements & limits
POST https://api.velora.tv/streamerbot/messages
Authorization: Bearer <your-token>
Content-Type: application/json
{
"channelId": "your_user_id",
"message": "/announceblue **Stream starting in 5 minutes!** Get ready!"
}More slash commands are documented in the dashboard under Chat Settings → Commands. Common ones include /timeout, /ban, /mod, /vip and /raid.
Common gotchas
“I connect, then disconnect within seconds”
You’re connecting to the wrong namespace. Use wss://api.velora.tv/chat, NOT wss://api.velora.tv/socket.io/ with no namespace.
“My messages are getting blocked”
Listen for commandResult — it tells you exactly why a message was rejected (slow-mode, sub-only, email-verification, etc.). The most common surprise is email-verification: bot accounts must have a verified email address attached.
“I’m receiving events for the wrong channel”
You forgot to leave a previous channel before joining a new one, or your bot is in multiple channels and needs to filter on the event payload’s channelId.
“CORS errors from a browser-based client”
The gateway accepts connections from *.velora.tv, localhost, and mobile app schemes (capacitor://, ionic://, file://). For other origins, use the OAuth-via-server pattern instead of speaking from the browser directly.
Need help?
File an issue on Nexus, or join the Velora Discord and ping a CM in #cm-workspace. If you’re hitting a specific event or payload-shape mismatch with what’s documented here, include the full client-side log and the connection URL — that gets an answer fastest.