SportWizzard · developer manual

The sports betting
data API

Live odds from 35+ sportsbooks and DFS apps in one flat schema, with the players, teams, box scores, and price history to build models on.

28 endpoints35+ booksJSONcursor paginationno SDK

Quickstart

Three steps from zero to live data.

base urlhttps://api.sportwizzard.comall endpoints under /api/v1
Create an API key
Sign in and create a key on the API Keys tab of your account. Keys are free and don't require a card. Reference endpoints work without one.
Make a request
Send your key in the X-Api-Key header. The API is plain REST and JSON, so it works from any language.
curl "https://api.sportwizzard.com/api/v1/events?league=mlb" \
  -H "X-Api-Key: sw_live_your_api_key_here"
Read the envelope
Every endpoint returns the same envelope. Results are in data. To page, pass nextCursor back as ?cursor=. When it's null, you're on the last page.
{
  "success": true,
  "data": [ /* … */ ],
  "nextCursor": "opaque-cursor-string-or-null",
  "meta": { "count": 50, "updated": "2026-07-09T16:41:27Z" }
}

Cache with ETags

Live-odds responses include an ETag header. Send it back as If-None-Match to get a free 304 when nothing changed. To stay in sync, poll /api/v1/odds/updated?since={timestamp} for the rows that changed.

What you can fetch

Eight resource groups cover the platform. Edges and arbitrage are computed from the same odds you can pull yourself.

Events

Games and matches. Filter by league, team, or time. Fetch one event for scores, venue, weather, lineups, and probable pitchers.

/v1/events/v1/events/{id}/v1/events/{id}/stats/v1/events/{id}/odds/v1/events/active

Odds

One flat feed across every book. Scope it by league, sportsbook, market, event, player, or team — or by scope=season for season-long futures. The delta feed returns only the rows that changed.

/v1/odds/v1/odds?scope=season/v1/odds/updated/v1/players/{id}/odds/v1/teams/{id}/odds

Stats

Box scores for players and teams, keyed to canonical IDs.

/v1/players/{id}/stats/v1/teams/{id}/stats/v1/stats/players

Snapshot

The whole live board in one gzip request. Add include_history=true to include each selection’s price history.

/v1/snapshot/v1/snapshot?include_history=true

Reference

Free catalog data: leagues, seasons, sportsbooks, teams, players, and market types. Leagues rotate with the calendar, so call /leagues first.

/v1/leagues/v1/seasons/v1/sportsbooks/v1/teams/v1/players/v1/markets/v1/status

Historical

Odds as they stood at a past moment, plus settled arbitrage. 5 credits per event.

/v1/historical/odds/v1/historical/arbitrage

Edges & arbitrage

Computed signals: soft DFS lines against no-vig book prices, and cross-book arbitrage. Verify a signal before you act on it.

/v1/edges/v1/arbitrage

Account

Your plan, rate limit, and usage for the month.

/v1/account/usage

How odds are shaped

Three ideas explain the whole API.

Events are the spine

Everything keys off an event: one game or match. Odds, box scores, and context all carry an eventId. List events, take an id, then pull that event's board with /v1/events/{id}/odds.

Odds are one flat table

Each row is one price at one book. A row repeats everything you need to interpret it, so you can filter, join, or load rows into a dataframe without walking a tree. The id is a stable composite key ({eventId}:{book}:{subtype}:{selectionId}) that survives price moves. Upsert on it.

{
  "id": "31cd6744-…-c4a7d1fce547:ballybet:SPREAD:019f495d-8558-7324-…",
  "sportsbook": "ballybet",
  "league": "mlb",
  "eventId": "31cd6744-9444-4fbd-b25c-c4a7d1fce547",
  "market": "SPREAD",
  "marketSubtype": "SPREAD",
  "period": "FULL",
  "selection": "KC Royals",
  "side": "AWAY",
  "teamSide": "AWAY",
  "teamName": "KC Royals",
  "line": -1.5,
  "priceAmerican": 200,
  "priceDecimal": 3.00,
  "suspended": false,
  "eventStartTime": "2026-07-10T23:05",
  "updated": "2026-07-10T14:53:35Z"
}

