Skip to Content
API ReferenceArbitrage

Arbitrage Opportunities

Find guaranteed-profit arbitrage opportunities across sportsbooks.

GET /api/v1/opportunities/arbitrage

AuthenticationPermalink for this section

Requires API key. Hobby tier or higher required. Your account must have the arbitrage feature enabled.

Query ParametersPermalink for this section

ParameterTypeDefaultDescription
sportstringallFilter by sport(s), comma-separated (e.g. basketball, football)
leaguestringallFilter by league(s), comma-separated (e.g. nba, nfl, nhl)
sportsbookstringtier-allowedFilter by sportsbook(s), comma-separated. Tier limits enforced.
marketstringallFilter by market type(s), comma-separated. Supports category aliases — see Odds: Market Category Aliases.
min_profitnumber0.5Minimum profit percentage (e.g. 1.0 = 1%)
livebooleantrue = live only, false = prematch only, omit = both
statestringpaUS state code appended as ?state= to each leg’s deep_link resolver URL (e.g. pa, nj, co, mi)
limitinteger50Results per page (max 200)
offsetinteger0Pagination offset (max 5000)

Profit cap: Opportunities with profit above 10% are automatically filtered out. These are almost always phantom arbs caused by stale or suspended odds rather than real opportunities.

Breaking change: The game_state field (score/period/clock) was removed from this response. Live game state is now served exclusively by the Game State endpoint and the gamestate stream channel. Join rows to game state by event_id.

Filtering Multiple ValuesPermalink for this section

Use comma-separated values for multi-select filters:

?sport=basketball,football&league=nba,nfl

Example RequestsPermalink for this section

curl -X GET "https://api.sharpapi.io/api/v1/opportunities/arbitrage?league=nba&min_profit=1" \ -H "X-API-Key: YOUR_API_KEY"

ResponsePermalink for this section

Success (200)Permalink for this section

Real response for GET /api/v1/opportunities/arbitrage?limit=1 (live soccer, captured 2026-07-02). Note deep_link is null on legs with no resolver link (e.g. exchanges) and carries the ?state= suffix (default pa) otherwise:

{ "data": [ { "detected_at": "2026-07-02T18:24:11.629938125Z", "estimated_net_profit_percent": 9.51, "ev_available": false, "ev_percentage": null, "event_id": "iceland_-_urvalsdeild_krreykjavik_thorakureyri_2026-07-02_b2", "event_name": "KR Reykjavik @ Thor Akureyri", "id": "d66158994938bfb8", "implied_total": 91.15, "is_alternate_line": false, "is_live": true, "is_player_prop": false, "league": "iceland_-_urvalsdeild", "league_label": "Iceland - Urvalsdeild", "legs": [ { "deep_link": null, "external_event_id": "20260704F0815C7E", "line": 0.75, "market_id": "asian_handicap", "odds_american": 143, "odds_decimal": 2.43, "odds_id": "105606613889332", "odds_probability": 0.4115, "selection": "KR Reykjavik", "selection_id": "19851-27567-2026-07-02:betfair_exchange:asian_handicap:kr_reykjavik_+0_75", "sportsbook": "betfair", "stake_percent": 45.15 }, { "deep_link": "https://api.sharpapi.io/api/v1/deeplink/146200835628306?state=pa", "external_event_id": "34333512", "line": -0.75, "market_id": "2_85317286", "odds_american": 100, "odds_decimal": 2, "odds_id": "146200835628306", "odds_probability": 0.5, "selection": "Thor Akureyri", "selection_id": "0HC85317286P75_1", "sportsbook": "draftkings", "stake_percent": 54.85 } ], "line": 0.75, "market_label": "Asian Handicap", "market_type": "asian_handicap", "oldest_odds_age_seconds": 29.013184226, "player_name": null, "possibly_stale": false, "profit_percent": 9.71, "sport": "soccer", "start_time": "2026-07-02T17:00:00Z", "stat_category": null, "warnings": [ "LIVE_HIGH_PROFIT_SUSPICIOUS", "LIVE_GAME" ] } ], "pagination": { "count": 1, "has_more": true, "limit": 1, "next_offset": 1, "offset": 0, "total": 71 }, "updated_at": "2026-07-02T18:24:11.672298584Z" }

Response HeadersPermalink for this section

