# Magisterial API changelog

Release notes for the /v1 developer API, newest first. Policy: at least 90
days' notice before any breaking change to /v1, announced here with
Deprecation and Sunset response headers on affected endpoints.

Human version with anchors: https://magisterial.ai/changelog

## 2026-10-19 — X-Monthly-Quota-Reset header, and quota headers on the quota 429
Tags: added, fixed

- Every response on a plan with a monthly quota now carries X-Monthly-Quota-Reset: the Unix time in seconds (like X-RateLimit-Reset) when the quota next resets. It resets at 00:00 UTC on the 1st of each calendar month for every account, not on your billing date. The 429 body already carried this as resets_at.
- A 429 monthly_quota_exceeded now carries X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining (0) and X-Monthly-Quota-Reset as well; before, only successful responses did. Plans with no monthly quota (Enterprise) send none of the three.

Links: Rate limits: https://magisterial.ai/docs#rate-limits

## 2026-10-19 — Roster and staff change tracking for every association, and changed_since filters
Tags: added, changed

- freshness.changed_at on rosters, coaching staffs and team detail is now when what this API returns for the team's latest season last changed: a player added, removed or changed in any returned field, a staff member added, removed or retitled. It no longer depends on which source a change came from, so it covers NJCAA, 3C2A, NWAC, NAIA, NCCAA and USCAA programs the same way as NCAA ones. Before, many junior-college and NAIA programs had no changed_at, and some changes made outside a program's main roster page did not move it.
- changed_at is never earlier than the change it reports. A program's first changed_at is when tracking began for it, not a change: every program holding a roster or staff when tracking started carries that same first timestamp, so one full read after it is your baseline.
- GET /v1/teams takes roster_changed_since and coaches_changed_since (ISO 8601). Set them to the start of your previous sync to list only the programs whose roster or staff changed since, then re-read those. Programs with no changed_at are left out.
- freshness.observed_at is now set for programs read through an association's central roster feed (the NJCAA, 3C2A and NAIA feeds) and for track and field rosters, which had shown no read, or one from August.
- New scheduled roster reads: NJCAA basketball, baseball and softball from the NJCAA's own roster feed, NAIA basketball, baseball and softball from school sites, 3C2A basketball, baseball and softball from the 3C2A feed, and NWAC rosters in seven sports from the colleges' own sites. NJCAA coaching staffs now refresh on schedule.

Links: List teams: https://magisterial.ai/docs#list-teams · Team roster: https://magisterial.ai/docs#get-team-roster

## 2026-10-14 — Season schedule: complete means the counts match, and a new inconsistent status
Tags: changed, fixed

- schedule.status on a team's season records is complete only when games_held equals games_played. Before, a season holding more games than the team's schedule lists was also complete, and its official_record counted the extra game.
- New value inconsistent: games_held is above games_played. A held game is not one of the season's (the same game held twice, an exhibition counted, another season's game) or the schedule as read is wrong. official_record is null and missing_games is 0; record_from_held_games should not be shown as the season's record.
- Fixed at the source the same day: 655 games filed under a season their own box score does not belong to were removed, and 491 exhibitions named in their box score links are no longer counted. Schedules are being re-read, so more seasons move to complete as that runs.

Links: Team detail: https://magisterial.ai/docs#get-team

## 2026-10-14 — Postseason results: NAIA softball and lacrosse
Tags: added

- GET /v1/teams/{team_id}/postseason holds the NAIA softball national championship for the 2013, 2015, 2022, 2023, 2025 and 2026 seasons, read from the NAIA's softball record book. Both stages are double elimination: result is regional for a team that went out in the opening round, championship_finals for one that went out in the ten-team World Series, then runner_up and champion. teams_remaining is the whole field (40, or 48 from 2025) for regional and 10 for championship_finals. seed is the World Series seed where the book prints one (2013 to 2023); the opening-round brackets' own seeds are not kept.
- Softball seasons not held: 2014, 2016 to 2019, 2021 and 2024. In each the book's game list does not add up to complete brackets (a deciding game left out, a game cut short by weather, lines run together), and a season is held only when every bracket does. There was no 2020 tournament.
- NAIA women's lacrosse 2021 to 2026 and men's lacrosse 2025 and 2026: eight-team brackets, quarterfinals to the final.

Links: Team postseason results: https://magisterial.ai/docs#get-team-postseason

## 2026-10-13 — Postseason results: NCAA back to 2013, bowl games and the playoff, NAIA
Tags: added