Field glossary

FieldMeaning
marketThe market family: MONEYLINE, SPREAD, TOTAL, TEAM_TOTAL, PLAYER_TOTAL, PLAYER_MILESTONE, MONEYLINE_3_WAY, and more.
marketSubtypeThe specific stat or variant, such as TOTAL_RUNS or PLAYER_TOTAL_SHOTS. Equals market for simple markets.
periodThe window the wager settles over. FULL is the whole game. Sport-specific partials appear, such as baseball 1INN and 1INN_5INN. On a future it is the window within the season: REG_SEASON or FULL (through the playoffs).
marketScopeWhich anchor the market hangs off: SEASON or TOURNAMENT. Absent on game markets — a row with no marketScope is an ordinary single-game line. See futures.
segmentWhich slice of the competition a future is scoped to: AFC_EAST, NFC, AL, SEC. Present only on segment-scoped markets. Without it, all 32 division-winner selections read as one race.
selection / sideThe human label of the pick, and its normalized side: HOME, AWAY, DRAW, OVER, or UNDER. Filter on side.
teamSide / teamNameWhich side of the event the selection belongs to. For a player prop, the player's team.
lineThe handicap or total the price is quoted against. Absent on pure moneylines.
priceAmerican / priceDecimalThe same price in both notations. DFS pick'em rows carry dfsMultiplier instead.
playerId / playerNamePresent only on player props: the canonical player the line is about.
suspendedtrue while the book has the line locked.
eventStartTime / updatedThe scheduled start, and when this line last refreshed (UTC). The delta feed compares since= against updated. On a future, eventStartTime is the season anchor's settlement date — identical for every book on that anchor, and never a kickoff. See futures.
Read edges with careAn edge compares a DFS line against the most favorable book's no-vig price, so it's optimistic by construction. Treat it as a screen, not a proven bet. Arbitrage margins hold only if every leg fills at the quoted price. Raw odds rows carry book prices only; there is no fair-value field.

Choose a read pattern

Live board/v1/odds
Cache-served and seconds-fresh. Scope by league, book, market, event, player, or team.Use for: Targeted reads of what is bettable now.
Delta feed/v1/odds/updated?since=
Only the rows that changed since your last sync. Takes the same filters as /odds.Use for: Cheap continuous polling.
Snapshot/v1/snapshot
The whole board in one gzip pull for 1 credit. ETag 304s are free.Use for: Bootstrapping a local copy.
Snapshot with history/v1/snapshot?include_history=true
The same snapshot with each selection’s priceHistory populated, for 5 credits. The schema is identical either way.Use for: Line-movement features without polling.
Historical replay/v1/historical/odds
Odds for a past event, priced at 5 credits per event.Use for: Backtesting settled games.

A typical pipeline: snapshot to bootstrap, then /odds/updated to stay in sync, /odds for targeted reads, include_history=true for line movement, and /historical/odds to replay the past.

Price history in the snapshot

Add ?include_history=true to /v1/snapshot and each selection's priceHistory is populated with its movement entries: fs/ls are first-seen and last-seen epoch seconds, pa/pd the American and decimal price, dm the DFS multiplier, and su: true marks a suspended span. Entries append on every price change, up to 50 per selection. The schema is identical either way: without the flag, priceHistory is null, so the same client code reads both. 1 credit without, 5 with. The two variants carry different ETags.

# board only (1 credit)            # board + line movement (5 credits), same schema
curl --compressed "https://api.sportwizzard.com/api/v1/snapshot" \
  -H "X-Api-Key: sw_live_…"        # …/api/v1/snapshot?include_history=true

Scope /v1/odds

Unscoped, /v1/odds spans every league and book. Always scope it, or use /v1/events/{id}/odds, /v1/players/{id}/odds, or /v1/teams/{id}/odds.

