MaxPreps APImaxpreps.com ↗
Access MaxPreps data via API: search schools, get team rosters, schedules, athlete profiles, and national/state rankings for high school sports.
What is the MaxPreps API?
The MaxPreps API covers 5 endpoints for high school sports data, including school search, team rosters with per-player fields like jersey number and grade, game schedules with scores and win/loss results, detailed athlete profiles with career history, and national or state rankings by sport. The get_rankings endpoint alone returns rank, record, movement, and school identifiers for any supported sport.
curl -X GET 'https://api.parse.bot/scraper/e0a033cc-4c08-49d5-8417-81682c9b3dbf/search_schools?query=Mater+Dei' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace maxpreps-com-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""
MaxPreps Sports API Client
Get your API key from: https://parse.bot/settings
"""
import os
import requests
from typing import Any, Dict, List, Optional
class ParseClient:
"""Client for interacting with the MaxPreps Sports API via Parse."""
def __init__(self, api_key: Optional[str] = None):
"""Initialize the Parse API client."""
self.base_url = "https://api.parse.bot"
self.scraper_id = "e0a033cc-4c08-49d5-8417-81682c9b3dbf"
self.api_key = api_key or os.getenv("PARSE_API_KEY")
if not self.api_key:
raise ValueError("API key not provided. Set PARSE_API_KEY environment variable.")
def _call(self, endpoint: str, method: str = "POST", **params) -> Dict[str, Any]:
"""Make an API call to the Parse bot."""
url = f"{self.base_url}/scraper/{self.scraper_id}/{endpoint}"
headers = {
"X-API-Key": self.api_key,
"Content-Type": "application/json"
}
if method == "GET":
response = requests.get(url, headers=headers, params=params)
else: # POST
response = requests.post(url, headers=headers, json=params)
response.raise_for_status()
return response.json()
def search_schools(self, query: str) -> Dict[str, Any]:
"""Search for schools by name or query.
Args:
query: School name or search query (e.g., 'Oak Hill Academy')
Returns:
Dictionary containing list of schools with details
"""
return self._call("search_schools", method="GET", query=query)
def get_team_roster(self, path: str, season: str = "24-25") -> Dict[str, Any]:
"""Get the roster for a specific team and season.
Args:
path: The school/team path (e.g., '/va/mouth-of-wilson/oak-hill-academy-warriors/basketball/')
season: The school year season (default: '24-25')
Returns:
Dictionary containing roster and team information
"""
return self._call("get_team_roster", method="GET", path=path, season=season)
def get_team_schedule(self, path: str, season: str = "24-25") -> Dict[str, Any]:
"""Get the schedule and results for a team.
Args:
path: The school/team path
season: The school year season (default: '24-25')
Returns:
Dictionary containing contests, tournaments, and team information
"""
return self._call("get_team_schedule", method="GET", path=path, season=season)
def get_athlete_profile(self, path: str, career_id: str) -> Dict[str, Any]:
"""Get detailed athlete profile and history.
Args:
path: The athlete profile path
career_id: The unique career ID for the athlete
Returns:
Dictionary containing prospect report, career data, and timeline
"""
return self._call("get_athlete_profile", method="GET", path=path, career_id=career_id)
def get_rankings(self, sport: str, state: str = "national") -> Dict[str, Any]:
"""Get national or state rankings for a sport.
Args:
sport: The sport name (e.g., 'basketball', 'football')
state: State code (e.g., 'va', 'il') or 'national' (default: 'national')
Returns:
Dictionary containing rankings and title
"""
return self._call("get_rankings", method="GET", sport=sport, state=state)
if __name__ == "__main__":
# Initialize the client
client = ParseClient()
print("=" * 70)
print("MaxPreps Sports API - Scout High School Basketball Players")
print("=" * 70)
# Step 1: Search for schools
print("\n[1] Searching for elite high schools...")
search_queries = ["Mater Dei", "Sierra Canyon", "Montverde Academy"]
all_schools = []
for query in search_queries:
try:
results = client.search_schools(query)
schools = results.get("data", {}).get("schools", [])
if schools:
all_schools.extend(schools)
for school in schools:
print(f" ✓ Found: {school['name']} ({school['mascot']}) - {school['city']}, {school['state']}")
except Exception as e:
print(f" ✗ Error searching '{query}': {str(e)}")
if not all_schools:
print(" No schools found. Exiting.")
exit(1)
# Step 2: Get rosters and identify top players
print("\n[2] Fetching basketball rosters and analyzing players...")
player_database = {}
for school in all_schools[:2]: # Analyze first 2 schools
try:
school_path = school.get("path")
basketball_path = f"{school_path}basketball/"
school_name = school.get("name")
roster_response = client.get_team_roster(basketball_path)
roster = roster_response.get("data", {}).get("roster", [])
print(f"\n {school_name} - {len(roster)} players on roster")
# Filter guards and forwards
guards = [p for p in roster if p.get("position") == "G"]
forwards = [p for p in roster if p.get("position") in ["F", "SF", "PF"]]
print(f" • Guards: {len(guards)}")
print(f" • Forwards: {len(forwards)}")
# Store player data for later analysis
for player in roster[:8]: # Top 8 players
player_key = f"{player['display_name']}_{school_name}"
player_database[player_key] = {
"name": player.get("display_name"),
"school": school_name,
"number": player.get("jersey"),
"position": player.get("position"),
"height": player.get("height"),
"grade": player.get("grade"),
"career_id": player.get("career_id"),
"profile_path": player.get("profile_url")
}
except Exception as e:
print(f" ✗ Error fetching roster for {school.get('name')}: {str(e)}")
# Step 3: Get detailed profiles for top prospects
print("\n[3] Analyzing top prospect profiles...")
top_prospects = list(player_database.values())[:5]
for prospect in top_prospects:
try:
if prospect["career_id"] and prospect["profile_path"]:
profile = client.get_athlete_profile(prospect["profile_path"], prospect["career_id"])
career_data = profile.get("data", {}).get("career_data", [])
timeline = profile.get("data", {}).get("timeline", [])
print(f"\n {prospect['name']} | {prospect['position']} | {prospect['height']}")
print(f" School: {prospect['school']} ({prospect['grade']})")
if career_data and isinstance(career_data, list) and len(career_data) > 0:
current_season = career_data[0]
stats = current_season.get("stats", [])
if stats:
ppg_stat = next((s for s in stats if "Points" in s.get("displayName", "")), None)
if ppg_stat:
print(f" PPG: {ppg_stat.get('value', 'N/A')}")
if timeline:
recent_events = timeline[:2]
print(f" Recent Activity: {len(timeline)} events")
for event in recent_events:
print(f" - {event.get('title', 'N/A')}")
except Exception as e:
print(f" ✗ Error fetching profile for {prospect['name']}: {str(e)}")
# Step 4: Get team schedules to see upcoming matchups
print("\n[4] Checking team schedules...")
for school in all_schools[:1]: # Schedule for first school
try:
basketball_path = f"{school.get('path')}basketball/"
schedule = client.get_team_schedule(basketball_path)
contests = schedule.get("data", {}).get("contests", [])
print(f"\n {school['name']} Basketball Schedule ({len(contests)} contests)")
wins = sum(1 for c in contests if c.get("result", "").startswith("W"))
losses = sum(1 for c in contests if c.get("result", "").startswith("L"))
print(f" Record: {wins}-{losses}")
# Show recent games
print(" Recent Results:")
for contest in contests[:5]:
opponent = contest.get("opponent", "Unknown")
result = contest.get("result", "TBD")
date = contest.get("date", "N/A")
print(f" {date[:10]} vs {opponent}: {result}")
except Exception as e:
print(f" ✗ Error fetching schedule: {str(e)}")
# Step 5: Get national rankings
print("\n[5] Checking national basketball rankings...")
try:
rankings = client.get_rankings("basketball", "national")
title = rankings.get("data", {}).get("title", "Rankings")
ranked_teams = rankings.get("data", {}).get("rankings", [])
print(f"\n {title}")
print(" Top 10 Teams:")
for team in ranked_teams[:10]:
rank = team.get("rank")
name = team.get("schoolName")
state = team.get("stateCode")
record = team.get("overall", "N/A")
movement = team.get("movement", "--")
print(f" {rank:2d}. {name:30s} ({state}) - {record} {movement}")
except Exception as e:
print(f" ✗ Error fetching rankings: {str(e)}")
print("\n" + "=" * 70)
print("Scout analysis complete!")
print("=" * 70)Search for schools by name or query. Returns matching schools with their IDs, locations, mascots, and paths for use in other endpoints.
| Param | Type | Description |
|---|---|---|
| queryrequired | string | School name or search query (e.g., 'Oak Hill Academy', 'Mater Dei') |
{
"type": "object",
"fields": {
"schools": "array of school objects with school_id, name, city, state, mascot, url, and path"
},
"sample": {
"data": {
"schools": [
{
"url": "https://www.maxpreps.com/va/mouth-of-wilson/oak-hill-academy-warriors/",
"city": "Mouth of Wilson",
"name": "Oak Hill Academy",
"path": "/va/mouth-of-wilson/oak-hill-academy-warriors/",
"state": "VA",
"mascot": "Warriors",
"school_id": "f80db136-2ddf-4840-8835-c02f4785634d"
}
]
},
"status": "success"
}
}About the MaxPreps API
School and Team Data
Start with search_schools to find any high school by name or partial query. Each result includes a school_id, name, city, state, mascot, and a path used as the base input for team endpoints. Append a sport to that path and pass it to get_team_roster or get_team_schedule. Both endpoints accept an optional season parameter in YY-YY format (e.g., 24-25) so you can pull historical data beyond the current year.
Rosters and Athlete Profiles
get_team_roster returns a roster array where each player object includes career_id, athlete_id, first_name, last_name, jersey, position, height, grade, and a photo_url. The career_id from this response is the required input for get_athlete_profile, which returns a timeline of events (articles, stat updates, game results), club_teams, season-by-season career_data with stats and awards, and a prospect_report object — or null if no prospect rating exists for that athlete.
Schedules and Rankings
get_team_schedule returns a contests array with date, home_team, away_team, opponent, and result fields, plus a separate tournaments array for postseason play. get_rankings accepts a sport string and an optional state code (e.g., ca, tx) or the literal string national. Each ranking object includes rank, schoolId, schoolName, stateCode, overall record, teamLink, and a movement indicator showing week-over-week rank change.
The MaxPreps API is a managed, monitored endpoint for maxpreps.com — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when maxpreps.com changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official maxpreps.com API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Build a high school football recruiting tracker using
get_athlete_profilecareer stats and prospect_report ratings. - Generate automated weekly rankings digests by polling
get_rankingswith sport and state parameters. - Power a school sports directory by combining
search_schoolsresults with roster data fromget_team_roster. - Track season results for a specific team by pulling
get_team_schedulecontests with scores and opponent names. - Compare rosters across seasons by calling
get_team_rosterwith differentYY-YYseason values for the same team path. - Identify club team affiliations for recruited athletes using the
club_teamsfield inget_athlete_profile. - Display per-player grade and position breakdowns for any high school team using the
get_team_rosterresponse fields.
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 100 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
One credit = one API call regardless of which marketplace API you call. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does MaxPreps have an official public developer API?+
What does the `get_athlete_profile` endpoint return beyond basic bio info?+
timeline array of event objects (articles, stat updates, and game results), a career_data array with season-by-season stats and awards, club_teams affiliations, and a prospect_report object containing prospect rating data — or null if no rating is available for that athlete.Can I retrieve play-by-play or box score data for individual games?+
get_team_schedule and career-level stats via get_athlete_profile, but individual game box scores are not exposed. You can fork this API on Parse and revise it to add a game-level box score endpoint.Does `get_rankings` support all sports, or only the major ones?+
sport parameter accepts string values like basketball, football, baseball, and volleyball. Coverage depends on what MaxPreps publishes rankings for, so niche or regional sports with limited ranking data may return sparse results.