- GET /v1/teams/{team_id}/postseason now holds NCAA championship tournaments from the 2013 season on, for the same sports and divisions as before: 404 tournaments in all. The 2020 winter and spring tournaments were not played and are not listed. One bracket is left out because the NCAA's own record of it contradicts itself (Division III women's volleyball, 2018).
- Division II and III baseball and softball before 2025 are published by the NCAA from the finals on. Where the earlier rounds could be rebuilt from the NCAA's scoreboard with every game accounted for, the whole bracket is held; for 29 older brackets they could not, and those seasons are in finals_only_seasons: the eight finalists are held, and a team with no entry may still have played in a regional.
- New kind bowl_game: FBS bowl games for the 2021 to 2024 seasons, 160 games. organizer and event are the bowl, under one name across seasons (Rose Bowl, Pop-Tarts Bowl), and result is won or lost. A bowl winner is not a champion, so result = champion still means a national title. Bowl names come from the NCAA's bowl record book, which ends with the 2024 season; 2025 bowls are not held yet.
- The College Football Playoff is a national_tournament with organizer CFP and division D1-FBS, seasons 2021 to 2025: champion, runner_up, semifinals, quarterfinals and round_of_12. A playoff quarterfinal or semifinal played as a bowl appears twice, as the team's playoff result and as that bowl; do not add the two entries' wins together.
- NAIA national championships (organizer NAIA, division NAIA), read from the NAIA's championship record books: men's soccer 2021, 2022, 2023 and 2025, women's soccer 2021, 2022, 2023 and 2025, and men's basketball 2022, 2024, 2025 and 2026. A season is held only when the book's games make a complete bracket; the seasons in between are ones where the book leaves a game out, and they are not held.
- In coverage, bowl games are one line per division with organizer 'FBS bowls'. A season listed there with no bowl_game entry is one the team played no bowl in.

Links: Team postseason results: https://magisterial.ai/docs#get-team-postseason

## 2026-10-13 — Team postseason results: conference titles
Tags: added, changed

- New on GET /v1/teams/{team_id}/postseason: two more kind values. conference_regular_season is a conference regular-season title. conference_tournament is a conference tournament title, or the championship game of a conference that decides its title in one. organizer is the conference, under the same label a team's conference carries.
- Every conference title is read from the conference's own published list of its champions. None is worked out from standings, and none is taken from an NCAA automatic-bid list.
- result is champion, or runner_up for the team that lost a conference tournament final where the conference names it. Two new fields on every entry: shared is true where a conference names co-champions (each has an entry), and conference_division names a division inside the conference (East, West) when the title is that division's. Both are false and null on national tournament entries.
- coverage now lists the conference titles held for the team, by the conference it was in each season, so a covered season with no entry means the team did not win that title. Two new lists on each coverage entry: no_champion_seasons (the conference named no champion of that kind: no tournament in the sport, a cancelled season, a vacated title) and champion_only_seasons (tournament seasons where the runner-up is not held).
- Held: 32 Division I conferences, in the sports where each publishes a list of its champions on its site or in its record book: ACC, America East, American, ASUN, Atlantic 10, Big 12, Big East, Big Sky, Big South, Big Ten, Big West, CAA, Conference USA, EIVA, Horizon League, Ivy League, MAAC (Metro), MAC, MEAC, MIVA, Missouri Valley, Mountain West, NEC, Ohio Valley, Pac-12 (2024), SEC, SoCon, Southland, Summit League, Sun Belt, SWAC and UAC. Seasons 2024 and 2025 in fall sports, and 2024 through 2026 in winter and spring sports; a record book printed before a season ended does not state it, and that season is not held. A conference and sport with no coverage entry is not held.
- Changed: teams_remaining and field_size can now be null. A regular-season title has no rounds, and a conference's list of champions does not state its tournament's field. Both are always set on national_tournament entries, as before.

Links: Team postseason results: https://magisterial.ai/docs#get-team-postseason

## 2026-10-13 — Team postseason results: NCAA tournaments
Tags: added

- New: GET /v1/teams/{team_id}/postseason. What a team did after the regular season, season by season. It opens with national tournaments: every NCAA championship tournament the team played in, with how far it went (result, round, teams_remaining), its seed, its wins and losses there, the field size and a link to the NCAA's bracket.
- Held: the last five NCAA tournaments in Divisions I, II and III for men's and women's soccer, men's and women's basketball, women's volleyball, baseball, softball, men's and women's lacrosse and men's volleyball (Division III and the National Collegiate championship), and the FCS, Division II and Division III football playoffs. Fall sports run from the 2021 season to 2025, the others from 2022 to 2026. Every result is read from the NCAA's own bracket.
- result is one vocabulary across sports: champion, runner_up, semifinals, quarterfinals, then round_of_<n> for a team that went out with n teams left. Baseball and softball use regional, super_regional and championship_finals. teams_remaining gives the same thing as a number, so teams_remaining <= 16 is 'reached the round of 16' whatever byes or play-in games a bracket has.
- The response carries coverage: the competitions and seasons held for the team's sport and division. Inside it, a season with no entry is one the team did not play in the tournament. Every bracket listed is held whole, from the first round. finals_only_seasons is there for a competition whose source publishes only its final stage; it is empty for every NCAA tournament.
- The resource is built to hold conference tournament results and conference regular-season titles as further kind values. They are not held yet.

