FIFA WORLD CUP 2026
Group AMexico·Czechia·South Africa·South KoreaGroup BBosnia & Herzegovina·Canada·Qatar·SwitzerlandGroup CBrazil·Haiti·Morocco·ScotlandGroup DAustralia·Paraguay·Türkiye·USAGroup ECuraçao·Ecuador·Germany·Côte d'IvoireGroup FJapan·Netherlands·Sweden·TunisiaGroup GBelgium·Egypt·Iran·New ZealandGroup HCabo Verde·Saudi Arabia·Spain·UruguayGroup IFrance·Iraq·Norway·SenegalGroup JAlgeria·Argentina·Austria·JordanGroup KColombia·DR Congo·Portugal·UzbekistanGroup LCroatia·England·Ghana·Panama Group AMexico·Czechia·South Africa·South KoreaGroup BBosnia & Herzegovina·Canada·Qatar·SwitzerlandGroup CBrazil·Haiti·Morocco·ScotlandGroup DAustralia·Paraguay·Türkiye·USAGroup ECuraçao·Ecuador·Germany·Côte d'IvoireGroup FJapan·Netherlands·Sweden·TunisiaGroup GBelgium·Egypt·Iran·New ZealandGroup HCabo Verde·Saudi Arabia·Spain·UruguayGroup IFrance·Iraq·Norway·SenegalGroup JAlgeria·Argentina·Austria·JordanGroup KColombia·DR Congo·Portugal·UzbekistanGroup LCroatia·England·Ghana·Panama
Open full hub →
Growing Discord community — direct access to the developer, live coverage & picks. Join the Discord Join now →
Leagues Matches Predictions Stats
← All sports
Tennis WebSocket · Live

Tennis. Point-by-point.

Subscribe to any live match and receive a score frame on every point — sets, games, point score and serve indicator. Same token as the REST API.

wss://sports.bzzoiro.com/ws/live/?token=YOUR_TOKEN
Always pass "sport":"tennis" in every subscribe and unsubscribe — without it the server treats the event_id as football.
Connect & Auth

Connect

Append your API token as a query parameter. After the connection opens, send subscribe messages. You can mix tennis and football subscriptions on the same socket.

connect
wss://sports.bzzoiro.com/ws/live/?token=YOUR_TOKEN
Same token as the BSD REST API. Find it in your dashboard.
Subscribe

Subscribe / Unsubscribe / Ping

Send these JSON messages over the open socket.

outbound
// subscribe — sport:"tennis" is required
{ "action": "subscribe",   "event_id": 36835, "sport": "tennis" }

// unsubscribe
{ "action": "unsubscribe", "event_id": 36835, "sport": "tennis" }

// keepalive — send if socket may sit idle >60s
{ "action": "ping" }

Ping / Pong

The server does not send unsolicited pings. Send a ping when your socket may be idle for more than ~60s. The server replies immediately:

→ outbound / ← inbound
// you send:
{ "action": "ping" }

// server replies:
{ "type": "pong" }
While subscribed to an active match you receive score frames on every point — ping is only needed when no matches are live.

Find live match IDs at /tennis/api/v2/matches/?status=live.

Frame

subscribed

Sent immediately after a successful subscribe. Contains the latest event snapshot so you can render a complete scoreboard without waiting for the next tick.

inbound · subscribed
{
  "type":     "subscribed",
  "event_id": 36835,
  "sport":    "tennis",
  "event":    { /* latest event frame */ },
  "livedata": [ /* most recent score frames */ ],
  "history":  []
}
Frame

event

Full match snapshot. Sent every ~30s and on status changes. Contains players, sets, stats and tournament.

inbound · event
{
  "type":     "event",
  "event_id": 36835,
  "sport":    "tennis",
  "home":     { "id": 1, "name": "Djokovic, N." },
  "away":     { "id": 2, "name": "Alcaraz, C." },
  "score": {
    "sets": [[6,3],[4,6],[2,1]],
    "home_sets": 1, "away_sets": 1,
    "home_games": 2, "away_games": 1,
    "point": "40-15", "server": "home", "set": 3
  },
  "status": { "name": "live" },
  "stats": {
    "home": { "aces": 8, "double_faults": 2, "first_serve_pct": 63.4, "winners": 22, "unforced_errors": 14 },
    "away": { "...": "same shape" }
  },
  "tournament": { "name": "Roland Garros", "surface": "Clay" }
}
Frame

score

Pushed on every point — typically every few seconds during active play. Use this to update your scoreboard in real time.

inbound · score
{
  "type":     "score",
  "event_id": 36835,
  "uts":      1780516577,    // unix timestamp (seconds)
  "sets":     [[6,3],[4,6],[2,1]],
  "set":      3,              // current set (1-indexed)
  "game":     "2-1",
  "point":    "40-15",
  "server":   "home"          // "home" | "away" | null
}
FieldTypeDescription
setsarray[[home, away], ...] — one entry per completed or current set
setintCurrent set number (1-indexed)
gamestringGames in current set, e.g. "2-1"
pointstring0 / 15 / 30 / 40 / Deuce / Ad
serverstring|null"home", "away", or null
utsintUnix timestamp in seconds
Reference

Error codes

codeDescription
auth_failedToken missing, invalid or expired
subscription_requiredToken valid but WebSocket addon not active
not_trackedMatch exists but no live data available right now
limit10 concurrent match limit reached; unsubscribe first
bad_actionUnknown action value
bad_event_idevent_id not found
bad_sportUnrecognised sport value (always pass "tennis")
Reference

Limits

  • 10 concurrent matches per socket. Mix tennis and football on the same connection.
  • score pushed on every point — typically every few seconds
  • event snapshot every ~30s when something changes
  • Latest state replayed on subscribe
Reference

Code examples

JavaScript

JavaScript
const ws = new WebSocket("wss://sports.bzzoiro.com/ws/live/?token=YOUR_TOKEN");

ws.onopen = () => {
  ws.send(JSON.stringify({ action:"subscribe", event_id:36835, sport:"tennis" }));
};

ws.onmessage = ({ data }) => {
  const f = JSON.parse(data);
  switch (f.type) {
    case "subscribed": if (f.event) applyEvent(f.event); break;
    case "score":      updateBoard(f.sets, f.game, f.point, f.server); break;
    case "event":      if (f.sport === "tennis") applyEvent(f); break;
    case "pong":       break; // keepalive confirmed
    case "error":      console.error(f.code, f.message); break;
  }
};

// keepalive every 45s when idle
setInterval(() => ws.readyState === WebSocket.OPEN && ws.send('{"action":"ping"}'), 45000);

Python (asyncio)

Python
import asyncio, json, websockets

async def main():
    url = "wss://sports.bzzoiro.com/ws/live/?token=YOUR_TOKEN"
    async with websockets.connect(url) as ws:
        await ws.send(json.dumps({"action":"subscribe","event_id":36835,"sport":"tennis"}))
        async for msg in ws:
            f = json.loads(msg)
            if f["type"] == "score":
                sets = " | ".join(f'{s[0]}-{s[1]}' for s in f["sets"])
                print(f'Sets: {sets}  Game: {f["game"]}  Pt: {f["point"]}  Srv: {f["server"]}')

asyncio.run(main())
Live demo

Try it — connect to a live match

Connects to wss://sports.bzzoiro.com/ws/live/ directly from your browser.

The live demo requires an active WebSocket subscription. Get access →

Get access — $3.00/month

Football + Tennis included · 10 concurrent matches · auto-renewing