Low Hold Opportunities
Find markets with the lowest vig (hold) across sportsbooks — the tightest lines available.
GET /api/v1/opportunities/low_holdThe canonical path uses an underscore. /opportunities/low-hold and /opportunities/lowhold respond with a 308 Permanent Redirect to /opportunities/low_hold.
Authentication
Requires API key. Pro tier or higher required. Your account must have the low_hold feature enabled.
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.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
sport | string | all | Filter by sport(s), comma-separated (e.g. basketball, football) |
league | string | all | Filter by league(s), comma-separated (e.g. nba, nfl, nhl) |
sportsbook | string | tier-allowed | Filter by sportsbook(s), comma-separated. Tier limits enforced. |
market | string | all | Filter by market type(s), comma-separated |
max_hold | number | 5.0 | Maximum hold percentage (vig). Lower = tighter lines. |
live | boolean | — | true = live only, false = prematch only, omit = both |
sort | string | hold | Sort field: hold (lowest first, default), market, sport |
limit | integer | 50 | Results per page (max 200) |
offset | integer | 0 | Pagination offset (max 5000) |
Filtering Multiple Values
Use comma-separated values for multi-select filters:
?sport=basketball,football&league=nba,nfl&max_hold=3Example Requests
cURL
# Low-hold moneylines under 2% vig
curl -X GET "https://api.sharpapi.io/api/v1/opportunities/low_hold?league=nba&max_hold=2&market=moneyline" \
-H "X-API-Key: YOUR_API_KEY"
# Prematch only, tightest first
curl -X GET "https://api.sharpapi.io/api/v1/opportunities/low_hold?league=mlb&live=false" \
-H "X-API-Key: YOUR_API_KEY"Response
Success (200)
Real response for GET /api/v1/opportunities/low_hold?league=mlb&limit=1 (captured 2026-07-02):
{
"data": [
{
"all_books": [
"prophetx",
"sx_bet"
],
"away_team": "Tampa Bay Rays",
"confidence": 50,
"detected_at": "2026-07-02T18:24:09Z",
"event_id": "mlb_rays_royals_2026-07-02_b3",
"event_name": "Tampa Bay Rays @ Kansas City Royals",
"hold_percentage": 0.22,
"home_team": "Kansas City Royals",
"id": "714fd29bebedf778",
"is_alternate_line": false,
"is_live": false,
"is_player_prop": false,
"league": "mlb",
"league_label": "MLB",
"line": null,
"market_label": "Moneyline",
"market_type": "moneyline",
"odds_age_seconds": 28.5,
"player_name": null,
"possibly_stale": false,
"side1": {
"books": [
"prophetx"
],
"external_event_id": "10078595",
"fair_probability": 0.4685,
"line": null,
"market_id": null,
"odds_american": 113,
"odds_decimal": 2.13,
"odds_probability": 0.4695,
"selection": "Kansas City Royals",
"selection_id": null
},
"side2": {
"books": [
"sx_bet"
],
"external_event_id": "L18646242",
"fair_probability": 0.5315,
"line": null,
"market_id": null,
"odds_american": -114,
"odds_decimal": 1.877,
"odds_probability": 0.5327,
"selection": "Tampa Bay Rays",
"selection_id": null
},
"side3": null,
"sport": "baseball",
"start_time": "2026-07-02T23:40:00Z",
"stat_category": null
}
],
"pagination": {
"count": 1,
"has_more": true,
"limit": 1,
"next_offset": 1,
"offset": 0,
"total": 66
},
"updated_at": "2026-07-02T18:24:10.961117123Z"
}Response Headers
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 296
X-RateLimit-Reset: 1707401000
X-Data-Delay: 0
X-Request-Id: 1782526326424224-82519Error Responses
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 Pro tier or higher",
"docs": "https://sharpapi.io/pricing",
"tier": "hobby",
"required_tier": "pro"
}
}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 pro tier (300/min)",
"retry_after": 1737853260000,
"tier": "pro",
"limit": 300,
"docs": "https://sharpapi.io/pricing"
}
}Response Fields
| Field | Type | Description |
|---|---|---|
id | string | Unique low-hold identifier (hash) |
event_id | string | Event identifier |
event_name | string | Human-readable event name |
sport | string | Sport identifier (lowercase) |
league | string | League identifier |
market_type | string | Market type (moneyline, point_spread, total_points, etc.) |
market_label | string | Human-readable market name |
league_label | string | Human-readable league name |
home_team | string | Home team name |
away_team | string | Away team name |
start_time | string|null | ISO 8601 event start time |
line | number|null | Spread/total line (e.g., -3.5, 220.5) |
hold_percentage | number | Market hold/vig percentage (e.g., 1.8 = 1.8%) |
side1 | object | First side of the market |
side2 | object | Second side of the market |
side3 | object|null | Third side (only for 3-way markets like soccer moneyline) |
is_live | boolean | Whether the event is currently live |
is_alternate_line | boolean | Whether this uses a non-standard line |
is_player_prop | boolean | Whether this is a player prop market |
player_name | string|null | Player name (if player prop) |
stat_category | string|null | Stat type (if player prop, e.g., points, rebounds) |
all_books | string[] | All sportsbooks participating in this market |
confidence | number | Confidence metric (0-100) |
odds_age_seconds | number | Age of the stalest odds in seconds |
possibly_stale | boolean | Whether odds data may have moved since detection |
detected_at | string | When the opportunity was detected (ISO 8601) |
Side Object
| Field | Type | Description |
|---|---|---|
selection | string | The selection name (e.g., “Lakers”, “Over”) |
books | string[] | Sportsbooks offering the best price on this side |
line | number|null | Line value for this side |
odds_american | number | American odds |
odds_decimal | number | Decimal odds |
odds_probability | number | Implied probability (0-1) |
fair_probability | number | Fair probability adjusted for hold |
selection_id | string|null | Sportsbook’s native selection/outcome ID |
market_id | string|null | Sportsbook’s native market ID |
external_event_id | string|null | Sportsbook’s native event ID |
What Is Hold?
Hold (also called vig or juice) is the sportsbook’s built-in margin on a market. It’s the difference between the combined implied probabilities and 100%.
Hold % = (implied_prob_side1 + implied_prob_side2 - 1) × 100Example
DraftKings: Lakers +145 (implied 40.8%)
Pinnacle: Celtics -155 (implied 60.8%)
Combined: 101.6%
Hold: 1.6%A 1.6% hold means the sportsbook keeps ~$1.60 of every $100 wagered on this market. Lower hold = better value for bettors.
Why Low Hold Matters
| Hold % | Quality | Typical Source |
|---|---|---|
| < 1.5% | Excellent | Sharp books, cross-book best price |
| 1.5 - 3% | Good | Competitive markets |
| 3 - 5% | Average | Standard retail pricing |
| 5%+ | Poor | Props, exotic markets |
Low-hold markets give you better odds regardless of which side you bet. Combined with +EV detection, they help maximize expected returns.
Low Hold vs Arbitrage
| Low Hold | Arbitrage | |
|---|---|---|
| Hold | Low but > 0% | Below 0% (negative hold) |
| Risk | Normal (you pick a side) | Zero (bet both sides) |
| Use case | Get the best price | Guarantee profit |
| Volume | Hundreds available | Rare (single digits) |
Low-hold opportunities are far more common than arbitrage. They represent the tightest available lines across books — ideal for bettors who want the best price without needing to bet both sides.
Three-Way Markets
For sports with three outcomes (soccer, hockey full-time result), the response includes side3:
{
"side1": { "selection": "Home Win", "..." : "..." },
"side2": { "selection": "Draw", "..." : "..." },
"side3": { "selection": "Away Win", "..." : "..." },
"hold_percentage": 2.1
}The hold calculation extends to all three sides: implied_prob_1 + implied_prob_2 + implied_prob_3 - 1.
Best Practices
- Set a tight
max_hold— Usemax_hold=2ormax_hold=3to focus on the best-value markets - Resolve bet slips separately — Low-hold rows return prices, not per-side deep links; use the Deep Links endpoint to route users to a book
- Combine with +EV data — Low hold + positive EV is the ideal combination
- Check
possibly_stale— Skip opportunities where odds may have already moved - Use streaming — Subscribe to
low_hold:detectedevents via SSE or WebSocket for real-time alerts - Monitor
all_books— More books participating generally means more reliable pricing
Related Endpoints
- +EV Opportunities — Positive expected value bets
- Arbitrage Opportunities — Guaranteed profit across books
- Middles — Line discrepancy opportunities
- Best Odds — Find the best price across all books