Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.odds-api.io/llms.txt

Use this file to discover all available pages before exploring further.

What are Value Bets?

A value bet occurs when the probability of an outcome is greater than what the bookmaker’s odds imply. The Odds-API.io automatically calculates expected value (EV) by comparing individual bookmaker odds against the market average.

How Value Bets Work

Fair odds are calculated from a panel of sharp bookmakers that consistently offer the tightest margins and accept high stakes. These books are stress-tested by professional bettors daily, so their prices reflect genuine market probability better than softer books with padded margins. We use this sharp consensus as the baseline rather than averaging all bookmakers, which would be skewed by recreational pricing. The API then compares each target bookmaker’s odds against this sharp baseline:
  1. Calculates fair odds from the sharp bookmaker consensus
  2. Compares the target bookmaker’s odds to the fair odds
  3. Identifies opportunities where the bookmaker offers higher odds than the sharp consensus implies
Formula:
Expected Value (EV) = (Fair Probability × Bookmaker Odds) - 1
A positive EV indicates the bookmaker is offering odds above what the sharp market considers fair.

Query Parameters

ParameterRequiredDescription
apiKeyYesYour API key
bookmakerYesBookmaker name (e.g. Bet365)
sportNoFilter by sport slug (e.g. baseball). Server-side filter — reduces response size and removes the need for client-side filtering.
leagueNoFilter by league slug (e.g. usa-mlb). Requires sport to also be set.
includeEventDetailsNoInclude match info (home, away, league, sport, date) in the response

Fetching Value Bets

Use the /v3/value-bets endpoint to get current value betting opportunities:
const apiKey = process.env.ODDS_API_KEY;
const bookmaker = 'Bet365';
const includeEventDetails = true;

const response = await fetch(
  `https://api.odds-api.io/v3/value-bets?apiKey=${apiKey}&bookmaker=${bookmaker}&includeEventDetails=${includeEventDetails}`
);

const valueBets = await response.json();
console.log(valueBets);

Filtering by Sport or League

Filter results server-side so only value bets from the sports or leagues you care about come back. This reduces response size and removes the need for client-side filtering.
curl "https://api.odds-api.io/v3/value-bets?apiKey=YOUR_KEY&bookmaker=Bet365&sport=baseball"
Validation rules:
  • Providing league without sport returns 400.
  • Unknown sport slug returns 400.
  • Unknown league for a valid sport returns 404.

Response Format

[
  {
    "id": "vb_123456_bet365_home",
    "eventId": 123456,
    "bookmaker": "Bet365",
    "market": {
      "name": "ML",
      "home": "2.10",
      "draw": "3.40",
      "away": "3.20",
      "hdp": null,
      "max": null
    },
    "betSide": "home",
    "expectedValue": 0.0523,
    "expectedValueUpdatedAt": "2025-10-04T10:30:00Z",
    "bookmakerOdds": {
      "home": "2.10",
      "draw": "3.40",
      "away": "3.20",
      "href": "https://bet365.com/..."
    },
    "event": {
      "home": "Manchester United",
      "away": "Liverpool",
      "date": "2025-10-15T15:00:00Z",
      "sport": "Football",
      "league": "England - Premier League"
    }
  }
]

Understanding the Response

FieldDescription
expectedValueThe calculated EV (positive means value)
betSideWhich outcome has value (home, draw, away, over, under, etc.)
marketMarket odds used for comparison
bookmakerOddsCurrent odds at the bookmaker
eventMatch details (when includeEventDetails=true)

Filtering Value Bets

Filter value bets to find the most profitable opportunities:
function filterValueBets(valueBets, minEV = 0.03) {
  return valueBets
    .filter(bet => bet.expectedValue >= minEV)
    .sort((a, b) => b.expectedValue - a.expectedValue);
}

// Get value bets with at least 3% expected value
const topValueBets = filterValueBets(valueBets, 0.03);

topValueBets.forEach(bet => {
  const evPercent = (bet.expectedValue * 100).toFixed(2);
  console.log(`${bet.event.home} vs ${bet.event.away}`);
  console.log(`Bet on: ${bet.betSide}`);
  console.log(`EV: ${evPercent}%`);
  console.log(`Odds: ${bet.bookmakerOdds[bet.betSide]}`);
  console.log('---');
});

Real-Time Value Bet Monitoring

Value bets are updated every 5 seconds. Here’s how to build a monitoring system:
async function monitorValueBets(bookmaker, minEV = 0.03) {
  const apiKey = process.env.ODDS_API_KEY;

  async function fetchAndProcess() {
    try {
      const response = await fetch(
        `https://api.odds-api.io/v3/value-bets?apiKey=${apiKey}&bookmaker=${bookmaker}&includeEventDetails=true`
      );
      const valueBets = await response.json();

      const filtered = valueBets.filter(bet => bet.expectedValue >= minEV);

      filtered.forEach(bet => {
        notifyUser(bet); // Send notification to users
        logBet(bet); // Log for analytics
      });
    } catch (error) {
      console.error('Error fetching value bets:', error);
    }
  }

  // Initial fetch
  await fetchAndProcess();

  // Poll every 5 seconds
  setInterval(fetchAndProcess, 5000);
}