Links: Team postseason results: https://magisterial.ai/docs#get-team-postseason

## 2026-10-13 — A change log for movements, and team national rankings
Tags: added, fixed, deprecated

- New: GET /v1/movements/changes, on every plan. It is the change log of the published movement feed, oldest change first: each movement that is or was published, in its current state, with state (published or retracted), a per-movement revision, changed_at and, for a retraction, the reason. A movement corrected after publication does not get a new published_at, and a retracted one is no longer returned by GET /v1/movements, so polling by published_at misses both. To keep a copy of the feed correct, read this endpoint until has_more is false, then pass the last changed_at as since on the next poll. It carries the same changes the movement webhooks push.
- A movement's key is (kind, id). Player and coach movements are numbered separately, so one id can belong to a player movement and to a coach movement. The reference now says so on the id field.
- New: GET /v1/teams/{team_id}/rankings. A team's national rankings by season: the NCAA's RPI, NET and NPI sheets and the coaches polls, as far back as each is held for the sport and division. Each entry is the team's rank on the season's latest release, with is_final true once that release is the season's final one.
- Deprecated, removed on 2027-01-12: team_ranking on a POST /v1/players/search row. The search takes no ranking filter or sort, so the field has been null on every row since it was added. Read a team's rankings from GET /v1/teams/{team_id}/rankings. The ranking fields GET /v1/filters/catalog lists in its player section (national_rank, ranking_system and the rest) have empty search_ops and alert_ops for the same reason: they are not filters.

Links: Movement changes: https://magisterial.ai/docs#get-movement-changes · Team rankings: https://magisterial.ai/docs#get-team-rankings · Versioning & deprecation: https://magisterial.ai/docs#versioning

## 2026-10-13 — A team's season says whether it is all there
Tags: added

- Every season in documents on GET /v1/teams/{team_id} now has a schedule object. games_played is how many completed, non-exhibition games the team's own published schedule lists for the season, and games_held is how many of them we hold. The record and stats on the season are counted from the games held, so a season is short when games_held is below games_played.
- status is complete (every game on the schedule is held), partial (the schedule lists more games than we hold; missing_games says how many) or unverified (we have not read the team's schedule for that season, so there is nothing to compare against, and games_played, missing_games, schedule_observed_at and schedule_source are null). official_record is the season's record when status is complete and null otherwise; record_from_held_games is the record over the games held, whatever the status.
- games_with_box_scores is how many of the held games have a team box score for the team, and is null in a sport with none. A season with games or a schedule read but no season document is now listed too, with only season, chunk_type and schedule.
- The schedule is read for each team as its pages are re-read, so unverified is the status of a season until then.
- Football season documents change with it. In stats_json, coverage expected is now the schedule's game count instead of the games held, coverage.schedule compares the two, games_held is new, and games_played is the schedule's count (null until the schedule is read). A football season known to be short has a null record and null season totals until its missing games are held, where it used to show a record over the games held.

Links: API reference: https://magisterial.aihttps://api.magisterial.ai/v1/docs

## 2026-10-12 — A team read by id follows the team when its division changes
Tags: changed

- division is now optional on GET /v1/teams/{team_id}, /roster and /coaches. Omit it and the team is read in its own current division. A team id names the program for good; its division is a label that changes when the program moves (from NJCAA to Independent, or from Division III to Division II).
- When a division is given and the team is not in it, the 404 (code team_not_found, as before) now says which division the team is in, in the message and as error.division. A request that names the right division behaves exactly as it did.

Links: API reference: https://magisterial.aihttps://api.magisterial.ai/v1/docs

## 2026-10-09 — The filter catalog says what /v1 accepts
Tags: added, fixed, deprecated

- GET /v1/filters/catalog now describes each field for /v1. search_ops lists how POST /v1/players/search can filter on it: eq and in are the field as one value or an array, neq and not_in are field_not, gte and lte are field_min and field_max, within_miles is the field as an object with latitude, longitude and miles (near, the hometown radius). alert_ops lists the op values an alert predicate on the field accepts. A field with neither list is a name in the rows /v1 returns, not a filter.
- Each stat in stats_by_sport has filterable: true means POST /v1/players/search takes a min and max for it under stats. The list now holds every key of the sport's stats object, the sort-only ones included (basketball's min_avg, turnovers_avg, fgm_avg and three_pt_m_avg). The player section gains name and near, the search body's name and hometown-radius filters.
- The response has a typed schema in the OpenAPI spec, and the spec's example is built from the real response.
- Fixed: the catalog was the Magisterial app's own, so it named parameters of the app's search that no /v1 endpoint accepts (request_key hometown_state for home_state, minimum_request_key min_goals for the soccer stat g). Sending those to POST /v1/players/search returned a validation error. The alert examples in the spec showed a filters object that matched every player; they now show a real predicate.
- Deprecated, removed on 2027-01-12. Until then these are still returned with the values they had, and the endpoint sends Deprecation and Sunset headers. On every field of sections and stats_by_sport: ops, normalize, values_endpoint, request_key, minimum_request_key, maximum_request_key, range_request_key, manual_search_supported and manual_search_operators. At the top level: ops_by_type, divisions (GET /v1/divisions lists them), divisions_by_sport (read divisions_by_sport_gender), division_multi_select_supported, division_scope_encoding and automation_features. In the player section: the player_name field, which is name on /v1.

