Events API

Real-time event streaming for your channel. Perfect for stream tools, bots, and integrations like Streamer.bot.

No webhook server required

Unlike webhooks, the Events API doesn't require you to host a server. Your application connects directly to Velora and receives events in real-time. This is ideal for desktop applications, stream tools, and situations where hosting a webhook endpoint isn't practical.

Overview

The Events API provides two ways to receive real-time events for your channel:

WebSocket

Persistent bidirectional connection using Socket.IO

wss://api.velora.tv/ws/events

Server-Sent Events (SSE)

HTTP-based streaming for simpler clients

GET /api/events/stream

Authentication

Both connection methods use your broadcaster OAuth access token for authentication. No special scopes are required—if you have a valid token for a broadcaster, you can receive their events.

No special permissions needed. Any valid broadcaster access token can receive events for that channel.

Getting an Access Token

Use the standard OAuth flow to get a broadcaster's access token. See the Authentication Guide for details.

WebSocket Connection

The WebSocket endpoint uses Socket.IO for reliable connections with automatic reconnection.

Connection URL

wss://api.velora.tv/ws/events

Connection Example (JavaScript)

import { io } from 'socket.io-client';

const socket = io('wss://api.velora.tv/ws/events', {
  auth: {
    token: 'YOUR_ACCESS_TOKEN'
  },
  // Or pass token as query parameter:
  // query: { token: 'YOUR_ACCESS_TOKEN' }
});

// Connection established
socket.on('connected', (data) => {
  console.log('Connected to Events API');
  console.log('Channel:', data.channelUsername);
});

// Listen for all events
socket.on('event', (payload) => {
  console.log('Event received:', payload.event);
  console.log('Data:', payload.data);
  console.log('Timestamp:', payload.timestamp);
});

// Handle errors
socket.on('error', (err) => {
  console.error('Connection error:', err.message);
});

// Handle disconnection
socket.on('disconnect', (reason) => {
  console.log('Disconnected:', reason);
});