// Start monitoring
monitorValueBets('Bet365', 0.03);

Multi-Bookmaker Strategy

Monitor value bets across multiple bookmakers:
const bookmakers = ['Bet365', 'Unibet', 'SingBet', 'William Hill'];

async function getAllValueBets(minEV = 0.03) {
  const apiKey = process.env.ODDS_API_KEY;

  const promises = bookmakers.map(bookmaker =>
    fetch(
      `https://api.odds-api.io/v3/value-bets?apiKey=${apiKey}&bookmaker=${bookmaker}&includeEventDetails=true`
    ).then(res => res.json())
  );

  const results = await Promise.all(promises);

  // Flatten and filter
  const allValueBets = results
    .flat()
    .filter(bet => bet.expectedValue >= minEV)
    .sort((a, b) => b.expectedValue - a.expectedValue);

  return allValueBets;
}

const topBets = await getAllValueBets(0.03);

Building a Value Bet Alert System

class ValueBetAlerter {
  constructor(apiKey, minEV = 0.03) {
    this.apiKey = apiKey;
    this.minEV = minEV;
    this.seenBets = new Set();
  }

  async checkForNewValueBets(bookmaker) {
    const response = await fetch(
      `https://api.odds-api.io/v3/value-bets?apiKey=${this.apiKey}&bookmaker=${bookmaker}&includeEventDetails=true`
    );
    const valueBets = await response.json();

    const newBets = valueBets.filter(bet => {
      if (bet.expectedValue < this.minEV) return false;
      if (this.seenBets.has(bet.id)) return false;

      this.seenBets.add(bet.id);
      return true;
    });

    return newBets;
  }

  async sendAlert(bet) {
    const message = `
      🎯 Value Bet Alert!

      ${bet.event.home} vs ${bet.event.away}
      League: ${bet.event.league}
      Sport: ${bet.event.sport}

      Market: ${bet.market.name}
      Bet on: ${bet.betSide}
      Odds: ${bet.bookmakerOdds[bet.betSide]}
      Expected Value: ${(bet.expectedValue * 100).toFixed(2)}%

      Bookmaker: ${bet.bookmaker}
      Place bet: ${bet.bookmakerOdds.href}
    `;

    // Send to your notification system
    // (Email, SMS, Discord, Telegram, etc.)
    console.log(message);
  }

  async monitor(bookmakers) {
    for (const bookmaker of bookmakers) {
      const newBets = await this.checkForNewValueBets(bookmaker);
      newBets.forEach(bet => this.sendAlert(bet));
    }

    // Check every 5 seconds
    setTimeout(() => this.monitor(bookmakers), 5000);
  }
}

// Usage
const alerter = new ValueBetAlerter(process.env.ODDS_API_KEY, 0.03);
alerter.monitor(['Bet365', 'Unibet', 'SingBet']);

Best Practices

Start with a minimum EV of 3-5%. Lower thresholds will generate more alerts but may include less significant opportunities.
Different bookmakers have different inefficiencies. Monitor several bookmakers to maximize opportunities.
Value bets can disappear quickly as bookmakers adjust odds. Implement fast notification systems.
Log all value bets and outcomes to analyze the accuracy of the expected value calculations over time.
Use the Kelly Criterion or similar methods to determine optimal stake sizes based on expected value.

Kelly Criterion Example

Calculate optimal stake using the Kelly Criterion:
function calculateKellyStake(probability, odds, bankroll, kellyFraction = 0.25) {
  // Kelly = (probability * odds - 1) / (odds - 1)
  const kelly = (probability * odds - 1) / (odds - 1);

  // Use fractional Kelly for safety (e.g., 25% of full Kelly)
  const fractionalKelly = kelly * kellyFraction;

  // Calculate stake
  const stake = bankroll * fractionalKelly;

  return Math.max(0, stake); // Don't bet if negative
}

// Example
const bet = valueBets[0];
const impliedProb = 1 / parseFloat(bet.bookmakerOdds[bet.betSide]);
const trueProbability = impliedProb * (1 + bet.expectedValue);
const odds = parseFloat(bet.bookmakerOdds[bet.betSide]);
const bankroll = 1000;

const stake = calculateKellyStake(trueProbability, odds, bankroll);
console.log(`Recommended stake: $${stake.toFixed(2)}`);

Limitations & Considerations

  • Value bets are theoretical - actual profitability depends on many factors
  • Bookmakers may limit accounts that consistently find value
  • Odds can change between viewing and placing a bet
  • Not all value bets will win (that’s the nature of probability)

Next Steps

Fetching Odds

Learn more about working with odds data

Best Practices

Optimize your API usage