game object plus a markets dict keyed by pn_market_type, where each value is a flat list of outcomes.
Polynode slug or raw
game_id.Your API key.
Comma-separated list of
pn_market_type values to include. Example: market=moneyline,spreads,totals. If omitted, all markets are returned.Comma-separated list of book names to include. Example:
book=DraftKings,Polymarket,BetMGM. If omitted, all books are returned.Response
Live NBA game (Portland @ Phoenix, Q3 03:42, 79-73) filtered to moneyline only, three books:Top-level shape
| Field | Type | Description |
|---|---|---|
game | object | Full game envelope — same as /v1/games/{id}. Includes teams, scores, venue, status. |
market_count | integer | Number of distinct pn_market_type keys returned (after filters). |
outcome_count | integer | Total number of outcomes across all markets (after filters). |
markets | object | Dict keyed by pn_market_type. Each value is a flat list of outcomes. Markets with zero outcomes after filtering are omitted. |
Outcome object
| Field | Type | Description |
|---|---|---|
book | string | Sportsbook name ("DraftKings", "BetMGM", "Polymarket", "bet365", etc.). Pass into ?book= to filter. |
outcome | string | Outcome label. Team name for moneyline ("Phoenix Suns"), "Over 4.5" / "Under 4.5" for totals, player name with line for player props ("LeBron James Over 24.5"). Same field name as the WS price_change event so REST and WS share vocabulary. |
price | number | American odds. Negative = favorite (-188 = risk 100), positive = underdog (+165 = risk 165). |
points | number | null | Spread or total line when applicable. null for moneyline. |
player_id | string | null | Upstream player id when the outcome is a player prop. |
Filtering examples
All books, moneyline only:200 with markets: {} and market_count: 0 — not a 404.
Post-restart warmup window
When the service restarts, the market poll loop backfills one market type at a time across all sports. For ~30 seconds after startup, you may see fewerpn_market_type keys than the steady-state total. Call the same endpoint again a few seconds later for a fuller view, or subscribe to /ws/odds to stream the fill as it happens.
Refresh semantics
- Live games are re-polled every ~1 second. In-play markets reflect upstream within 1-2 seconds.
- Idle games (unplayed or final) are re-polled every ~10 seconds.
- Subscribe to
/ws/oddsto receiveprice_changedeltas as soon as any book moves.
Market types available per sport
The exact set depends on sport and whether the game is pre-match or live.- NBA / WNBA / NCAAB:
moneyline,spreads,totals,first_half_*,points,rebounds,assists,threes,double_doubles,assists_points_rebounds - NFL / NCAAF:
moneyline,spreads,totals,first_half_*, passing/rushing/receiving yards, anytime TD - MLB:
moneyline,run_line,totals,nrfi, hits, strikeouts, total bases - NHL:
moneyline,puck_line,totals, shots on goal, player goalscorer - Soccer (all leagues):
moneyline(1x2),double_chance,both_teams_to_score,correct_score,total_goals,total_corners,soccer_anytime_goalscorer,soccer_halftime_result - Tennis:
moneyline,set_handicap,total_games - UFC / MMA:
moneyline,method_of_victory,go_the_distance
Rate limits
The REST API enforces 600 requests per minute per API key, with a burst allowance of 60 requests. Requests beyond the limit return429 Too Many Requests with retry-after: 60. WebSocket connections are not counted against this limit — stream consumers don’t need to poll.