X-RateLimit-Limit: 300 X-RateLimit-Remaining: 297 X-RateLimit-Reset: 1707401000 X-Data-Delay: 0 X-Request-Id: 1782526326424224-82519

Error ResponsesPermalink for this section

401 Unauthorized

No key supplied returns missing_api_key; a bad key returns invalid_api_key.

{ "error": { "code": "missing_api_key", "message": "API key required. Pass via X-API-Key header, api_key query parameter, or Bearer token.", "docs": "https://sharpapi.io/docs/authentication" } }

403 Tier Restricted

{ "error": { "code": "tier_restricted", "message": "This endpoint requires Hobby tier or higher", "docs": "https://sharpapi.io/pricing", "tier": "free", "required_tier": "hobby" } }

429 Rate Limited

retry_after is a Unix-millisecond timestamp of the next window (not a duration); the Retry-After header carries the equivalent seconds value.

{ "error": { "code": "rate_limited", "message": "Rate limit exceeded for hobby tier (120/min)", "retry_after": 1737853260000, "tier": "hobby", "limit": 120, "docs": "https://sharpapi.io/pricing" } }

Response FieldsPermalink for this section

FieldTypeDescription
idstringUnique arbitrage identifier (hash)
event_idstringEvent identifier
event_namestringHuman-readable event name
sportstringSport identifier (lowercase)
leaguestringLeague identifier
market_typestringMarket type (moneyline, point_spread, total_points, etc.)
linenumber|nullSpread/total line (e.g., -3.5)
profit_percentnumberGuaranteed profit as a percentage (e.g., 1.83 = 1.83%)
estimated_net_profit_percentnumberProfit % after estimated bet-placement friction (rounding/limits)
league_labelstringHuman-readable league name
market_labelstringHuman-readable market name
implied_totalnumberSum of implied probabilities across all legs (below 100 = arb exists)
is_livebooleanWhether the event is currently live
start_timestring|nullISO 8601 event start time
is_alternate_linebooleanWhether this uses a non-standard line
possibly_stalebooleanWhether odds may have moved since detection
oldest_odds_age_secondsnumber|nullAge of the stalest leg’s odds in seconds
warningsstring[]Warning flags. Possible values: LIVE_GAME (any leg live), LIVE_HIGH_PROFIT_SUSPICIOUS (live and profit > 3%), HIGH_PROFIT_SUSPICIOUS (prematch and profit > 5%), LIVE_STALE_ODDS (live, stale leg), POTENTIALLY_STALE_ODDS / VERY_STALE_ODDS (prematch staleness tiers). LOW_IMPLIED_TOTAL (2-leg arb with implied total below 96% — verify the prices before betting) is Reserved — not currently emitted on this endpoint.
ev_availablebooleanWhether an EV opportunity exists on this market
ev_percentagenumber|nullEV percentage if available
is_player_propbooleanWhether this is a player prop market
player_namestring|nullPlayer name (if player prop)
stat_categorystring|nullStat type (if player prop, e.g., points, rebounds)
legsarrayArray of bet legs that form the arbitrage
detected_atstringISO 8601 timestamp when the arb was first detected

Leg ObjectPermalink for this section

FieldTypeDescription
sportsbookstringSportsbook for this leg
selectionstringThe selection (team name, Over/Under, etc.)
odds_americannumberAmerican odds for this leg
odds_decimalnumberDecimal odds for this leg
odds_probabilitynumberImplied probability of this leg’s odds (0.0 to 1.0)
linenumber|nullSpread/total line for this leg
stake_percentnumberPercentage of total stake to place on this leg
odds_idstringUnderlying odds row ID (joins back to /odds)
deep_linkstring|nullResolver URL to this leg’s bet slip (pass state= for state subdomains). The key is always present — explicit null when no resolver link exists for the leg.
external_event_idstring|nullSportsbook’s native event ID
selection_idstring|nullSportsbook’s selection/outcome ID
market_idstring|nullSportsbook’s market ID
homeobject|undefinedReserved — not currently emitted on this endpoint. Nested home-team reference: {id, numerical_id, name, abbreviation, logo, city, mascot, conference, division}. See Entity reference IDs.
awayobject|undefinedReserved — not currently emitted on this endpoint. Nested away-team reference (same shape as home).
sport_refobject|undefinedReserved — not currently emitted on this endpoint. Nested sport reference: {id, numerical_id, name}.
league_refobject|undefinedReserved — not currently emitted on this endpoint. Nested league reference: {id, numerical_id, label}.
market_refobject|undefinedReserved — not currently emitted on this endpoint. Nested market reference: {id, numerical_id, label}.
sportsbook_refobject|undefinedReserved — not currently emitted on this endpoint. Nested sportsbook reference for this leg’s book: {id, numerical_id, label}.

