If you build betting models, run a +EV or arbitrage tool, or just track closing-line value, you already know the one line everyone benchmarks against: Pinnacle. Lowest margins, highest limits, no winner bans — its price is the closest thing the industry has to a "true price."
The catch: in July 2025 Pinnacle shut down its public API, restricting access to "select high-value bettors and commercial partnerships." A lot of tooling broke overnight. Here's a practical, keyless way to still pull Pinnacle's lines in Python — and, more importantly, turn them into the number you actually bet on: the no-vig fair price.
The demo: a live Pinnacle line, de-vigged
Pulled a few minutes ago — Pinnacle's moneyline on a Champions League qualifier:
Thun vs Dinamo Zagreb (h2h) — overround 7.1%:
| Outcome | Pinnacle price | Implied % | No-vig fair % | Fair odds |
|---|---|---|---|---|
| Thun (home) | 3.45 | 29.0% | 27.1% | 3.70 |
| Draw | 3.68 | 27.2% | 25.4% | 3.94 |
| Dinamo (away) | 1.96 | 51.0% | 47.6% | 2.10 |
The raw prices bake in Pinnacle's ~7% margin. Strip it out and Dinamo's fair price is 2.10, not 1.96 — that de-vigged number is what you compare every other book against to find +EV. The math is tiny:
prices = {"home": 3.45, "draw": 3.68, "away": 1.96}
implied = {k: 1/v for k, v in prices.items()}
overround = sum(implied.values()) # 1.071 -> 7.1% vig
fair_prob = {k: v/overround for k, v in implied.items()}
fair_odds = {k: 1/p for k, p in fair_prob.items()} # away -> 2.10
Do that across every book and the gaps are your edge. The hard part was never the math — it's getting Pinnacle's price reliably.
Pulling the odds
Pinnacle Odds Scraper does the fetch, keyless (no login, no API key). Minimal input:
{
"mode": "pre_match_and_live",
"sports": ["soccer", "tennis"],
"markets": ["h2h", "spreads", "totals"]
}
You get one normalized row per outcome — homeTeam, awayTeam, league, marketType, outcomeLabel, price, commenceTime, isLive — for pre-match and in-play. Add "specials" for Pinnacle's 5,000+ per-sport markets (futures, exact-totals, first-to-score, team props) — the depth most odds feeds don't carry. Pay-per-use: $0.01 per pre-match snapshot, $0.02 live, $0.04 for the specials tier — no $249/mo subscription, you pay for what you poll.
Honest note: The Odds API also carries Pinnacle's main markets from $30/mo if you want a fixed-quota REST API — this actor's edge is the specials depth, the built-in no-vig/CLV derivation, and per-use pricing.
Why it's a recurring job, not a one-off
Two numbers matter to a serious bettor, and both need repeated pulls:
- The line when you bet — odds move every few seconds; you snapshot at decision time.
- The closing line — the single best predictor of long-run edge. Capturing CLV means pulling the price again right before kickoff, every event you track.
So the natural setup is a schedule: point it at your leagues, run it every minute pre-match and near-continuously toward kickoff, and log the series. Turn on delta mode + an Apify Schedule and each run only returns what changed — a gap-free odds history you pay for only when the line actually moves.
Sports don't have an off-season
Soccer, tennis, basketball, MMA, baseball — something sharp is priced year-round, so a Pinnacle feed is about as evergreen as alt-data gets. If you're building anything that needs a true-price benchmark, this is the input.
Ready-to-clone presets (closing-line EV, live in-play, specials/futures) are on the Actor's examples tab. Questions or a market you need? Open an issue on the Actor page.
Top comments (0)