

## How fresh is the data? [#how-fresh-is-the-data]

Short answer: depends on the resource and whether the game is live. The table below is the
contract we operate against — if you observe drift outside these windows, page support with
your `request_id`.

| Resource                   | Live in-game                              | Post-game            | Where freshness is recorded |
| -------------------------- | ----------------------------------------- | -------------------- | --------------------------- |
| Scoreboard / status        | ≤ 30 seconds                              | n/a                  | `meta.fetched_at`           |
| Box score                  | ≤ 90 seconds during play, locked at final | ≤ 5 min              | per-resource header         |
| Contest detail             | ≤ 2 minutes                               | ≤ 10 min after final | `meta.fetched_at`           |
| Person / team season stats | next morning rebuild                      | nightly              | `meta.fetched_at`           |
| Standings                  | hourly during the season                  | hourly               | `meta.fetched_at`           |
| Rosters                    | hourly + on-transaction                   | hourly               | `meta.fetched_at`           |
| Competition schedules      | nightly + on-change                       | nightly              | `meta.fetched_at`           |

<Callout type="info" title="meta.fetched_at is the source of truth">
  Every response carries `meta.fetched_at` — the ISO timestamp of the data, not the request.
  Use it for staleness checks. `meta.cache: "HIT"` means you got a warm cached copy inside
  its TTL (`"STALE"` means a refresh is already running in the background); either way,
  freshness is represented in `fetched_at`. See the
  [cache contract](/docs/reference/cache) for the full semantics.
</Callout>

## Live windows [#live-windows]

A game is "live" from puck/tip/first-pitch drop until the final-confirmed marker. During this
window, we suppress some long TTLs and re-poll upstreams aggressively. Two consequences:

1. **Cache hit rate drops** — expect `meta.cache: "MISS"` for box scores in active games.
2. **Read-your-write timing** — back-to-back calls might see different `fetched_at` values
   inside the same minute. That is correct behaviour, not a bug.

## What freshness is not [#what-freshness-is-not]

* Not a real-time push channel. The API is HTTP — poll, don't stream. We may publish a
  WebSocket feed for live windows; that's not a v1 commitment.
* Not market data. Lines, prices, and odds are out of scope. `/v1/analysis/player-prop`
  accepts a `line` parameter and returns hit rates against it, but the line itself is
  yours to supply.
* Not historical replay. Older seasons can have sparse phase coverage.
  Check `games` and `hit_rate.games` before treating the average as reliable.

## Polling cadence [#polling-cadence]

A polite client polls box scores at 30–60 second intervals during live games and never more
than once per minute for non-live resources. The per-minute rate limit defaults to 100; you
can hold a comfortable polling loop well inside that ceiling.

See [Rate limits](/docs/getting-started/rate-limits) for the headers that tell you exactly how
much window you have left.
