SportsGameOdds API

website·Indexed 32 days ago

https://sportsgameodds.com/docs

A sports betting odds data API for developers featuring real-time streaming via WebSockets and REST endpoints for fetching games, odds, players, leagues, and markets. Includes SDKs for TypeScript, Python, Ruby, Go, and Java, as well as guides for cursor-based pagination, V1 to V2 migration, and building tools like arbitrage calculators and live odds trackers.

Tokens
34.4K
Snippets
134
Records
207
Agent score
67%

What's inside SportsGameOdds

  1. V2 API Key Changes and Improvements

    The V2 API introduces several functional changes:

    • Combined Endpoints: /v2/events now contains both event metadata and odds breakdowns.
    • Persistence: Bookmaker-specific odds now persist even when inactive, using an available field to indicate if they are open for wagers.
    • Deeplinks: Added deeplink fields for major US sportsbooks (FanDuel, DraftKings, BetMGM).
    • Player IDs: Player IDs are now unique across all teams in a league, regardless of team changes.
    • Performance: Faster response times and higher polling frequency for odds data.
  2. Implement Same Game Parlay (SGP) correlation checks

    For Same Game Parlays, you must check for specific correlated bet types (e.g., Spread and Over/Under) within the same event to determine if the combination is allowed.
    function checkCorrelation(leg1, leg2) {
      if (leg1.eventID !== leg2.eventID) {
        return false; // Different games, no correlation
      }
    
      // Check for correlated bets
      const correlatedPairs = [
        ["sp", "ou"], // Spread and total often correlated
        ["ml", "ou"], // Moneyline and total often correlated
      ];
    
      const pair = [leg1.betTypeID, leg2.betTypeID].sort();
      return correlatedPairs.some((cp) => cp[0] === pair[0] && cp[1] === pair[1]);
    }
  3. Identify player props in API responses

    Player props are distinguished from team-level odds by the statEntityID field. Team-level odds use generic values like 'all', 'home', or 'away', whereas player props contain a specific player identifier (e.g., 'LEBRON_JAMES_1_NBA').
    stat_entity = odd.get('statEntityID', 'all')
    
    # Skip team-level odds
    if stat_entity in ['all', 'home', 'away']:
        continue
    
    # This is a player prop
    player = stat_entity
  4. Implement a Parlay Calculator using JavaScript and SportsGameOdds API

    This example demonstrates how to build an interactive CLI tool that fetches real-time sports odds, allows users to select multiple bet legs, and calculates the total parlay payout and implied probability. The implementation handles American-to-Decimal odds conversion, filters for specific bookmakers (e.g., DraftKings), and prevents correlated bets (multiple bets from the same game).
    // calculator.js
    const fetch = require("node-fetch");
    const readline = require("readline");
    
    const API_KEY = process.env.SPORTSGAMEODDS_KEY;
    const API_BASE = "https://api.sportsgameodds.com/v2";
    
    const rl = readline.createInterface({
      input: process.stdin,
      output: process.stdout,
    });
    
    // Utility functions
    const americanToDecimal = (american) => {
      if (american > 0) {
        return american / 100 + 1;
      }
      return 100 / Math.abs(american) + 1;
    };
    
    const decimalToAmerican = (decimal) => {
      if (decimal >= 2.0) {
        return Math.round((decimal - 1) * 100);
      }
      return Math.round(-100 / (decimal - 1));
    };
    
    const formatOdds = (american) => {
      return american > 0 ? `+${american}` : american.toString();
    };
    
    // Fetch games
    async function fetchGames(league = "NBA") {
      try {
        const response = await fetch(`${API_BASE}/events?leagueID=${league}&finalized=false&oddsAvailable=true&limit=20`, { headers: { "x-api-key": API_KEY } });
    
        if (!response.ok) {
          throw new Error(`HTTP ${response.status}`);
        }
    
        return await response.json();
      } catch (error) {
        console.error("Error fetching games:", error.message);
        return { data: [] };
      }
    }
    
    // Display available bets
    function displayAvailableBets(events) {
      const bets = [];
      let betId = 1;
    
      events.forEach((event) => {
        const awayName = event.teams.away.names.long;
        const homeName = event.teams.home.names.long;
        const matchup = `${awayName} @ ${homeName}`;
    
        // Get spread odds (DraftKings)
        const spreadOdds = Object.values(event.odds || {}).filter((odd) => odd.betTypeID === "sp" && odd.periodID === "game" && odd.byBookmaker?.draftkings);
    
        spreadOdds.forEach((odd) => {
          const dkOdds = odd.byBookmaker.draftkings;
          if (!dkOdds.available) return;
    
          const team = odd.sideID === "home" ? homeName : awayName;
          const line = dkOdds.spread || "0";
    
          bets.push({
            id: betId++,
            matchup,
            description: `${team} ${line}`,
            odds: parseInt(dkOdds.odds),
            decimalOdds: americanToDecimal(parseInt(dkOdds.odds)),
            eventID: event.eventID,
            oddID: odd.oddID,
            betTypeID: odd.betTypeID,
            sideID: odd.sideID,
            spread: dkOdds.spread,
          });
        });
    
        // Get moneyline odds
        const mlOdds = Object.values(event.odds || {}).filter((odd) => odd.betTypeID === "ml" && odd.periodID === "game" && odd.byBookmaker?.draftkings);
    
        mlOdds.forEach((odd) => {
          const dkOdds = odd.byBookmaker.draftkings;
          if (!dkOdds.available) return;
    
          const team = odd.sideID === "home" ? homeName : awayName;
    
          bets.push({
            id: betId++,
            matchup,
            description: `${team} ML`,
            odds: parseInt(dkOdds.odds),
            decimalOdds: americanToDecimal(parseInt(dkOdds.odds)),
            eventID: event.eventID,
            oddID: odd.oddID,
          });
        });
    
        // Get totals (over/under)
        const totalOdds = Object.values(event.odds || {}).filter((odd) => odd.betTypeID === "ou" && odd.periodID === "game" && odd.byBookmaker?.draftkings);
    
        totalOdds.forEach((odd) => {
          const dkOdds = odd.byBookmaker.draftkings;
          if (!dkOdds.available) return;
    
          const side = odd.sideID === "over" ? "Over" : "Under";
    
          bets.push({
            id: betId++,
            matchup,
            description: `${side} ${dkOdds.overUnder}`,
            odds: parseInt(dkOdds.odds),
            decimalOdds: americanToDecimal(parseInt(dkOdds.odds)),
            eventID: event.eventID,
            oddID: odd.oddID,
            betTypeID: odd.betTypeID,
            sideID: odd.sideID,
            overUnder: dkOdds.overUnder,
          });
        });
      });
    
      return bets;
    }
    
    // Calculate parlay odds
    function calculateParlay(legs, stake = 100) {
      if (legs.length === 0) return null;
    
      const combinedDecimalOdds = legs.reduce((acc, leg) => acc * leg.decimalOdds, 1);
      const combinedAmericanOdds = decimalToAmerican(combinedDecimalOdds);
      const payout = stake * combinedDecimalOdds;
      const profit = payout - stake;
    
      return {
        legs: legs.length,
        combinedDecimalOdds: combinedDecimalOdds.toFixed(2),
        combinedAmericanOdds: formatOdds(combinedAmericanOdds),
        stake,
        payout: payout.toFixed(2),
        profit: profit.toFixed(2),
      };
    }
    
    // Display parlay summary
    function displayParlay(parlay, legs) {
      console.log("\n" + "=".repeat(80));
      console.log("PARLAY SUMMARY");
      console.log("=".repeat(80));
    
      console.log("\nSelected Legs:\n");
      legs.forEach((leg, i) => {
        console.log(`${i + 1}. ${leg.description} (${leg.matchup})`);
        console.log(`   Odds: ${formatOdds(leg.odds)} (${leg.decimalOdds.toFixed(2)} decimal)`);
        console.log();
      });
    
      console.log("-".repeat(80));
      console.log(`\nCombined Odds: ${parlay.combinedAmericanOdds} (${parlay.combinedDecimalOdds} decimal)`);
      console.log(`Stake: $${parlay.stake.toFixed(2)}`);
      console.log(`Potential Payout: $${parlay.payout}`);
      console.log(`Potential Profit: $${parlay.profit}`);
    
      const impliedProb = (1 / parseFloat(parlay.combinedDecimalOdds)) * 100;
      console.log(`Implied Probability: ${impliedProb.toFixed(1)}%`);
      console.log("\n" + "=".repeat(80));
      console.log("Remember: ALL legs must win for parlay to pay out!");
      console.log("=".repeat(80) + "\n");
    }
    
    async function main() {
      console.log("Parlay Calculator - SportsGameOdds API\n");
      const { data: events } = await fetchGames("NBA");
    
      if (!events || events.length === 0) {
        console.log("No upcoming NBA games found");
        rl.close();
        process.exit(1);
      }
    
      const availableBets = displayAvailableBets(events);
      if (availableBets.length === 0) {
        console.log("No DraftKings odds available");
        rl.close();
        process.exit(1);
      }
    
      console.log("Available Bets:\n");
      availableBets.forEach((bet) => {
        console.log(`${bet.id}. ${bet.description} ${formatOdds(bet.odds)} - ${bet.matchup}`);
      });
    
      const selectedLegs = [];
      const selectLeg = () => {
        rl.question('\nEnter bet ID to add to parlay (or "done" to finish): ', (answer) => {
          if (answer.toLowerCase() === "done") {
            if (selectedLegs.length < 2) {
              console.log("\nParlay requires at least 2 legs!\n");
              selectLeg();
              return;
            }
            rl.question("\nEnter stake amount ($): ", (stakeInput) => {
              const stake = parseFloat(stakeInput) || 100;
              const parlay = calculateParlay(selectedLegs, stake);
              displayParlay(parlay, selectedLegs);
              rl.close();
            });
            return;
          }
    
          const betId = parseInt(answer);
          const bet = availableBets.find((b) => b.id === betId);
          if (!bet) { console.log("Invalid bet ID"); selectLeg(); return; }
          if (selectedLegs.find((l) => l.id === bet.id)) { console.log("Bet already in parlay"); selectLeg(); return; }
          if (selectedLegs.find((l) => l.eventID === bet.eventID)) { console.log("Cannot parlay multiple bets from same game"); selectLeg(); return; }
    
          selectedLegs.push(bet);
          console.log(`Added: ${bet.description} ${formatOdds(bet.odds)}`);
          selectLeg();
        });
      };
      selectLeg();
    }
    
    main();
  5. Implement efficient polling and pagination

    To optimize API usage and costs:

    • Vary Polling Intervals: Poll less frequently for games far in the future and more frequently as the game start time approaches (odds change less often for distant games).
    • Pagination: Use the limit and cursor parameters together. Increase the limit first to maximize results per request before utilizing the cursor for subsequent pages.
    • Avoid Over-polling: Data typically updates every 30 to 60 seconds; polling more frequently than this wastes your quota.
  6. Install the sports-odds-api-mcp server

    The sports-odds-api-mcp server allows AI tools to interact directly with the API to list endpoints, fetch live data (events, odds, teams, etc.), search documentation, monitor usage, and stream events (AllStar plan only). The server requires the SPORTS_ODDS_API_KEY_HEADER environment variable.
    # Claude Code installation
    claude mcp add sports-game-odds --env SPORTS_ODDS_API_KEY_HEADER="your-api-key-here" -- npx -y sports-odds-api-mcp
    
    # VS Code installation
    code --add-mcp '{"name":"sports-game-odds","command":"npx","args":["-y","sports-odds-api-mcp@latest"],"env":{"SPORTS_ODDS_API_KEY_HEADER":"your-api-key-here"}}'
  7. Install SportsGameOdds SDK for Go

    Install the Go SDK using go get from the official GitHub repository.
    go get github.com/SportsGameOdds/sports-odds-api-go
  8. Fetch documentation pages in Markdown format

    Every documentation page has a Markdown representation (excluding HTML, navigation, and scripts). You can request these using content negotiation or by appending a file extension to the URL.
    # Use content negotiation
    curl -H "Accept: text/markdown" https://sportsgameodds.com/docs/basics/quickstart
    
    # Or append .md / .mdx to the URL
    curl https://sportsgameodds.com/docs/basics/quickstart.mdx
    curl https://sportsgameodds.com/leagues/nfl-odds-api.md
  9. Migrate from V1 to V2 API endpoints

    To upgrade to the V2 API, replace v1 with v2 in your request URLs. Note that the /v1/events and /v1/odds endpoints have been merged into a single /v2/events endpoint; there is no separate /v2/odds endpoint.
    - https://api.sportsgameodds.com/v1/events...
    - https://api.sportsgameodds.com/v1/odds...
    + https://api.sportsgameodds.com/v2/events...