ParameterWhat it does
scopeWhich kind of market: event (a single game), season (season-long futures), or tournament (tournament outrights). Matching is exact — scope=season excludes TOURNAMENT. Omit it and you get all three, as before. Only /v1/odds takes this; any other value returns 400 naming the valid ones.
league, sportsbook, marketAny-of filters. Up to 20 comma-separated values each, such as sportsbook=draftkings,fanduel.
event_id, player_id, team_idEntity scoping. Combine freely with the filters above.
odds_formatamerican, decimal, probability, or all. The default returns both price fields.
is_main=trueKeep only each market’s primary line per book. Not available on the delta feed.
cursor, limitOpaque cursor pagination. limit sizes the page, up to 1000.

Futures and season-long markets

A future prices a whole season, not a game. 18 of the books we cover post them, and they arrive on the same flat rows as everything else.

Three fields, three questions

A game line only has to say which team, in which game. A future has to answer three independent questions, so it uses three independent fields. Read them together and any row is unambiguous.

FieldQuestion it answersValues
marketScopeWhich anchor does this market hang off?SEASON (a synthetic season event, not a game) or TOURNAMENT. Absent entirely on game markets, which are unchanged.
periodWhich window inside that anchor does it settle over?REG_SEASON (division winner, win totals) or FULL (through the playoffs — Super Bowl, World Series). Same field games use for 1H or 1INN.
segmentWhich slice of the competition is it scoped to?AFC_EAST, NFC, AL, NL, SEC, BIG_12… Present only when the market is segment-scoped.

The axes are orthogonal: a conference winner is SEASON + FULL + AFC, a division winner is SEASON + REG_SEASON + AFC_EAST, and a season passing-yards total is SEASON + REG_SEASON with no segment at all. Season player props reuse the same PLAYER_TOTAL_* subtypes as game props, so marketScope is the only thing separating a 3,750.5-yard season line from a game line. Check it before you model on it.

Ask for them: ?scope=

/v1/odds takes a scope filter. Matching is exact: scope=season does not include tournament outrights, and vice versa. Omit it and you get every scope, which is the unchanged default. This parameter is on /v1/odds only — the delta feed and the player/team odds endpoints do not accept it today.

# season-long futures only
curl "https://api.sportwizzard.com/api/v1/odds?scope=season&league=nfl&limit=200" \
  -H "X-Api-Key: sw_live_…"

# scope=event  → game markets     scope=tournament → tournament outrights
# omitted      → all three (default, unchanged)

# a typo fails loudly instead of looking like "no futures exist"
curl "https://api.sportwizzard.com/api/v1/odds?scope=futures"
# 400 {"detail":"Invalid scope 'futures'. Use scope=event (game markets),
#       scope=season (season-long futures), scope=tournament (tournament
#       outrights), or omit the parameter for all scopes.",
#      "validValues":["event","season","tournament"]}

Why segment is load-bearing

Every NFL future for a season hangs off one synthetic season event, so all 32 DIVISION_WINNER selections share a single eventId. Group by eventId + marketSubtype alone and they read as one 32-team race whose implied probabilities sum to about 8. Group by segment as well and you get the eight real four-team markets. Note that segment is a response field, not a query filter — pull the subtype and split on it client-side.

{
  "id": "b2e737f7-…-852ce6b8d255:draftkings:DIVISION_WINNER:01a01c2f-a38f-76ec-…",
  "sportsbook": "draftkings",
  "league": "nfl",
  "eventId": "b2e737f7-dfb6-4535-bdc4-852ce6b8d255",
  "market": "CATEGORICAL",
  "marketSubtype": "DIVISION_WINNER",
  "period": "REG_SEASON",
  "selection": "BUF Bills",
  "priceAmerican": -136,
  "priceDecimal": 1.7400,
  "side": "YES",
  "teamSide": "NONE",
  "teamName": "BUF Bills",
  "suspended": false,
  "eventStartTime": "2027-02-16T23:59",
  "updated": "2026-08-20T16:44:17Z",
  "marketScope": "SEASON",
  "segment": "AFC_EAST"
}

Winner and award markets are categorical: one side: "YES" selection per competitor and teamSide: "NONE", because most books never post a NO side. Do not expect a two-sided market here.

One season event, every book on it

Futures from different books converge on the same season anchor, so a single eventId carries every book's price for the same outcome. Cross-book comparison on futures is a group-by, not a matching problem — which is the whole reason this data is worth having, since retail books and exchanges disagree most on the long-dated stuff.

