Documentación API

URL base: https://zenhodl.net

ZenHodl Weekly

Mantente al día con los resultados en vivo y los cambios del API.

Un correo semanal con resultados en vivo, una idea del modelo y novedades del producto.

Útil si te importan las pruebas, los endpoints y lo que cambió.

Inicio rápido

Obtén tu primera señal con edge en 30 segundos. Para contexto sobre los modelos y la metodología, lee nuestra research paper. research paper.

1
Obtén tu API key

Crea una cuenta gratis en /signup (sin tarjeta), o elige un plan de pago en /pricing.

2
Obtén edges en vivo
curl -H "X-API-Key: sk_live_YOUR_KEY" https://zenhodl.net/v1/edges
3
Usa el edge

Cada señal te dice: la probabilidad justa del modelo, el precio ask del mercado y la diferencia (edge) entre ambos.

// Signal: NCAAMB, Purdue (away), fair_wp=0.74, market_ask=0.63, edge=+11c
// Action: BUY Purdue at 63c. Model says it's worth 74c. Hold to settlement.
Python quickstart
import requests

resp = requests.get(
    "https://zenhodl.net/v1/edges",
    headers={"X-API-Key": "sk_live_YOUR_KEY"},
    params={"min_edge": 8}
)
for signal in resp.json()["signals"]:
    print(f"{signal['sport']} {signal['team']}: "
          f"fair={signal['fair_wp']:.0%} ask={signal['market_ask']:.0%} "
          f"edge=+{signal['edge']*100:.1f}c ({signal['confidence']})")

¿Qué endpoint debería usar?

I want the smallest live feed of tradable signals

Use /v1/edges. This is the fastest first integration for alerting, bots, and scanners.

I want the full live board with score, clock, and market state

Use /v1/games. This is the best endpoint for dashboards and game-level monitoring.

I want richer per-sport prediction objects

Use /v1/predict/{sport}/live or /v1/predict/{sport}/pregame. These are the cleanest prediction endpoints for model consumers.

I want push instead of polling

Use /v1/ws/stream for browser/app clients, or /v1/webhooks for server-to-server delivery.

I want saved personal automation

Use /v1/watchlists and /v1/preferences to save filters and alert settings tied to a user account.

Key Concepts

Fair Win Probability (fair_wp)

Our ML model's estimate of the true probability a team wins, based on score, time, Elo, and sport-specific features. Ranges from 0.0 to 1.0. Independent from market prices — this is what makes edge detection possible.

Market Ask (market_ask)

The current Polymarket ask price for the contract. This is what you'd pay to buy. Ranges from 0.0 to 1.0 (equivalent to 0c to 100c).

Edge

edge = fair_wp - market_ask. When positive, the model thinks the contract is underpriced. An edge of 0.11 means the model sees an 11-cent probability gap before fees and slippage. Not the same as expected profit — actual profit depends on execution costs (~2-3c) and model accuracy. Our default minimum threshold is 8c.

Settlement

Prediction market contracts resolve to $1.00 (win) or $0.00 (lose) after the game ends. Buy at 63c, win = +37c profit. Buy at 63c, lose = -63c. The edge is your statistical advantage over many trades.

Authentication

All authenticated endpoints require an API key. Pass it via the X-API-Key header:

Security Note

Always pass your API key via the X-API-Key header, not in URL parameters. URL parameters appear in browser history, server logs, and referrer headers.

# curl
curl -H "X-API-Key: sk_live_your_key_here" https://zenhodl.net/v1/games
# Python
import requests
headers = {"X-API-Key": "sk_live_your_key_here"}
games = requests.get("https://zenhodl.net/v1/games", headers=headers).json()
// JavaScript (fetch)
const resp = await fetch("https://zenhodl.net/v1/games", {
  headers: { "X-API-Key": "sk_live_your_key_here" }
});
const data = await resp.json();

Get your API key at /signup (free tier) or /pricing (paid plans). Keys start with sk_live_. Keep it secret — treat it like a password.

Rate Limits

