Skip to main content

Overview

Predexon separates sports market discovery from live game state. Market discovery answers: what can I trade? Live state answers: what is happening in the underlying game? That separation keeps identifiers clear:
IdentifierMeaningExample
game_idBroad real-world gamemlb-ari-pit-2026-05-07
event_idCanonical market/question attached to a gamemlb-ari-pit-2026-05-07 for current game_winner v1
predexon_idCanonical tradable outcomepx-xz7fw6lsywv2rnwr
Live state is keyed by game_id, not event_id, because future spreads, totals, and props can all share the same live score while using different market/question IDs.
predexon_id is now canonical. It identifies one Predexon outcome across matched venues; it is not a venue-native token ID, ticker, condition ID, or legacy per-venue identifier.

Availability

SurfaceStatusPurpose
GET /v2/sports/liveAvailableList live-state snapshots by game.
GET /v2/sports/live/{game_id}AvailableFetch one live-state snapshot.
wss://wss.predexon.com/v1/<API_KEY>WebSocketStream aggregate live-state changes on the sports_live channel.
If live state is not yet available for a game, REST can return the game shell with reliability.state = "no_data" and null score fields. For an application that displays sports markets with live score context:
1. GET /v2/sports/games?league=mlb
   -> discover games and canonical predexon_ids

2. GET /v2/sports/live?league=mlb
   -> hydrate visible games with score/status snapshots

3. Subscribe to WSS by league or game_ids
   -> receive aggregate live-state changes

4. GET /v2/sports/outcomes/{predexon_id}
   -> resolve execution venues when the user trades
Do not use live state as a tradable identifier. Trading and routing continue to use outcome-level predexon_id.

Canonical predexon_id

For sports, predexon_id lives at the canonical outcome layer:
game_id       -> broad real-world game
event_id      -> canonical market/question
predexon_id   -> canonical tradable outcome
token_id      -> venue-native executable token, when a venue has one
market_ticker -> Kalshi venue-native ticker
condition_id  -> CTF condition ID, not an outcome ID
Example:
game_id:     mlb-ari-pit-2026-05-07
event_id:    mlb-ari-pit-2026-05-07
outcome:     ari
predexon_id: px-xz7fw6lsywv2rnwr
If Kalshi, Polymarket, and Predict.fun all list “Arizona Diamondbacks win” for that game, each matched venue listing returns the same canonical predexon_id. Use predexon_id for routing, positions, orderbook subscriptions, and GET /v2/sports/outcomes/{predexon_id}. Use venue-native identifiers only when executing directly on a specific venue.

Data Sources

Sports live state v1 sources data from Polymarket and Kalshi. Predexon normalizes those updates into one stable game-state object keyed by game_id. We are integrating with additional sports data providers soon to expand coverage and improve source redundancy.

Game Coverage

Sports live state covers Predexon’s matched canonical sports games: the same game universe exposed by GET /v2/sports/games. Use the discovery endpoints to get the current event list:
GET /v2/sports/games
GET /v2/sports/games?league=mlb
GET /v2/sports/live
The websocket all-games subscription follows that same matched sports coverage:
{
  "action": "subscribe",
  "platform": "predexon",
  "version": 1,
  "type": "sports_live",
  "filters": {
    "game_ids": ["*"]
  }
}
Current sports market coverage follows the venue coverage matrix. Live-state data is available when one of the live-state sources has data for that covered game.

Key Incidents and Event Lists

The live-state object includes a normalized event list in significant_events[]. significant_events[] is for key incidents, not full box-score or every vendor-specific stat. When source data is available, events can include:
Event typeDescription
score_changeA scoring event, including soccer goals, basketball made shots/free throws, or other source-supported score changes.
yellow_cardSoccer yellow card.
red_cardSoccer red card.
substitutionSoccer substitution or other source-supplied substitution event.
period_startStart of a period, half, quarter, map, or similar segment when exposed by the source.
period_endEnd of a period, half, quarter, map, or similar segment when exposed by the source.
game_startGame started.
game_endGame ended or final status reached.
otherSource-supplied incident that does not map cleanly to a standard type yet.
Example:
{
  "type": "score_change",
  "team": "home",
  "period": "2H",
  "clock": "58'",
  "player": "Ramos, Guilherme",
  "description": "Goal for the home team",
  "source": "kalshi"
}
Incident availability is source- and sport-dependent. Kalshi can provide detailed game-stat/play-by-play data for supported milestones. In the current Kalshi feed, soccer commonly includes goals, cards, substitutions, period events, and game-end events; basketball can include made shots/free throws and period boundaries; baseball play-by-play is available for some games but is not always returned as typed key incidents. Polymarket’s sports websocket primarily provides score, period, status, clock, and game-level state. If no key incidents are available for a game, significant_events is returned as an empty array.

