BALLDONTLIE Lab API

v1.0.0

Build, backtest, and deploy betting models programmatically. The Lab API gives you access to pre-built analytical factors, model creation, historical backtesting, and prediction generation across multiple sports.

Quick Start

  1. Create an account at lab-app.balldontlie.io
  2. Upgrade to PRO or ALL-ACCESS (free tiers cannot access the API)
  3. Grab your API key from your account settings

Authentication

All endpoints require authentication via API key in the Authorization header:

bash
curl "https://api.balldontlie.io/lab/v1/factors" \
  -H "Authorization: YOUR_API_KEY"

Rate Limits

LimitValue
Requests per minute100

Rate limit headers are included in every response:

HeaderDescription
X-RateLimit-LimitMaximum requests per minute
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix timestamp when the limit resets

Supported Sports

SportCodeStatus
NBAnbaAvailable
NFLnflAvailable
NHLnhlAvailable
MLBmlbAvailable

Subscription Tiers

TierBacktest HistoryModelsAPI Access
ALL-ACCESS6 yearsUnlimitedFull
LAB PRO6 yearsUnlimitedFull

Subscribe at lab-app.balldontlie.io to get started.

Base URL

https://api.balldontlie.io
GET/lab/v1/factors

List all factors

Returns all available factors for building prediction models.

Factors are pre-built analytical components that can be combined to create models.

Parameters

categorystringquery

Filter by factor category (team_performance, matchup, situational, player, market)

sportSportquery

Filter by sport (default nba)

Responses

200List of factors
dataFactor[]
Example Response
{
  "data": [
    {
      "id": 1,
      "slug": "string",
      "name": "string",
      "description": "string",
      "category": "string"
    }
  ]
}
Error Responses
400Invalid parameters

Example Request

cURL
curl -X GET "https://api.balldontlie.io/lab/v1/factors" \
  -H "Authorization: YOUR_API_KEY"
GET/lab/v1/factors/{id}

Get a factor

Returns details of a specific factor.

Parameters

idintegerpathrequired

Factor ID

Responses

200Factor details
dataFactor
Example Response
{
  "data": {
    "id": 1,
    "slug": "string",
    "name": "string",
    "description": "string",
    "category": "string"
  }
}
Error Responses
400Invalid factor ID
404Factor not found

Example Request

cURL
curl -X GET "https://api.balldontlie.io/lab/v1/factors/{id}" \
  -H "Authorization: YOUR_API_KEY"
GET/lab/v1/models

List user's models

Returns all models owned by the authenticated user.

Parameters

sportstringquery

Filter by sport

bet_typestringquery

Filter by bet type

per_pageintegerquery

Number of results per page

cursorintegerquery

Cursor for pagination

Responses

200List of models
dataModel[]
metaCursorPagination
Example Response
{
  "data": [
    null
  ],
  "meta": {
    "next_cursor": 1,
    "prev_cursor": 1,
    "per_page": 1
  }
}
Error Responses
400Invalid parameters

Example Request

cURL
curl -X GET "https://api.balldontlie.io/lab/v1/models" \
  -H "Authorization: YOUR_API_KEY"
POST/lab/v1/models

Create a model

Creates a new prediction model.

For weighted mode, factor weights must sum to 100.

Request Body

namestringrequired

Model name

descriptionstring

Model description

sportSport

Supported sports

nbanhlnflmlb
bet_typeBetTyperequired

Type of bet the model predicts

spreadmoneylineover_underplayer_prop
prop_typestring

Specific prop type (for player_prop bet_type)

modeModelModerequired

Model calculation mode: - simple: Assign importance (Low/Medium/High) to each factor - weighted: Assign precise weights that must sum to 100%

simpleweighted
factorsModelFactorInput[]required

Factors to include in the model

Example Request
{
  "name": "string",
  "description": "string",
  "sport": "nba",
  "bet_type": "spread",
  "prop_type": "string"
}

Responses

201Model created
dataModel
Example Response
{
  "data": null
}
Error Responses
400Invalid request body or weights don't sum to 100