Rate limits are per-minute. Every response includes these headers:

X-RateLimit-Limit: 300
X-RateLimit-Remaining: 297
X-RateLimit-Tier: pro
Tier Requests/min Monthly Cap WebSocket Sports Delay
Free 10500-All 75 min
Starter ($49) 6010,0001All 7Real-time
Pro ($149) 300100,0005All 7Real-time
Enterprise (Custom) 1,000Unlimited20All 7Real-time

Monthly usage is metered on authenticated REST endpoints. /v1/usage is excluded so you can always inspect your own usage without consuming quota. WebSocket connection limits are enforced separately from monthly REST usage.

Errors

All errors return JSON with a detail field:

{"detail": "Rate limit exceeded (300 req/min for pro tier)."}
CodeMeaningExample
401Missing or invalid API key"Invalid or inactive API key."
402Payment required"Payment not completed."
403Tier too low / dashboard-only key"Your plan includes dashboard access only."
404Resource not found"No predictions for 20260101."
429Rate limit exceeded"Rate limit exceeded (60 req/min for starter tier)."

GET /v1/health

System health check. No authentication required. Use this to verify the API is running and check how many games are active.

curl https://zenhodl.net/v1/health

Response:

{
  "status": "ok",
  "uptime_seconds": 3600.5,
  "active_games": 12,
  "sports_loaded": ["NBA", "NCAAMB", "NCAAWB", "CFB", "NFL", "NHL", "MLB"],
  "last_espn_poll": "2026-03-22T19:30:00Z",
  "last_ws_update": "2026-03-22T19:30:01Z"
}
FieldDescription
statusok, starting, or degraded
active_gamesNumber of live games being tracked right now
sports_loadedWhich sport models are loaded and active
last_espn_pollLast time ESPN scores were fetched (UTC)

GET /v1/games

All live games with ML fair win probabilities and market prices. This is the primary endpoint for getting a full view of every tracked game.

ParamTypeDescription
sportstringFilter by sport (NBA, NCAAMB, NCAAWB, CFB, NFL, NHL, MLB). Optional.
venuestringFilter venue_prices to a specific venue (polymarket, kalshi, draftkings, fanduel, betmgm). Optional.
curl -H "X-API-Key: sk_live_..." "https://zenhodl.net/v1/games?sport=NBA&venue=polymarket"
import requests

games = requests.get(
    "https://zenhodl.net/v1/games",
    headers={"X-API-Key": "sk_live_..."},
    params={"sport": "NBA"}
).json()

for g in games["games"]:
    edge = (g["home_fair_wp"] - (g["home_market_ask"] or 0)) * 100
    print(f"{g['event_title']} | {g['time_display']} | edge: {edge:+.1f}c")

Response:

{
  "timestamp": "2026-03-22T19:30:00Z",
  "count": 5,
  "games": [{
    "sport": "NBA",
    "game_id": "401810889",
    "event_title": "Knicks vs. Wizards",
    "home_team": "NY", "away_team": "WSH",
    "home_score": 78, "away_score": 65,
    "period": 3, "seconds_remaining": 420.0,
    "time_display": "Q3 7:00",
    "status": "live",
    "home_fair_wp": 0.82,
    "away_fair_wp": 0.18,
    "home_market_ask": 0.75,
    "away_market_ask": 0.27,
    "home_edge": 0.07,
    "away_edge": -0.09,
    "model_confidence": "high",
    "is_score_change": false,
    "last_updated": "2026-03-22T19:29:55Z"
  }]
}

Response fields

home_fair_wpModel's fair probability for home team (0.0–1.0)
home_market_askCurrent Polymarket ask price (0.0–1.0). null if no market match
home_edgefair_wp - market_ask. Positive = underpriced. 0.07 = 7 cents edge
model_confidencehigh (edge >12c), medium (6–12c), low (<6c)
is_score_changetrue if a score change happened in the last 30 seconds (prices may lag)
statuslive, scheduled, final
seconds_remainingTotal seconds left in regulation (e.g. 420 = 7 minutes)