Links: Versioning & deprecation: https://magisterial.ai/docs#versioning · API reference: https://magisterial.aihttps://api.magisterial.ai/v1/docs

## 2026-10-09 — Players exports name the player
Tags: added

- A players file from POST /v1/exports now carries name, first_name and last_name on every row. name is natural order ("Jordan Rivera"), as on the player and roster endpoints. first_name and last_name are set when the roster source published the name in split form; otherwise they are empty in CSV and null in JSONL.
- In CSV the three columns are the last in the header, after the sport's stat columns, so every column that was already in the file is where it was. In JSONL they are top-level keys beside id, outside stats.
- A file made before this change does not have the columns. Start the export again to get them.

Links: Bulk exports: https://magisterial.ai/docs#post-exports

## 2026-10-09 — Coach contacts on Developer Pro and Ultra, NAIA football, and one spelling for player names
Tags: added, changed, fixed

- The coach directory is now part of Developer Pro, Developer Ultra and Enterprise. A key with the coach.contact.directory_read scope reads coach email and phone on GET /v1/teams/{team_id}/coaches. When contacts are withheld the response says why in contacts_unavailable_reason (plan_required or key_scope_required). A coach who asked not to be contacted is listed with contact_opt_out true and no contact fields.
- NAIA football is in scope: sport=football accepts division=NAIA, alone or combined (102 programs with rosters, staffs, schedules and season stats).
- Changed: a player's name is now natural order ("Jordan Rivera") on every player, roster, transfer-portal, movement and managed-athlete record. It used to be returned as each roster source published it, mostly "Rivera, Jordan". New first_name and last_name fields are set when the source published the name in split form. If you matched on name, re-read; ids are unchanged.
- The 400 unknown_parameter error now suggests the parameter that was probably meant, when the endpoint accepts one that is close ("search" on a list that takes q).
- Discovery: GET /v1/sports lists the divisions each gender of a sport is offered in, and GET /v1/divisions takes sport and gender to return one sport's list. GET /v1/teams gains status (active, discontinued, all); every team and every program on GET /v1/schools/{school_id} carries status and discontinued_at.
- Roster and coaching-staff responses carry coverage, which says what the list means: held, season_not_held, none_listed, not_collected (we have not read a source for the program yet), not_sponsored or discontinued. Both now return freshness when the list is empty.
- Movements: the published feed now carries every transfer resolved to its transfer edge (the arrival at the new school and the departure from the old one) and every coach move resolved to the post at another school the coach held the season before, alongside confirmed head-coach changes. Before, only transfers the NCAA portal corroborated and head-coach changes were published. Events confirmed before this change enter the feed with a published_at of the day it shipped; observed_at keeps the date they happened.

Links: Coaching staff and contacts: https://magisterial.ai/docs#get-team-coaches · Movements: https://magisterial.ai/docs#get-movements

## 2026-10-09 — Player stats use the filter catalog's names on every endpoint
Tags: changed, deprecated, removed

