> ## Documentation Index
> Fetch the complete documentation index at: https://docs.linegap.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Data Freshness

> Polling cadence, snapshot types, and freshness indicators — how often Line Gap pulls odds and stats, how stale data can get, and how to know.

Line Gap operates on a polling cadence rather than a real-time feed. Here's exactly how the data flows so you know what you're looking at.

## Polling schedule

| Source                           | What it captures                                          | Cadence                                    |
| -------------------------------- | --------------------------------------------------------- | ------------------------------------------ |
| **Odds API — league poll**       | Latest lines for all props in a league                    | Every 30 min                               |
| **Odds API — closing-line poll** | Per-event close snapshot for tracked bets / Discord picks | Every 10 min during 0–20 min tipoff window |
| **ESPN — player stats**          | Game logs for completed games                             | Daily (10:00 UTC)                          |
| **ESPN — injuries**              | Player injury status changes                              | Daily (10:00 UTC)                          |
| **CLV settlement**               | Compute closing line value on settled bets                | Hourly                                     |

All of these run as scheduled jobs. The 30-min and 10-min jobs were moved to **GitHub Actions** because the Vercel Hobby tier caps cron schedules to daily frequency. GitHub Actions runs them for free and triggers our Vercel routes via authenticated HTTPS.

## Freshness indicators

The dashboard shows a **last-updated badge** at the page header, displaying the relative time since the most recent snapshot in the visible dataset:

* **Under 5 min** — green, considered live
* **5–30 min** — neutral, expected for a 30-min polling cycle
* **Over 30 min** — yellow, may indicate the cron skipped a beat
* **Over 60 min** — red, treat as stale

If you see a stale warning, hit the manual **Refresh** button next to the badge. That triggers an on-demand poll for the current league.

## Snapshot types

Every captured row has a `snapshot_timestamp` and a snapshot type:

* **Opening** — earliest captured value for a prop, marked `is_opening_line=true`
* **Scheduled** — regular 30-min polling cycle
* **Closing** — captured during the tipoff window for tracked events

This lets us reliably build the line movement timeline and compute CLV, even if the dashboard query returns only the latest active row.

## Bets-driven closing-line capture

The closing-line cron is **bets-driven** — it only fetches close snapshots for events where:

1. A user has a pending bet with an `odds_id` referencing the event, OR
2. A parlay leg references the event, OR
3. The Discord bot has scheduled a pick for the event

This keeps API costs predictable. League-wide closing capture would burn \~99% of credits on props nobody bet. Bets-driven scales linearly with what users actually care about.

A **daily Odds API budget cap** (`ODDS_API_DAILY_BUDGET_CREDITS`, default 400) hard-stops the cron if projected spend exceeds the cap.

## What "real-time" would require

True sub-second live odds require a different data tier — typically \$5,000+/month. Line Gap is built around what affordable polling can deliver well, which is **pre-game** intelligence: line movement charts, sharp signal detection, cross-book comparison, CLV. Live in-game betting is explicitly not supported.

## Coming soon

<Card title="Per-user webhooks for tracked bets" icon="webhook">
  <span className="text-xs text-muted-foreground">Tracked as enhancement</span>

  Trigger a closing-line snapshot the moment any user tracks a new bet, rather than waiting for the next 10-minute scan. Would tighten close coverage for last-minute bets.
</Card>