GET /v1/edges

Current edge signals — only games where the model disagrees with the market by at least min_edge. This is the "actionable trades" endpoint.

ParamTypeDescription
sportstringFilter by sport. Optional.
min_edgefloatMinimum edge in cents. Default: 8.0
venuestringFilter by venue (polymarket, kalshi, draftkings, etc.). Optional.
curl -H "X-API-Key: sk_live_..." "https://zenhodl.net/v1/edges?sport=NCAAMB&min_edge=10"
edges = requests.get(
    "https://zenhodl.net/v1/edges",
    headers={"X-API-Key": "sk_live_..."},
    params={"sport": "NCAAMB", "min_edge": 10}
).json()

for s in edges["signals"]:
    print(f"BUY {s['team']} @ {s['market_ask']:.0%} "
          f"(fair: {s['fair_wp']:.0%}, edge: +{s['edge']*100:.1f}c)")

Response:

{
  "timestamp": "2026-03-22T19:30:00Z",
  "count": 1,
  "min_edge": 0.10,
  "signals": [{
    "sport": "NCAAMB",
    "game_id": "401810889",
    "event_title": "Purdue vs. Illinois",
    "team": "Purdue",
    "side": "away",
    "fair_wp": 0.74,
    "market_ask": 0.63,
    "edge": 0.11,
    "period": 2,
    "seconds_remaining": 480.0,
    "score": "52-44",
    "confidence": "high",
    "is_score_change": false,
    "timestamp": "2026-03-22T19:29:55Z"
  }]
}

Response fields

teamTeam name the signal is for
sidehome or away
fair_wpModel's fair probability (0.0–1.0)
market_askPolymarket ask price (0.0–1.0)
edgefair_wp − market_ask. 0.11 = 11-cent probability gap (before fees/slippage)
confidencehigh (≥12c), medium (6–12c), low (<6c)

GET /v1/sports

Available sports and model metadata. Useful for discovering what models are loaded and their backtest performance.

curl -H "X-API-Key: sk_live_..." https://zenhodl.net/v1/sports

Response:

{
  "sports": [{
    "sport": "NCAAMB",
    "model_type": "xgb_isotonic",
    "train_games": 15230,
    "elo_teams": 362,
    "features": ["score_diff", "seconds_remaining", "period",
                 "time_fraction", "elo_diff", "pregame_wp"],
    "backtest_wr": 0.738,
    "backtest_c_per_trade": 12.0
  }]
}

GET /v1/predictions/latest

Download today's pre-game fair probability predictions as CSV. Also available by date: /v1/predictions/{YYYYMMDD}

# Today's predictions
curl -H "X-API-Key: sk_live_..." https://zenhodl.net/v1/predictions/latest -o predictions.csv

# Specific date
curl -H "X-API-Key: sk_live_..." https://zenhodl.net/v1/predictions/20260322 -o predictions.csv

Sample CSV row:

sport,game_id,home_team,away_team,start_time,home_fair_wp,away_fair_wp,elo_diff,model_pick,confidence
NCAAMB,401810889,Illinois,Purdue,2026-03-22T19:00:00Z,0.426,0.574,-92,Purdue,high

CSV files include a license header with your email and download token. See data license.

POST /v1/backtest

Pro tier and above

Run a WP model backtest with custom strategy parameters against our 25M+ row dataset. Test different edge thresholds, periods, and fee assumptions.

FieldTypeDefaultDescription
sportstringNBASport to backtest (NBA, NCAAMB, CFB, NFL, etc.)
min_edge_cfloat8.0Minimum edge in cents to enter a trade
max_edge_cfloat50.0Maximum edge (filter out suspicious outliers)
min_fair_wp_cfloat65.0Only trade if model confidence ≥ this
max_entry_cfloat78.0Don't buy above this price
min_entry_cfloat35.0Don't buy below this price
min_periodint2Earliest game period to enter
max_per_gameint3Max entries per game (both sides combined)
seasonslistallFilter by season, e.g. ["2024-25"]
taker_fee_cfloat2.0Platform taker fee per trade (cents)
slippage_cfloat1.0Expected slippage per trade (cents)
curl -X POST -H "X-API-Key: sk_live_..." -H "Content-Type: application/json" \
  -d '{"sport":"NCAAMB","min_edge_c":10,"min_period":2,"seasons":["2025-26"]}' \
  https://zenhodl.net/v1/backtest
