Positive EV API: odds vs fair prices

Positive EV API data: every book’s price next to the no-vig fair line from the market consensus or a sharp book like Pinnacle, ranked by edge.

A positive EV API compares every price with the fair probability once the margin is removed. PreciseAPI returns every book’s price through /v1/odds for you to de-vig, and the find_outliers MCP tool ranks the prices that beat the no-vig consensus or a sharp book like Pinnacle by edge.

A positive EV API answers one question for every price on the board: does this price pay more than the fair probability says it should? PreciseAPI has no /v1/ev endpoint. It gives you every book's price on every market through /v1/odds, so you can remove the margin and compare, and it has an MCP tool, find_outliers, that does the comparison for you: each price against the no-vig market consensus or a sharp book such as Pinnacle, ranked by edge. This page covers the formula, the reference line, the requests and code, and what the numbers can and can't tell you.

How expected value is calculated

Every positive EV API rests on one formula. Expected value per unit staked is:

EV = fair probability × decimal price − 1

The decimal price is what the book offers. The fair probability is your best estimate of how often the bet wins, and for data work that usually means the market's own estimate with the bookmaker's margin taken out. A positive result means the price pays more than the fair probability implies; a negative one means you pay the margin.

A worked example. Pinnacle prices a game at −150 on the favorite and +135 on the underdog. The implied probabilities are 60.00% and 42.55%, which add up to 102.55%. Dividing each by the total (multiplicative de-vig) gives fair probabilities of 58.51% and 41.49%, so the fair price on the underdog is about +141. If another book offers the underdog at +150 (decimal 2.50), EV = 0.4149 × 2.50 − 1 = +3.7%. The EV calculator and the no vig calculator run these steps on any prices you enter.

Choosing the fair line: consensus or a sharp book

The fair probability is only as good as the market it comes from. There are two common choices, and the MCP tool supports both.

A sharp book. Pinnacle, Circa and BookMaker carry the sharp tag in our catalog: books that take large bets from professionals and move quickly. In that sense PreciseAPI works as a sharp odds API, with those books' prices in the same shape as every other source. De-vig the sharp book's market and use it as the reference. The Pinnacle odds API page and why Pinnacle odds matter explain why it is the usual choice.

The consensus. De-vig every book's market at the same line, take the median fair probability for each side, and rescale so the sides add up to 100%. A median isn't pulled around by one stale or mispriced book. Keep in mind that books sharing a trading platform, such as BetOnline, SportsBetting, MyBookie, BUSR and BetNow, often post identical prices and each counts separately.

Either way, compare identical lines only. A spread of −3.5 at one book and −4 at another are different bets, and a fair price for one says nothing exact about the other.

Positive EV API data from /v1/odds

/v1/odds returns every source's markets for a league, grouped by book, with the same event and outcome ids everywhere. One call costs 2 credits and covers up to 200 events of game lines; requests that include player props are served 25 events at a time. Ask for format=decimal and the prices are ready for the EV formula, or format=probability for implied probabilities with the margin still in.

curl "https://api.preciseapi.com/v1/odds?league=nba&markets=main&format=decimal" \
  -H "Authorization: Bearer $PRECISEAPI_KEY"

One event, cut down to two books and one market:

