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.
Live Scoreboard
Poll live matches and render a scrolling scoreboard.
Real-Time Feed
Stream score and odds updates over a WebSocket.
Odds Comparison
Pull odds across books and compute the best line.
Historical Backtest
Pull multi-season data into a Python notebook.
Webhook Listener
Receive match events as they happen, no polling.
Pick a pattern by use case
All five examples call the same underlying API — the difference is how data reaches your application.
| Use case | Example | Best for |
|---|---|---|
| Show live scores on a website or app | Live Scoreboard | Low to medium traffic, simplest to build |
| Sub-second updates, many concurrent viewers | Real-Time Feed | Trading desks, high-frequency widgets |
| Compare prices across bookmakers | Odds Comparison | Odds aggregation, pricing tools |
| Analyze past seasons at scale | Historical Backtest | Research, modeling, reports |
| React to match events the instant they happen | Webhook Listener | Event-driven backends, notifications |
Before you start
Every example below assumes the same two things.
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 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);
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.
Stream updates instead of polling
One persistent WebSocket connection replaces thousands of polling requests and delivers updates the instant they happen.
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'));
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.typeclient-side. - See the WebSocket API reference for the full list of event types.
Find the best available line
Normalized odds make it trivial to compare bookmakers directly, without unit conversion.
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 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.
Pull multi-season data into pandas
Historical Data returns the same schema as live fixtures, so backtests reuse the same parsing code.
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_pagesrather 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.
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 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);
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.
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.
Related pages
Explore more of the developer platform.
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.