result = requests.post(
    "https://zenhodl.net/v1/backtest",
    headers={"X-API-Key": "sk_live_..."},
    json={"sport": "NCAAMB", "min_edge_c": 10, "min_period": 2}
).json()

s = result["summary"]
print(f"{s['total_trades']} trades, {s['win_rate']:.1%} WR, "
      f"+{s['c_per_trade_net']:.1f}c/trade net")

Response:

{
  "summary": {
    "total_trades": 854,
    "wins": 630,
    "losses": 224,
    "win_rate": 0.738,
    "gross_pnl_c": 12024.0,
    "net_pnl_c": 10280.0,
    "avg_edge_c": 11.8,
    "c_per_trade_net": 12.0,
    "max_drawdown_c": 340.0,
    "best_streak": 18,
    "worst_streak": 5
  },
  "by_edge": [
    {"bucket": "8-10c", "trades": 412, "win_rate": 0.71, "c_per_trade": 9.8},
    {"bucket": "10-12c", "trades": 198, "win_rate": 0.76, "c_per_trade": 14.2},
    {"bucket": "12-15c", "trades": 144, "win_rate": 0.79, "c_per_trade": 16.5}
  ],
  "by_period": [
    {"period": 1, "trades": 320, "win_rate": 0.72, "c_per_trade": 10.1},
    {"period": 2, "trades": 534, "win_rate": 0.75, "c_per_trade": 13.2}
  ],
  "sample_trades": [{"game_id": "...", "side": "away", "edge_c": 11.1, "entry_c": 63.0, "profit_c": 37.0, "won": true}]
}

GET /v1/backtest/sports

List available sports and seasons for backtesting.

curl -H "X-API-Key: sk_live_..." https://zenhodl.net/v1/backtest/sports

Response:

{
  "sports": {
    "NCAAMB": {"seasons": ["2023-24", "2024-25", "2025-26"], "files": 3, "model_available": true},
    "NBA": {"seasons": ["2023-24", "2024-25", "2025-26"], "files": 3, "model_available": true},
    "CFB": {"seasons": ["2023", "2024"], "files": 2, "model_available": true}
  }
}

WS /v1/ws/stream

Real-time WebSocket stream. Updates every 5 seconds via WebSocket push.

URL: wss://zenhodl.net/v1/ws/stream
Push interval: 5 seconds
Auth: session cookie or WebSocket subprotocol
Connection limits: Per tier (1/5/20)
const API_KEY = "sk_live_your_key_here";
const ws = new WebSocket(
  "wss://zenhodl.net/v1/ws/stream",
  ["zenhodl.v1", API_KEY]
);

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);

  if (msg.type === "edge_alert") {
    const d = msg.data;
    console.log(`EDGE: ${d.sport} ${d.team} | `
      + `fair=${d.fair_wp}c ask=${d.market_ask}c edge=+${d.edge}c`);
  }

  if (msg.type === "game_update") {
    const d = msg.data;
    console.log(`${d.event_title} ${d.time_display} | `
      + `fair=${d.home_fair_wp} ask=${d.home_market_ask}`);
  }
};

ws.onclose = () => setTimeout(() => location.reload(), 5000); // auto-reconnect
import asyncio, websockets, json

API_KEY = "sk_live_your_key_here"

async def stream():
    uri = "wss://zenhodl.net/v1/ws/stream"
    async with websockets.connect(uri, subprotocols=["zenhodl.v1", API_KEY]) as ws:
        async for raw in ws:
            msg = json.loads(raw)
            if msg["type"] == "edge_alert":
                d = msg["data"]
                print(f"EDGE: {d['sport']} {d['team']} "
                      f"fair={d['fair_wp']}c ask={d['market_ask']}c "
                      f"edge=+{d['edge']}c ({d['confidence']})")