curl "https://api.sportwizzard.com/api/v1/odds?scope=season&league=nfl&market=CATEGORICAL&limit=1000" \
  -H "X-Api-Key: sw_live_…" \
  | jq -r '.data[]
      | select(.marketSubtype=="CHAMPIONSHIP_WINNER" and (.teamName|test("Bills")))
      | [.sportsbook, .priceAmerican, .eventId, .eventStartTime] | @tsv' | sort

ballybet         1000  b2e737f7-dfb6-4535-bdc4-852ce6b8d255  2027-02-16T23:59
betonline        1000  b2e737f7-dfb6-4535-bdc4-852ce6b8d255  2027-02-16T23:59
betparx          1000  b2e737f7-dfb6-4535-bdc4-852ce6b8d255  2027-02-16T23:59
betrivers-kambi  1000  b2e737f7-dfb6-4535-bdc4-852ce6b8d255  2027-02-16T23:59
betway           1000  b2e737f7-dfb6-4535-bdc4-852ce6b8d255  2027-02-16T23:59
draftkings       1000  b2e737f7-dfb6-4535-bdc4-852ce6b8d255  2027-02-16T23:59
fanduel          1000  b2e737f7-dfb6-4535-bdc4-852ce6b8d255  2027-02-16T23:59
hardrock         1000  b2e737f7-dfb6-4535-bdc4-852ce6b8d255  2027-02-16T23:59
novig             953  b2e737f7-dfb6-4535-bdc4-852ce6b8d255  2027-02-16T23:59
pinnacle          988  b2e737f7-dfb6-4535-bdc4-852ce6b8d255  2027-02-16T23:59
polymarket       1011  b2e737f7-dfb6-4535-bdc4-852ce6b8d255  2027-02-16T23:59
prophetx          960  b2e737f7-dfb6-4535-bdc4-852ce6b8d255  2027-02-16T23:59
rebet            1000  b2e737f7-dfb6-4535-bdc4-852ce6b8d255  2027-02-16T23:59
thescore         1000  b2e737f7-dfb6-4535-bdc4-852ce6b8d255  2027-02-16T23:59

Fourteen books, one eventId, one anchor date, captured live. The retail books sit on a round +1000 while the exchanges price it themselves. Note the team label differs by book (BUF Bills vs Buffalo Bills) — match on teamId or the canonical /v1/teams catalog, never on the display string.

Two things futures are notThey never appear in edges or arbitrage. Season and tournament markets are excluded from the de-vig and edge math on /v1/edges and /v1/arbitrage by design, not by omission: a 32-way categorical market has no clean two-way no-vig fair value, so fabricating one would only manufacture fake signals. Futures are raw prices for you to model. And eventStartTime is not a kickoff. On a futures row it is the season anchor's own settlement date, normalized server-side: always present, and the same value for every book on that anchor. It tells you when the market resolves, not when anything starts, so do not treat it as a game time. Use updated for freshness.

Real responses

Captured from the live API and trimmed. Pick a league, then flip between the event, its odds board, a settled box score, and a computed signal.

GET/api/v1/events?league=mlb&limit=1
{
  "success": true,
  "data": [
    {
      "id": "3a4170cb-0064-48b6-933d-4c4a6ce27283",
      "homeTeamId": "7d0a7f60-138a-11f1-aba1-de512ebea802",
      "homeTeamName": "Miami Marlins",
      "awayTeamId": "7d0a8055-138a-11f1-aba1-de512ebea802",
      "awayTeamName": "Seattle Mariners",
      "startTime": "2026-07-09T22:40Z",
      "status": "scheduled",
      "league": "mlb",
      "hasOdds": true,
      "venueId": "b948390b-3a35-4fc3-a00b-08d8b6959ade",
      "seasonYear": 2026,
      "context": {
        "probable_pitchers": {
          "home_id": "7ebc2295-138a-11f1-aba1-de512ebea802",
          "away_id": "7ebc6aeb-138a-11f1-aba1-de512ebea802"
        }
      }
    }
  ],
  "meta": {
    "count": 1,
    "updated": "2026-07-09T18:24:55Z"
  }
}
live response from api.sportwizzard.com · captured 2026-07-09 · trimmed