{
  "id": "evt_1iazqk4srnb",
  "league": "nba",
  "status": "scheduled",
  "home": { "id": "nba_phx", "name": "Phoenix Suns", "abbr": "PHX" },
  "away": { "id": "nba_sas", "name": "San Antonio Spurs", "abbr": "SAS" },
  "bookmakers": [
    {
      "id": "pinnacle", "name": "Pinnacle", "type": "sportsbook",
      "markets": [{ "id": "mkt_1dougx7qnw5", "key": "moneyline", "period": "full_game",
        "outcomes": [
          { "id": "sel_2d3ja0zugwd", "name": "Phoenix Suns", "side": "home", "price": 1.667 },
          { "id": "sel_1pojklgy6cc", "name": "San Antonio Spurs", "side": "away", "price": 2.35 }
        ], "suspended": false, "updated_at": "2026-11-11T18:01:52.310Z" }]
    },
    {
      "id": "draftkings", "name": "DraftKings", "type": "sportsbook",
      "markets": [{ "id": "mkt_14r1od1l1vw", "key": "moneyline", "period": "full_game",
        "outcomes": [
          { "id": "sel_2d3ja0zugwd", "name": "Phoenix Suns", "side": "home", "price": 1.571 },
          { "id": "sel_1pojklgy6cc", "name": "San Antonio Spurs", "side": "away", "price": 2.5 }
        ], "suspended": false, "updated_at": "2026-11-11T18:01:47.902Z" }]
    }
  ]
}

Computing positive EV in Python

This script groups each book's prices by market and line, builds the fair line from the consensus or from one reference book, and prints every price with an edge of 2% or more:

import os
import statistics
from collections import defaultdict

import requests

REFERENCE = None  # None = consensus of every book, or a book id such as "pinnacle"
MIN_BOOKS, MIN_EDGE = 5, 0.02

resp = requests.get(
    "https://api.preciseapi.com/v1/odds",
    params={"league": "nba", "markets": "main", "format": "decimal"},
    headers={"Authorization": f"Bearer {os.environ['PRECISEAPI_KEY']}"},
    timeout=15,
)
resp.raise_for_status()

def devig(decimals):
    implied = [1 / d for d in decimals]
    return [p / sum(implied) for p in implied]

for event in resp.json()["data"]:
    groups = defaultdict(dict)  # (key, period, line) -> {book: {side: price}}
    for book in event["bookmakers"]:
        for m in book["markets"]:
            prices = {o["side"]: o["price"] for o in m["outcomes"] if o.get("price")}
            groups[(m["key"], m["period"], m.get("line"))][book["id"]] = prices
    for (key, period, line), quotes in groups.items():
        sides = sorted({s for q in quotes.values() for s in q})
        quotes = {b: q for b, q in quotes.items() if set(q) == set(sides)}
        if len(sides) < 2 or len(quotes) < MIN_BOOKS:
            continue
        fair = {b: dict(zip(sides, devig([q[s] for s in sides]))) for b, q in quotes.items()}
        if REFERENCE:
            if REFERENCE not in fair:
                continue
            ref = fair[REFERENCE]
        else:
            med = {s: statistics.median(f[s] for f in fair.values()) for s in sides}
            ref = {s: med[s] / sum(med.values()) for s in sides}
        for b, q in quotes.items():
            for s in sides:
                ev = ref[s] * q[s] - 1
                if b != REFERENCE and ev >= MIN_EDGE:
                    print(event["id"], key, line, s, b, q[s], f"fair {1 / ref[s]:.3f}", f"EV {ev:+.1%}")

find_outliers: an odds outliers API over MCP

The PreciseAPI MCP server, which works in Claude, ChatGPT, Cursor and other AI clients, has the same scan built in. find_outliers takes a league and checks its upcoming games, up to 60 per call or 25 player prop boards, for prices that beat the fair line by at least min_edge_pct (1% by default). The edge is computed exactly as above: fair probability × decimal price − 1, with the fair line from multiplicative de-vig.