asyncio.run(stream())

Message types

game_update Sent for every live game on each tick
{"type": "game_update", "data": {
  "sport": "NBA", "game_id": "401810889", "event_title": "Knicks vs. Wizards",
  "home_team": "NY", "away_team": "WSH", "home_score": 78, "away_score": 65,
  "period": 3, "time_display": "Q3 7:00",
  "home_fair_wp": 0.82, "away_fair_wp": 0.18,
  "home_market_ask": 0.75, "away_market_ask": 0.27,
  "home_edge": 0.07, "away_edge": -0.09
}}
edge_alert Sent when edge exceeds threshold
{"type": "edge_alert", "data": {
  "sport": "NCAAMB", "team": "Purdue", "side": "away",
  "fair_wp": 74.1, "market_ask": 63.0, "edge": 11.1,
  "score": "52-44", "confidence": "high"
}}

GET /v1/predict/{sport}/live

All live games with win probabilities and multi-venue edges. Returns fair ML odds and per-venue pricing from Polymarket, Kalshi, and major sportsbooks.

curl -H "X-API-Key: sk_live_..." "https://zenhodl.net/v1/predict/NBA/live"
import requests

resp = requests.get(
    "https://zenhodl.net/v1/predict/NBA/live",
    headers={"X-API-Key": "sk_live_..."}
).json()

for g in resp["games"]:
    print(f"{g['home_team']} vs {g['away_team']}: "
          f"P(home)={g['home_win_prob']:.0%} ML={g['fair_home_ml']}")
    for venue, v in (g.get("venues") or {}).items():
        if v.get("home_edge") and v["home_edge"] > 0.05:
            print(f"  +EV at {venue}: edge={v['home_edge']:.1%}")
const resp = await fetch("https://zenhodl.net/v1/predict/NBA/live", {
  headers: { "X-API-Key": "sk_live_..." }
});
const { games } = await resp.json();
games.forEach(g => console.log(`${g.home_team} ${g.fair_home_ml} | ${g.away_team} ${g.fair_away_ml}`));

Response:

{
  "timestamp": "2026-03-28T22:00:00Z",
  "sport": "NBA",
  "count": 5,
  "games": [{
    "game_id": "401585432",
    "sport": "NBA",
    "home_team": "LAL", "away_team": "BOS",
    "home_score": 78, "away_score": 75,
    "period": 3, "clock": "Q3 8:42",
    "home_win_prob": 0.72,
    "away_win_prob": 0.28,
    "model_confidence": "high",
    "fair_home_ml": -257,
    "fair_away_ml": 215,
    "venues": {
      "Polymarket": {"home_ask": 0.62, "home_edge": 0.10},
      "Kalshi": {"home_ask": 0.63, "home_edge": 0.09},
      "DraftKings": {"home_ml": "-150", "home_implied": 0.60, "home_edge": 0.12},
      "FanDuel": {"home_ml": "-165", "home_implied": 0.623, "home_edge": 0.097}
    },
    "best_home_venue": "DraftKings"
  }]
}

GET /v1/predict/{sport}/pregame

Today's upcoming games with Elo-based pregame win probabilities. No live game state needed — uses Elo ratings only.

curl -H "X-API-Key: sk_live_..." "https://zenhodl.net/v1/predict/NBA/pregame"

Response:

{
  "sport": "NBA", "count": 8,
  "games": [{
    "game_id": "401810900",
    "home_team": "LAL", "away_team": "BOS",
    "home_win_prob": 0.42, "away_win_prob": 0.58,
    "fair_home_ml": 138, "fair_away_ml": -138,
    "status": "scheduled"
  }]
}

GET /v1/predict/{sport}/{game_id}

Single game detail with full model output, multi-venue edges, and game state.

curl -H "X-API-Key: sk_live_..." "https://zenhodl.net/v1/predict/NBA/401585432"

