Developer API — Preview

Start building with Magisterial

Everything you need to integrate college sports data into your product — from your first API call to production.

Base URL https://api.magisterial.ai/v1

curl https://api.magisterial.ai/v1/players/search \
  -H "Authorization: Bearer mag_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "sport": "soccer",
    "gender": "men",
    "division": "D1"
  }'

Quick start

Get an API key from the developer console, then make your first request. Keys are created and managed from your account — sign in and the console opens straight to key management.

1Create an API key

Open the console, create a key, and copy it — the full token is shown only once.

2Make your first request
curl https://api.magisterial.ai/v1/sports \
  -H "Authorization: Bearer mag_live_xxxxxxxxxxxxxxxxxxxx"

Introduction

The API is organized around predictable, resource-oriented URLs. It accepts JSON request bodies, returns JSON responses, and uses standard HTTP verbs, status codes, and authentication. Every response you receive is scoped to exactly the sports and divisions your plan includes — the same data you see inside the Magisterial app.

Authentication

Authenticate with an API key sent as a bearer token in the Authorization header. Keys are created and rotated from your account settings. Live keys are prefixed mag_live_ and test keys mag_test_. Treat keys like passwords — they carry your plan’s full access. Never embed a live key in client-side code.

curl https://api.magisterial.ai/v1/players/search \
  -H "Authorization: Bearer mag_live_xxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "sport": "soccer", "gender": "men", "division": "D1" }'

Requests without a valid key return 401 Unauthorized.

Scoping & access

Access is governed per sport and per division by your subscription tier. Every request must declare a scope — a sport, gender, and division — and results never span beyond what your plan entitles you to. A request for a division you don’t hold returns 403 Forbidden with the required tier, rather than silently returning nothing.

Multi-division scope. NCAA divisions can be combined into one query — pass "D1,D2,D3" to search across all three at once. NAIA and NJCAA are separate associations and cannot be combined with NCAA divisions.

Rate limits

Every account may make up to 120 requests per minute across all /v1 endpoints, shared by all of its keys. Each response reports where you stand:

X-RateLimit-Limit: 120
X-RateLimit-Remaining: 119
X-RateLimit-Reset: 1751990460

X-RateLimit-Reset is the Unix time (seconds) when the window resets. Exceeding the limit returns 429 Too Many Requests with a Retry-After header (seconds to wait) and the standard error body:

{
  "error": {
    "type": "rate_limited",
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded (120 per 1 minute). Wait for the window to reset and retry."
  }
}

Pagination & errors

List endpoints are cursor-paginated. Pass limit (max 100) and follow next_cursor from each response until it is null.

{
  "data": [ /* ... */ ],
  "next_cursor": "eyJvZmZzZXQiOjEwMH0",
  "has_more": true
}

Errors use standard status codes and a consistent body:

{
  "error": {
    "type": "forbidden",
    "code": "tier_required",
    "message": "This division requires a Pro plan or higher for soccer.",
    "required_tier": "pro"
  }
}

Usage-billed endpoints (portal, query, alerts) add billing errors: 403 api_billing_not_enabled until billing is enabled in the console, 403 api_billing_past_due after a failed invoice, and 402 budget_exceeded once month-to-date spend reaches your budget cap (the response includes budget_usd and spent_usd).

Sports & divisions

Discovery endpoints returning the sports, divisions, and conferences your key can query. Use these to populate pickers and validate scope before issuing a data request.

GET/v1/sports
List supported sports and the genders available for each.
GET/v1/divisions
List divisions your plan includes (D1, D2, D3, NAIA, NJCAA and JUCO levels).
GET/v1/conferences
divisionstringrequired
List conferences within a division, e.g. D1.

Filter catalog

Returns the queryable fields, operators, and allowed values for a given sport — the same catalog that powers search and automations in the app. Build valid /players/search filters from this rather than hard-coding field names.

GET/v1/filters/catalog
sportstringrequired
The sport whose filterable fields to return.

Players

Players and their per-season statistics. Search returns matches within your scope; the detail endpoints return a single player and their season history.

POST/v1/players/search

Body

sportstringrequired
Sport to search within.
divisionstringrequired
Division scope; may be a comma-joined NCAA list.
genderstringoptional
men or women (ignored for single-gender sports).
filtersarrayoptional
Field/operator/value filters from the filter catalog.
limitintegeroptional
Page size, max 100.
GET/v1/players/{id}
Retrieve a single player’s profile.
GET/v1/players/{id}/seasons
Retrieve a player’s per-season statistics.

