Kalshi Sports Betting Odds – NFL, NBA, MLB & NHL Lines avatar

Kalshi Sports Betting Odds – NFL, NBA, MLB & NHL Lines

Pricing

from $1.00 / 1,000 games

Go to Apify Store
Kalshi Sports Betting Odds – NFL, NBA, MLB & NHL Lines

Kalshi Sports Betting Odds – NFL, NBA, MLB & NHL Lines

One row per game from Kalshi, the CFTC-regulated exchange: both teams' prices, vig-free probabilities, overround, volume, spreads, totals and price history. NFL, NBA, MLB, NHL, EPL, UCL and more.

Pricing

from $1.00 / 1,000 games

Rating

0.0

(0)

Developer

Rowfeed

Rowfeed

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

13 hours ago

Last modified

Share

Kalshi Sports Odds Scraper – Game Lines, Spreads & Totals

Get live Kalshi sports odds as one clean JSON row per game: moneyline prices for both teams, joined spread and total lines, and vig-removed fair probabilities. Built for odds bots, sports dashboards and AI agents that need to ask "what are the Kalshi odds for this game right now" without a login, an API key or a headless browser. Kalshi is the only CFTC-regulated, licensed exchange for sports event contracts in the US, so its prices come from real money changing hands, not a bookmaker's model. Plain HTTPS calls with retries and a silent-failure check, so a scheduled run keeps working when the exchange hiccups.

What you get

  • One row per game – both teams' YES price, bid, ask, mid, implied probability, volume and open interest, plus a 3-way draw leg whenever Kalshi lists a Draw/Tie market (soccer, including the "Reg Time: Tie" variant; null for two-way sports).
  • Spreads and totals joined in – every point-spread and total-points/goals market for the game attached as spreads/totals lists, matched to the moneyline by Kalshi's own event code.
  • Vig removed for you – overround (the book's built-in edge) and fair_probability_a/_b/_draw (each side's mid price re-normalised to sum to 1) computed for every game still trading, plus favorite.
  • Finished games show the result – with status: "settled" each side carries Kalshi's own result and payout instead of a stale price (see "Settled and closed games" below).
  • Covers 17 leagues – NFL, NBA, MLB, NHL, EPL, NCAAF, NCAAB, UCL, La Liga, Serie A, Bundesliga, Ligue 1, MLS, WNBA, ATP and WTA tennis, and UFC fights (one row per fight, the two fighters in team_a/team_b), or poll one game directly by its event ticker.

Sample row

One open NFL game, maxGames: 1. Trimmed here: spreads/totals to one entry each (a real run returns every joined market), and team_b to its prices (real rows give it the same fields as team_a).

{
"event_ticker": "KXNFLGAME-26SEP24ATLGB",
"league": "NFL",
"series_ticker": "KXNFLGAME",
"title": "Atlanta vs Green Bay",
"sub_title": "ATL vs GB (Sep 24)",
"expires_at": "2026-09-25T06:15:00Z",
"close_time": "2026-09-27T00:15:00Z",
"status": "active",
"team_a": {
"name": "Green Bay",
"ticker": "KXNFLGAME-26SEP24ATLGB-GB",
"last_price": 0.71,
"yes_bid": 0.70,
"yes_ask": 0.71,
"mid": 0.705,
"implied_probability": 0.705,
"volume": 864084.8,
"volume_24h": 448478.57,
"open_interest": 687846.03
},
"team_b": {
"name": "Atlanta",
"ticker": "KXNFLGAME-26SEP24ATLGB-ATL",
"last_price": 0.30,
"yes_bid": 0.29,
"yes_ask": 0.30,
"mid": 0.295,
"implied_probability": 0.295
},
"draw": null,
"overround": 0.01,
"fair_probability_a": 0.705,
"fair_probability_b": 0.295,
"favorite": "Green Bay",
"spreads": [
{ "ticker": "KXNFLSPREAD-26SEP24ATLGB-GB28", "yes_sub_title": "GB Packers wins by over 27.5 points", "floor_strike": 27.5, "yes_bid": 0.04, "yes_ask": 0.05 }
],
"totals": [
{ "ticker": "KXNFLTOTAL-26SEP24ATLGB-26", "yes_sub_title": "Over 25.5 points scored", "floor_strike": 25.5, "yes_bid": 0.93, "yes_ask": 0.94 }
],
"url": "https://kalshi.com/markets/kxnflgame",
"scraped_at": "2026-09-23T16:39:50+00:00"
}