GET /v1/fair-lines/{sport}

Fair moneyline odds in American format for all live games. Designed for integration into odds comparison tools.

curl -H "X-API-Key: sk_live_..." "https://zenhodl.net/v1/fair-lines/NBA"

Response:

{
  "sport": "NBA", "count": 5,
  "lines": [{
    "game_id": "401585432",
    "home_team": "LAL", "away_team": "BOS",
    "home_win_prob": 0.72, "away_win_prob": 0.28,
    "fair_home_ml": -257, "fair_away_ml": 215,
    "clock": "Q3 8:42", "status": "live"
  }]
}

GET /v1/usage

Your current month's API usage. Track request counts against your monthly cap.

curl -H "X-API-Key: sk_live_..." "https://zenhodl.net/v1/usage"

Response:

{
  "month": "2026-03",
  "requests_used": 4521,
  "requests_cap": 10000,
  "by_endpoint": {
    "/v1/predict/NBA/live": 3200,
    "/v1/predict/NHL/live": 821,
    "/v1/fair-lines/NBA": 500
  },
  "tier": "starter",
  "resets_at": "2026-04-01T00:00:00+00:00"
}
Tier Monthly Cap Price
Free500$0
Starter10,000$49/mo
Pro100,000$149/mo
EnterpriseUnlimitedCustom

Model Quality & Analytics

Endpoints for evaluating model quality, tracking closing line value (CLV), and monitoring data venues.

GET /v1/model/performance

Model quality metrics for all trained sports: Brier score, ROC-AUC, ECE (calibration error), accuracy, and full uncertainty/conformal prediction tables.

ParamTypeDescription
sportstringFilter to a single sport. Optional.
curl -H "X-API-Key: sk_live_..." "https://zenhodl.net/v1/model/performance?sport=NBA"
{
  "sports": [{
    "sport": "NBA",
    "brier_score": 0.139,
    "roc_auc": 0.890,
    "ece": 0.106,
    "accuracy": 0.803,
    "model_type": "Split-Phase",
    "trained_date": "2026-03-24T15:52:54Z",
    "n_test_games": 90,
    "conformal_table": [{"tf_lo": 0.0, "tf_hi": 0.1, "width": 0.029, "n_samples": 35672}, ...]
  }]
}

GET /v1/model/clv

Live Closing Line Value tracking. CLV measures how often the model's entry price beats the final market price — the gold standard for edge validation. Starter+ tier.

ParamTypeDescription
sportstringFilter by sport. Optional.
daysintLookback window in days. Default: 7
curl -H "X-API-Key: sk_live_..." "https://zenhodl.net/v1/model/clv?sport=NBA&days=30"
{
  "total_signals": 142,
  "avg_clv_c": 3.8,
  "clv_beat_pct": 61.2,
  "by_sport": [{"sport": "NBA", "count": 42, "avg_clv_c": 4.1, "beat_pct": 64.3}],
  "by_edge_bucket": [{"bucket": "8-12c", "count": 85, "avg_clv_c": 2.1, "beat_pct": 55.3}]
}

GET /v1/venues

List all connected data venues with real-time status. Shows which exchanges and sportsbooks are currently providing price data.

curl -H "X-API-Key: sk_live_..." "https://zenhodl.net/v1/venues"
{
  "venues": [
    {"venue": "polymarket", "status": "connected", "connection_type": "websocket", "markets_active": 7770},
    {"venue": "kalshi", "status": "connected", "connection_type": "websocket"},
    {"venue": "draftkings", "status": "polling", "connection_type": "rest_polling"}
  ]
}

GET /v1/snapshots/{sport}/{date}

Intraday win probability snapshots archived every 30 seconds during live games. Use for backtesting entry timing, studying momentum, or building custom models. Pro+ tier.

ParamTypeDescription
sportpathSport code (NBA, NHL, etc.)
datepathDate in YYYYMMDD format
curl -H "X-API-Key: sk_live_..." "https://zenhodl.net/v1/snapshots/NBA/20260330"