Aggregate State

The aggregate state is the primary client object.
{
  "game_id": "mlb-ari-pit-2026-05-07",
  "league": "mlb",
  "sport": "baseball",
  "game_date": "2026-05-07",
  "title": "Arizona Diamondbacks vs Pittsburgh Pirates",
  "home_team": {
    "code": "pit",
    "name": "Pittsburgh Pirates"
  },
  "away_team": {
    "code": "ari",
    "name": "Arizona Diamondbacks"
  },
  "participants": [
    { "code": "ari", "name": "Arizona Diamondbacks" },
    { "code": "pit", "name": "Pittsburgh Pirates" }
  ],
  "status": "InProgress",
  "status_text": "In Progress",
  "live": true,
  "ended": false,
  "period": "Top 5",
  "clock": null,
  "score": {
    "home": 2,
    "away": 4,
    "display": "2-4"
  },
  "winner": null,
  "last_play": null,
  "significant_events": [],
  "reliability": {
    "state": "single_source",
    "source_count": 1,
    "sources": ["polymarket"],
    "conflict": false,
    "stale": false
  },
  "updated_at": "2026-05-07T23:42:10Z"
}

Field Semantics

FieldMeaning
game_idBroad sports fixture ID. Same value used by /v2/sports/games.
home_team / away_teamHome/away teams when source mapping is known. May be null before source mapping is available.
participantsKnown participants from canonical game metadata. Present even when home/away is unknown.
statusNormalized or source-derived game status.
status_textHuman-readable status when available.
liveWhether the game is currently in progress.
endedWhether the game has ended.
periodSport-specific period: inning, quarter, half, map number, etc.
clockSport-specific clock when available. May be null for sports like baseball.
score.home / score.awayScore by home/away team when home/away mapping is known.
score.displaySource or aggregate display score.
winnerWinner when known: typically home, away, draw, or a source-native value.
last_playLatest notable play when available. When present, it maps to the most recent item in significant_events. It can be null when no notable incident has happened yet or the source has not supplied one at that time.
significant_eventsNormalized key incident list. Can include score changes, cards, substitutions, period events, game start/end, or source-supported other events. Empty when no incidents are available.
reliabilitySource agreement and freshness summary.
updated_atLast aggregate update timestamp.

Reliability

reliability is not a model confidence score. It is a data-quality summary based on direct source names, source agreement, and freshness.
StateMeaning
no_dataThe game exists, but no source has written live state.
single_sourceOne source has current state.
confirmedTwo or more sources agree on material fields.
conflictSources disagree on material fields such as score, winner, or ended status.
staleLatest available source state is too old for a live game.
The boolean fields make the state easy to consume:
FieldMeaning
sourcesDirect source names used for the aggregate, such as polymarket or kalshi.
source_countNumber of source snapshots used. Equal to sources.length when source names are available.
conflictWhether material source disagreement exists.
staleWhether the aggregate is stale or absent.
For normal product surfaces, use the aggregate fields and reliability. For debugging or auditing, request source rows with include_sources=true.

Source Snapshots

REST can include source-level rows:
GET /v2/sports/live/{game_id}?include_sources=true
Source snapshots are intended for audit/debug, not primary UI rendering.
{
  "source": "polymarket",
  "source_game_id": "19439",
  "source_url": null,
  "status": "InProgress",
  "status_text": "InProgress",
  "live": true,
  "ended": false,
  "period": "Top 5",
  "clock": null,
  "score": {
    "home": 2,
    "away": 4,
    "display": "2-4"
  },
  "winner": null,
  "last_play": null,
  "significant_events": [],
  "details": {
    "slug": "mlb-pit-ari-2026-05-07"
  },
  "observed_at": "2026-05-07T23:42:09Z",
  "updated_at": "2026-05-07T23:42:10Z"
}

