Skip to main content
Value Bets require a Pro plan or higher.

GET /api/value-bets

Returns betting opportunities detected in the last 30 minutes where a bookmaker’s implied probability is lower than Pinnacle’s devigged fair probability — i.e., the bookmaker is offering higher-than-fair odds. All results have already passed the quality filters described below. No stale or suspicious bets are returned.

How EV Is Calculated

# 1. Sum Pinnacle implied probabilities → raw TRJ (their margin)
TRJ = 1/pinnacle_odds_home + 1/pinnacle_odds_draw + 1/pinnacle_odds_away

# 2. Devig: remove Pinnacle's margin to get fair price
fair_odds = (N × pinnacle_odds) / (N − pinnacle_odds × (1/TRJ − 1))
# N = 2 for two-way markets, N = 3 for three-way (football 1X2)

# 3. Apply safety floor (prevents noise at edge of threshold)
fair_odds_final = fair_odds × 1.01          # all markets
fair_odds_final = fair_odds × 1.01 × 1.03  # player props only

# 4. Compute edge
EV% = (bookmaker_odds / fair_odds_final − 1) × 100
Devigging removes Pinnacle’s margin to produce the true consensus probability. Requires all Pinnacle sides — a single-side devig produces unreliable fair odds. Why some 2–3% EV bets don’t appear: The fair-odds floor means bookmakers need roughly +2% raw edge (standard markets) or +5% raw edge (player props) over devigged Pinnacle before a bet passes EV ≥ 1%.
See the EV Math Guide for full step-by-step worked examples of implied probability, devigging, fair odds, EV%, and payout rate.

Quality Filters Applied Before Response

All returned bets have passed every gate — nothing stale or suspicious is returned:
FilterThresholdReason
EV ≥ 1%Minimum edgeSub-1% is noise; line movement eliminates it before placement
EV ≤ 20%Maximum edgeAbove this = stale or miscoded odds, not real edge
EV ≤ 10% (moneyline / spread)Efficient market capThese markets don’t produce 10%+ edges legitimately
payout_rate ∈ [99%, 105%]Quality gateCombines bookmaker price with raw opposite Pinnacle odds — must form a near-100% market
Raw Pinnacle TRJ ≤ 1.05Structural sanityAbove 1.05 = duplicate sides or arbitrage data
Bookmaker odds freshness≤ 15 minutes oldRejects stale prices
Both Pinnacle sides presentRequiredPrevents single-side devig errors
Odds ratio≤ 1.15× fair priceRejects structural mismatches

Query Parameters

ParameterTypeDefaultDescription
sportstringFilter by sport name (e.g. Football, Basketball)
competitionstringFilter by competition code (e.g. EPL, NBA)
bookmakerstringFilter by bookmaker name
min_evfloat1.0Minimum EV % (e.g. 2.5 for 2.5%+ edge only)
max_evfloat20.0Maximum EV % guard cap (don’t raise above 20)
limitinteger100Max results, up to 500

Response

{
  "data": [
    {
      "match_name": "Cleveland Cavaliers / Toronto Raptors",
      "selection": "RJ Barrett Rebounds Under 4.5",
      "bookmaker": "Unibet.fr",
      "market_type": "player_prop",
      "period": 0,
      "odds": 2.12,
      "pinnacle_odds": 1.70,
      "fair_odds": 1.883,
      "ev_pct": 12.59,
      "payout_rate": 1.018,
      "liquidity": 750.0,
      "competition": "NBA",
      "sport": "Basketball",
      "detected_at": "2026-04-20T13:51:28Z",
      "match_date": "2026-04-20T23:00:00Z"
    },
    {
      "match_name": "PSG - Lyon",
      "selection": "Over 2.5",
      "bookmaker": "Betsson",
      "market_type": "total",
      "period": 0,
      "odds": 2.10,
      "pinnacle_odds": 2.05,
      "fair_odds": 1.98,
      "ev_pct": 5.8,
      "payout_rate": 1.018,
      "liquidity": 4500.0,
      "competition": "LIG1",
      "sport": "Football",
      "detected_at": "2026-04-20T14:30:00Z",
      "match_date": "2026-04-20T20:00:00Z"
    }
  ],
  "meta": {
    "count": 12,
    "rate_limit_remaining": 294
  }
}