- A stat now has one name everywhere. The stat fields GET /v1/filters/catalog lists for a sport are the names POST /v1/players/search filters and sorts by, and the names in every stats object: a search row's stats, each season of a player, and the stat columns of a players export. In soccer, sh%, sog% and sv% are sh_pct, sog_pct and sv_pct, and cards and penalty kicks are four numbers you can filter and sort by: yc, rc, pk_made and pk_att. Other sports' stat names are unchanged.
- Every stat field of the sport is present on every row. A stat the source did not publish is null instead of a missing key. The spec has one stat schema per sport, and its examples are built from the real field lists.
- Player rows carry their profile at the top level, under the names the filters use: person_id, team_id, team_logo_url, sport, gender, sport_path, height_inches, jersey_number, home_city, home_state, home_country, high_school, major, minor, bats and throws. Roster entries gain the same height and home fields. A team's national ranking is the team_ranking object. Track and field athletes report their best mark in track, as best_mark_seconds, best_mark_meters or best_points.
- GET /v1/players/{id} and GET /v1/players/{id}/seasons return stats_by_season (a list, newest first, each entry a season, its team_id and the same stats object), stats_totals and, for track and field, track_bests. Each school in career has its own stats_by_season and stats_totals.
- A request that fails validation (422) now answers in the same error envelope as every other error: code validation_error, with error.fields naming each field.
- Deprecated, removed on 2027-01-12. Until then these are still returned beside the new fields, and the three player endpoints send Deprecation and Sunset headers: inside a search row's stats, the copies of the profile fields (team_id, logo_url, sport_path, jersey_number, home_town, home_state, home_country, high_school, major, minor, bats, throws), the soccer keys sh%, sog%, sv%, yc-rc and pg-pa, the team-ranking keys and the track keys; season_stats on a player, on each career entry and on season history; and the detail list on a 422.
- Removed now: ingest bookkeeping that was never part of the documented response. stats_source, stats_source_at and provenance_status no longer appear in season rows, and volleyball's points_source, source_reported_points and stats_field_sources no longer appear in season rows or in a search row's stats.

Links: Versioning & deprecation: https://magisterial.ai/docs#versioning · API reference: https://magisterial.aihttps://api.magisterial.ai/v1/docs

## 2026-10-09 — Alert filters: a condition the alert cannot read is an error
Tags: fixed

- Fixed: POST /v1/alerts dropped any key in filters that is not a section (portal, player, stats, any_of). A body with a player condition and a flat "position": "Goalkeeper" beside it was saved as an alert on the player condition alone. It now returns 400 invalid_filters, naming the key and the section the field belongs in. Coach conditions, which a portal alert never read, are refused the same way.
- Fixed: a section that is not a list of condition objects returned a 500. It now returns 400 invalid_filters.
- Fixed: the example body for POST /v1/alerts showed filters as {"position": "Goalkeeper"}, which the endpoint rejects with 400 invalid_filters because it holds no condition. The reference and the Postman collection now show the working form: {"player": [{"field": "position", "op": "in", "value": ["Goalkeeper"]}]}.
- Saved alerts are unchanged and keep matching as before.

Links: API reference: https://magisterial.ai/docs

## 2026-10-09 — Independent programs (IND)
Tags: added

- division=IND (Independent) is now accepted: programs outside the associations we cover. It is offered for football, soccer, basketball, baseball, softball and women's volleyball (not men's volleyball), alone or combined with other divisions, for example D1,IND. GET /v1/divisions lists it.

Links: Divisions: https://magisterial.ai/docs#get-divisions

## 2026-10-09 — Filters on every list endpoint, and a Postman collection
Tags: added, changed, fixed

- Every list endpoint now filters the same way: field=value, comma lists for any-of, field_not to exclude, field_min and field_max for ranges, q for a name search, and sort_by with sort_order. Schools filter by state, city, control and the programs they field; teams by name, school, conference and state; rosters by position, class year, jersey, home state and country; coaching staffs by title and head coach; games by opponent, home and away team, winner, conference, conference game, neutral site, venue, location, attendance and score; movements by sport, division, team, school, IPEDS UNITID, conference, state, event type and season; the transfer portal by status, cycle, school, conference, entry date and grad-transfer status.
- POST /v1/players/search accepts every filter field of the sport: bio fields by name, height as a range, and every season stat as a range under stats, keyed by the fields GET /v1/filters/catalog lists. Position, class year and home state filters match every spelling rosters use, and a conference can be named by its abbreviation.
- GET /v1/movements needs no scope: school_id alone returns one school's movements in every sport.
- Changed: a query parameter or body field an endpoint does not declare now returns 400 unknown_parameter (422 for a body field) with the list it accepts. Before, it was ignored and the unfiltered list came back. sort_by on player search is checked the same way; the sortable fields are in the filter catalog.
- Fixed: POST /v1/players/search stopped at 500 results with has_more false. It now pages to the end of the result. The transfer-portal year field is documented as what it holds, the portal cycle ("2025-26"), not a class year.
- A Postman collection of every endpoint is served at /v1/postman.json, generated from the OpenAPI spec. Set the api_key collection variable once and a pre-request script sends it on every request.

Links: Filtering: https://magisterial.ai/docs#filtering · Postman collection: https://magisterial.aihttps://api.magisterial.ai/v1/postman.json

## 2026-10-08 — Teams on Developer Pro, Developer Ultra and Enterprise
Tags: added

