Skip to main content

Introduction

The Fantasy Basketball Analytics API is a Flask-based REST API that combines Yahoo Fantasy Sports data with NBA statistics to provide comprehensive fantasy basketball analytics. The API uses session-based authentication and returns all responses in JSON format.

Base URL Structure

The API runs on Flask’s development server with the following configuration:
app.run(debug=True, port=5000, host='0.0.0.0')
All API endpoints are prefixed with /api/ for data endpoints:
  • /api/scoreboard - Weekly matchup data
  • /api/season_avg - Season average statistics
  • /api/league_settings - League configuration
  • /api/draft/keepers - Keeper player information
  • /api/nba_players - NBA player roster data
  • /api/nba_player_stats/<player_id> - Individual player statistics

Response Format

All API responses are returned in JSON format. The API uses Flask’s jsonify() function to ensure consistent JSON serialization:
return jsonify(data)

Successful Response Example

{
  "players": [
    {
      "id": 2544,
      "full_name": "LeBron James",
      "team_abbreviation": "LAL",
      "position": "F"
    }
  ]
}

Error Handling

The API implements consistent error handling patterns across all endpoints:

Authentication Errors

if "token" not in session:
    return jsonify({"error": "authentication required"}), 401
Response:
{
  "error": "authentication required"
}
Status Code: 401 Unauthorized

Missing League Context

if "league_key" not in session:
    return jsonify({"error": "no league chosen"}), 400
Response:
{
  "error": "no league chosen"
}
Status Code: 400 Bad Request

Yahoo API Errors

When Yahoo API calls fail, the error is caught and returned with appropriate status codes:
except requests.exceptions.HTTPError as e:
    status_code = e.response.status_code if e.response is not None else 502
    error_detail = "Failed to fetch keeper data from Yahoo."
    try:
        yahoo_error = e.response.json() if e.response is not None else None
    except Exception:
        yahoo_error = None
    if isinstance(yahoo_error, dict):
        error_detail = yahoo_error.get("error", {}).get("description", error_detail)
    return jsonify({"error": error_detail}), status_code

Generic Server Errors

except Exception as e:
    log.error(f"Error fetching data: {e}")
    return jsonify({"error": str(e)}), 500
Status Code: 500 Internal Server Error
Always check the response status code. A 200 status indicates success, while 4xx codes indicate client errors (authentication, missing parameters) and 5xx codes indicate server errors.

Rate Limiting Considerations

The API currently does not implement rate limiting on the Flask application level. However, you must consider rate limits from external services:

Yahoo Fantasy Sports API

Yahoo Fantasy Sports API has rate limits that vary by endpoint. The API implements automatic token refresh to maintain session continuity:
def yahoo_api(rel_path: str, *, _retry: bool = True) -> Dict[str, Any]:
    token = session["token"]
    resp = requests.get(
        f"https://fantasysports.yahooapis.com/{rel_path}",
        headers={"Authorization": f"Bearer {token['access_token']}"},
        params={"format": "json"},
        timeout=20,
    )
    if resp.status_code == 401 and _retry:
        _refresh_token()
        return yahoo_api(rel_path, _retry=False)
    resp.raise_for_status()
    return resp.json()

NBA Stats API

The NBA Stats API (via nba_api library) may throttle requests. The application implements fallback mechanisms:
try:
    player_data_df = playerindex.PlayerIndex(season=season_str, league_id="00").get_data_frames()[0]
except Exception as e:
    # Fallback to static players list
    active_players_basic = nba_static_players.get_active_players()
Implement client-side throttling when making repeated API calls to avoid hitting external API rate limits.

Session Configuration

The API uses Flask sessions with the following configuration:
app.secret_key = os.getenv("FLASK_SECRET_KEY", "dev-key")
app.config.update(
    SESSION_COOKIE_SAMESITE="Lax",
    SESSION_COOKIE_SECURE=False,
    PERMANENT_SESSION_LIFETIME=60 * 60,  # 1 hour
)
Sessions expire after 1 hour of inactivity. Ensure your client handles session expiration gracefully.

Build docs developers (and LLMs) love