GET /v1/predictions/batch

Bulk download predictions for a date range as CSV. Max 90 days per request. Pro+ tier.

ParamTypeDescription
startstringStart date (YYYYMMDD). Required.
endstringEnd date (YYYYMMDD). Required.
sportstringFilter by sport. Optional.
curl -H "X-API-Key: sk_live_..." "https://zenhodl.net/v1/predictions/batch?start=20260301&end=20260330&sport=NBA" -o batch.csv

Webhooks

Push notifications when edge signals are detected. Register a URL and receive a signed POST request in real-time — no polling needed. Starter+ tier.

POST /v1/webhooks

Register a new webhook. Limits: Starter=1, Pro=3, Enterprise=10.

curl -X POST -H "X-API-Key: sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"url": "https://your-server.com/hook", "filters": {"sport": "NBA", "min_edge_c": 10}}' \
  "https://zenhodl.net/v1/webhooks"

Each webhook POST includes an X-Webhook-Signature header (HMAC-SHA256) for verification.

GET /v1/webhooks

List your active webhooks.

curl -H "X-API-Key: sk_live_..." "https://zenhodl.net/v1/webhooks"

DELETE /v1/webhooks/{webhook_id}

Deactivate a webhook.

curl -X DELETE -H "X-API-Key: sk_live_..." "https://zenhodl.net/v1/webhooks/abc123"

Watchlists & Preferences

Store user-specific game lists and notification settings. These endpoints are useful when you want durable scanner filters or alert automation tied to an account.

GET /v1/watchlists

List the current user's saved watchlists.

curl -H "X-API-Key: sk_live_..." "https://zenhodl.net/v1/watchlists"

POST /v1/watchlists

Create a saved watchlist with your own filters and thresholds.

curl -X POST -H "X-API-Key: sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"name": "High Edge NBA", "sports": ["NBA"], "teams": [], "min_edge_c": 10, "max_entry_c": 78}' \
  "https://zenhodl.net/v1/watchlists"

GET /v1/preferences

Read the user's alert and notification preferences.

curl -H "X-API-Key: sk_live_..." "https://zenhodl.net/v1/preferences"

PUT /v1/preferences

Update user notification settings for dashboard alerts and watchlists.

curl -X PUT -H "X-API-Key: sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"daily_summary": true, "weekly_summary": true, "alert_threshold_c": 9, "favorite_sports": ["NBA", "NHL"], "timezone": "America/New_York"}' \
  "https://zenhodl.net/v1/preferences"

Confidence Intervals

All prediction endpoints now include confidence_interval — calibrated prediction bands from conformal prediction tables. Use these to assess uncertainty and size positions appropriately.

{
  "home_fair_wp": 0.72,
  "confidence_interval": {
    "lower": 0.68,
    "upper": 0.76,
    "width": 0.08
  }
}

Width narrows as games progress (more data = more certainty). Early game: 10-15c width. Late game: 3-5c width.

Free Samples

Two public sample endpoints — no API key needed. Signed-in free accounts get broader delayed access on the authenticated API.

GET /v1/predictions/sample.csv

Download a CSV with live edge signals + resolved trade examples showing actual P&L (wins and losses).

curl https://zenhodl.net/v1/predictions/sample.csv -o sample.csv

GET /v1/edges/sample

Top 3 edge signals as JSON from the public sample feed. Delayed 15 minutes, NBA + NHL only. Create a free account for the live dashboard plus delayed /v1/games and /v1/edges access across all 7 sports.

curl https://zenhodl.net/v1/edges/sample
{
  "count": 2,
  "delay_minutes": 15,
  "note": "Delayed 15 min. Upgrade for real-time across 7 sports.",
  "signals": [
    {"sport": "NBA", "team": "NY", "edge": 11.2, "fair_wp": 78.5, "confidence": "high"},
    {"sport": "NHL", "team": "BOS", "edge": 9.1, "fair_wp": 71.3, "confidence": "medium"}
  ]
}

Ready to get started?

Get your API key and start receiving real-time edge signals.