A lot of sports-data tutorials assume you're building a frontend widget, but plenty of us just need this data flowing into a backend service — a Discord bot, a Telegram alert, an internal dashboard, whatever. Here's how to pull live football scores in Python and expose them through a tiny FastAPI wrapper of your own.
Why wrap it at all
You could call the API directly from wherever you need the data, but wrapping it behind your own FastAPI endpoint gives you a place to cache responses, add your own auth, or reshape the data before it hits your frontend — without every client needing to know about your upstream API key.
Setup
Grab a free API key first (no card needed): sign up here. If you'd rather see what the raw responses look like before writing any code, there's a public sandbox: orbistats.com/developers/sandbox.html
Install what you need:
pip install requests fastapi uvicorn python-dotenv
Store your key in a .env file rather than hardcoding it:
ORBISTATS_API_KEY=your_key_here
Step 1: A small client function
import os
import requests
from dotenv import load_dotenv
load_dotenv()
API_KEY = os.getenv("ORBISTATS_API_KEY")
BASE_URL = "https://api.orbistats.com/v1"
def get_live_football_scores():
response = requests.get(
f"{BASE_URL}/football/live",
headers={"Authorization": f"Bearer {API_KEY}"}
)
response.raise_for_status()
return response.json()
Calling it directly gives you something like:
matches = get_live_football_scores()
for match in matches:
home = match["home"]["name"]
away = match["away"]["name"]
print(f"{home} {match['home']['score']} - {match['away']['score']} {away} ({match['minute']}')")
Step 2: Wrap it in FastAPI
from fastapi import FastAPI
app = FastAPI()
@app.get("/scores/live")
def live_scores():
return get_live_football_scores()
Run it with uvicorn main:app --reload and you've got your own /scores/live endpoint that your frontend, bot, or internal tool can hit without ever touching the upstream key directly.
Caching so you don't burn through your rate limit
Since live scores don't change every second, a simple in-memory cache with a short TTL keeps you well within free-tier limits:
from cachetools import TTLCache
cache = TTLCache(maxsize=1, ttl=15)
@app.get("/scores/live")
def live_scores():
if "matches" not in cache:
cache["matches"] = get_live_football_scores()
return cache["matches"]
Polling vs WebSockets
This pattern works fine for polling every 15-30 seconds. If you need genuinely real-time push updates instead of polling — say for a live odds board — it's worth looking at the WebSocket API rather than repeatedly hitting REST: documentation here
Wrapping up
Same pattern extends to fixtures, results, historical data, and odds — just swap the endpoint path and response shape. Full list of what's available is in the API reference.
Anyone else building small backend wrappers like this instead of calling third-party APIs directly from the frontend? Curious what caching strategies people land on for data that updates every few seconds.

Top comments (0)