# Kalshi vs sportsbook odds: compare player props on a no-vig basis

To compare a Kalshi contract with a sportsbook line you need both on the same scale. GetOdds returns each Kalshi player-prop contract with its best ask as an implied probability, the BetRivers over and under prices for the same player, stat and line, the sportsbook no-vig probability for that side, and edge_vs_sportsbook_no_vig, the difference between them. Positive edge means the contract costs less than the sportsbook's fair price implies.

Canonical page: https://getoddsapi.com/kalshi-vs-sportsbook-odds

**Price.** Free development allowance: 1,000 requests per UTC day and 60 per minute per account, with no payment step. Paid: the Developer Bundle at $149 per month, with 10,000 monthly requests or credits on each of four sources. Prediction-market reads count against the same allowance and need no extra grant.

## Free API key

Get a free GetOdds API key: **1,000 requests per UTC day and 60 per minute, no card**. One key covers REST and the hosted MCP server.

Sign up: https://getoddsapi.com/sign-up?ref=ai-claudebot

## Quickstart

1. Create an account at https://getoddsapi.com/sign-up?ref=ai-claudebot, open https://getoddsapi.com/dashboard and issue a key with the sources you need (draftkings, fanduel, betrivers, prizepicks or underdog). Keep it in a server environment variable named GETODDS_API_KEY.
2. Read current DraftKings NBA spreads with curl:

```bash
curl --fail-with-body "https://getoddsapi.com/api/v1/odds?sport=NBA&market=spread&fresh_only=true&limit=50" \
  -H "Authorization: Bearer $GETODDS_API_KEY"
```

3. The same request in Python (standard library only):

```python
import json, os, urllib.request

req = urllib.request.Request(
    "https://getoddsapi.com/api/v1/odds?sport=NBA&market=spread&fresh_only=true&limit=50",
    headers={"Authorization": "Bearer " + os.environ["GETODDS_API_KEY"]},
)
with urllib.request.urlopen(req) as res:
    rows = json.load(res)["data"]
for row in rows:
    print(row["away"], "at", row["home"], row["side"], row["line"], row["american"], row["observed_at"])
```

4. Check `observed_at`, `age_seconds` and `stale` on every row before using a price. Full reference: https://getoddsapi.com/docs

## Use with Claude (MCP)

```bash
claude mcp add --transport http getodds https://getoddsapi.com/api/mcp \
  --header "Authorization: Bearer $GETODDS_API_KEY"
```

The MCP tools follow the key's source grants and share its allowance. Setup guide: https://getoddsapi.com/use-with-claude

## Pricing

| Plan | Allowance | Price |
| --- | --- | --- |
| Free key | 1,000 requests a day, 60 a minute | $0, no card |
| Developer Bundle | 10,000 requests or credits a month on each of four sources | $149 a month |

Free development allowance: 1,000 requests per UTC day and 60 per minute per account, with no payment step. Paid: the Developer Bundle at $149 per month, with 10,000 monthly requests or credits on each of four sources.
Details: https://getoddsapi.com/bundle

## Facts

- **Prediction market:** Kalshi (or Polymarket)
- **Sportsbook:** BetRivers, Pennsylvania
- **Match:** Same player, stat and line
- **Output:** edge_vs_sportsbook_no_vig

## The math, step by step

A sportsbook price includes the book's margin. Convert both sides to implied probability (for -240: 240 / 340 = 0.7059; for +170: 100 / 270 = 0.3704), then divide each by their sum (1.0763) to remove the margin: the over is 0.6559. A Kalshi yes contract on the same 0.5 threshold priced at $0.70 implies 0.70. Edge is 0.6559 - 0.70 = -0.0441: here the contract is more expensive than the book's fair price.

GetOdds returns every one of those numbers in the row, so you can check the arithmetic.

| Quantity | Value |
| --- | --- |
| BetRivers over / under | -240 / +170 |
| Implied over / under | 0.7059 / 0.3704 |
| No-vig over | 0.6559 |
| Kalshi yes ask (over 0.5 threes) | $0.70, or -233 |
| edge_vs_sportsbook_no_vig | -0.0441 |

## Find the cheapest contracts in Python

Rows without both sportsbook sides have a null no-vig probability and a null edge; the example skips them. Only lines the sportsbook also offers can be compared.

```python
import json, os
from urllib.request import Request, urlopen

H = {"Authorization": "Bearer " + os.environ["GETODDS_API_KEY"]}
url = "https://getoddsapi.com/api/v1/prediction-markets?source=kalshi&league=NBA&limit=200"
with urlopen(Request(url, headers=H), timeout=20) as r:
    rows = json.load(r)["data"]

# Contracts priced below the sportsbook's no-vig probability for the same side
edges = [x for x in rows if x["edge_vs_sportsbook_no_vig"] is not None]
for x in sorted(edges, key=lambda x: -x["edge_vs_sportsbook_no_vig"])[:10]:
    print(x["player"], x["stat"], x["line"], x["side"],
          "kalshi", x["price"]["probability"],
          "book fair", x["sportsbook"]["no_vig_probability"],
          "edge", x["edge_vs_sportsbook_no_vig"])
```

## What the comparison does not tell you

Edge is a price comparison, not a forecast. Kalshi charges trading fees, the ask can move before your order fills, and the sportsbook price is one book in one state. Treat a positive edge as a lead to check, not a guaranteed profit.

- Kalshi price: best ask, before fees
- Sportsbook: BetRivers Pennsylvania only
- Freshness: venue scopes captured in the last 30 minutes
- Matching: exact player name, stat label and line

## FAQ

### Are Kalshi odds better than sportsbook odds?

Sometimes. Kalshi prices have no built-in sportsbook margin but do carry fees and a bid-ask spread. The edge field shows where a contract is cheaper or dearer than a book's no-vig price for the same prop.

### Which sportsbook is used for the comparison?

BetRivers Pennsylvania prices, stored from its Kambi feed, for the same player, stat and line.

### Does the edge include Kalshi fees?

No. Fees and fills are not modeled; subtract them yourself before acting.

### Can I compare Polymarket the same way?

Yes. Use source=polymarket on the same endpoint; the fields are identical.

---

GetOdds is an independent developer product and is not affiliated with any sportsbook or pick’em operator. Prices describe data, not betting advice.