Endpoints

All 28 v1 endpoints. Try any of them in the interactive reference.

MethodEndpointDescriptionAccess
GET/api/v1/eventsList events. Filter by league, team, status, or time.Reference
GET/api/v1/events/activeEvents that have live markets right now.Reference
GET/api/v1/events/{id}One event with scores, venue, weather, lineups, and probable pitchers.Reference
GET/api/v1/events/{id}/statsFull box score: team totals and per-player stats.API key
GET/api/v1/events/{id}/oddsThe full odds board for one event.API key
GET/api/v1/oddsThe normalized odds feed. Scope it with filters, including ?scope=season for futures.API key
GET/api/v1/odds/updatedOnly the rows that changed since a timestamp.API key
GET/api/v1/players/{id}/oddsEvery live line for one player.API key
GET/api/v1/teams/{id}/oddsEvery live line for one team.API key
GET/api/v1/players/{id}/statsPlayer box stats by season.API key
GET/api/v1/teams/{id}/statsTeam box stats by season.API key
GET/api/v1/stats/playersBulk player box stats. Filter by event, team, or player.API key
GET/api/v1/snapshotThe whole live board as one gzip blob. Add ?include_history=true for price history (5 credits instead of 1).Growth+
GET/api/v1/statusTotal live markets and sportsbook count.Reference
GET/api/v1/leaguesLeagues with an in-progress season. Call this first.Reference
GET/api/v1/seasonsSeasons for a year, across all leagues.Reference
GET/api/v1/sportsbooksSportsbooks and DFS platforms, with market counts.Reference
GET/api/v1/marketsThe market-type catalog.Reference
GET/api/v1/markets/activeMarket types with live markets.Reference
GET/api/v1/teamsList teams. Filter by league.Reference
GET/api/v1/teams/{id}Get one team.Reference
GET/api/v1/playersList players. Filter by league or team.Reference
GET/api/v1/players/{id}Get one player.Reference
GET/api/v1/historical/oddsOdds as they stood at a past moment. 5 credits per event.Pro+
GET/api/v1/historical/arbitrageSettled arbitrage history. 5 credits per event.Pro+
GET/api/v1/edgesDFS edge signals.API key
GET/api/v1/arbitrageTwo-way and three-way arbitrage signals.API key
GET/api/v1/account/usageYour plan, rate limit, and monthly usage.Reference

Pricing and limits

1 credit = 1 event served. Bulk pulls are flat. Empty responses, 304s, and reference endpoints are always free.

TierPriceRate limitCredits / monthHistoricalSnapshot
Free$02 / min5,000
Pro$25 / mo10 / min500,000×5 credits
Growth$50 / mo30 / min1,500,000×5 credits5-min refresh
Enterprise$100 / mo60 / minSoft-unlimited×5 creditsReal-time

Snapshot pulls are flat: 1 credit, or 5 with include_history=true. Your usage comes back in the X-Credits-Cost and X-Credits-Remaining response headers. Annual billing gets 2 months free. Full details on the pricing page.

MCP server

Wire SportWizzard into Claude, Codex, or any MCP client.

A hosted server runs at mcp.sportwizzard.com with bearer-key auth and no install. An open-source stdio server offers the same 20 tools over npm, including download_snapshot with an include_history option and a mock mode for development.

github.com/adamruehle/sportwizzard-mcp →

Working in a coding agent? See the agent quickstart.

hosted · Claude Code
claude mcp add --transport http sportwizzard \
  https://mcp.sportwizzard.com/mcp \
  --header "Authorization: Bearer sw_live_…"
local stdio · claude_desktop_config.json
{
  "mcpServers": {
    "sportwizzard": {
      "command": "npx",
      "args": ["-y", "sportwizzard-mcp"],
      "env": { "SPORTWIZZARD_API_KEY": "sw_live_…" }
    }
  }
}

Start free

The free tier includes 5,000 credits a month. No card required.