- A developer account can now have a team. Invite people from the console's Team page: Developer Pro has 5 seats, Developer Ultra 50 and Enterprise 100 by default, the owner included.
- Everyone on the account shares its plan: one set of rate limits, one monthly request quota, one included usage allowance and one bill. Each person keeps their own API keys, alerts and query runs.
- Three roles. The owner changes the plan, the budget and the payment method and decides who is an admin. Admins invite and remove members, see and revoke every key on the account, and read its usage, request log and bill. Members manage their own keys.
- Rate limits and the monthly quota are now counted per account rather than per person, so adding people does not add capacity.

Links: Team: https://magisterial.ai/console/team

## 2026-10-08 — Developer plans in the app: chat on the plan, no coaching tier
Tags: changed

- A paid developer plan no longer changes an account's tier in the Magisterial app. It pays for chat there: each answer is one request against the plan's monthly quota and draws on the included query usage, as POST /v1/query does. Chat reaches what the account's API key reaches.
- Search, pages, the transfer portal and alerts in the app follow the account's coaching plan and are no longer counted against a developer plan.
- An account's alert count covers the alerts made through the API. Alerts made in the app are not counted against a developer plan or billed to it.

Links: Developer API pricing: https://magisterial.ai/pricing/developers

## 2026-10-07 — Four paid plans: Plus, Premium, Developer Pro and Developer Ultra
Tags: added, changed

- The Developer plan is now Developer Pro: same price, same limits, and the API still returns it as plan "developer". Three plans join it: Plus ($19.99/month, 20 requests/minute, 25,000 per month), Premium ($49.99/month, 100 requests/minute, 100,000 per month) and Developer Ultra ($499/month, ten times Developer Pro on every limit). Plans are switched in the console and prorated.
- Transfer-portal requests and alerts are no longer usage-billed on Developer Pro, Developer Ultra or Enterprise; they count against the plan's request quota and alert count. Plus and Premium bill them at $0.05 per request and $5 per alert per month. The portal still needs a verified coach on every plan.
- Every paid plan includes natural-language query usage each month ($5, $15, $40 and $250 at list price), spent before any usage is billed.
- Every paid plan opens the Magisterial app at the top tier in every sport. Searches, pages, chat and alerts there draw on the plan's limits; chat shares the included query usage.
- Enterprise defaults rise to 6,000 requests per minute, 500 alerts and 10,000,000 rows per export. An account's alert count now covers every alert it owns, however it was made.

Links: Developer API pricing: https://magisterial.ai/pricing/developers

## 2026-09-28 — Portal API opens on the Developer plan; entries link to player records
Tags: changed, added

- GET /v1/portal is now open on the Developer plan (or Enterprise) with API billing enabled; the Max coaching plan for the sport is no longer required. The key still needs the portal.entry.read scope and must belong to an active verified coach, and athlete contacts still require portal.contact.read. Per-request pricing is unchanged.
- Portal entries now carry player_id and person_id, linking each athlete to their player record (GET /v1/players/{player_id}) and cross-program career (GET /v1/persons/{person_id}). Both are null when an entry is not yet linked. The fields are additive; existing clients are unaffected.
- API portal alerts are unchanged and still follow the coaching-plan policy.

Links: Portal API docs: https://magisterial.ai/docs#list-portal-entries

## 2026-09-18 — Schools, freshness, movement tiers, and managed athletes
Tags: added, changed

- GET /v1/teams and GET /v1/teams/{team_id} now include a school object (id, slug, athletics domain, and the federal IPEDS UNITID); list teams can also filter to one school with ?ipeds_unitid=. New GET /v1/schools and GET /v1/schools/{school_id} endpoints look institutions up directly and list every program a school fields, cross-sport and cross-division.
- Record-level freshness: GET /v1/teams/{team_id} adds a freshness object per data kind (roster, coaches, season_stats, schedule), and the roster and coaching-staff endpoints add their own freshness plus contacts_included on coaches. GET /v1/coverage adds a freshness snapshot of ingest-lane runs and the seasonal cadence policy.
- GET /v1/movements gains a status parameter: published (curated, every plan, unchanged default), resolved and observed (Enterprise, the underlying resolver stream). Entries now carry status, resolution_status, resolved_at, school_id, and ipeds_unitid.
- GET /v1/teams/{team_id}/coaches gains on_behalf_of, letting an Enterprise key read coach contacts on a managed athlete's behalf; each delegated read is recorded in the athlete's access log. Not metered.
- Custom Enterprise plans can include the coach directory outright: with coach_contact_directory on the plan, a key carrying the exact coach.contact.directory_read scope reads coach contacts without on_behalf_of, like any other read. Coach opt-outs are honored and contact fields never appear in bulk exports.
- Python and TypeScript SDKs 0.5.0 add schools and athletes resources, the ipeds_unitid team filter, the movements status tier, and on_behalf_of on team coaches.
- New Managed athletes endpoints (Enterprise, managed_athlete.manage key scope): POST /v1/athletes invites a player to authorize your account, GET /v1/athletes and GET /v1/athletes/{grant_id} list and fetch grants, POST /v1/athletes/{grant_id}/resend and DELETE /v1/athletes/{grant_id} manage them, and GET /v1/athletes/{grant_id}/access is the per-athlete audit log.