Example response

{
  "data": [
    {
      "id": "plr_8fk2...",
      "person_id": "prs_1a9c...",
      "name": "Jordan Reyes",
      "position": "GK",
      "team": { "id": "tm_44...", "name": "Georgetown" },
      "division": "D1",
      "class_year": "Junior"
    }
  ],
  "next_cursor": null,
  "has_more": false
}

Persons & careers

A person is a real individual linked across every school, season, and transfer they appear in. Use this to follow a career across programs — the identity that survives a transfer, where a player is one school-season slice.

GET/v1/persons/{id}
Retrieve a person’s consolidated profile and linked player records.
GET/v1/persons/{id}/transfers
Retrieve a person’s transfer history between programs.

Teams & coaches

Programs, their rosters, and coaching staffs.

GET/v1/teams
divisionstringrequired
List teams in a division, optionally filtered by conference.
GET/v1/teams/{id}
Retrieve a single team.
GET/v1/teams/{id}/roster
seasonstringoptional
Roster for a season; defaults to the most recent.
GET/v1/teams/{id}/coaches
Coaching staff for a team, with tenure by season.

Transfer portal

The live NCAA transfer portal. Returns players currently in the portal within your scope, with entry status and timing. Access follows NCAA rules — verified coaches do not see their own school’s players. Usage-billed per request; contact info appears only for Pro/Max accounts, matching the in-app paywall.

GET/v1/portal
sportstringrequired
Sport to query.
divisionstringrequired
Division scope.
genderstringoptional
‘men’ or ‘women’; ignored for single-gender sports.
statusstringoptional
Filter by NCAA record status: INC (active), MAT, SIG, WTH, REACT.
sincestring (ISO 8601)optional
Only players first seen in the portal on or after this timestamp.
limitintegeroptional
Page size, 1–100 (default 50). Paginate with the returned cursor.

Games

Fixtures with box scores and, where available, play-by-play. Filter by team, date range, or season.

GET/v1/games
team_idstringoptional
Filter to a single team’s games.
fromstring (ISO 8601)optional
Start of date range.
tostring (ISO 8601)optional
End of date range.
GET/v1/games/{id}
Retrieve a single game with box score and play-by-play.

Natural-language query

Ask a question in plain English and get a structured answer with the data behind it. Queries run as asynchronous jobs — create a run, then poll it to completion. This is the same assistant that powers the app. Usage-billed at model cost with a markup; the final billed amount is returned with the result.

POST/v1/query
promptstringrequired
The natural-language question.
sportstringrequired
Scope the query to a sport.
divisionstringoptional
Division scope (default D1).
genderstringoptional
‘men’ or ‘women’; ignored for single-gender sports.
GET/v1/query/{run_id}
Retrieve a run’s status. When terminal, includes the answer plus a usage block with tokens and the billed amount.
POST /v1/query
{ "prompt": "Which D2 goalkeepers had a save percentage above 80% last season?",
  "sport": "soccer", "division": "D2" }

// 202 Accepted
{ "run_id": "9b1f...", "status": "queued" }

GET /v1/query/9b1f...
// 200 OK (terminal)
{ "run_id": "9b1f...", "status": "done",
  "answer": "Five D2 goalkeepers finished above 80%...",
  "usage": { "tokens_in": 41230, "tokens_out": 902,
             "model": "claude-sonnet-4-6", "billed_usd": 0.42 } }

Alerts & webhooks

Instead of scanning the portal yourself, register a watch alert and poll its matches. Alerts are evaluated automatically as new portal data lands and are billed per active alert per month. Webhook delivery is coming soon — a stored webhook_url will start receiving events when it ships; until then, poll the matches endpoint.

POST/v1/alerts
namestringrequired
Human label for the alert.
sportstringrequired
Sport scope.
divisionstringrequired
Division scope.
filtersobjectrequired
Filter criteria that trigger the alert.
webhook_urlstringoptional
Optional HTTPS endpoint; stored now, delivery coming soon.
GET/v1/alerts
List alerts created via the API.
GET/v1/alerts/{id}/matches
Recent portal entries that matched the alert, newest first.
DELETE/v1/alerts/{id}
Remove an alert. The current month’s charge is not refunded.
This reference is a preview of the v1 surface. Endpoints and shapes may change before general availability. See plans for included divisions and rate limits.