Response Fields

FieldTypeDescription
match_namestringEvent name
selectionstringThe specific outcome (e.g. "Over 2.5", "PSG", "R. Barrett Rebounds Under 4.5")
bookmakerstringBookmaker offering the +EV odds
market_typestringMarket type
periodintegerTime period (0=full time, 1=first half)
oddsfloatBookmaker’s current decimal odds for this selection
pinnacle_oddsfloatPinnacle’s raw quoted odds for the same selection
fair_oddsfloatDevigged fair-value price — the true market consensus
ev_pctfloatExpected value as a percentage (e.g. 5.8 = +5.8% edge over fair price)
payout_ratefloatPinnacle TRJ (Total Return on Juice). Value near 1.0 = very sharp line, e.g. 1.018 = 1.8% juice
liquidityfloat | nullPinnacle’s maximum bet size for this line — proxy for market confidence
competitionstringCompetition code
sportstringSport
detected_atISO-8601 stringWhen this opportunity was detected
match_dateISO-8601 string | nullScheduled kick-off time (UTC)

Key Fields Explained

fair_odds — This is the critical reference price. It’s the implied price after removing Pinnacle’s margin. A bookmaker offering odds > fair_odds means their market underestimates the true probability for this outcome. ev_pct — Direct measure of edge. A 5% EV bet means you expect to profit 5forevery5 for every 100 wagered, long-run. Only bets with EV between min_ev and 20% are returned. payout_rate — Pinnacle’s TRJ: the sum of implied probabilities across all outcomes. A value of 1.018 means Pinnacle takes 1.8% margin. The closer to 1.0, the sharper the line. Bets are only shown when Pinnacle’s TRJ is between 0.99 and 1.05 (very sharp market). liquidity — Pinnacle’s max bet size. Higher values indicate more confidence in the line. A 4500maxbetonanEPLmoneylineisareliablereference;a4500 max bet on an EPL moneyline is a reliable reference; a 200 max bet on a niche prop may be less reliable.

Code Examples

# Football value bets with EV > 2%
curl "https://api.oddsstream.io/api/value-bets?sport=Football&min_ev=2" \
  -H "X-Api-Key: os_live_YOUR_KEY"

# High-EV basketball props from Unibet
curl "https://api.oddsstream.io/api/value-bets?sport=Basketball&bookmaker=Unibet.fr&min_ev=5" \
  -H "X-Api-Key: os_live_YOUR_KEY"
import requests

resp = requests.get(
    "https://api.oddsstream.io/api/value-bets",
    params={"sport": "Football", "min_ev": 2.0, "limit": 50},
    headers={"X-Api-Key": "os_live_YOUR_KEY"}
)
for bet in resp.json()["data"]:
    print(
        f"{bet['match_name']} | {bet['selection']} @ {bet['odds']} "
        f"({bet['ev_pct']:.1f}% EV) via {bet['bookmaker']}"
    )
const resp = await fetch(
  "https://api.oddsstream.io/api/value-bets?sport=Football&min_ev=2",
  { headers: { "X-Api-Key": "os_live_YOUR_KEY" } }
);
const { data: bets, meta } = await resp.json();
console.log(`${meta.count} value bets found`);

for (const bet of bets) {
  const edge = bet.ev_pct.toFixed(1);
  console.log(`${bet.match_name}${bet.selection}: ${bet.odds} (+${edge}% EV) @ ${bet.bookmaker}`);
}
Always verify the current price on the bookmaker’s site before placing a bet. Odds can move significantly between detection and placement. A bet with +5% EV at detection time may be 0% or negative if the line has moved.

EV Math Guide

Full step-by-step walkthrough of implied probability, devigging, fair odds, EV%, and payout rate with worked examples.

Best Practices

Freshness checks, retry patterns, and production tips.