

## Everything a player card needs [#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:

```python title="player_overview.py"
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.
  `null` for 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}/stats` serves.
* **`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.

<Callout type="info" title="Default season">
  Omit `season` and the overview serves the **latest season the player has data for** in
  that competition — a retired player resolves to their real last season, not an empty
  current one. Pass `season` explicitly to pin a year (start-year convention: `2025` =
  the 2025-26 NBA season).
</Callout>

<Callout type="info" title="Built for CDNs">
  Successful responses carry `Cache-Control: public, max-age=300, s-maxage=900,
  stale-while-revalidate=3600` — browsers may reuse for 5 minutes and shared caches for
  15, so a popup or a public player page can sit behind a CDN without hammering the API.
</Callout>

<PlaygroundLink href="/docs/api">
  Open /persons/

  {'{'}

  person_id

  {'}'}

  /overview in the playground →
</PlaygroundLink>
