Examples

Worked examples across languages and use cases

Full end-to-end snippets — not just single calls — for the integrations developers build most often: live scores, real-time feeds, odds comparison, historical analysis and webhooks.

Which One Do I Need?

Pick a pattern by use case

All five examples call the same underlying API — the difference is how data reaches your application.

Use caseExampleBest for
Show live scores on a website or appLive ScoreboardLow to medium traffic, simplest to build
Sub-second updates, many concurrent viewersReal-Time FeedTrading desks, high-frequency widgets
Compare prices across bookmakersOdds ComparisonOdds aggregation, pricing tools
Analyze past seasons at scaleHistorical BacktestResearch, modeling, reports
React to match events the instant they happenWebhook ListenerEvent-driven backends, notifications
00Prerequisites

Before you start

Every example below assumes the same two things.

1 A free Orbistats API key
2 Node.js 18+ or Python 3.9+ installed
i Every snippet also works as a plain HTTP request with a Bearer token — the SDK just removes boilerplate around auth, retries and pagination. See SDKs for install instructions.
01Example — Live Scoreboard

Poll live matches every few seconds

A minimal loop that keeps a scoreboard in sync with in-play matches — the simplest way to show live scores.

const orbistats = require('@orbistats/sdk');
const client = new orbistats.Client(process.env.ORBISTATS_API_KEY);

async function refreshScoreboard() {
  try {
    const live = await client.football.matchesLive();
    renderScoreboard(live.data);
  } catch (err) {
    console.error('Failed to fetch live matches:', err.message);
  }
}

refreshScoreboard();
setInterval(refreshScoreboard, 5000);
import os, time
from orbistats import Client

client = Client(api_key=os.environ["ORBISTATS_API_KEY"])

def refresh_scoreboard():
  try:
    live = client.football.matches_live()
    render_scoreboard(live["data"])
  except Exception as exc:
    print(f"Failed to fetch live matches: {exc}")

while True:
  refresh_scoreboard()
  time.sleep(5)
  • Polling every 5 seconds is frequent enough for a live board and well under the free-tier rate limit.
  • The try/except block means one failed request never crashes the loop.
  • matchesLive() only returns fixtures currently in play, so there's no client-side filtering to do.
→ For sub-second updates or many concurrent boards, skip polling entirely and use the Real-Time Feed example below instead.
02Example — Real-Time Feed

Stream updates instead of polling

One persistent WebSocket connection replaces thousands of polling requests and delivers updates the instant they happen.

const WebSocket = require('ws');

const socket = new WebSocket('wss://stream.orbistats.com/v1/football?apikey=YOUR_API_KEY');

socket.on('open', () => console.log('Connected to live feed'));

socket.on('message', (raw) => {
  const event = JSON.parse(raw);
  if (event.type === 'score_update') {
    updateScoreboard(event.fixture_id, event.score);
  }
});

socket.on('close', () => console.log('Disconnected — reconnect logic goes here'));
import asyncio, json, websockets

async def listen():
  uri = "wss://stream.orbistats.com/v1/football?apikey=YOUR_API_KEY"
  async with websockets.connect(uri) as ws:
    async for raw in ws:
      event = json.loads(raw)
      if event["type"] == "score_update":
        update_scoreboard(event["fixture_id"], event["score"])

asyncio.run(listen())
  • Always handle the close/error event and reconnect with exponential backoff in production.
  • The feed carries score updates, match events and odds changes on the same stream — filter by event.type client-side.
  • See the WebSocket API reference for the full list of event types.
03Example — Odds Comparison

Find the best available line

Normalized odds make it trivial to compare bookmakers directly, without unit conversion.

odds = client.football.odds(match_id=884213)
markets = odds["data"]["markets"]["1X2"]

best_home = max(markets, key=lambda m: m["home"])
print(f"Best home price: {best_home['home']} at {best_home['bookmaker']}")
const odds = await client.football.odds({ matchId: 884213 });
const markets = odds.data.markets['1X2'];

const bestHome = markets.reduce((a, b) => (a.home > b.home ? a : b));
console.log(`Best home price: ${bestHome.home} at ${bestHome.bookmaker}`);
  • Odds are normalized to decimal format across every connected bookmaker, so no conversion is needed before comparing.
  • Every market entry is tagged with a bookmaker name, so you can always trace where a price came from.
  • Combine this with the Webhook Listener below to react the moment a line moves, instead of re-polling.
04Example — Historical Backtest

Pull multi-season data into pandas

Historical Data returns the same schema as live fixtures, so backtests reuse the same parsing code.

import pandas as pd

results = client.football.historical(season="2019-2025")
df = pd.DataFrame(results["data"])

df["over_2_5"] = (df["home_goals"] + df["away_goals"]) > 2.5
print(df.groupby("competition")["over_2_5"].mean())
  • The historical schema mirrors live fixtures field-for-field, so the same parsing code works for both.
  • Results are paginated — for multi-season pulls, loop through pagination.total_pages rather than assuming one response covers everything.
  • This pattern is what powers our own research reports — good for a notebook, a trading model, or a write-up of your own.
05Example — Webhook Listener

Receive match events as they happen

Register an endpoint once in the dashboard, then let Orbistats push events to you — no polling loop to maintain.

const express = require('express');
const app = express();
app.use(express.json());

app.post('/webhooks/orbistats', (req, res) => {
  const event = req.body;

  if (event.event === 'fixture.finished') {
    console.log(`${event.fixture_id} finished: ${event.final_score.home}-${event.final_score.away}`);
  }

  res.sendStatus(200); // acknowledge quickly — Orbistats retries on non-2xx
});

app.listen(3000);
from flask import Flask, request

app = Flask(__name__)

@app.route("/webhooks/orbistats", methods=["POST"])
def orbistats_webhook():
  event = request.get_json()

  if event["event"] == "fixture.finished":
    print(f"{event['fixture_id']} finished: {event['final_score']}")

  return "", 200 # acknowledge quickly — Orbistats retries on non-2xx
  • Respond with a 2xx status within a few seconds. Slow or failing endpoints get retried, then temporarily paused.
  • Choose which event types to receive from the dashboard, not in code.
  • Verify the signature header on production endpoints so only genuine Orbistats requests are processed.
→ Full payload shapes, event types and signature verification live in the Webhooks reference.
06FAQs

Common questions

Should I use polling or WebSockets for live scores?

Polling every few seconds is simple and fine for low to medium traffic. For sub-second updates or many concurrent viewers, a persistent WebSocket connection is far more efficient.

Do these examples work without an SDK?

Yes. Every example also works with plain HTTP requests and a Bearer token — the SDK just removes boilerplate around auth, retries and pagination.

How do I test a webhook endpoint locally?

Use a tunneling tool such as ngrok to expose your local server, then register the temporary public URL as your webhook endpoint in the dashboard.

Can I combine these examples, like odds comparison with webhooks?

Yes — a common pattern is to trigger the odds comparison logic from an odds.changed webhook instead of polling, reacting the moment a price moves.

07Next Steps

Take it further

See Also

Related pages

Explore more of the developer platform.

Get Started

Start free. Upgrade when you need enterprise SLAs.

Self-serve API keys for developers today — dedicated infrastructure, custom feeds and SLAs when you're ready.