Links: Schools docs: https://magisterial.ai/docs#schools · Data sources & freshness: https://magisterial.ai/docs#data-sources · Managed athletes: https://magisterial.ai/docs#managed-athletes

## 2026-09-17 — Developer plan is sold on its own; new Developer API pricing page
Tags: changed

- Max subscriptions no longer include the Developer API plan. The Developer plan ($99.99 per month) is bought from Console -> Billing or arranged as part of an Enterprise agreement; every other account, whatever its coaching plan, is on Free (10 requests per minute, 1,000 per month). Accounts that already held keys before the plan ladder launched were kept on Developer by hand.
- Developer API pricing has its own page at /pricing/developers (and /pricing/developers.md for agents). The Pricing tab in the developer navigation now points there; /pricing keeps the per-sport coaching plans.

Links: Developer API pricing: https://magisterial.ai/pricing/developers · Plans in the docs: https://magisterial.ai/docs#plans

## 2026-09-16 — API plans: Free, Developer, and Enterprise
Tags: added, changed

- Every API key now inherits its owner's plan. Free ($0, every account) reads at 10 requests per minute and 1,000 requests per calendar month, with the usage-billed endpoints closed. Developer ($99.99 per month, included with every Max subscription) reads at 300 requests per minute and 250,000 per month and opens the transfer portal, natural-language query, alerts, and bulk exports at their list prices. Enterprise is a per-customer agreement with custom limits and no monthly cap.
- Free-plan calls to /v1/portal, /v1/query, /v1/alerts, and /v1/exports return 403 plan_required. Exceeding a plan's monthly quota returns 429 monthly_quota_exceeded with quota, used, and resets_at; every response carries X-Magisterial-Plan and capped plans add X-Monthly-Quota-Limit and X-Monthly-Quota-Remaining.
- The previous single limit of 120 requests per minute is retired. Keys on accounts without Max drop to the Free limits; upgrade to Developer from Console -> Billing. Buying Developer enables usage billing on the same subscription.
- Alert counts, in-flight query and export ceilings, and the export row cap are now per plan (Developer: 25 alerts, 3 queries and 2 exports in flight, 500,000 rows per export).

Links: Plans & pricing: https://magisterial.ai/docs#plans · Console billing: https://magisterial.ai/console/billing

## 2026-08-11 — Season-scoped rosters and SDKs 0.4.0
Tags: added

- GET /v1/teams/{team_id}/roster now accepts an optional four-digit season and returns the selected season on every page, while continuing to default to the latest roster held.
- Python and TypeScript SDKs 0.4.0 expose the season parameter, retain it across cursor pagination, and surface the response season on each page.

Links: Roster API docs: https://magisterial.ai/docs#get-team-roster · SDK documentation: https://magisterial.ai/sdk

## 2026-08-11 — Portal API authorization is now explicit and subscription-bound
Tags: changed, fixed

- GET /v1/portal and API portal alerts now require both usage billing and current application authority: an active verified coach, the Max plan for the requested sport, and an exact delegated portal capability on the key. API billing alone no longer grants portal access.
- Athlete contacts require the separate portal.contact.read scope under the same current actor and sport policy. Keys are intersected with current authority on every request; role changes, downgrades, scope reduction, and revocation take effect without recreating the account session.
- The response schema and SDK method signatures are unchanged. Existing keys that depended on implicit owner-full authority must be recreated or assigned reviewed exact scopes in the developer console.
- Stored portal notifications, chats, runs, cards, and drafts are reauthorized or sanitized on every read and are retained but unreadable after authority loss. Previously delivered email cannot be recalled; all future evaluation and delivery stops until authority is restored.

Links: Portal API docs: https://magisterial.ai/docs#list-portal-entries

## 2026-08-01 — Movements feed: confirmed coaching changes and transfers
Tags: added

- GET /v1/movements is live: a published feed of roster and coaching-staff movements — confirmed head-coach changes and corroborated transfers — newest first. Cross-division with no scope parameters; filter by kind (player or coach), sport path, and a since timestamp; cursor-paginated. Entries carry a display snapshot of the person (never contact info) plus person and transfer ids that join into /v1/persons and transfer histories.
- Entries are curated: an event only appears once our pipeline confirms it (portal-corroborated transfers, verified head-coach changes) or an editor publishes it — this is not the raw scraper diff stream.
- SDKs 0.3.0 (PyPI and npm) add the movements resource: client.movements.list(...) in both.