Example Request

cURL
curl -X POST "https://api.balldontlie.io/lab/v1/models" \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "string",
  "description": "string",
  "sport": "nba",
  "bet_type": "spread",
  "prop_type": "string"
}'
GET/lab/v1/models/{id}

Get a model

Returns details of a specific model owned by the user.

Parameters

idintegerpathrequired

Model ID

Responses

200Model details
dataModel
Example Response
{
  "data": null
}
Error Responses
400Invalid model ID
404Model not found

Example Request

cURL
curl -X GET "https://api.balldontlie.io/lab/v1/models/{id}" \
  -H "Authorization: YOUR_API_KEY"
PUT/lab/v1/models/{id}

Update a model

Updates an existing model.

For weighted mode, factor weights must sum to 100.

Note: Editing factors, mode, bet_type, or advanced_config clears any existing performance data.

Parameters

idintegerpathrequired

Model ID

Request Body

namestring

Model name

descriptionstring

Model description

bet_typeBetType

Type of bet the model predicts

spreadmoneylineover_underplayer_prop
prop_typestring

Specific prop type (for player_prop bet_type)

modeModelMode

Model calculation mode: - simple: Assign importance (Low/Medium/High) to each factor - weighted: Assign precise weights that must sum to 100%

simpleweighted
factorsModelFactorInput[]

Factors to include in the model

Example Request
{
  "name": "string",
  "description": "string",
  "bet_type": "spread",
  "prop_type": "string",
  "mode": "simple"
}

Responses

200Model updated
dataModel
Example Response
{
  "data": null
}
Error Responses
400Invalid request body or weights don't sum to 100
404Model not found

Example Request

cURL
curl -X PUT "https://api.balldontlie.io/lab/v1/models/{id}" \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "string",
  "description": "string",
  "bet_type": "spread",
  "prop_type": "string",
  "mode": "simple"
}'
DELETE/lab/v1/models/{id}

Delete a model

Deletes a model and all associated data (predictions, performance, jobs).

Parameters

idintegerpathrequired

Model ID

Responses

204Model deleted
Error Responses
400Invalid model ID
404Model not found

Example Request

cURL
curl -X DELETE "https://api.balldontlie.io/lab/v1/models/{id}" \
  -H "Authorization: YOUR_API_KEY"
GET/lab/v1/predictions

List predictions for a model

Returns predictions for a specific model with game details.

Parameters

model_idintegerqueryrequired

Model ID (required)

resultstringquery

Filter by result (win, loss, push)

start_datestringquery

Filter by start date (ISO8601)

end_datestringquery

Filter by end date (ISO8601)

per_pageintegerquery

Number of results per page

cursorintegerquery

Cursor for pagination

Responses

200List of predictions with game details
dataPredictionWithGame[]
metaCursorPagination
Example Response
{
  "data": [
    null
  ],
  "meta": {
    "next_cursor": 1,
    "prev_cursor": 1,
    "per_page": 1
  }
}
Error Responses
400Invalid parameters
404Model not found

Example Request

cURL
curl -X GET "https://api.balldontlie.io/lab/v1/predictions" \
  -H "Authorization: YOUR_API_KEY"
GET/lab/v1/predictions/stats

Get prediction statistics

Returns aggregate statistics for a model's predictions.

Parameters

model_idintegerqueryrequired

Model ID (required)

Responses

200Prediction statistics
dataPredictionStats
Example Response
{
  "data": {
    "total": 1,
    "wins": 1,
    "losses": 1,
    "pushes": 1,
    "win_rate": 0.5
  }
}
Error Responses
400Invalid parameters
404Model not found

Example Request

cURL
curl -X GET "https://api.balldontlie.io/lab/v1/predictions/stats" \
  -H "Authorization: YOUR_API_KEY"
GET/lab/v1/predictions/{id}

Get a prediction

Returns details of a specific prediction.

Parameters

idintegerpathrequired

Prediction ID

Responses