The reference argument is consensus (the default: the median of every book's no-vig price at the same line) or a book id such as pinnacle or circa. books flags only the books you can bet at, while every book still counts toward the consensus. min_books sets how many books must quote a line before it is judged, 5 by default and 3 for props. Each call costs 3 credits.

{
  "reference": "Pinnacle no-vig",
  "markets_scanned": 96,
  "outliers": [
    {
      "event_id": "evt_1iazqk4srnb",
      "game": "San Antonio Spurs @ Phoenix Suns",
      "starts": "Wed, Nov 11, 9:00 PM EST",
      "market": "Moneyline",
      "bet": "San Antonio Spurs",
      "book": "DraftKings",
      "price": "+150",
      "fair_price": "+141",
      "fair_probability_pct": 41.5,
      "edge_pct": 3.73,
      "books_compared": 24
    }
  ]
}

The server also offers a ready-made "Value scan" prompt that runs this tool and flags anything that looks like a stale line. The odds API MCP guide covers setup.

Building an odds API for EV tools

Most positive EV screens built on a positive EV API refresh pre-game boards on a timer. On Edge a /v1/odds call for one league costs 2 credits, and Edge's 150,000 monthly credits go a long way for a few leagues; Sharp and Syndicate have unlimited credits. In-play odds and the WebSocket stream, which pushes only the markets that changed, are on Syndicate.

A plus EV odds API for player props

Props are where soft prices last longest, and they work the same way: an over and an under at the same line, de-vigged per book. Request them from /v1/props (3 credits) or pass markets=props to find_outliers. Leave out one-sided milestone props and DFS pick'em lines, since neither has a two-way cash price to de-vig. The player props API page covers the shape.

What an outlier does and doesn't mean

A price that beats the fair line is an observation, not a conclusion:

Verify every price on the book's site before acting. PreciseAPI is a data provider: no picks, no betting advice, no promise of profit.

Plans and credit costs

EdgeSharpSyndicate
Price$49.99 / month$199.99 / month$249.99 / month
Credits150,000 / monthUnlimitedUnlimited
/v1/odds (2 credits), /v1/props (3)Pre-gamePre-gamePre-game and in-play
find_outliers over MCP (3 credits)Pre-gamePre-gamePre-game and in-play
Rate limit300 / minute1,200 / minute3,000 / minute

The free Sandbox has 50 credits for the dashboard chat but no API or MCP access, so the positive EV API workflow starts on Edge. See odds API pricing.

Frequently asked questions

Does PreciseAPI have an EV endpoint?

No. There is no /v1/ev REST endpoint, and REST prices are each book's posted prices with the margin left in. You compute EV from /v1/odds, or call the find_outliers MCP tool, which de-vigs the market and ranks prices by edge for you.

Is PreciseAPI an EV betting API with picks?

No. It is an EV betting API only in the sense that it delivers the prices and, over MCP, the edge calculation. It gives no picks, places no bets and makes no recommendations.

Which reference should I use for fair odds?

find_outliers supports the consensus of every book and any single book, and the sharp books Pinnacle, Circa and BookMaker are the usual single references. Many tools check both: a price that beats the sharp book and the consensus is less likely to be noise.

Can I scan live games for positive EV?

Only on Syndicate, which includes in-play odds. On Edge and Sharp, /v1/odds and find_outliers cover games that haven't started.

Where the fair price comes from

Expected value compares a book’s price with a fair probability, and the fair probability comes from de-vigging a market. Use a sharp book such as Pinnacle, Circa or BookMaker, or the consensus: the median no-vig probability across every book quoting the identical line. /v1/odds returns every book’s price in one call for 2 credits, with format=decimal or format=probability, so the de-vig and the EV formula run in a few lines of your own code.

Outliers over MCP

In Claude, ChatGPT or Cursor, find_outliers scans a league’s upcoming games, de-vigs every market quoted by at least five books (three for props), and lists the prices that beat the fair line by your minimum edge, 1% by default. Choose the consensus or a reference book, and flag only the books you can bet at. Each call costs 3 credits. An outlier is often a book that hasn’t moved yet, so verify the price before acting; PreciseAPI gives no picks.

Example request

GET /v1/odds?league=nba&markets=main&format=decimal

Endpoint

What teams build with it

Related reading

More products

Responses use the same event, market and outcome ids as every other endpoint. Prices are American odds by default, with format=decimal and format=probability for the other two, and a market whose source has stopped reporting is flagged suspended instead of being shown as live.

Every source and league is on the coverage page, and what each request costs is on the pricing page.