Cookbook
Player overview in one call
Profile, current team, capabilities, season stats, and a recent game log — one composed, cacheable read.
Everything a player card needs
Rendering a player popup used to take four or five calls (profile, team, stats,
capabilities, game log). /persons/{id}/overview composes them into one:
import os, requests
KEY = os.environ["STATSHAWK_KEY"]
BASE = "https://api.statshawk.ai/v1"
person = requests.get(
f"{BASE}/persons",
headers={"X-API-Key": KEY},
params={"q": "Aaron Judge", "limit": 1},
timeout=10,
).json()["data"]["items"][0]
ov = requests.get(
f"{BASE}/persons/{person['id']}/overview",
headers={"X-API-Key": KEY},
params={"competition": "mlb"}, # season optional — see below
timeout=10,
).json()["data"]
team = ov["team"]["name"] if ov["team"] else "—"
print(f"{ov['person']['bio']['full_name']} · {team} · season {ov['season']}")
for phase, measures in ov["season_stats"].items():
print(f" {phase}: {measures}")
print(f"Recorded phases: {[c['phase'] for c in ov['capabilities']]}")
if ov["game_log"]:
last = ov["game_log"][-1]
opp = last["opponent"]["name"] if last["opponent"] else "?"
print(f"Last game: vs {opp} on {last['kickoff']}")What you get back in data:
person— the assembled profile; bio enrichment (headshot, position, height, weight) is optional and never load-bearing — render a fallback from name/team/position when absent.team— the player's current team (their most recent membership), name included.nullfor a player with no membership on record.capabilities— only the phases/measures the player actually recorded that season, so you never have to probe for a pitcher's batting props.season_stats— the same materialized aggregate/persons/{id}/statsserves.game_log— the most recent 30 context-rich entries (most recent last), the same shape as/persons/{id}/game-log; page that endpoint for the full log.