200Prediction details
dataPrediction
Example Response
{
  "data": {
    "id": 1,
    "model_id": 1,
    "game_id": 1,
    "predicted_value": 0.5,
    "confidence": 0.5
  }
}
Error Responses
400Invalid prediction ID
404Prediction not found

Example Request

cURL
curl -X GET "https://api.balldontlie.io/lab/v1/predictions/{id}" \
  -H "Authorization: YOUR_API_KEY"
POST/lab/v1/models/{id}/predictions/generate

Generate predictions

Creates a background job to generate predictions for upcoming games.

Poll the job endpoint to get results.

Note: Only one prediction generation job can run per model at a time. If a pending

or running job already exists, a 409 Conflict is returned.

Parameters

idintegerpathrequired

Model ID

Responses

201Job created
dataJob
Example Response
{
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "model_id": 1,
    "job_type": "preview",
    "status": "pending",
    "output": null
  }
}
Error Responses
400Invalid model ID
404Model not found
409Prediction generation already running

Example Request

cURL
curl -X POST "https://api.balldontlie.io/lab/v1/models/{id}/predictions/generate" \
  -H "Authorization: YOUR_API_KEY"
POST/lab/v1/performance/preview

Create preview job

Creates a background job to preview model performance without saving.

Returns historical performance and predictions for upcoming games.

Poll the job endpoint to get results.

Request Body

bet_typeBetTyperequired

Type of bet the model predicts

spreadmoneylineover_underplayer_prop
modeModelModerequired

Model calculation mode: - simple: Assign importance (Low/Medium/High) to each factor - weighted: Assign precise weights that must sum to 100%

simpleweighted
sportSport

Supported sports

nbanhlnflmlb
advanced_configAdvancedConfig
factorsPreviewFactorInput[]required

Factors for the preview

start_seasonstring

Start season (format "YYYY-YY", e.g., "2023-24")

end_seasonstring

End season (format "YYYY-YY", e.g., "2024-25")

Example Request
{
  "bet_type": "spread",
  "mode": "simple",
  "sport": "nba",
  "advanced_config": null,
  "factors": [
    {
      "factor_id": 1,
      "importance": "low",
      "weight": 0,
      "parameters": {}
    }
  ]
}

Responses

201Preview job created
dataJob
Example Response
{
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "model_id": 1,
    "job_type": "preview",
    "status": "pending",
    "output": null
  }
}
Error Responses
400Invalid request body

Example Request

cURL
curl -X POST "https://api.balldontlie.io/lab/v1/performance/preview" \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "bet_type": "spread",
  "mode": "simple",
  "sport": "nba",
  "advanced_config": null,
  "factors": [
    {
      "factor_id": 1,
      "importance": "low",
      "weight": 0,
      "parameters": {}
    }
  ]
}'
GET/lab/v1/models/{id}/performance

Get model performance

Returns performance evaluation results for a model.

Returns null if evaluation has not been run yet.

Parameters

idintegerpathrequired

Model ID

Responses

200Performance results (null if not evaluated)
dataoneOf
Example Response
{
  "data": null
}
Error Responses
400Invalid model ID
404Model not found

Example Request

cURL
curl -X GET "https://api.balldontlie.io/lab/v1/models/{id}/performance" \
  -H "Authorization: YOUR_API_KEY"
POST/lab/v1/models/{id}/performance

Trigger performance evaluation

Creates a background job to run performance evaluation for a model against historical data.

Returns immediately with a job object - poll the job endpoint to get results.

Clears any existing performance data before running.

Season Format: "YYYY-YY" (e.g., "2024-25")

Allowed Seasons: 2020-21 through 2025-26

Note: Only one evaluation job can run per model at a time. If a pending or running

evaluation job already exists, a 409 Conflict is returned.

Parameters

idintegerpathrequired

Model ID

Request Body

start_seasonstring

Start season (format "YYYY-YY", e.g., "2024-25"). Allowed range 2020-21 to 2025-26.

end_seasonstring

End season (format "YYYY-YY", e.g., "2024-25"). Allowed range 2020-21 to 2025-26.

