API Endpoints
This is the full customer-facing REST API reference for Scottfree Sports.
Production base URL:
https://sports-api.scottfreellc.com
All /api/v1/* endpoints require an API key unless explicitly marked public. The production OpenAPI schema is also available at:
https://sports-api.scottfreellc.com/openapi.json
Common Path Values
Sports:
| Code | League |
|---|---|
mlb | Major League Baseball |
nba | National Basketball Association |
nfl | National Football League |
nhl | National Hockey League |
ncaaf | NCAA Football |
ncaab | NCAA Basketball |
Model types:
| Model type | Market | Positive side | Negative side |
|---|---|---|---|
over_under | Total | Over | Under |
won_on_points | Moneyline | Home team | Away team |
won_on_spread | Spread | Home spread | Away spread |
Prediction model columns:
| Column | Meaning |
|---|---|
IMPLIED | Market-implied no-vig probability for the positive side |
AI | AI model probability, when present in the prediction artifact |
BLEND | Ensemble blend probability |
CATB | CatBoost |
RF | Random Forest |
LGB | LightGBM |
LOGR | Logistic Regression |
XGB | XGBoost |
XT | Extra Trees |
For moneyline and spread, probabilities are home-team relative. For over/under, probabilities are over-relative.
Authentication
Use the X-API-Key header:
curl -H "X-API-Key: $SFS_API_KEY" \
https://sports-api.scottfreellc.com/api/v1/sports
Bearer auth also works:
curl -H "Authorization: Bearer $SFS_API_KEY" \
https://sports-api.scottfreellc.com/api/v1/sports
Query-string auth works but is not recommended for production because keys can appear in logs:
curl "https://sports-api.scottfreellc.com/api/v1/sports?api_key=$SFS_API_KEY"
Root And Health
GET /
Unauthenticated service root. Useful only for a quick connectivity check.
curl https://sports-api.scottfreellc.com/
Response shape:
{
"message": "AlphaPy Sports API",
"version": "1.0.0",
"docs": "Contact support for documentation",
"security_scan": "disabled",
"deployment_test": "ready"
}
GET /api/v1/health
Unauthenticated health check for production monitoring. Includes dependency status for Firestore, Redis, and GCS.
curl https://sports-api.scottfreellc.com/api/v1/health
GET /api/v1/readiness
Unauthenticated readiness check used by Cloud Run.
curl https://sports-api.scottfreellc.com/api/v1/readiness
GET /api/v1/liveness
Unauthenticated liveness check used by Cloud Run.
curl https://sports-api.scottfreellc.com/api/v1/liveness
Discovery
GET /api/v1/sports
Returns supported sports and model types.
Tier: Basic and Premium.
curl -H "X-API-Key: $SFS_API_KEY" \
https://sports-api.scottfreellc.com/api/v1/sports
Response:
{
"sports": [
{"code": "mlb", "name": "Major League Baseball"},
{"code": "nba", "name": "National Basketball Association"},
{"code": "ncaab", "name": "NCAA Basketball"},
{"code": "ncaaf", "name": "NCAA Football"},
{"code": "nfl", "name": "National Football League"},
{"code": "nhl", "name": "National Hockey League"}
],
"model_types": [
{"code": "over_under", "name": "Over/Under"},
{"code": "won_on_points", "name": "Moneyline"},
{"code": "won_on_spread", "name": "Point Spread"}
]
}
Predictions
GET /api/v1/predictions/{sport}/{model_type}
Returns model probabilities and market line fields for the current slate. Games are sorted by date and ET game time.
Tier: Basic and Premium.
Query parameters:
| Name | Type | Default | Description |
|---|---|---|---|
upcoming_only | boolean | true | When true, excludes games before today's ET slate. If today's model run has not completed yet, the endpoint keeps the latest valid slate visible instead of disappearing at midnight. Set false to include the whole prediction artifact. |
Examples:
curl -H "X-API-Key: $SFS_API_KEY" \
"https://sports-api.scottfreellc.com/api/v1/predictions/mlb/won_on_points"
curl -H "X-API-Key: $SFS_API_KEY" \
"https://sports-api.scottfreellc.com/api/v1/predictions/nba/won_on_spread?upcoming_only=false"
Response shape:
{
"sport": "mlb",
"model_type": "won_on_points",
"predictions_date": "2026-05-23T14:12:05.000000",
"games": [
{
"date": "2026-05-23",
"time": "19:10:00",
"away_team": "new_york_yankees",
"home_team": "colorado_rockies",
"predictions": {
"IMPLIED": 0.3741,
"BLEND": 0.4112,
"XGB": 0.3929,
"RF": 0.4255
},
"away_money_line": -135,
"home_money_line": 115,
"open_away_money_line": -128,
"open_home_money_line": 108,
"ev_away_ml": -3.1,
"ev_home_ml": 1.8
}
],
"models_used": ["IMPLIED", "AI", "BLEND", "CATB", "RF", "LGB", "LOGR", "XGB", "XT"]
}
Market-specific fields:
| Model type | Current line fields | Opening line fields | EV fields |
|---|---|---|---|
over_under | over_under, over_line, under_line | open_over_under | ev_pos, ev_neg |
won_on_spread | away_point_spread, home_point_spread, away_point_spread_line, home_point_spread_line | open_away_point_spread, open_home_point_spread | ev_away_spread, ev_home_spread |
won_on_points | away_money_line, home_money_line | open_away_money_line, open_home_money_line | ev_away_ml, ev_home_ml |
EV fields are informational calculations from model probability and market price. They are not a validated betting selector and should not be treated as a guaranteed edge.
Public ML Predictions
GET /api/v1/public/ml-picks/{sport}/{market}
Public, unauthenticated endpoint used by the free website ML Predictions page. This is intentionally limited: it shows free model probabilities and current market line context, but it excludes account tooling, API key data, MCP/CLI, and paid app workflows.
Markets:
| Public market | Backing model type |
|---|---|
over_under | over_under |
moneyline | won_on_points |
spread | won_on_spread |
Query parameters:
| Name | Type | Default | Description |
|---|---|---|---|
upcoming_only | boolean | true | Same current-slate behavior as the authenticated predictions endpoint. |
Example:
curl "https://sports-api.scottfreellc.com/api/v1/public/ml-picks/mlb/moneyline"
Response shape:
{
"sport": "mlb",
"market": "moneyline",
"model_type": "won_on_points",
"predictions_date": "2026-05-23T14:12:05.000000",
"games": [
{
"date": "2026-05-23",
"time": "19:10:00",
"away_team": "New York Yankees",
"home_team": "Colorado Rockies",
"pick": "Colorado Rockies ML",
"pick_side": "home",
"blend_probability": 0.4112,
"confidence": 0.1776,
"market_line": "ML -135/+115",
"implied_probability": 0.3741,
"lines": {
"away_money_line": -135,
"home_money_line": 115
},
"models": {
"BLEND": 0.4112,
"XGB": 0.3929
}
}
],
"models_used": ["BLEND", "XGB", "RF", "LGB", "CATB", "LOGR", "XT"],
"note": "Free ML predictions only. App workflows, MCP/CLI tools, and account features require a paid Scottfree Sports plan."
}
Odds
GET /api/v1/odds/{sport}
Returns current game odds for a sport.
Tier: Basic and Premium.
curl -H "X-API-Key: $SFS_API_KEY" \
https://sports-api.scottfreellc.com/api/v1/odds/mlb
Response shape:
{
"sport": "mlb",
"date": "2026-05-23T16:00:00.000000",
"games": [
{
"match_id": "abc123",
"date": "2026-05-23",
"time": "19:10:00",
"away_team": "new_york_yankees",
"home_team": "colorado_rockies",
"away_point_spread": -1.5,
"away_point_spread_line": 145,
"home_point_spread": 1.5,
"home_point_spread_line": -165,
"away_money_line": -135,
"home_money_line": 115,
"over_under": 10.5,
"over_line": -110,
"under_line": -110,
"last_updated": "2026-05-23 15:55:00"
}
],
"last_updated": "2026-05-23T16:00:00.000000"
}
Results
GET /api/v1/results/{sport}/{model_type}
Returns recent graded prediction results. The response is intentionally flexible because result rows come from the generated model artifacts and can include additional columns.
Tier: Basic and Premium.
Query parameters:
| Name | Type | Default | Description |
|---|---|---|---|
limit | integer | 100 | Maximum result rows to return. |
Example:
curl -H "X-API-Key: $SFS_API_KEY" \
"https://sports-api.scottfreellc.com/api/v1/results/mlb/won_on_points?limit=25"
Response shape:
{
"sport": "mlb",
"model_type": "won_on_points",
"results": [
{
"date": "2026-05-22",
"time_est": "19:10:00",
"away_team": "new_york_yankees",
"home_team": "colorado_rockies",
"away_score": 4.0,
"home_score": 2.0,
"won_on_points": 0.0,
"BLEND": 0.4112,
"IMPLIED": 0.3741,
"open_home_money_line": 108.0,
"home_money_line": 115.0
}
],
"last_updated": "2026-05-23T14:20:00.000000"
}
GET /api/v1/results/{sport}/{model_type}/rolling
Returns precomputed 4-week rolling result curves by season for the selected sport and market. Used by the Results page visualizations.
Tier: Basic and Premium.
curl -H "X-API-Key: $SFS_API_KEY" \
https://sports-api.scottfreellc.com/api/v1/results/nfl/won_on_spread/rolling
Response includes:
| Field | Description |
|---|---|
sport | Sport code |
model_type | Model type |
seasons | Season-level rolling curves |
historical_average | Average curve across included seasons, when generated |
last_updated | Artifact timestamp |
GET /api/v1/results/{sport}/{model_type}/density
Returns precomputed result-density or distribution data for the selected sport and market. Used by Results page charts.
Tier: Basic and Premium.
curl -H "X-API-Key: $SFS_API_KEY" \
https://sports-api.scottfreellc.com/api/v1/results/nba/over_under/density
Response includes the generated chart payload and last_updated.
GET /api/v1/results/{sport}/{model_type}/team-form
Returns current-season team form from the daily-refreshed game-score tape, not from the limited live-results file.
Tier: Basic and Premium.
curl -H "X-API-Key: $SFS_API_KEY" \
https://sports-api.scottfreellc.com/api/v1/results/mlb/won_on_points/team-form
Response shape:
{
"sport": "mlb",
"model_type": "won_on_points",
"current_season": "2026",
"season_end": "2026-05-23",
"last_n": 20,
"teams": [
{
"team": "new_york_yankees",
"games": 20,
"wins": 12,
"losses": 8,
"win_pct": 0.6,
"last_10": [1, 0, 1, 1, 0, 1, 0, 1, 1, 0],
"streak": "W1"
}
],
"last_updated": "2026-05-23T16:00:00.000000"
}
Summary
GET /api/v1/summary/{sport}/{model_type}
Returns model performance summaries for the selected sport and market.
Tier: Basic and Premium.
curl -H "X-API-Key: $SFS_API_KEY" \
https://sports-api.scottfreellc.com/api/v1/summary/mlb/won_on_points
Response shape:
{
"sport": "mlb",
"model_type": "won_on_points",
"summaries": [
{
"model": "BLEND",
"total_games": 420,
"wins": 214,
"losses": 206,
"win %": 50.95,
"win % 4W": 51.8,
"fade %": 49.05,
"home %": 52.1,
"away %": 47.9,
"home % 1W": 48.5,
"away % 1W": 51.5,
"ev roi": null,
"bt bets": 0,
"bt units": null
}
],
"generated_date": "2026-05-23T14:20:00.000000"
}
Summary labels are market-relative:
| Model type | Positive label | Negative label |
|---|---|---|
over_under | over | under |
won_on_points | home | away |
won_on_spread | home | away |
Customer Account
GET /api/v1/customers/me
Returns the current customer record for the API key.
Tier: Basic and Premium. Sports Data keys can call this too, but may have api_plan: null or a zero API quota if they do not have Basic/Premium.
curl -H "X-API-Key: $SFS_API_KEY" \
https://sports-api.scottfreellc.com/api/v1/customers/me
Response shape:
{
"customer_id": "cus_abc123",
"email": "customer@example.com",
"name": "Customer Name",
"tier": "basic",
"api_plan": "basic",
"api_subscription_status": "active",
"subscription_status": "active",
"monthly_requests": 128,
"monthly_limit": 50000,
"created_at": "2026-05-20T17:11:00+00:00"
}
GET /api/v1/customers/me/usage
Returns current API quota state.
curl -H "X-API-Key: $SFS_API_KEY" \
https://sports-api.scottfreellc.com/api/v1/customers/me/usage
Response shape:
{
"monthly_requests": 128,
"monthly_limit": 50000,
"requests_remaining": 49872,
"tier": "basic",
"api_plan": "basic",
"api_subscription_status": "active",
"subscription_status": "active",
"reset_date": "2026-06-01T00:00:00+00:00"
}
GET /api/v1/customers/me/api-keys
Lists the current customer's API keys. Keys are masked in list responses.
curl -H "X-API-Key: $SFS_API_KEY" \
https://sports-api.scottfreellc.com/api/v1/customers/me/api-keys
Response shape:
[
{
"api_key": "sk_alphapysports_abcd*****",
"name": "Default Key",
"tier": "basic",
"created_at": "2026-05-20T17:11:00+00:00",
"is_active": true,
"expires_at": null
}
]
POST /api/v1/customers/me/api-keys
Creates a new API key for the current customer.
curl -X POST \
-H "X-API-Key: $SFS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Terminal"}' \
https://sports-api.scottfreellc.com/api/v1/customers/me/api-keys
Response shape:
{
"api_key": "sk_alphapysports_new_key_value",
"message": "API key created successfully",
"warning": "Store this key securely - it cannot be retrieved again"
}
PATCH /api/v1/customers/me/api-keys/rename
Renames one of the current customer's API keys. You may pass the full key or the masked value returned by GET /api/v1/customers/me/api-keys.
curl -X PATCH \
-H "X-API-Key: $SFS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"api_key_to_rename":"sk_alphapysports_abcd*****","new_name":"Production App"}' \
https://sports-api.scottfreellc.com/api/v1/customers/me/api-keys/rename
Response shape:
{
"message": "API key renamed successfully"
}
DELETE /api/v1/customers/me/api-keys/{api_key}
Revokes an API key. The API refuses to revoke the key currently being used for the request.
curl -X DELETE \
-H "X-API-Key: $SFS_API_KEY" \
https://sports-api.scottfreellc.com/api/v1/customers/me/api-keys/sk_alphapysports_abcd*****
Response shape:
{
"message": "API key revoked successfully"
}
Scottfree Sports Data
These endpoints support the separate Scottfree Sports Data subscription. Sports Data lets a customer refresh historical datasets they previously purchased from the shop. It does not by itself grant Basic/Premium API access to predictions, results, summary, CLI, or MCP.
GET /api/v1/scottfree-sports-data/status
Returns the caller's Sports Data entitlement state. This does not consume a refresh.
curl -H "X-API-Key: $SFS_API_KEY" \
https://sports-api.scottfreellc.com/api/v1/scottfree-sports-data/status
Response shape:
{
"has_scottfree_sports_data": true,
"expires_at": "2026-06-13T00:00:00+00:00",
"owned_products": ["nfl_historical"],
"owned_sports": ["nfl"],
"refreshes_used": 1,
"refreshes_remaining": 7,
"refresh_limit": 8,
"next_reset_at": "2026-06-01T00:00:00+00:00"
}
POST /api/v1/scottfree-sports-data/refresh
Generates signed download URLs for every refreshable historical dataset the customer owns. This consumes one of the customer's 8 monthly Sports Data refreshes only after all URLs are successfully generated.
curl -X POST \
-H "X-API-Key: $SFS_API_KEY" \
https://sports-api.scottfreellc.com/api/v1/scottfree-sports-data/refresh
Response shape:
{
"refreshes_remaining": 7,
"next_reset_at": "2026-06-01T00:00:00+00:00",
"downloads": [
{
"sport": "nfl",
"filename": "nfl_game_scores_1g.csv",
"url": "https://storage.googleapis.com/...",
"expires_at": "2026-05-23T16:15:00+00:00"
}
]
}
The signed URLs expire after 15 minutes.
Compatibility Pick Endpoints
These endpoints exist so older clients do not break, but no validated betting selector is active. They return explicit empty payloads.
GET /api/v1/picks/today
curl -H "X-API-Key: $SFS_API_KEY" \
https://sports-api.scottfreellc.com/api/v1/picks/today
Response:
{
"date": "2026-05-23",
"picks": [],
"summary": {"total_picks": 0, "by_sport": {}},
"note": "No validated betting selector is active."
}
GET /api/v1/picks/{date}
Same empty payload shape as /picks/today, for a supplied YYYY-MM-DD date.
GET /api/v1/picks/performance
Optional query parameters:
| Name | Values |
|---|---|
sport | MLB, NBA, NFL, NHL, NCAAF, NCAAB |
market | spread, total, moneyline |
Returns zeroed performance windows with the note No validated betting selector is active.
GET /api/v1/edge-picks
Public-compatible endpoint for edge-pick experiments. It currently returns an empty payload.
Optional query parameters:
| Name | Description |
|---|---|
sport | Accepted for compatibility; ignored while no selector is active. |
GET /api/v1/edge-picks/{date_str}
Same empty edge-picks payload for a supplied date.
GET /api/v1/edge-picks/track-record
Returns an empty track record while no selector is active.
Errors
The API error handler returns this shape:
{
"error": "HTTP_401",
"detail": "Invalid or expired API key",
"timestamp": "2026-05-23T16:00:00.000000"
}
Common statuses:
| Status | Meaning |
|---|---|
400 | Invalid request or invalid parameter |
401 | Missing, invalid, expired, or revoked API key |
403 | Valid key, but the plan does not allow that operation |
404 | Data artifact not available for that sport/model/date |
429 | Per-second or monthly quota exceeded |
500 | Server error |
503 | Dependency temporarily unavailable |
Sports Docs