Links: Movements docs: https://magisterial.ai/docs#get-movements

## 2026-07-21 — Games listing, coaching staffs, and bulk exports
Tags: added, changed

- GET /v1/games is live: list games in a sport/division scope, newest first, with team, season, date-range, and status filters. One row per real-world game, side-anchored (home/away), with team ids — no more perspective-duplicated rows.
- GET /v1/teams/{team_id}/coaches is live: the coaching staff for a team-season, head coach first, defaulting to the latest season held. Coach email is included for Pro/Max accounts only, matching the portal-contacts carve-out.
- Behavior change on GET /v1/games/{game_id}: game ids now come from our fixture store — the same ids GET /v1/games returns and /v1/query answers reference (previously the two id spaces did not match). Ids fetched before today no longer resolve; re-list via GET /v1/games. The payload is richer: the fixture under detail.game plus team and player box scores, play-by-play, and per-sport extras (drives, recaps).
- Bulk exports: POST /v1/exports starts an async job that writes players, teams, games, or coaches for one sport/division scope to a gzipped CSV or JSONL flat file; GET /v1/exports/{export_id} returns a short-lived signed download URL when it succeeds. Usage-billed on success by result size ($0.10 per started 10,000-row block); failed exports are never billed. Files are kept for 7 days.

Links: Games docs: https://magisterial.ai/docs#get-games · Bulk exports docs: https://magisterial.ai/docs#exports

## 2026-07-21 — Interactive docs, retrievable test keys, and this changelog
Tags: added, changed

- The API reference at /docs is now interactive: sign in and every example is pre-filled with your own test key, with a Run it button that sends real requests from the browser and shows status, latency, and rate-limit headers.
- Test keys (mag_test_) are now retrievable: the docs playground fetches your newest test key automatically (minting a "Docs playground" key on first visit), and test-key tokens are stored encrypted so they can be re-shown. Live keys remain visible only once, at creation.
- Behavior change for test keys: they now return 403 test_key_paid_endpoint on the usage-billed endpoints (/v1/portal, /v1/query, /v1/alerts). All free read endpoints keep working unchanged, so a test key can never create charges.
- Published our versioning and deprecation policy — at least 90 days' notice before any breaking change to /v1, with Deprecation and Sunset response headers on affected endpoints.

Links: Authentication docs: https://magisterial.ai/docs#authentication · Deprecation policy: https://magisterial.ai/changelog#policy

## 2026-07-21 — Coverage endpoint and published OpenAPI spec
Tags: added

- GET /v1/coverage: the full data-coverage matrix — per sport and division, how many teams, coaches, games, and players we hold, with season ranges and transfer-portal tracking counts. Free at the standard read rate limit; use it to confirm coverage before issuing billed requests.
- The complete API contract is now published as OpenAPI 3.1 at https://api.magisterial.ai/v1/openapi.json, with an interactive rendering at https://api.magisterial.ai/v1/docs. Import it into Postman, generate typed clients, or hand it to an agent.

Links: Coverage endpoint docs: https://magisterial.ai/docs#get-coverage

## 2026-07-20 — Rich cards in the Claude connector; billing accuracy fixes
Tags: added, fixed

- The MCP connector now returns rich inline widgets in claude.ai: player and coach cards with headshots and season stats, and results tables with charts.
- Fixed token accounting on /v1/query: prompt-cache activity is now billed correctly end-to-end, and a double-billing path for /v1 runs was closed. If you saw slightly inconsistent billed_usd values on query runs before this date, this is why.

Links: Connectors: https://magisterial.ai/connectors

## 2026-07-15 — Football opens on /v1; web-search-augmented queries
Tags: added, changed

- Football is now queryable through the public API, including the D1-FBS and D1-FCS subdivisions and 3C2A, everywhere a division scope is accepted.
- Natural-language query runs can now consult the web to fill gaps (recent news, off-dataset context) when the account's plan includes it, and inline coach cards appear in answers where relevant.

## 2026-07-13 — Developer platform launch
Tags: added

- API keys (live and test) managed from the developer console, with rotate and revoke.
- The /v1 API: players search and profiles, season stats, teams and rosters, cross-program careers and transfers, games, conferences, and the filter catalog — free at 120 requests/minute.
- Usage-billed endpoints with a monthly budget cap you control: the live transfer-portal feed ($0.05/request), natural-language query (model cost with markup), and portal watch alerts ($5/alert/month) with match polling.
- MCP server with OAuth 2.1 at https://api.magisterial.ai/mcp, so Claude and other MCP clients can use Magisterial directly.

Links: API reference: https://magisterial.ai/docs · Pricing: https://magisterial.ai/pricing