WebSocket

The websocket streams aggregate changes, not every raw upstream source message. This keeps client integrations simple and avoids making consumers reconcile Polymarket/Kalshi differences themselves. Endpoint:
wss://wss.predexon.com/v1/<API_KEY>
Authentication uses the same data key as REST, passed in the websocket URL:
wss://wss.predexon.com/v1/YOUR_DATA_KEY

Subscription Messages

Subscribe to all matched sports games Predexon currently covers:
{
  "action": "subscribe",
  "platform": "predexon",
  "version": 1,
  "type": "sports_live",
  "filters": {
    "game_ids": ["*"]
  }
}
Subscribe by league:
{
  "action": "subscribe",
  "platform": "predexon",
  "version": 1,
  "type": "sports_live",
  "filters": {
    "leagues": ["mlb"]
  }
}
Subscribe by explicit games:
{
  "action": "subscribe",
  "platform": "predexon",
  "version": 1,
  "type": "sports_live",
  "filters": {
    "game_ids": ["mlb-ari-pit-2026-05-07"]
  }
}
Filters:
FieldTypeMeaning
game_idsstring[]Subscribe to specific games. Use ["*"] for all matched games.
leaguesstring[]Subscribe to all games in one or more leagues.
sportsstring[]Subscribe to all games in one or more sports.
Exactly one of game_ids, leagues, or sports is required. Unsubscribe:
{
  "action": "unsubscribe",
  "subscription_id": "sub_01"
}

Server Messages

Subscription acknowledgement:
{
  "type": "ack",
  "subscription_id": "sub_01",
  "channel": "sports_live"
}
Aggregate update:
{
  "type": "event",
  "subscription_id": "sub_01",
  "data": {
    "event_type": "sports_live_state",
    "sequence": 1842,
    "game_id": "mlb-ari-pit-2026-05-07",
    "league": "mlb",
    "sport": "baseball",
    "home_team": {
      "code": "pit",
      "name": "Pittsburgh Pirates"
    },
    "away_team": {
      "code": "ari",
      "name": "Arizona Diamondbacks"
    },
    "updated_at": "2026-05-07T23:42:10Z",
    "status": "InProgress",
    "live": true,
    "ended": false,
    "period": "Top 5",
    "clock": null,
    "score": {
      "home": 2,
      "away": 4,
      "display": "2-4"
    },
    "winner": null,
    "reliability": {
      "state": "single_source",
      "source_count": 1,
      "sources": ["polymarket"],
      "conflict": false,
      "stale": false
    }
  }
}
Error:
{
  "type": "error",
  "code": "INVALID_FILTERS",
  "message": "Sports live subscriptions require exactly one of game_ids, leagues, or sports"
}

Heartbeats and Reconnects

The gateway uses websocket ping/pong frames for connection liveness. Clients should respond to ping frames according to their websocket library’s normal behavior. If the connection drops, clients should reconnect and resubscribe. The REST endpoint should be used to rehydrate current state after reconnect:
GET /v2/sports/live?league=mlb
The websocket version does not require clients to track replay cursors. If replay is added later, it should be additive through a field such as since_sequence.

Update Policy

The websocket emits an update when the aggregate changes materially:
  • Score changed
  • Period changed
  • Clock changed
  • Key incidents changed
  • live or ended changed
  • Winner changed
  • Reliability changed
  • Source conflict appeared or resolved
  • Stale state appeared or resolved
The websocket does not emit every upstream heartbeat or duplicate source message.

Sports-Specific Notes

SportCommon period / clock behavior
MLBperiod may be inning state such as Top 5; clock is usually null.
NBA/NFL/CFBperiod is quarter; clock is game clock when supplied.
Soccerperiod is half/status; clock may be elapsed match time.
NHLperiod is period/overtime/shootout; clock is game clock when supplied.
Tennis/esportsperiod may be set/map number; score display can be source-specific.

Non-Goals

The live-state API is not intended to expose every possible vendor-specific stat. The stable public contract is:
  • Current score
  • Period/clock/status
  • Winner/end state
  • Significant events when available
  • Source reliability
  • Optional source snapshots for audit/debug
Full play-by-play, detailed box scores, and sport-specific stat feeds may be added later as separate endpoints if needed.