-
Notifications
You must be signed in to change notification settings - Fork 0
API DOCUMENTATION
Comprehensive API reference for MCP tools, Backend HTTP endpoints, and Frontend architecture.
The MCP server exposes 30+ tools to Claude Desktop via stdio transport. All responses follow the pattern:
{
"success": true,
"data": { ... },
"error": "error message" // only on failure
}List all available sports from The Odds API.
Parameters:
-
all_sports(bool): If False (default), returns only in-season sports
Response:
{
"success": true,
"data": [
{
"key": "americanfootball_nfl",
"title": "NFL",
"group": "American Football",
"active": true,
"has_outrights": false
}
]
}Get current betting odds for upcoming games.
Parameters:
-
sport(str): Sport key (e.g.,americanfootball_nfl,basketball_nba) -
regions(str): Comma-separated bookmaker regions (us, us2, uk, au, eu) -
markets(str): Comma-separated markets (h2h, spreads, totals, player_points, etc.) -
odds_format(str): american, decimal, or fractional -
date_format(str): iso or unix
Markets:
-
Game Markets:
h2h(moneyline),spreads,totals,outrights -
Player Props: 70+ markets including
player_points,player_rebounds,player_assists,player_pass_tds,player_rush_yds,player_home_runs,player_shots_on_goal
Response:
{
"success": true,
"data": [
{
"id": "event_id",
"sport_key": "basketball_nba",
"commence_time": "2026-01-09T19:00:00Z",
"home_team": "Los Angeles Lakers",
"away_team": "Boston Celtics",
"bookmakers": [
{
"key": "draftkings",
"title": "DraftKings",
"markets": [
{
"key": "h2h",
"outcomes": [
{"name": "Los Angeles Lakers", "price": -150},
{"name": "Boston Celtics", "price": +130}
]
}
]
}
]
}
],
"usage": {
"remaining": "492",
"used": "8"
}
}Get live and recent scores.
Parameters:
-
sport(str): Sport key -
days_from(int): Number of days back to retrieve scores
Response:
{
"success": true,
"data": [
{
"id": "event_id",
"sport_key": "basketball_nba",
"commence_time": "2026-01-08T19:00:00Z",
"completed": true,
"home_team": "Los Angeles Lakers",
"away_team": "Boston Celtics",
"scores": [
{"name": "Los Angeles Lakers", "score": "112"},
{"name": "Boston Celtics", "score": "108"}
]
}
]
}Get detailed odds for a specific event.
Natural language search for odds by team name or matchup.
Parameters:
-
query(str): Team name or matchup (e.g., "Lakers", "Lakers vs Celtics") -
sport(str): Optional sport key to narrow search -
markets(str): Comma-separated markets to include
Get raw ESPN scoreboard data (JSON).
Parameters:
-
sport(str): Sport type (football, basketball, baseball, hockey, soccer) -
league(str): League code (nfl, nba, mlb, nhl, etc.) -
date(str): Optional date in YYYYMMDD format -
limit(int): Max games (default 10, max 25)
Response:
{
"success": true,
"data": {
"leagues": [...],
"events": [
{
"id": "401547516",
"name": "Los Angeles Lakers at Boston Celtics",
"shortName": "LAL @ BOS",
"competitions": [...]
}
]
}
}Get formatted Markdown scoreboard table.
Returns: Markdown table with:
- Team names, scores
- Game status (🔴 LIVE, ✅ FINAL, 🕐 Scheduled)
- Time/broadcast info
Get interactive React artifact scoreboard.
Returns: Structured data for Claude to render as interactive cards with team colors, logos, expandable odds.
Get ASCII art matchup cards.
Returns: Text with box-drawing characters:
┌────────────────────────────────────────────────────────────────┐
│ │
│ MATCHUP │
│ │
├────────────────────────────────────────────────────────────────┤
│ │
│ Los Angeles Lakers vs Boston Celtics │
│ │
│ 112 - 108 │
│ │
│ Tue, Jan 08 @ 07:00 PM │
│ │
└────────────────────────────────────────────────────────────────┘
Get league standings.
List all teams in a league.
Get detailed team information.
Get team schedule and results.
Get latest news articles.
Search for teams/players/content.
Combines ESPN game data with betting odds.
Compare odds across bookmakers in Markdown table.
Get quick reference table of team IDs, abbreviations, and divisions.
Parameters:
-
sport(str): nfl, nba, or nhl
Returns: Markdown table with all teams.
Fuzzy match team name to ESPN ID.
Express + TypeScript REST API for the web dashboard. Base URL: http://localhost:3001/api
All /api/mcp/* routes require authentication via Bearer token:
Authorization: Bearer <token>All endpoints return:
{
"status": "success" | "error",
"data": { ... }, // on success
"message": "...", // on error
"error": "..." // detailed error message
}OAuth2 authentication with Microsoft and Google providers.
Get authentication status and available providers.
Response:
{
"authEnabled": true,
"authMode": "oauth2",
"user": {
"id": "uuid",
"email": "user@example.com",
"name": "John Doe",
"provider": "microsoft"
},
"providers": {
"microsoft": true,
"google": true
}
}Initiate Microsoft/Azure AD OAuth2 flow.
Redirects to Microsoft login page with configured scopes (openid, profile, email).
OAuth2 callback endpoint (handled automatically).
Initiate Google OAuth2 flow.
Redirects to Google login page with configured scopes.
Google OAuth2 callback endpoint (handled automatically).
Log out current user and destroy session.
Response:
{
"success": true
}Get current authenticated user.
Response:
{
"user": {
"id": "uuid",
"email": "user@example.com",
"name": "John Doe",
"provider": "microsoft"
},
"authEnabled": true
}401 Response if not authenticated:
{
"error": "Not authenticated"
}Manage API keys for programmatic access (alternative to OAuth2).
List all API keys for current user.
Response:
{
"success": true,
"data": {
"keys": [
{
"id": "uuid",
"name": "Production Bot",
"keyPrefix": "btk_abc123",
"permissions": {
"read": true,
"write": true,
"bets": true,
"stats": true
},
"lastUsedAt": "2026-01-13T10:30:00Z",
"expiresAt": "2027-01-13T00:00:00Z",
"revoked": false,
"createdAt": "2026-01-01T00:00:00Z",
"updatedAt": "2026-01-13T10:30:00Z"
}
]
}
}Note: Full API key is never returned in list endpoints. keyPrefix shows first 10 characters only.
Create a new API key.
Request Body:
{
"name": "Production Bot",
"permissions": {
"read": true,
"write": true,
"bets": true,
"stats": true
},
"expiresAt": "2027-01-13T00:00:00Z" // optional
}Response:
{
"success": true,
"data": {
"key": "btk_abc123xyz789def456ghi...", // Full key - only shown ONCE!
"id": "uuid",
"name": "Production Bot",
"keyPrefix": "btk_abc123",
"permissions": { ... },
"expiresAt": "2027-01-13T00:00:00Z",
"createdAt": "2026-01-13T10:30:00Z"
},
"message": "API key created successfully. Save this key - it will not be shown again."
}Update API key name or permissions.
Request Body:
{
"name": "Updated Name",
"permissions": {
"read": true,
"write": false,
"bets": true,
"stats": true
}
}Response:
{
"success": true,
"data": {
"id": "uuid",
"name": "Updated Name",
"permissions": { ... },
"updatedAt": "2026-01-13T11:00:00Z"
}
}Note: Cannot update keyHash, keyPrefix, expiresAt, or revoked via this endpoint.
Revoke (soft delete) an API key.
Response:
{
"success": true,
"message": "API key revoked successfully"
}Note: Revoked keys are not deleted but marked as revoked: true. They can no longer be used for authentication.
Include API key in request header:
Authorization: Bearer btk_abc123xyz789def456ghi...Or as query parameter (not recommended for production):
GET /api/games?apiKey=btk_abc123xyz789def456ghi...
Authentication Order:
- Check for API key in
Authorizationheader - Check for API key in query parameter
- Check for session authentication (OAuth2)
List bets with filters.
Query Parameters:
-
status(string): Filter by status (pending, won, lost, push, cancelled) -
betType(string): Filter by type (single, parlay, teaser) -
sportKey(string): Filter by sport -
startDate(ISO string): Filter by date range start -
endDate(ISO string): Filter by date range end -
limit(number): Max results (default: 50) -
offset(number): Pagination offset
Response:
{
"status": "success",
"data": {
"bets": [
{
"id": "uuid",
"name": "Lakers ML",
"betType": "single",
"stake": 100.00,
"status": "pending",
"oddsAtPlacement": -150,
"potentialPayout": 166.67,
"createdAt": "2026-01-08T10:00:00Z",
"legs": [
{
"id": "uuid",
"gameId": "uuid",
"selectionType": "moneyline",
"selection": "home",
"teamName": "Los Angeles Lakers",
"odds": -150,
"status": "pending",
"game": {
"awayTeamName": "Boston Celtics",
"homeTeamName": "Los Angeles Lakers",
"commenceTime": "2026-01-09T19:00:00Z"
}
}
]
}
],
"total": 42,
"limit": 50,
"offset": 0
}
}Create a new bet.
Request Body:
{
"name": "Lakers ML + Celtics Spread",
"betType": "parlay",
"stake": 50.00,
"legs": [
{
"gameId": "uuid",
"selectionType": "moneyline",
"selection": "home",
"teamName": "Los Angeles Lakers",
"odds": -150
},
{
"gameId": "uuid",
"selectionType": "spread",
"selection": "away",
"teamName": "Boston Celtics",
"line": -5.5,
"odds": -110
}
],
"notes": "Feeling confident about both teams"
}Response:
{
"status": "success",
"data": {
"id": "uuid",
"name": "Lakers ML + Celtics Spread",
"betType": "parlay",
"stake": 50.00,
"status": "pending",
"oddsAtPlacement": 179.55,
"potentialPayout": 139.77,
"legs": [...]
}
}Get single bet with full details.
Update bet (name, stake, notes).
Request Body:
{
"name": "Updated Name",
"stake": 75.00,
"notes": "Updated notes"
}Delete a bet.
Manually settle a bet.
Request Body:
{
"status": "won",
"actualPayout": 166.67
}Get betting statistics.
Query Parameters:
-
sportKey(string): Filter by sport -
betType(string): Filter by bet type -
startDate(ISO string): Date range start -
endDate(ISO string): Date range end
Response:
{
"status": "success",
"data": {
"totalBets": 142,
"totalStake": 7150.00,
"totalPayout": 8234.50,
"netProfit": 1084.50,
"roi": 15.17,
"winRate": 54.23,
"avgOdds": -114.5,
"byStatus": {
"pending": 12,
"won": 77,
"lost": 48,
"push": 5
},
"byType": {
"single": 89,
"parlay": 53
},
"bySport": {
"basketball_nba": { "bets": 45, "netProfit": 523.50 },
"americanfootball_nfl": { "bets": 62, "netProfit": 561.00 }
}
}
}List games with filters (timezone-aware).
Query Parameters:
-
date(YYYY-MM-DD): Filter by specific date in user's local timezone -
sport(string): Sport key (e.g.,basketball_nba,americanfootball_nfl, orall) -
status(string): Game status (scheduled, in_progress, completed) -
timezoneOffset(number): User's timezone offset in minutes (e.g., 420 for MST/UTC-7)
Timezone Handling: The API accepts the user's timezone offset to correctly filter games by date. For example:
- User in MST (UTC-7) requests
date=2026-01-09&timezoneOffset=420 - API converts to UTC range:
2026-01-09 07:00:00Zto2026-01-10 06:59:59Z - Returns all games occurring during Jan 9 in MST
Response:
{
"status": "success",
"data": {
"games": [
{
"id": "uuid",
"exterKey": "basketball_nba",
"sportName": "NBA Basketball",
"sport": {
"id": "uuid",
"key": "basketball_nba",
"name": "NBA Basketball",
"groupName": "Basketball",
"isActive": trueltics",
"homeTeamName": "Los Angeles Lakers",
"commenceTime": "2026-01-09T19:00:00Z",
"status": "scheduled",
"completed": false,
"sport": {
"key": "basketball_nba",
"name": "NBA Basketball"
},
"currentOdds": [
{
"id": "uuid",
"bookmaker": "draftkings",
"marketType": "h2h",
"selection": "home",
"price": -150,
"lastUpdated": "2026-01-08T15:30:00Z"
}
]
}
],
"count": 15
}
}
**Response:**
```json
{
"status": "success",
"data": {
"id": "uuid",
"externalId": "odds_api_event_id",
"sportId": "uuid",
"awayTeamName": "Boston Celtics",
"homeTeamName": "Los Angeles Lakers",
"commenceTime": "2026-01-09T19:00:00Z",
"statgameId": "uuid",
"bookmaker": "draftkings",
"marketType": "spread",
"selection": "home",
"price": -110,
"point": -5.5
}
],
"count": 245
}
}Manage futures bets (championship winners, season awards, long-term props).
Get all active futures with current odds.
Query Parameters:
-
sportKey(string): Filter by sport (e.g.,basketball_nba,americanfootball_nfl) -
status(string): Filter by status (active,completed,settled) - default:active
Response:
{
"futures": [
{
"id": "uuid",
"externalId": "odds_api_future_id",
"sportId": "uuid",
"sport": {
"key": "basketball_nba",
"name": "NBA Basketball"
},
"title": "NBA Championship Winner 2025-26",
"description": "Which team will win the 2026 NBA Championship?",
"status": "active",
"commenceTime": "2025-10-22T00:00:00Z",
"closeTime": "2026-06-01T00:00:00Z",
"settleTime": null,
"currentOdds": [
{
"id": "uuid",
"outcome": "Boston Celtics",
"bookmaker": "draftkings",
"price": 400,
"lastUpdated": "2026-01-13T10:00:00Z"
},
{
"outcome": "Los Angeles Lakers",
"bookmaker": "draftkings",
"price": 650,
"lastUpdated": "2026-01-13T10:00:00Z"
}
],
"groupedOutcomes": [
{
"outcome": "Boston Celtics",
"bookmakers": [
{ "bookmaker": "draftkings", "price": 400 },
{ "bookmaker": "fanduel", "price": 380 },
{ "bookmaker": "betmgm", "price": 425 }
],
"bestOdds": 425
}
],
"createdAt": "2025-10-01T00:00:00Z",
"updatedAt": "2026-01-13T10:00:00Z"
}
]
}Note: groupedOutcomes consolidates all bookmaker odds for each outcome, making it easier to compare odds across sportsbooks.
Get a specific future with all odds and historical snapshots.
Response:
{
"id": "uuid",
"externalId": "odds_api_future_id",
"sportId": "uuid",
"sport": {
"key": "basketball_nba",
"name": "NBA Basketball"
},
"title": "NBA Championship Winner 2025-26",
"description": "Which team will win the 2026 NBA Championship?",
"status": "active",
"commenceTime": "2025-10-22T00:00:00Z",
"closeTime": "2026-06-01T00:00:00Z",
"currentOdds": [ ... ],
"groupedOutcomes": [
{
"outcome": "Boston Celtics",
"bookmakers": [
{
"bookmaker": "draftkings",
"price": 400,
"lastUpdated": "2026-01-13T10:00:00Z"
}
],
"bestOdds": 425,
"averageOdds": 402
}
],
"oddsSnapshots": [
{
"id": "uuid",
"outcome": "Boston Celtics",
"bookmaker": "draftkings",
"price": 380,
"capturedAt": "2026-01-12T10:00:00Z"
},
{
"outcome": "Boston Celtics",
"bookmaker": "draftkings",
"price": 400,
"capturedAt": "2026-01-13T10:00:00Z"
}
],
"outcomes": [
{
"id": "uuid",
"outcome": "Boston Celtics",
"status": "pending",
"settledAt": null
}
]
}Line Movement Data: The oddsSnapshots array contains the last 100 historical snapshots for tracking odds movement over time. Use this data to:
- Display line movement charts
- Identify best odds entry points
- Track market sentiment shifts
Simplified bet creation endpoint for AI/MCP integration using game IDs.
Authentication: Requires API key via apiKeyAuth middleware.
Create a bet from AI-extracted data.
Request Body:
{
"selections": [
{
"gameId": "uuid",
"type": "moneyline",
"selection": "home",
"odds": -150,
"teamName": "Los Angeles Lakers"
},
{
"gameId": "uuid2",
"type": "spread",
"selection": "away",
"odds": -110,
"line": 5.5,
"teamName": "Boston Celtics"
}
],
"betType": "parlay",
"stake": 100.00,
"notes": "AI recommendation from Claude",
"source": "mcp"
}Field Definitions:
-
selections(array, required): Array of bet selections-
gameId(string, required): UUID of the game from database -
type(string, required):moneyline,spread, ortotal -
selection(string, required):home,away,over, orunder -
odds(number, required): American odds (e.g., -150, +200) -
line(number, required for spread/total): The line/point value -
teamName(string, optional): Display name for the selection
-
-
betType(string, required):single,parlay, orteaser -
stake(number, required): Amount to wager -
teaserPoints(number, optional): Points for teaser (6, 6.5, or 7) -
notes(string, optional): Additional notes about the bet -
source(string, optional): Source of bet (mcp,image,text,conversation) - default:mcp
Response:
{
"success": true,
"data": {
"bet": {
"id": "uuid",
"name": "2-Leg Parlay",
"betType": "parlay",
"stake": 100.00,
"status": "pending",
"oddsAtPlacement": 264,
"potentialPayout": 364.00,
"notes": "AI recommendation from Claude",
"source": "mcp",
"createdAt": "2026-01-13T10:30:00Z",
"legs": [
{
"id": "uuid1",
"gameId": "uuid",
"selectionType": "moneyline",
"selection": "home",
"teamName": "Los Angeles Lakers",
"odds": -150,
"status": "pending"
},
{
"id": "uuid2",
"gameId": "uuid2",
"selectionType": "spread",
"selection": "away",
"teamName": "Boston Celtics",
"line": 5.5,
"odds": -110,
"status": "pending"
}
]
},
"isSameGameParlay": false,
"parlayCalculation": {
"decimalOdds": [1.67, 1.91],
"combinedDecimal": 3.19,
"americanOdds": 264,
"potentialPayout": 364.00
}
}
}Same Game Parlay (SGP) Detection: The endpoint automatically detects when multiple selections are from the same game:
- Groups selections by
gameId - For SGP games, multiplies all leg odds together
- Sets
isSameGameParlay: truein response - Provides detailed parlay calculation breakdown
Validation:
- All
gameIdvalues must exist in database (404 if not found) -
typemust be valid:moneyline,spread,total -
selectionmust be valid:home,away,over,under -
oddsis required for all selections -
lineis required forspreadandtotalbets -
stakemust be positive number -
betTypemust besingle,parlay, orteaser
Error Responses:
400 - Missing or invalid fields:
{
"success": false,
"error": "Selection 1 missing required odds value"
}400 - Game IDs not found:
{
"success": false,
"error": "Some game IDs not found",
"details": {
"requestedGames": 2,
"foundGames": 1,
"missingGameIds": ["uuid2"]
}
}Retrieve live game statistics, player performance, and historical team data from API-Sports integration.
Get comprehensive game statistics including live scores, team stats, player stats, and season averages.
Path Parameters:
-
gameId(string): The game's unique identifier
Response:
{
"teamStats": [
{
"id": "uuid",
"gameId": "uuid",
"teamId": "uuid",
"isHome": true,
"homeScore": 105,
"awayScore": 98,
"quarterScores": [28, 25, 27, 25],
"stats": {
"field_goals": 42,
"field_goal_percentage": 48.3,
"three_pointers": 12,
"rebounds": 45,
"assists": 24,
"steals": 8,
"blocks": 5,
"turnovers": 12
},
"team": {
"id": "uuid",
"name": "Los Angeles Lakers",
"abbreviation": "LAL"
}
}
],
"playerStats": [
{
"id": "uuid",
"gameId": "uuid",
"playerId": "uuid",
"stats": {
"minutes": "35:24",
"points": 28,
"rebounds": 8,
"assists": 6,
"field_goals_made": 10,
"field_goals_attempts": 18,
"three_pointers_made": 4,
"free_throws_made": 4
},
"player": {
"id": "uuid",
"name": "LeBron James",
"externalId": "237"
}
}
],
"seasonAverages": [
{
"teamId": "uuid",
"totalGames": 45,
"homeGames": 23,
"awayGames": 22,
"avgStats": {
"points": 112.5,
"field_goal_percentage": 46.8,
"three_pointers": 13.2,
"rebounds": 44.3,
"assists": 26.1,
"steals": 7.8,
"blocks": 5.2
}
}
]
}Features:
- Live Updates: Real-time scores and stats during games
- Quarter Breakdown: Period-by-period scoring (NBA: 4 quarters, NFL: 4 quarters, NHL: 3 periods, Soccer: final score)
- Season Averages: Calculated averages across all games this season for both teams
- Home/Away Splits: Separate statistics for home and away performances
Get team season statistics with home/away filtering and historical game log.
Path Parameters:
-
teamId(string): The team's unique identifier
Query Parameters:
-
season(number, optional): Specific season year (defaults to current season) -
location(string, optional): Filter by location -home,away, orall(default:all)
Response:
{
"seasonStats": {
"teamId": "uuid",
"season": 2026,
"gamesPlayed": 45,
"wins": 32,
"losses": 13,
"avgPoints": 112.5,
"avgOpponentPoints": 106.8
},
"gameHistory": [
{
"id": "uuid",
"gameId": "uuid",
"teamId": "uuid",
"isHome": true,
"homeScore": 105,
"awayScore": 98,
"stats": { "..." },
"game": {
"id": "uuid",
"commenceTime": "2026-01-28T19:00:00Z",
"homeTeam": { "name": "Lakers" },
"awayTeam": { "name": "Celtics" }
}
}
],
"splits": {
"home": {
"gamesPlayed": 23,
"avgPoints": 115.2,
"avgRebounds": 46.1,
"avgAssists": 27.3,
"field_goal_percentage": 48.5
},
"away": {
"gamesPlayed": 22,
"avgPoints": 109.7,
"avgRebounds": 42.5,
"avgAssists": 24.9,
"field_goal_percentage": 45.1
},
"overall": {
"gamesPlayed": 45,
"avgPoints": 112.5,
"avgRebounds": 44.3,
"avgAssists": 26.1,
"field_goal_percentage": 46.8
}
}
}Features:
- Location Filtering: View stats for home games only, away games only, or all games
- Split Statistics: Compare home vs away performance automatically
- Historical Averages: Season-long averages for all numeric stats
- Game Log: Up to 20 most recent games with full stats
Get individual player statistics and game log.
Path Parameters:
-
playerId(string): The player's unique identifier
Query Parameters:
-
season(number, optional): Specific season year (defaults to current season) -
limit(number, optional): Number of recent games to return (default: 10, max: 50)
Response:
{
"player": {
"id": "uuid",
"externalId": "237",
"name": "LeBron James",
"sport": "basketball_nba",
"team": {
"id": "uuid",
"name": "Los Angeles Lakers",
"abbreviation": "LAL"
}
},
"seasonStats": {
"gamesPlayed": 42,
"avgPoints": 27.8,
"avgRebounds": 7.2,
"avgAssists": 8.5,
"field_goal_percentage": 52.3,
"three_point_percentage": 38.9,
"free_throw_percentage": 73.1
},
"gameLog": [
{
"id": "uuid",
"gameId": "uuid",
"stats": {
"minutes": "35:24",
"points": 28,
"rebounds": 8,
"assists": 6
},
"game": {
"id": "uuid",
"commenceTime": "2026-01-28T19:00:00Z",
"homeTeam": { "name": "Lakers" },
"awayTeam": { "name": "Celtics" }
}
}
]
}Supported Sports:
- Basketball (NBA, NCAAB): Points, rebounds, assists, shooting percentages, steals, blocks, turnovers
- Football (NFL, NCAAF): Passing yards/TDs, rushing yards/TDs, receptions, receiving yards, tackles, sacks
- Hockey (NHL): Goals, assists, points, shots on goal, plus/minus, penalty minutes
- Soccer (EPL, MLS, etc.): Goals, assists, shots, passes, tackles, interceptions, cards, goalkeeper saves
Notes:
- Stats sync runs every 15 seconds during game hours (10 AM - 2 AM ET)
- Requires
API_SPORTS_KEYenvironment variable to be configured - Free tier API-Sports accounts limited to 10 requests/day
- Rate limiting: 5 requests/second for Pro tier
Administrative endpoints for system management and data initialization.
Initialize sports data in database.
Response:
{
"status": "success",
"message": "Initialized 7 sports",
"data": [
{
"id": "uuid",
"key": "americanfootball_nfl",
"name": "NFL",
"groupName": "American Football",
"isActive": true
}
]
}Sports Initialized:
- NFL (americanfootball_nfl)
- NBA (basketball_nba)
- NCAAB (basketball_ncaab)
- NHL (icehockey_nhl)
- MLB (baseball_mlb)
- EPL (soccer_epl) - inactive by default
- UEFA Champions League (soccer_uefa_champs_league) - inactive by default
Manually trigger odds synchronization from The Odds API.
Request Body:
{
"sportKey": "basketball_nba" // optional, omit to sync all active sports
}Response:
{
"status": "success",
"message": "Odds sync started in background",
"data": {
"sportKey": "basketball_nba"
}
}Note: Sync runs asynchronously. Check logs for progress and completion.
Manually trigger bet outcome resolution.
Checks completed games and automatically settles bets based on results.
Response:
{
"status": "success",
"message": "Outcome resolution started in background"
}Get database statistics and overview.
Response:
{
"status": "success",
"data": {
"database": {
"sports": 7,
"teams": 124,
"games": 458,
"currentOdds": 6847,
"oddsSnapshots": 45283,
"bets": 142,
"betLegs": 267
},
"activeSports": [
{ "key": "americanfootball_nfl", "name": "NFL" },
{ "key": "basketball_nba", "name": "NBA" }
],
"recentGames": 127
}
}Detailed health check with database connectivity test.
Response:
{
"status": "success",
"data": {
"database": "connected",
"dataInitialized": true,
"hasGames": true,
"timestamp": "2026-01-09T15:30:00Z"
}Get current odds for a specific game.
Query Parameters:
-
bookmaker(string): Filter by bookmaker key (e.g.,draftkings) -
marketType(string): Filter by market type (h2h,spreads,totals)
Response:
{
#### `GET /api/games/:id/odds/history`
Get historical odds snapshots for line movement tracking.
**Query Parameters:**
- `bookmaker` (string): Filter by bookmaker key
- `marketType` (string): Filter by market type
- `hours` (number): Number of hours back to retrieve (default: 24)
#### `GET /api/games/:id`
Get single game with all odds.
#### `GET /api/games/:id/odds-history`
Get historical odds snapshots for line movement tracking.
**Response:**
```json
{
"status": "success",
"data": {
"snapshots": [
{
"timestamp": "2026-01-08T10:00:00Z",
"bookmaker": "draftkings",
"marketType": "spread",
"selection": "home",
"price": -110,
"point": -5.5
}
]
}
}Authentication Required - All routes require Bearer token.
Get all pending bets for MCP integration.
Response:
{
"status": "success",
"data": {
"activeBets": [
{
"id": "uuid",
"name": "Lakers ML",
"betType": "single",
"stake": 100.00,
"potentialPayout": 166.67,
"legs": [...]
}
],
"count": 12,
"totalExposure": 1200.00
}
}Get quick betting summary for MCP context.
Response:
{
"status": "success",
"data": {
"pending": {
"count": 12,
"totalStake": 1200.00,
"potentialWin": 1650.00
},
"recentResults": {
"last7Days": {
"won": 8,
"lost": 5,
"netProfit": 345.50
}
},
"favorites": {
"bestSport": "basketball_nba",
"bestBetType": "single"
}
}
}Get full context for AI betting advice.
Response: Extended summary with:
- All active bets
- Recent performance by sport
- Betting patterns and tendencies
- Risk exposure by game/sport
Get games with user's betting positions.
Query Parameters:
-
sport(string): Filter by sport -
onlyWithBets(boolean): Show only games with active bets
Response:
{
"status": "success",
"data": {
"games": [
{
"game": {
"id": "uuid",
"awayTeamName": "Boston Celtics",
"homeTeamName": "Los Angeles Lakers",
"commenceTime": "2026-01-09T19:00:00Z"
},
"userBets": [
{
"betId": "uuid",
"name": "Lakers ML",
"stake": 100.00,
"selection": "home",
"selectionType": "moneyline"
}
],
"totalExposure": 100.00,
"potentialWin": 166.67
}
]
}
}Simplified bet creation for MCP.
Request Body:
{
"game_id": "uuid",
"selection_type": "moneyline",
"selection": "home",
"stake": 50.00,
"odds": -150,
"name": "Lakers ML"
}Health check endpoint.
Response:
{
"status": "healthy",
"timestamp": "2026-01-08T15:30:00Z",
"database": "connected",
"uptime": 3600
}React + TypeScript + Vite + Redux Toolkit + Tailwind CSS
src/
├── components/ # Reusable UI components
│ ├── bets/ # Bet-related components
│ ├── odds/ # Odds display components
│ ├── stats/ # Statistics components
│ └── common/ # Shared components
├── pages/ # Route pages
├── store/ # Redux store
├── services/ # API clients
├── hooks/ # Custom React hooks
├── types/ # TypeScript types
└── utils/ # Utility functions
import { configureStore } from '@reduxjs/toolkit';
import betSlipReducer from './betSlipSlice';
export const store = configureStore({
reducer: {
betSlip: betSlipReducer,
},
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;State:
interface BetSlipState {
legs: BetLeg[];
betType: 'single' | 'parlay' | 'teaser';
stake: number;
teaserPoints: number;
}Actions:
-
addLeg(leg)- Add/update bet leg (auto-dedupes by gameId + selectionType) -
removeLeg(index)- Remove bet leg -
updateLeg(index, updates)- Update specific leg -
setBetType(type)- Set bet type -
setStake(amount)- Set stake amount -
setTeaserPoints(points)- Set teaser points (6, 6.5, 7) -
clearBetSlip()- Clear all legs -
updateOdds(gameId, odds)- Update odds for specific game
Auto-behaviors:
- Adding 2+ legs auto-switches to parlay
- Removing to 1 leg auto-switches to single
- Clearing legs resets stake to 0
import axios from 'axios';
const apiClient = axios.create({
baseURL: 'http://localhost:3001/api',
headers: { 'Content-Type': 'application/json' },
});
// Auto-adds Bearer token from localStorage
apiClient.interceptors.request.use((config) => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// Auto-handles 401 Unauthorized
apiClient.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
localStorage.removeItem('token');
// Redirect to login
}
return Promise.reject(error);
}
);Interactive bet slip widget.
Features:
- Add/remove legs dynamically
- Adjust stake with validation
- Calculate potential payout (parlay calculations)
- Teaser control for NFL/NBA spreads/totals
- Submit bet to API
Props: None (uses Redux state)
Display single bet with all details.
Props:
interface BetCardProps {
bet: Bet;
onSettle?: (betId: string, status: 'won' | 'lost' | 'push') => void;
onDelete?: (betId: string) => void;
onEdit?: (betId: string) => void;
}Display game with odds from multiple bookmakers.
Props:
interface GameCardProps {
game: Game;
onAddToBetSlip: (leg: BetLeg) => void;
showOdds?: boolean;
collapsed?: boolean;
}Features:
- Expandable odds table
- Click odds to add to bet slip
- Line movement indicators
- Team logos and colors
Grid of games with odds comparison.
Props:
interface OddsGridProps {
sport?: string;
date?: Date;
bookmakers?: string[];
}Features:
- Filter by sport, date
- Sort by commence time
- Toggle between moneyline/spread/total views
- Refresh odds button
Statistics and performance charts.
Features:
- Win rate charts (by sport, by bet type)
- P&L timeline graph
- ROI by bookmaker
- Bet distribution pie charts
- Filters: date range, sport, bet type
export const useBetSlip = () => {
const dispatch = useDispatch();
const betSlip = useSelector((state: RootState) => state.betSlip);
const addLeg = (leg: BetLeg) => dispatch(addLegAction(leg));
const removeLeg = (index: number) => dispatch(removeLegAction(index));
const calculatePayout = () => { /* Calculate based on betType */ };
return { betSlip, addLeg, removeLeg, calculatePayout };
};export const useOddsPolling = (gameId: string, interval: number = 30000) => {
const [odds, setOdds] = useState<Odds[]>([]);
useEffect(() => {
const fetchOdds = async () => {
const response = await apiClient.get(`/games/${gameId}`);
setOdds(response.data.data.currentOdds);
};
fetchOdds();
const timer = setInterval(fetchOdds, interval);
return () => clearInterval(timer);
}, [gameId, interval]);
return odds;
};List of all bets with filters and search.
Features:
- Tabs: Active, Won, Lost, All
- Search by name
- Filter by sport, date range
- Sort by date, stake, potential win
- Pagination
Performance analytics and insights.
Features:
- Overview cards (total bets, win rate, ROI, net profit)
- Charts: P&L over time, win rate by sport, bet distribution
- Best/worst performing sports/bet types
- Recent activity feed
// types/game.types.ts
export interface Game {
id: string;
externalId: string;
sportId: string;
awayTeamName: string;
homeTeamName: string;
commenceTime: Date;
status: 'scheduled' | 'in_progress' | 'completed';
completed: boolean;
sport: Sport;
currentOdds: Odds[];
}
export interface Sport {
id: string;
key: string;
name: string;
active: boolean;
}
export interface Odds {
id: string;
gameId: string;
bookmaker: string;
marketType: 'h2h' | 'spreads' | 'totals';
selection: 'home' | 'away' | 'over' | 'under';
price: number;
point?: number;
lastUpdated: Date;
}
// types/bet.types.ts
export interface Bet {
id: string;
name: string;
betType: 'single' | 'parlay' | 'teaser';
stake: number;
status: 'pending' | 'won' | 'lost' | 'push' | 'cancelled';
oddsAtPlacement: number;
potentialPayout: number;
actualPayout?: number;
teaserPoints?: number;
notes?: string;
createdAt: Date;
settledAt?: Date;
legs: BetLeg[];
}
export interface BetLeg {
id: string;
betId: string;
gameId: string;
selectionType: 'moneyline' | 'spread' | 'total';
selection: 'home' | 'away' | 'over' | 'under';
teamName?: string;
line?: number;
odds: number;
userAdjustedLine?: number;
userAdjustedOdds?: number;
status: 'pending' | 'won' | 'lost' | 'push' | 'cancelled';
result?: number;
game: Game;
}# .env
VITE_API_URL=http://localhost:3001/api
VITE_ENABLE_MOCK_API=false
VITE_ODDS_REFRESH_INTERVAL=30000cd mcp
python sports_mcp_server.pycd dashboard/backend
npm run dev # http://localhost:3001cd dashboard/frontend
npm run dev # http://localhost:5173# Backend
cd dashboard/backend
npm test
# MCP (when implemented)
cd mcp
pytest tests/ -v