Every row also carries home_team/away_team (always null - Kalshi doesn't label a home side, and this Actor never guesses), start_time (always null for the same honesty reason - use expires_at/close_time instead), and raw_event with Kalshi's own event fields.

Filters

InputDefaultWhat it does
leagues["NFL","NBA","MLB","NHL","EPL","NCAAF","UCL"]Leagues to scrape. Also: NCAAB, UCL, LALIGA, SERIEA, BUNDESLIGA, LIGUE1, MLS, WNBA, ATP, WTA, UFC.
seriesTickers[]Extra game series by ticker (advanced), e.g. ["KXWNBAGAME"], for leagues not in the list above.
eventTickers[]Poll specific games directly, e.g. ["KXNFLGAME-26SEP24ATLGB"]. An unknown ticker becomes an uncharged error row and never fails the run: it is your input, not an outage.
team""Case-insensitive substring match against the title and both team names, e.g. "Green Bay" or "GB".
statusopenopen, closed, settled or all. What settled and closed rows contain is described below.
includeSpreadsTotalstrueJoin spread/total markets onto each row.
includeHistoryfalseAdd 7 days of hourly candlesticks for both moneyline markets.
maxGames100Cap on rows (1-1000), soonest-expiring first; settled and closed games most recent first.

Leagues or games with nothing matching the status filter simply contribute zero rows - not an error. A default run (no filters) returns whichever of the 7 default leagues currently have games in that status.

Tennis and UFC have moneyline markets only, so spreads and totals are empty lists there. A newly listed fight or match that nobody has traded yet can show placeholder quotes (for example bid 0.05 / ask 0.83 on both fighters of a Contender Series bout, with zero volume); check team_a.volume and team_b.volume before treating those prices as a market view.

Settled and closed games

status: "settled" returns finished games. When Kalshi settles a market it empties the order book, so every leg reads yes_bid 0 and yes_ask 1 and there is no price left. On those rows (status is finalized) the fields mid, implied_probability, fair_probability_a/_b/_draw, overround and favorite are null, never a made-up 50/50. Instead, each leg and each joined spread or total market carries Kalshi's own outcome:

  • result: "yes" for the side that won, "no" for the others, and "scalar" when Kalshi paid out a fraction (an NFL tie pays half on both teams).
  • settlement_value: what one YES contract paid out, in dollars: 1.0, 0.0, or the fraction (0.5 for a tie).

last_price is kept as Kalshi reports it. On a settled leg it is the final trade (usually 0.99 or 0.01), not a pre-game price. Here is the sample game above after it finished, trimmed to the fields that change:

{
"event_ticker": "KXNFLGAME-26SEP24ATLGB",
"status": "finalized",
"team_a": { "name": "Green Bay", "last_price": 0.01, "yes_bid": 0.0, "yes_ask": 1.0, "mid": null, "implied_probability": null, "result": "no", "settlement_value": 0.0 },
"team_b": { "name": "Atlanta", "last_price": 0.99, "yes_bid": 0.0, "yes_ask": 1.0, "mid": null, "implied_probability": null, "result": "yes", "settlement_value": 1.0 },
"overround": null,
"fair_probability_a": null,
"fair_probability_b": null,
"favorite": null
}

Settled rows come most recent first, so maxGames keeps the latest results. Kalshi only serves market data for recently settled games. On 25 September 2026 the cut-off was about 18 July for every league, so how far back you get depends on each league's calendar. MLB, tennis and UFC went back to mid-July. NFL and the big European soccer leagues only went back to their first games in August, NHL to its first preseason games in mid-September, and NBA returned nothing because its season ended in June. Older games have moved to Kalshi's archive and come back without markets, so the Actor skips them and counts them as skipped_incomplete in the run's STATS record. Use status: "settled" for recent results, not for season-long history.

status: "closed" returns games where trading has ended but Kalshi has not settled them yet. That window usually lasts minutes, so the list is often empty. Kalshi shows those markets with an empty book too, so the price fields are null, and result appears only once Kalshi has decided the outcome. Open games never carry result or settlement_value.

Pricing

Pay per event, no subscription: $1 per 1,000 games, $2 per 1,000 history fetches and $0.001 per run start (kept tiny so you can poll one game at a time). Fetching spreads and totals is free - they ride along on the game row. Set a maximum charge on the run and the Actor stops cleanly when it is reached, charging only for rows actually saved.

Details

  • Source: Kalshi's public trade API v2 (api.elections.kalshi.com/trade-api/v2). No authentication, no proxies, no browser, no personal data. Not affiliated with Kalshi.
  • Prices are probabilities: Kalshi is a real-money exchange, so every YES price is a dollar amount between $0 and $1 that a trader is willing to pay for a $1 payout if that outcome happens - which makes it, by construction, the market's implied probability of that outcome.
  • Overround and fair probability: overround sums every leg's ask price and subtracts 1, so it's the total edge baked into the current asks (a healthy two-way market runs a few cents over 0). fair_probability_* divides each leg's mid price by the sum of all legs' mids, so the vig cancels out and the fair probabilities always sum to 1. A settled or closed game has no quote, so both are null there.
  • Reliability: 429 and 5xx responses are retried with exponential backoff (5 tries), a 200 without the expected data counts as a failure, and one bad ticker never stops the run - it becomes an error row (event_ticker, error, errorMessage) and the rest continues. A run fails only when it produced no rows and the source failed (network, rate limit, blocked); an unknown ticker or a league with nothing open is a successful run with no charged rows.
  • Run stats: the STATS record in the run's key-value store holds games, history fetches, error rows, skipped incomplete events, request and error counts per category.
  • Output: one dataset row per game with the columns above, sorted soonest-expiring first (settled and closed games most recent first). Export as JSON, CSV or Excel, fetch through the Apify API, or schedule runs and pipe them into Google Sheets, Make, Zapier, n8n or your own code. Eligible for agentic use via Apify's MCP server.