Connection Example (C# / Streamer.bot)

using SocketIOClient;

var socket = new SocketIO("wss://api.velora.tv/ws/events", new SocketIOOptions
{
    Auth = new { token = "YOUR_ACCESS_TOKEN" }
});

socket.On("connected", response =>
{
    var data = response.GetValue<ConnectedData>();
    Console.WriteLine($"Connected as {data.ChannelUsername}");
});

socket.On("event", response =>
{
    var payload = response.GetValue<EventPayload>();
    Console.WriteLine($"Event: {payload.Event}");
    // Handle the event...
});

await socket.ConnectAsync();

Server-Sent Events (SSE)

SSE is a simpler alternative that works over standard HTTP. Great for languages without good Socket.IO support.

Endpoint

GET https://api.velora.tv/api/events/stream

Headers

HeaderValue
AuthorizationBearer YOUR_ACCESS_TOKEN
Accepttext/event-stream

Optional: Filter Events

You can filter which events you receive using the events query parameter:

GET /api/events/stream?events=channel.follow,channel.subscribe,chat.message

Connection Example (JavaScript)

const eventSource = new EventSource(
  'https://api.velora.tv/api/events/stream',
  {
    headers: {
      'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
    }
  }
);

// Connection established
eventSource.addEventListener('connected', (e) => {
  const data = JSON.parse(e.data);
  console.log('Connected:', data.channelUsername);
});

// Listen for specific event types
eventSource.addEventListener('channel.follow', (e) => {
  const payload = JSON.parse(e.data);
  console.log('New follower:', payload.data.username);
});

eventSource.addEventListener('channel.subscribe', (e) => {
  const payload = JSON.parse(e.data);
  console.log('New sub:', payload.data.username);
});

// Or listen for all events
eventSource.onmessage = (e) => {
  const payload = JSON.parse(e.data);
  console.log('Event:', payload.event, payload.data);
};

eventSource.onerror = (e) => {
  console.error('SSE error:', e);
};

Connection Example (curl)

curl -N -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
     -H "Accept: text/event-stream" \
     "https://api.velora.tv/api/events/stream"

Event Format

All events follow a consistent format:

{
  "event": "channel.follow",
  "timestamp": "2026-02-10T12:00:00.000Z",
  "data": {
    "userId": "user_abc123",
    "username": "newviewer",
    "displayName": "NewViewer",
    "followedAt": "2026-02-10T12:00:00.000Z"
  }
}
FieldTypeDescription
eventstringThe event type (e.g., "channel.follow")
timestampstringISO 8601 timestamp when the event occurred
dataobjectEvent-specific payload data

Available Events

Stream Events

EventDescription
stream.onlineStream goes live
stream.offlineStream ends
stream.updateStream title or category changes

Chat Events

EventDescription
chat.messageChat message sent in your channel (includes regular messages and card messages like stickers/sounds)

chat.message Payload

FieldTypeDescription
messageIdstringUnique message identifier
userIdstringSender's user ID
usernamestringSender's username
displayNamestringSender's display name
messagestringThe message text content
badgesstring[]Badge slugs for this user
isModbooleanWhether the user is a moderator
isVipbooleanWhether the user is a VIP
isSubscriberbooleanWhether the user is subscribed
subscriberMonthsnumber?Subscription tenure in months (if subscribed)
colorstring?User's accent color (hex)
mentionsAdded 2026-03-02Array<{username, userId, displayName}>?Resolved @mentions found in the message. Only present when the message contains valid @username mentions.
cardAdded 2026-03-02object?Present on card messages (stickers, sounds, celebrations). Contains type and payload.
isSystemboolean?True for system/card messages

Card types include: sticker-send, sound-send, emote-sticker-send, volts-celebration, subscription-celebration, gift-celebration, and more. Check data.card.type to identify the card type.

Channel Events

EventDescription
channel.followSomeone follows the channel
channel.subscribeNew or renewed subscription
channel.subscription.giftGift subscription(s) given
channel.voltsUser sends Volts
channel.raidChannel receives a raid
channel.banUser banned from channel
channel.unbanUser unbanned from channel
channel.moderator.addModerator added
channel.moderator.removeModerator removed
channel.channel_points_redemptionChannel points reward redeemed

Interaction Events

EventDescription
channel.poll.beginPoll starts
channel.poll.endPoll ends
channel.prediction.beginPrediction starts
channel.prediction.lockPrediction betting locks
channel.prediction.endPrediction ends/resolves
channel.hype_train.beginHype train starts
channel.hype_train.progressHype train level increases
channel.hype_train.endHype train ends

Fetching Channel Point Rewards

To build a bot that responds to channel point redemptions, you'll want to know what rewards a channel has configured. You can fetch them via REST API or directly through WebSocket.

Option 1: REST API Endpoint

GET https://api.velora.tv/api/channel-points/{channelId}/items/with-built-in

No authentication required. This endpoint is public, so you can fetch rewards without an access token.

Option 2: WebSocket Request

If you're already connected via WebSocket, you can request the rewards list directly:

// Request rewards over WebSocket
socket.emit('channel:getRewards');

// Listen for the response
socket.on('channel:rewards', (rewards) => {
  console.log('Channel rewards:', rewards);
  // [
  //   { id: '...', name: 'Highlight My Message', cost: 500, ... },
  //   { id: '...', name: 'First', cost: 1, builtInType: 'first', ... }
  // ]
});

// Handle errors
socket.on('error', (err) => {
  if (err.code === 'SERVICE_UNAVAILABLE') {
    // Channel points service not available
  }
});

Example REST Response

{
  "items": [
    {
      "id": "reward_abc123",
      "name": "Highlight My Message",
      "cost": 500,
      "description": "Make your message stand out!",
      "iconUrl": "https://...",
      "builtInType": null,  // null = custom reward
      "enabled": true,
      "requiresModeratorApproval": false,
      "maxPerStream": null,
      "maxPerUserPerStream": 3
    },
    {
      "id": "reward_xyz789",
      "name": "First",
      "cost": 1,
      "description": "Be the first to claim this each stream!",
      "builtInType": "first",  // Built-in reward type
      "enabled": true
    }
  ]
}

WebSocket Response Format

The WebSocket channel:rewards response returns an array directly:

[
  {
    "id": "reward_abc123",
    "name": "Highlight My Message",
    "cost": 500,
    "description": "Make your message stand out!",
    "iconUrl": "https://...",
    "enabled": true,
    "isBuiltIn": false,
    "builtInType": null
  },
  {
    "id": "reward_xyz789",
    "name": "First",
    "cost": 1,
    "description": "Be the first to claim this each stream!",
    "iconUrl": null,
    "enabled": true,
    "isBuiltIn": true,
    "builtInType": "first"
  }
]

Matching Redemptions to Rewards

When you receive a channel.channel_points_redemption event, it includes the rewardId and rewardTitle. Match these against your fetched rewards list to trigger the appropriate action:

// Redemption event payload
{
  "event": "channel.channel_points_redemption",
  "timestamp": "2026-02-10T12:00:00Z",
  "data": {
    "redemptionId": "red_abc123",
    "rewardId": "reward_abc123",     // Match this to your rewards list
    "rewardTitle": "Highlight My Message",
    "rewardCost": 500,
    "userId": "user_xyz",
    "username": "viewer123",
    "displayName": "Viewer123",
    "userInput": "Check out my message!",  // If reward accepts input
    "status": "unfulfilled",
    "redeemedAt": "2026-02-10T12:00:00Z"
  }
}

Events API vs Webhooks

FeatureEvents APIWebhooks
Server requiredNoYes
Desktop app friendlyYesNo
Connection typePersistent (outbound)On-demand (inbound)
LatencyLower (real-time)Slightly higher
Retry handlingAutomatic reconnectServer retries
Best forStream tools, bots, desktop appsWeb servers, automation

Related Documentation