Example Request
{
  "start_season": "string",
  "end_season": "string"
}

Responses

201Evaluation job created
dataJob
Example Response
{
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "model_id": 1,
    "job_type": "preview",
    "status": "pending",
    "output": null
  }
}
Error Responses
400Invalid request (season format, etc.)
404Model not found
409Evaluation already running

Example Request

cURL
curl -X POST "https://api.balldontlie.io/lab/v1/models/{id}/performance" \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "start_season": "string",
  "end_season": "string"
}'
DELETE/lab/v1/models/{id}/performance

Clear performance data

Clears all performance evaluation data for a model.

Parameters

idintegerpathrequired

Model ID

Responses

204Performance data cleared
Error Responses
400Invalid model ID
404Model not found

Example Request

cURL
curl -X DELETE "https://api.balldontlie.io/lab/v1/models/{id}/performance" \
  -H "Authorization: YOUR_API_KEY"
GET/lab/v1/models/{id}/performance/games

Get per-game performance details

Returns paginated per-game breakdown of performance evaluation.

Parameters

idintegerpathrequired

Model ID

limitintegerquery

Number of results per page

offsetintegerquery

Number of results to skip

resultstringquery

Filter by result

winlosspushpending

Responses

200Per-game performance details
dataPerformanceGameResult[]
metaOffsetPagination
Example Response
{
  "data": [
    {
      "game_id": 1,
      "date": "2024-01-15",
      "home_team": {
        "id": "...",
        "abbreviation": "...",
        "name": "..."
      },
      "away_team": {
        "id": "...",
        "abbreviation": "...",
        "name": "..."
      },
      "home_score": 1
    }
  ],
  "meta": {
    "total": 1,
    "limit": 1,
    "offset": 1
  }
}
Error Responses
400Invalid parameters
404Model not found

Example Request

cURL
curl -X GET "https://api.balldontlie.io/lab/v1/models/{id}/performance/games" \
  -H "Authorization: YOUR_API_KEY"
GET/lab/v1/jobs/{id}

Get job status

Returns the status and output of a background job.

Poll this endpoint until status is "completed" or "failed".

Parameters

idstringpathrequired

Job ID (UUID)

Responses

200Job status and output
dataJob
Example Response
{
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "model_id": 1,
    "job_type": "preview",
    "status": "pending",
    "output": null
  }
}
Error Responses
400Invalid job ID (must be valid UUID)
404Job not found

Example Request

cURL
curl -X GET "https://api.balldontlie.io/lab/v1/jobs/{id}" \
  -H "Authorization: YOUR_API_KEY"
DELETE/lab/v1/jobs/{id}

Cancel a pending job

Cancels a pending job. Only jobs with status "pending" can be cancelled.

Running jobs cannot be cancelled as they are already being processed.

Cancelled jobs have their status set to "failed" with error message "Cancelled by user".

Parameters

idstringpathrequired

Job ID (UUID)

Responses

200Job cancelled successfully
dataJob
Example Response
{
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "model_id": 1,
    "job_type": "preview",
    "status": "pending",
    "output": null
  }
}
Error Responses
400Job cannot be cancelled (not pending status)
404Job not found

Example Request

cURL
curl -X DELETE "https://api.balldontlie.io/lab/v1/jobs/{id}" \
  -H "Authorization: YOUR_API_KEY"
GET/lab/v1/models/{id}/jobs/active

Get active jobs for a model

Returns all pending and running jobs for a specific model.

Used to determine if a model has jobs in progress that would prevent new jobs from being created.

Parameters

idintegerpathrequired

Model ID

Responses

200List of active jobs
dataJob[]
Example Response
{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "model_id": 1,
      "job_type": "preview",
      "status": "pending",
      "output": null
    }
  ]
}
Error Responses
400Invalid model ID
404Model not found

Example Request

cURL
curl -X GET "https://api.balldontlie.io/lab/v1/models/{id}/jobs/active" \
  -H "Authorization: YOUR_API_KEY"