Skip to main content
Returns a single game with its complete set of markets. Accepts optional ?book= and ?market= query filters so you can pull only the slices you care about in one round trip.
curl -s "https://books.polynode.dev/v1/games/nba-por-phx-2026-04-15?key=pn_live_YOUR_KEY"
The path parameter accepts either a polynode slug (lib-gar-est-2026-04-14) or a raw game_id (40664-16839-2026-04-14). Both resolve to the same record. Unmatched games where pn_slug is null still work — just use the game_id.
id
string
required
Polynode slug (e.g. nba-mia-cha-2026-04-14) or raw game_id (e.g. 40664-16839-2026-04-14).
key
string
required
Your API key. Accepted via query param or Authorization: Bearer header.
market
string
Comma-separated list of pn_market_type values to include (e.g. moneyline,spreads,totals). Omit for all markets.
book
string
Comma-separated list of book names to include (e.g. DraftKings,Polymarket,BetMGM). Omit for all books.

Response

This is a real response for a live NBA game (Portland @ Phoenix, Q3 03:42) filtered to market=moneyline on three books:
curl "https://books.polynode.dev/v1/games/nba-por-phx-2026-04-15?market=moneyline&book=FanDuel,Polymarket,BetMGM&key=pn_live_YOUR_KEY"
{
  "game": {
    "game_id": "24860-38874-2026-04-14",
    "pn_slug": "nba-por-phx-2026-04-15",
    "pn_league_code": "nba",
    "sport_category": "basketball",
    "start_date": "2026-04-15T02:00:00Z",
    "status": "live",
    "venue": "Mortgage Matchup Center",
    "broadcast": "Amazon",
    "home_team": {
      "name": "Phoenix Suns",
      "city": "Phoenix",
      "mascot": "Suns",
      "abbreviation_pn": "phx"
    },
    "away_team": {
      "name": "Portland Trail Blazers",
      "city": "Portland",
      "mascot": "Trail Blazers",
      "abbreviation_pn": "por"
    },
    "scores": {
      "status": "Live",
      "score_home": 73,
      "score_away": 79,
      "period": "3",
      "clock": "03:42",
      "is_live": true
    }
  },
  "market_count": 1,
  "outcome_count": 6,
  "markets": {
    "moneyline": [
      { "book": "BetMGM",     "outcome": "Portland Trail Blazers", "price": -225.0, "points": null, "player_id": null },
      { "book": "FanDuel",    "outcome": "Portland Trail Blazers", "price": -205.0, "points": null, "player_id": null },
      { "book": "Polymarket", "outcome": "Portland Trail Blazers", "price": -184.0, "points": null, "player_id": null },
      { "book": "BetMGM",     "outcome": "Phoenix Suns",            "price":  175.0, "points": null, "player_id": null },
      { "book": "FanDuel",    "outcome": "Phoenix Suns",            "price":  170.0, "points": null, "player_id": null },
      { "book": "Polymarket", "outcome": "Phoenix Suns",            "price":  165.0, "points": null, "player_id": null }
    ]
  }
}

Top-level shape

FieldTypeDescription
gameobjectFull game envelope: teams, scores, venue, status, start_date, broadcast. Same shape returned by List Live Games.
market_countintegerNumber of distinct pn_market_type keys in markets after filtering.
outcome_countintegerTotal number of outcomes across all markets after filtering.
marketsobjectDict keyed by pn_market_type. Each value is a flat list of outcomes. Markets with zero outcomes after filtering are omitted.

Outcome object

FieldTypeDescription
bookstringSportsbook name exactly as upstream labels it ("DraftKings", "FanDuel", "BetMGM", "Polymarket", "Polymarket (USA)", "bet365"). Pass into ?book= to filter.
outcomestringOutcome label. Team name for moneyline, "Over 4.5" / "Under 4.5" for totals, player name with line for player props. Same field name as the WS price_change event.
pricenumberAmerican odds. Negative = favorite (-225 = risk 225towin225 to win 100), positive = underdog (+175 = risk 100towin100 to win 175). Prediction-market books sometimes emit extreme values like +9900 or -99900 when a market is near-resolved — cap or convert to implied probability client-side if you’re running arb math.
pointsnumber | nullSpread or total line when applicable (-6.5, 2.5, 217.5). null for moneyline.
player_idstring | nullUpstream player id when the outcome is a player prop.

Same endpoint as /markets

/v1/games/{id} and /v1/games/{id}/markets return identical shapes and accept identical filters. They are aliases. Use whichever URL reads better in your code.

Book coverage varies by league and market

Not every book carries every market. A live NBA moneyline is carried by 60-90 books; a live AHL game might only have 5-10. DraftKings’ mainline sportsbook does not currently publish NBA moneylines — their NBA odds ship under the DraftKings Predictions book name. If you filter to ?book=DraftKings on an NBA game and get empty results, that’s why. Use List Books to see which books are currently known to the system.

Post-restart warmup window

For ~30 seconds after the service restarts, the market backfill runs one market type at a time across all sports. You may see fewer pn_market_type keys than the steady-state total. Retry a few seconds later or subscribe to /ws/odds to stream the fill as it happens.

Refresh semantics

  • Live games re-poll every ~1 second.
  • Idle (unplayed / final) games re-poll every ~10 seconds.
  • For real-time deltas, subscribe to /ws/odds and apply price_change events on top of this baseline.