Skip to main content

Overview

The WebSocket feed delivers real-time odds updates with the same response format as the REST API /odds endpoint. Instead of polling, you receive instant updates whenever odds change.
Add-on Feature: WebSocket access is available as an add-on. Subscribe through odds-api.io to enable it for your account.

Connection

Endpoint:
wss://api.odds-api.io/v3/ws?apiKey=YOUR_API_KEY
Authentication:
  • API key passed as query parameter
  • One connection per API key
  • New connections automatically close older ones
Pricing: 2x the REST API price Bookmakers: The WebSocket automatically sends updates for all bookmakers you have selected in your account. Manage your bookmakers via the /bookmakers/selected/select endpoint.

Filter Parameters

The markets parameter is required. You must specify which markets you want to receive.
ParameterTypeMaxDescription
marketscomma-separated20Required. Market names (e.g., ML,Spread,Totals)
sportcomma-separated10Filter by sport slugs (e.g., football,basketball)
leaguescomma-separated20Filter by league slugs (e.g., england-premier-league)
eventIdscomma-separated50Filter by specific event IDs
statussingle value-live or prematch
Using leagues or eventIds is recommended to reduce bandwidth. You cannot use both together.

Example URLs

# Live football with main markets
wss://api.odds-api.io/v3/ws?apiKey=xxx&sport=football&status=live&markets=ML,Spread,Totals

# Specific leagues
wss://api.odds-api.io/v3/ws?apiKey=xxx&leagues=england-premier-league,spain-la-liga&markets=ML

# Specific events
wss://api.odds-api.io/v3/ws?apiKey=xxx&eventIds=12345,67890

# Multiple sports, prematch only
wss://api.odds-api.io/v3/ws?apiKey=xxx&sport=football,basketball&status=prematch

Error Responses (400 Bad Request)

ErrorCause
Too many sports. Maximum 10 allowed.Exceeded limit
Too many leagues. Maximum 20 allowed.Exceeded limit
Too many event IDs. Maximum 50 allowed.Exceeded limit
Too many markets. Maximum 20 allowed.Exceeded limit
Cannot use both 'leagues' and 'eventIds' filters together.Mutual exclusion
Invalid status filter. Use 'prematch' or 'live'Invalid value

Message Types

TypeDescription
welcomeConnection confirmed with active filters
createdNew match added
updatedMatch or market changed
deletedMatch removed
no_marketsMatch exists but currently no markets available

Welcome Message

Sent immediately after connection:
{
  "type": "welcome",
  "message": "Connected to OddsAPI WebSocket",
  "user_id": "user123",
  "bookmakers": ["Bet365", "Pinnacle"],
  "sport_filter": ["Football"],
  "leagues_filter": ["england-premier-league"],
  "event_id_filter": [],
  "status_filter": "live",
  "market_filter": ["ML", "SPREAD", "TOTALS"],
  "connected_at": "2026-01-15T21:00:00Z"
}

Message Format

{
  "type": "updated",
  "timestamp": "2025-08-18T14:52:52.983Z",
  "id": "63017989",
  "bookie": "SingBet",
  "url": "https://www.singbet.com/sports/football/match/63017989",
  "markets": [
    {
      "name": "ML",
      "updatedAt": "2024-01-15T10:30:00Z",
      "odds": [
        {
          "home": "1.85",
          "draw": "3.25",
          "away": "2.10",
          "max": 500
        }
      ]
    },
    {
      "name": "Totals",
      "updatedAt": "2024-01-15T10:30:00Z",
      "odds": [
        {
          "hdp": 2.5,
          "over": "1.85",
          "under": "2.10",
          "max": 500
        }
      ]
    }
  ]
}

Quick Start

const WebSocket = require('ws');

const apiKey = process.env.ODDS_API_KEY;
const params = new URLSearchParams({
  apiKey,
  markets: 'ML,Spread,Totals',
  sport: 'football',
  status: 'live'
});

const ws = new WebSocket(`wss://api.odds-api.io/v3/ws?${params}`);

ws.onopen = () => console.log("Connecting...");

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);

  if (data.type === 'welcome') {
    console.log("Connected! Filters:", data.sport_filter, data.status_filter);
  } else if (data.type === 'updated') {
    console.log(`Match ${data.id} at ${data.bookie}:`, data.markets.length, "markets");
  }
};

ws.onerror = (err) => console.error("Error:", err);
ws.onclose = () => console.log("Disconnected");

Handling Message Types

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);

  switch (data.type) {
    case 'welcome':
      console.log(`Connected: ${data.message}`);
      console.log(`Filters: ${data.sport_filter}, ${data.status_filter}`);
      break;

    case 'created':
      console.log(`New match: ${data.id} at ${data.bookie}`);
      break;

    case 'updated':
      console.log(`Match updated: ${data.id} at ${data.bookie}`);
      break;

    case 'deleted':
      console.log(`Match deleted: ${data.id} at ${data.bookie}`);
      break;

    case 'no_markets':
      console.log(`No markets: ${data.id}`);
      break;
  }
};

Best Practices

Use leagues or eventIds filters when you only need specific data. This reduces bandwidth and improves performance.
Always implement exponential backoff for reconnections to handle network issues gracefully.
Handle welcome, created, updated, deleted, and no_markets to keep your data in sync.
New connections automatically close older ones. Don’t create multiple connections with the same API key.
If receiving many updates, process them asynchronously to avoid blocking your main thread.

Benefits Over REST API

FeatureREST APIWebSocket
Latency100-500ms (polling)<150ms (push)
Request overheadMultiple HTTP requestsSingle persistent connection
Real-time updatesManual pollingAutomatic push
BandwidthHigher (repeated headers)Lower (single connection)
Best forBatch requestsLive updates

Get Access

Enable WebSocket Access

Subscribe to WebSocket as an add-on through your odds-api.io account