Nested reference blocks on each leg (reserved)Permalink for this section

The leg schema reserves six nested reference objects (home, away, sport_ref, league_ref, market_ref, sportsbook_ref) mirroring the blocks on /odds. As of 2026-07-02 the arbitrage engine does not stamp them, so live legs never include these blocks — today they appear only on /odds rows for atlas-mapped books. Treat every block (and every inner field) as optional and never require them; when emitted they will be purely additive — the flat top-level fields (sport, league, market_type) and per-leg sportsbook / selection strings are unchanged. See Entity reference IDs for the shape and guarantees.

How Arbitrage WorksPermalink for this section

Arbitrage exploits price differences between sportsbooks to guarantee a profit regardless of the outcome. When the combined implied probabilities across all legs of a market total less than 100%, an arbitrage opportunity exists.

The Core PrinciplePermalink for this section

Book A: Team X +150 (implied 40.0%) Book B: Team Y -130 (implied 56.5%) Total implied: 96.5% < 100% = ARBITRAGE

When the total is below 100%, you can bet proportionally on every outcome and guarantee a profit.

Profit CalculationPermalink for this section

Profit % = (100 / implied_total) - 100

Using the example above:

Profit % = (100 / 96.5) - 100 = 3.63%

This means for every $1,000 wagered, you are guaranteed approximately $36.30 in profit.

Calculating Optimal StakesPermalink for this section

To guarantee equal returns regardless of outcome, allocate stakes proportionally:

// Decimal odds: Team X = 2.50, Team Y = 1.77 const impliedX = 1 / 2.50; // 0.400 const impliedY = 1 / 1.77; // 0.565 const total = impliedX + impliedY; // 0.965 const stakeX = impliedX / total; // 41.5% of bankroll const stakeY = impliedY / total; // 58.5% of bankroll

Full Stake ExamplePermalink for this section

Total bankroll for this arb: $1,000

LegStakeOddsPayout if Wins
Team X @ DraftKings$415+150$1,037.50
Team Y @ Pinnacle$585-130$1,035.00

Guaranteed profit: ~$35-38 (3.5-3.8%) regardless of outcome.

Three-Way ArbitragePermalink for this section

Sports like soccer and hockey have three-way markets (home/draw/away), which can also produce arbitrage:

Home Win: +200 (33.3%) Draw: +250 (28.6%) Away Win: +180 (35.7%) Total implied: 97.6% -> 2.4% arbitrage profit

The same stake calculation applies — divide each leg’s implied probability by the total to determine the stake allocation.

Why Arbs ExistPermalink for this section

  1. Timing differences - Sportsbooks update odds at different speeds
  2. Differing opinions - Books have different risk models and exposure
  3. Promotions - Boosted odds from one book create artificial gaps
  4. Errors - Occasionally, a book posts incorrect odds

Best PracticesPermalink for this section

Account Risk: Sportsbooks actively monitor for arbitrage activity. Accounts that exclusively place arb bets may be limited or restricted. Consider mixing arbitrage bets with recreational activity.

  1. Act fast - Arb windows are often short-lived (seconds to minutes)
  2. Round your stakes - A bet of $47.32 looks suspicious; round to $50
  3. Use pre-calculated stakes - The stake_percent field gives you optimal allocation
  4. Verify odds before placing - Always confirm the odds at the sportsbook have not moved
  5. Start with larger arbs - Focus on min_profit=1 or higher to account for line movement
  6. Track the implied_total - Lower totals mean larger guaranteed profits
  7. Diversify sportsbooks - Spreading activity across many books reduces individual account risk

Arb vs +EV BettingPermalink for this section

AspectArbitrage+EV Betting
RiskZero (guaranteed profit)Variance exists
Profit per bet1-3% typical2-10% edge
Account riskHigh (limits likely)Lower
Capital requiredHigh (bet both sides)Lower
SustainabilityLimited by account healthLong-term viable

Many experienced bettors prefer +EV betting over arbitrage because accounts last longer and the expected edges are often larger. See the +EV Opportunities endpoint for details.

Last updated on