Skip to content

Academic API ​

Base URL: /api/v1/academic/

Manage academic calendar, courses, sections, degrees, majors, minors, and requirements.

Endpoints Overview ​

Academic Calendar ​

ResourceEndpointDescription
Academic Years/academic-yearsAcademic year management
Terms/termsTerm/semester management
Sub-Terms/sub-termsSub-term management
Term Campus Offerings/term-campus-offeringsCampus-specific term availability

Courses & Sections ​

ResourceEndpointDescription
Courses/coursesCourse catalog management
Course Attributes/course-attributesCourse attribute tags
Course Requisites/course-requisitesPrerequisites/corequisites
Course Equivalents/course-equivalentsCourse equivalencies
Course Patterns/course-patternsFlexible course matching patterns
Course Substitutions/course-substitutionsCourse substitution rules
Student Course Substitutions/student-course-substitutionsStudent-specific substitutions
Course Bulletins/course-bulletinsCourse-to-bulletin assignments
Course Materials/course-materialsCourse material assignments
Sections/sectionsCourse section management
Section Schedules/section-schedulesMeeting times
Section Instructors/section-instructorsInstructor assignments
Section Materials/section-materialsSection material assignments
Section Scheduling/sections/{sectionID}/schedulingMeeting times for a section
Materials/materialsMaterial/textbook catalog

Programs & Requirements ​

ResourceEndpointDescription
Degrees/degreesDegree programs
Degree Levels/degree-levelsDegree level definitions (Bachelor's, Master's, etc.)
Degree Blocks/degree-blocksDegree-to-requirement block associations
Majors/majorsMajor programs
Minors/minorsMinor programs
Requirement Blocks/requirement-blocksDegree requirement blocks
Requirement Items/requirement-itemsItems within requirement blocks
Requirement Groups/requirement-groupsRequirement groupings
Requirement Group Rules/requirement-group-rulesRules within requirement groups
Schedule Templates/schedule-templatesSchedule template management

Grading & Bulletins ​

ResourceEndpointDescription
Grading Systems/grading-systemsGrading scale definitions
Grades/gradesGrade values within systems
Bulletins/bulletinsCourse catalogs by year

Academic Calendar ​

Academic Years ​

List Academic Years ​

GET /api/v1/academic/academic-years

Query Parameters ​

ParameterTypeDescription
is_currentbooleanFilter by current year
searchstringSearch in year_code
orderingstringSort by: year_code, start_date

Success Response (200 OK) ​

json
{
  "count": 5,
  "results": [
    {
      "academic_year_id": 1,
      "year_code": "2024-2025",
      "start_date": "2024-08-01",
      "end_date": "2025-07-31",
      "is_current": true,
      "term_count": 3
    }
  ]
}

Custom Actions ​

ActionMethodEndpointDescription
Get TermsGET/academic-years/{id}/termsGet all terms for a year
CurrentGET/academic-years/currentGet the current academic year

Academic Terms ​

List Terms ​

GET /api/v1/academic/terms

Query Parameters ​

ParameterTypeDescription
academic_yearintegerFilter by academic year ID
is_currentbooleanFilter by current term
term_type_idintegerFilter by term type
searchstringSearch in term_code, term_name
orderingstringSort by: start_date, term_code

Success Response (200 OK) ​

json
{
  "count": 12,
  "results": [
    {
      "term_id": 1,
      "term_code": "FA2024",
      "term_name": "Fall 2024",
      "academic_year_id": 1,
      "academic_year_code": "2024-2025",
      "term_type_code": "FALL",
      "start_date": "2024-08-26",
      "end_date": "2024-12-13",
      "registration_open_date": "2024-04-01",
      "is_current": true
    }
  ]
}

Custom Actions ​

ActionMethodEndpointDescription
CurrentGET/terms/currentGet the current term
SectionsGET/terms/{id}/sectionsGet sections offered in term
AvailableGET/terms/available_for_registrationTerms open for registration. With student_id, a term with registration windows also carries my_registration_opens_on and my_registration_window for that student

add_deadline is the add/drop deadline. On create and update it must be on or before withdrawal_deadline (validation error on add_deadline), and drop_deadline is set equal to it: drop_deadline is returned but not accepted, and a value sent is ignored (migration 300). An update that touches neither deadline leaves them as they are, so past summer terms that keep their own drop date can still be edited. The database also holds drop_deadline <= withdrawal_deadline as a CHECK. registration_open_date cannot be moved after the term's earliest registration window.

Registration Windows ​

Staged registration start dates for a term (migration 289). A student may register from the earliest window whose rule they match. A window with rule: null is "everyone else", at most one per term. See Registration Windows.

MethodEndpointNodeDescription
GET/terms/{termID}/registration-windowsACADEMIC.TERMSThe term's windows and its open date
GET/terms/{termID}/registration-windows/preview[?student_id=]ACADEMIC.TERMSHow many current students each window decides; with student_id, that student's day and the facts behind it
POST/terms/{termID}/registration-windowsACADEMIC.REGISTRATION_WINDOWSCreate a window
PUT/terms/{termID}/registration-windows/{windowID}ACADEMIC.REGISTRATION_WINDOWSReplace a window
DELETE/terms/{termID}/registration-windows/{windowID}ACADEMIC.REGISTRATION_WINDOWSDelete a window
POST/registration-windows/rule-matchesACADEMIC.REGISTRATION_WINDOWSCount the current students an unsaved rule selects
GET/registration-windows/fieldsACADEMIC.REGISTRATION_WINDOWSFields a rule may test

Request Body (POST, PUT) ​

FieldTypeRequiredDescription
namestringYesMax 100
start_datedateYesYYYY-MM-DD, on or after the term's registration_open_date
ruleobject | nullNoExpression tree (internal/shared/expr, the same language as the billing selectors). null = everyone else
sort_orderintegerNo

Rule fields: campus, program (major), minor, cohort, student_list, academic_level, class_standing, academic_status, gpa (cumulative, at the student's level). Each node has a kind: and / or / not with children, or test with field, op and value (or values for in). Test operators are eq, ne, in, matches, not_matches (a trailing % pattern), gte, lte, gt, lt, is_set and is_not_set.

A second everyone-else window is refused with 409, and so is deleting the everyone-else window while group windows remain.

List Response ​

json
{
  "term_id": 42,
  "registration_open_date": "2026-11-02",
  "has_everyone_window": true,
  "fields": ["campus", "program", "minor", "cohort", "student_list", "academic_level", "class_standing", "academic_status", "gpa"],
  "windows": [
    {
      "term_registration_window_id": 7,
      "term_id": 42,
      "name": "Seniors",
      "start_date": "2026-11-02",
      "rule": { "kind": "test", "field": "class_standing", "op": "eq", "value": "SR" },
      "rule_description": "class standing is SR",
      "is_everyone": false,
      "sort_order": 0
    }
  ]
}

Enforcement is in registration: the cart (REGISTRATION_CLOSED, excused by the transaction's override_deadline), plan submission, direct registration and joining a waitlist. On the direct paths a caller holding REGISTRATION.OVERRIDE.DEADLINE is not held to the window.

TypeScript Types ​

typescript
interface AcademicTerm {
  term_id: number
  academic_year_id: number
  academic_year_code: string
  term_code: string
  term_name: string
  term_type_code: string
  term_type_display: string
  start_date: string
  end_date: string
  census_date: string | null
  add_deadline: string | null
  drop_deadline: string | null
  withdrawal_deadline: string | null
  grades_due_date: string | null
  registration_open_date: string | null
  is_current: boolean
  is_offered_at_all_campuses: boolean
  sub_terms?: SubTerm[]
  campus_offerings?: TermCampusOffering[]
}

Courses ​

List Courses ​

GET /api/v1/academic/courses

Query Parameters ​

ParameterTypeDescription
departmentintegerFilter by department ID
status_idintegerFilter by status
is_repeatablebooleanFilter repeatable courses
grading_systemintegerFilter by grading system
searchstringSearch in course_code, title, description
orderingstringSort by: course_code, title, created_at

Success Response (200 OK) ​

json
{
  "count": 500,
  "results": [
    {
      "course_id": 101,
      "course_code": "MATH 101",
      "title": "College Algebra",
      "description": "Fundamental concepts of algebra...",
      "department_id": 5,
      "department_code": "MATH",
      "department_name": "Mathematics",
      "credit_display": "3",
      "status_code": "ACTIVE",
      "status_display": "Active",
      "effective_date": "2024-01-01",
      "in_current_bulletin": true,
      "bulletin_count": 2
    }
  ]
}

Get Course Details ​

GET /api/v1/academic/courses/{id}

Returns full course details including attributes, requisites, and equivalents.

Custom Actions ​

ActionMethodEndpointDescription
SearchGET/courses/search?q={query}Quick search (min 2 chars)
SectionsGET/courses/{id}/sectionsGet sections for course
EquivalentsGET/courses/{id}/equivalentsGet course equivalents
MaterialsGET/courses/{id}/materialsGet assigned materials

Create/Update Course ​

POST /api/v1/academic/courses
PATCH /api/v1/academic/courses/{id}
FieldTypeRequiredDescription
course_codestringYesUnique course code
titlestringYesCourse title
descriptionstringNoCourse description
department_idintegerYesDepartment ID
credit_hours_mindecimalYesMinimum credits
credit_hours_maxdecimalYesMaximum credits
contact_hoursdecimalNoContact hours
is_variable_creditbooleanNoThe course may carry a credit range. Students choose credits only on sections that also set is_variable_credit
is_repeatablebooleanNoRepeatable for credit
max_repeatsintegerNoTotal attempts allowed for a repeatable course, the first included; blank or 0 = unlimited
grading_system_idintegerNoGrading system
status_idintegerYesStatus

TypeScript Types ​

typescript
interface Course {
  course_id: number
  course_code: string
  title: string
  description: string | null
  department_id: number
  department_code: string
  department_name: string
  credit_hours_min: number
  credit_hours_max: number
  credit_display: string
  is_variable_credit: boolean
  is_repeatable: boolean
  status_code: string
  status_display: string
  attributes?: CourseAttribute[]
  requisites?: CourseRequisite[]
  equivalents?: CourseEquivalent[]
}

Course Sections ​

List Sections ​

GET /api/v1/academic/sections

Query Parameters ​

ParameterTypeDescription
course_idintegerFilter by course ID
term_idintegerFilter by term ID
campus_idintegerFilter by campus
section_status_idintegerFilter by status
searchstringSearch in section_code, course code
orderingstringSort by section_code (default), max_enrollment or current_enrollment; prefix with - to reverse

There is no modality filter

Neither instruction_mode_id nor instructional_method_id is a supported query parameter. Both are returned on each section (see below), but the list endpoint cannot be filtered by either — CourseSectionQueryParams in internal/domain/academic/repository.go is the exact set, and an unrecognised ordering value falls back to the default rather than erroring.

Success Response (200 OK) ​

json
{
  "count": 1500,
  "results": [
    {
      "section_id": 512,
      "course_id": 101,
      "course_code": "MATH 101",
      "course_title": "College Algebra",
      "section_code": "001",
      "term_id": 8,
      "term_code": "FA2024",
      "instruction_mode_code": "IN_PERSON",
      "instruction_mode_display": "In Person",
      "instructional_method_code": "LEC",
      "instructional_method_display": "Lecture",
      "section_status_code": "OPEN",
      "section_status_display": "Open",
      "campus_id": 1,
      "campus_name": "Main Campus",
      "enrollment_count": 25,
      "enrollment_max": 30,
      "waitlist_count": 2,
      "waitlist_max": 10,
      "credits": 3.0
    }
  ]
}

Modality and pedagogy are two different fields ​

A section carries both, and they answer different questions. Reading one for the other is the mistake migration 263 exists to prevent.

FieldLookupValuesAnswersOrigin
instruction_mode_idINSTRUCTION_MODE4 — IN_PERSON, ONLINE, HYBRID, REMOTEWhere is the student?Derived by the importer
instructional_method_idINSTRUCTIONAL_METHOD26 — LEC, LAB, SEM, ONL, HYB, …What kind of teaching is it?Declared by Colleague, stored verbatim

Twenty-four of the twenty-six methods say nothing about modality at all; only ONL and HYB overlap, and those are two of the inputs the mode is derived from. Storing the declared method alongside the derived mode is what lets the derivation rule be re-audited, or changed, without re-importing from ODS.

Both are returned as *_code / *_display pairs, and both are null on sections Colleague has not declared. See Section fields for the derivation rule itself.

Custom Actions ​

ActionMethodEndpointDescription
SchedulingGET/sections/{sectionID}/schedulingGet meeting times and rooms
Set schedulingPOST/sections/{sectionID}/schedulingCreate or replace the schedule
Clear schedulingDELETE/sections/{sectionID}/schedulingRemove the schedule
LinkPOST/sections/{sectionID}/scheduling/linkLink to another section's schedule
UnlinkPOST/sections/{sectionID}/scheduling/unlinkBreak a schedule link
RosterGET/sections/{sectionID}/rosterGet the roster
AvailableGET/sections/availableGet available sections for registration
MaterialsGET/sections/{id}/materialsGet assigned materials

Variable credits ​

Sections carry is_variable_credit (students choose their credits) and credit_increment (default 1, must be > 0), both writable on create and update (migration 279). Responses also include effective_credit_hours_min and effective_credit_hours_max, which are the section's own range or else the course's.

Saving is_variable_credit: true is refused (validation error) when the course is not a variable-credit course, when the range does not span at least one increment, or when billing_credits is set. A variable section bills the credits the student chose. The choice is sent to registration as credits (direct registration) or credits_selected (plans and transaction items); see the Registration API.

Requisites ​

/course-requisites reads and writes the hand-entered records.course_requisites rows. Registration enforces the imported Colleague rules instead (records.course_requisite_links, migration 285, which no API route writes), and of the hand-entered rows only corequisites (COREQ / COREQUISITE) are checked, as warnings. See Course fields.


Programs ​

Degree Levels ​

Manage degree level definitions (Bachelor's, Master's, Doctorate, etc.).

MethodEndpointDescription
GET/degree-levelsList all degree levels
GET/degree-levels/{levelID}Get degree level details

Read-only reference data — no create, update or delete endpoint exists, and these are gated on ACADEMIC.YEARS rather than ACADEMIC.DEGREES.


Degrees ​

List Degrees ​

GET /api/v1/academic/degrees

Query Parameters ​

ParameterTypeDescription
degree_levelintegerFilter by degree level ID
status_idintegerFilter by status
departmentintegerFilter by department
searchstringSearch in degree_code, name

Success Response (200 OK) ​

json
{
  "count": 50,
  "results": [
    {
      "degree_id": 1,
      "degree_code": "BS-CS",
      "name": "Bachelor of Science in Computer Science",
      "degree_level_id": 1,
      "degree_level_name": "Bachelor's",
      "department_id": 10,
      "department_name": "Computer Science",
      "total_credits_required": 120,
      "status_code": "ACTIVE",
      "status_display": "Active",
      "major_count": 1,
      "requirement_block_count": 8
    }
  ]
}

Custom Actions ​

ActionMethodEndpointDescription
BlocksGET/degrees/{id}/blocksGet requirement blocks for degree
Add BlockPOST/degrees/{id}/add_blockAssociate a requirement block
Remove BlockDELETE/degrees/{id}/remove_blockRemove a requirement block association
CopyPOST/degrees/{id}/copyCopy a degree with its blocks

Degree Blocks ​

Manage associations between degrees and requirement blocks.

MethodEndpointDescription
GET/degree-blocksList degree-block associations
POST/degree-blocksCreate association
GET/degree-blocks/{id}Get association details
PATCH/degree-blocks/{id}Update association
DELETE/degree-blocks/{id}Delete association

Majors ​

List Majors ​

GET /api/v1/academic/majors

Success Response (200 OK) ​

json
{
  "count": 75,
  "results": [
    {
      "major_id": 1,
      "major_code": "CS",
      "name": "Computer Science",
      "department_id": 10,
      "department_name": "Computer Science",
      "degree_ids": [1, 2],
      "status_code": "ACTIVE",
      "credits_required": 45
    }
  ]
}

Custom Actions ​

ActionMethodEndpointDescription
BlocksGET/majors/{id}/blocksGet requirement blocks for major
Add BlockPOST/majors/{id}/add_blockAssociate a requirement block
Remove BlockDELETE/majors/{id}/remove_blockRemove a requirement block association
CampusesGET/majors/{id}/campusesGet campus offerings
Add CampusPOST/majors/{id}/add_campusAdd campus offering
Remove CampusPOST/majors/{majorID}/remove_campusRemove campus offering (POST, not DELETE)
Add Degree LevelPOST/majors/{id}/add_degree_levelAdd degree level association
Remove Degree LevelDELETE/majors/{id}/remove_degree_levelRemove degree level association
Add DegreePOST/majors/{id}/add_degreeAdd degree association
Remove DegreeDELETE/majors/{id}/remove_degreeRemove degree association

Major Default Advisors ​

MethodEndpointDescription
GET/major-default-advisorsList default advisors
GET/major-default-advisors/for_majorDefault advisors for one major
GET/major-default-advisors/{advisorID}Get one default advisor
POST/major-default-advisorsAdd default advisor
PATCH/major-default-advisors/{advisorID}Update default advisor
DELETE/major-default-advisors/{advisorID}Remove default advisor

Minors ​

List Minors ​

GET /api/v1/academic/minors

Success Response (200 OK) ​

json
{
  "count": 30,
  "results": [
    {
      "minor_id": 1,
      "minor_code": "MATH-MIN",
      "name": "Mathematics Minor",
      "department_id": 5,
      "department_name": "Mathematics",
      "status_code": "ACTIVE",
      "credits_required": 18
    }
  ]
}

Custom Actions ​

ActionMethodEndpointDescription
BlocksGET/minors/{minorID}/blocksGet requirement blocks for minor
CampusesGET/minors/{minorID}/campusesGet campus offerings
Add CampusPOST/minors/{minorID}/add_campusAdd campus offering
Remove CampusPOST/minors/{minorID}/remove_campusRemove campus offering

Minors have no block, degree or degree-level association endpoints — only campus offerings. Removing a campus is a POST, not a DELETE.

Minor Default Advisors ​

MethodEndpointDescription
GET/minor-default-advisorsList default advisors
GET/minor-default-advisors/for_minorDefault advisors for one minor
GET/minor-default-advisors/{advisorID}Get one default advisor
POST/minor-default-advisorsAdd default advisor
PATCH/minor-default-advisors/{advisorID}Update default advisor
DELETE/minor-default-advisors/{advisorID}Remove default advisor

Degree Default Advisors ​

MethodEndpointDescription
GET/degree-default-advisorsList default advisors
GET/degree-default-advisors/for_degreeDefault advisors for one degree
GET/degree-default-advisors/{advisorID}Get one default advisor
POST/degree-default-advisorsAdd default advisor
PATCH/degree-default-advisors/{advisorID}Update default advisor
DELETE/degree-default-advisors/{advisorID}Remove default advisor

Requirement Blocks ​

List Requirement Blocks ​

GET /api/v1/academic/requirement-blocks

Query Parameters ​

ParameterTypeDescription
degreeintegerFilter by degree ID
majorintegerFilter by major ID
minorintegerFilter by minor ID
block_type_idintegerFilter by block type
searchstringSearch in block_code, name

Success Response (200 OK) ​

json
{
  "count": 200,
  "results": [
    {
      "block_id": 1,
      "block_code": "CS-CORE",
      "name": "Computer Science Core Requirements",
      "block_type_code": "MAJOR_CORE",
      "block_type_display": "Major Core",
      "credits_required": 24,
      "courses_required": 8,
      "item_count": 8
    }
  ]
}

Custom Actions ​

ActionMethodEndpointDescription
GroupsGET/requirement-blocks/{id}/groupsGet requirement groups within block
ChildrenGET/requirement-blocks/{id}/childrenGet child blocks
CopyPOST/requirement-blocks/{id}/copyCopy a requirement block

Requirement Items ​

GET /api/v1/academic/requirement-items

Individual courses or course patterns that satisfy requirements.

Success Response (200 OK) ​

json
{
  "count": 500,
  "results": [
    {
      "item_id": 1,
      "block_id": 1,
      "course_id": 201,
      "course_code": "CS 101",
      "course_title": "Intro to Programming",
      "credits": 3,
      "is_required": true,
      "sequence_number": 1
    }
  ]
}

Requirement Groups ​

Manage logical groupings of requirements within blocks.

MethodEndpointDescription
GET/requirement-groupsList requirement groups
POST/requirement-groupsCreate requirement group
GET/requirement-groups/{id}Get requirement group details
PATCH/requirement-groups/{id}Update requirement group
DELETE/requirement-groups/{id}Delete requirement group

Requirement Group Rules ​

Manage rules within requirement groups (e.g., "choose 3 of the following").

MethodEndpointDescription
GET/requirement-group-rulesList group rules
POST/requirement-group-rulesCreate group rule
GET/requirement-group-rules/{id}Get group rule details
PATCH/requirement-group-rules/{id}Update group rule
DELETE/requirement-group-rules/{id}Delete group rule

Course Patterns ​

Flexible course matching patterns used in requirements (e.g., "any 300-level MATH course").

Custom Actions ​

ActionMethodEndpointDescription
Test PatternPOST/course-patterns/test_patternTest a pattern against course catalog
PreviewGET/course-patterns/{id}/previewPreview matching courses

Course Equivalents ​

Manage course equivalency relationships.

MethodEndpointDescription
GET/course-equivalentsList all equivalencies
POST/course-equivalentsCreate equivalency
DELETE/course-equivalents/{id}Delete equivalency
GET/courses/{id}/equivalentsGet equivalents for a specific course

Course Substitutions ​

Manage course substitution rules (institutional-level substitution policies).

MethodEndpointDescription
GET/course-substitutionsList substitution rules
POST/course-substitutionsCreate substitution rule
GET/course-substitutions/{id}Get substitution rule details
PATCH/course-substitutions/{id}Update substitution rule
DELETE/course-substitutions/{id}Delete substitution rule

Student Course Substitutions ​

Manage student-specific course substitutions with approval workflow.

MethodEndpointDescription
GET/student-course-substitutionsList student substitutions
POST/student-course-substitutionsCreate student substitution
GET/student-course-substitutions/{id}Get substitution details
PATCH/student-course-substitutions/{id}Update substitution
DELETE/student-course-substitutions/{id}Delete substitution
POST/student-course-substitutions/{id}/advisor-approveAdvisor approval
POST/student-course-substitutions/{id}/registrar-approveRegistrar approval
POST/student-course-substitutions/{id}/deactivateDeactivate substitution

Schedule Templates ​

Manage reusable schedule templates for course sections.

MethodEndpointDescription
GET/schedule-templatesList schedule templates
POST/schedule-templatesCreate schedule template
GET/schedule-templates/dropdownGet templates for dropdown selection
GET/schedule-templates/{id}Get template details
PATCH/schedule-templates/{id}Update template
DELETE/schedule-templates/{id}Delete template

Classes ​

Retired. Scheduling became section-centric in July 2026. /classes is gone and no /classes/{id}/* sub-resource exists; the frontend route redirects to /sections, and the REGISTRATION.CLASSES permission node survives only as an inactive row.

Use /sections/{sectionID}/scheduling and /sections/{sectionID}/roster instead.

The records.classes and records.class_sections tables do still exist as lazily created schedule containers for cross-listed sections, and /class-schedules below is the live source of meeting times. The retired thing is the concept in the interface, not the tables.


Class Schedules ​

Manage individual class meeting schedules.

MethodEndpointDescription
GET/class-schedulesList class schedules
POST/class-schedulesCreate class schedule
GET/class-schedules/{id}Get schedule details
PATCH/class-schedules/{id}Update schedule
DELETE/class-schedules/{id}Delete schedule
POST/class-schedules/check_conflictCheck for scheduling conflicts

Materials ​

Manage the material/textbook catalog.

MethodEndpointDescription
GET/materialsList all materials
POST/materialsCreate material
GET/materials/{id}Get material details
PATCH/materials/{id}Update material
DELETE/materials/{id}Delete material

Course Materials ​

Manage material assignments to courses.

MethodEndpointDescription
GET/courses/{courseID}/materialsList materials for a course
POST/courses/{courseID}/materialsAssign material to course
POST/sections/{sectionID}/materialsAttach a material to a section
GET/course-materials/{id}Get course material assignment details
PATCH/course-materials/{id}Update course material assignment
DELETE/course-materials/{id}Delete course material assignment

Section Materials ​

Manage material assignments to sections.

MethodEndpointDescription
GET/sections/{sectionID}/materialsList materials for a section
POST/sections/{sectionID}/materialsAssign material to section
GET/section-materials/{id}Get section material assignment details
PATCH/section-materials/{id}Update section material assignment
DELETE/section-materials/{id}Delete section material assignment

Grading Systems ​

List Grading Systems ​

GET /api/v1/academic/grading-systems

Success Response (200 OK) ​

json
{
  "count": 3,
  "results": [
    {
      "grading_system_id": 1,
      "system_code": "STANDARD",
      "name": "Standard Letter Grades",
      "description": "Traditional A-F grading",
      "is_active": true,
      "grade_count": 12
    }
  ]
}

Grades ​

GET /api/v1/academic/grades

Query Parameters ​

ParameterTypeDescription
grading_systemintegerFilter by grading system ID
is_passingbooleanFilter passing grades
counts_toward_gpabooleanFilter GPA-counted grades

Success Response (200 OK) ​

json
{
  "count": 12,
  "results": [
    {
      "grade_id": 1,
      "grading_system_id": 1,
      "letter_grade": "A",
      "display_name": "A",
      "quality_points": 4.0,
      "is_passing": true,
      "counts_toward_gpa": true,
      "sort_order": 1
    },
    {
      "grade_id": 10,
      "grading_system_id": 1,
      "letter_grade": "W",
      "display_name": "Withdrawal",
      "quality_points": null,
      "is_passing": false,
      "counts_toward_gpa": false,
      "sort_order": 10
    }
  ]
}

Bulletins (Course Catalogs) ​

List Bulletins ​

GET /api/v1/academic/bulletins

Success Response (200 OK) ​

json
{
  "count": 5,
  "results": [
    {
      "bulletin_id": 3,
      "bulletin_code": "2024-2025",
      "name": "2024-2025 Undergraduate Catalog",
      "effective_date": "2024-08-01",
      "is_current": true,
      "course_count": 500
    }
  ]
}

Custom Actions ​

ActionMethodEndpointDescription
CurrentGET/bulletins/currentGet the current bulletin
CoursesGET/bulletins/{id}/coursesGet courses in a bulletin
Copy CoursesPOST/bulletins/{id}/copy_coursesCopy courses from another bulletin

Course Bulletins ​

Manage course-to-bulletin assignments.

MethodEndpointDescription
GET/course-bulletinsList course-bulletin assignments
POST/course-bulletinsCreate assignment
GET/course-bulletins/{id}Get assignment details
PATCH/course-bulletins/{id}Update assignment
DELETE/course-bulletins/{id}Delete assignment
POST/course-bulletins/bulk_createBulk assign courses to bulletin



Complete endpoint reference ​

Every route this domain registers, with the permission node that gates it. Generated from the route table, so it is complete by construction — the sections above explain behaviour, this one guarantees nothing is missing.

Paths are relative to /api/v1/academic. A node in italics is an exemption rather than a grant: selfservice acts only on the caller's own record, public needs no session at all, and custom carries its own wrapper.

MethodEndpointPermission nodeDescription
GET/academic-yearsACADEMIC.YEARSList academic years
POST/academic-yearsACADEMIC.YEARSCreate a academic year
GET/academic-years/currentACADEMIC.YEARSGet the current record
DELETE/academic-years/{yearID}ACADEMIC.YEARSDelete a academic year
GET/academic-years/{yearID}ACADEMIC.YEARSGet one academic year
PATCH/academic-years/{yearID}ACADEMIC.YEARSUpdate a academic year
GET/academic-years/{yearID}/termsACADEMIC.YEARSList the academic year's terms
GET/bulletinsACADEMIC.BULLETINSList bulletins
POST/bulletinsACADEMIC.BULLETINSCreate a bulletin
GET/bulletins/currentACADEMIC.BULLETINSGet the current record
DELETE/bulletins/{bulletinID}ACADEMIC.BULLETINSDelete a bulletin
GET/bulletins/{bulletinID}ACADEMIC.BULLETINSGet one bulletin
PATCH/bulletins/{bulletinID}ACADEMIC.BULLETINSUpdate a bulletin
POST/bulletins/{bulletinID}/copy_coursesACADEMIC.BULLETINSCopy courses for a bulletin
GET/bulletins/{bulletinID}/coursesACADEMIC.BULLETINSList the bulletin's courses
GET/class-schedulesREGISTRATION.SECTIONSList class schedules
POST/class-schedulesREGISTRATION.SECTIONSCreate a class schedule
POST/class-schedules/check_conflictREGISTRATION.SECTIONSCheck conflict
DELETE/class-schedules/{scheduleID}REGISTRATION.SECTIONSDelete a class schedule
GET/class-schedules/{scheduleID}REGISTRATION.SECTIONSGet one class schedule
PATCH/class-schedules/{scheduleID}REGISTRATION.SECTIONSUpdate a class schedule
POST/course-attributesACADEMIC.COURSESCreate a course attribute
DELETE/course-attributes/{attributeID}ACADEMIC.COURSESDelete a course attribute
GET/course-bulletinsACADEMIC.BULLETINSList course bulletins
POST/course-bulletinsACADEMIC.BULLETINSCreate a course bulletin
POST/course-bulletins/bulk_createACADEMIC.BULLETINSBulk create
DELETE/course-bulletins/{courseBulletinID}ACADEMIC.BULLETINSDelete a course bulletin
GET/course-bulletins/{courseBulletinID}ACADEMIC.BULLETINSGet one course bulletin
PATCH/course-bulletins/{courseBulletinID}ACADEMIC.BULLETINSUpdate a course bulletin
GET/course-equivalentsACADEMIC.COURSESList course equivalents
POST/course-equivalentsACADEMIC.COURSESCreate a course equivalent
DELETE/course-equivalents/{equivalentID}ACADEMIC.COURSESDelete a course equivalent
DELETE/course-materials/{courseMaterialID}ACADEMIC.COURSESDelete a course material
GET/course-materials/{courseMaterialID}ACADEMIC.COURSESGet one course material
PATCH/course-materials/{courseMaterialID}ACADEMIC.COURSESUpdate a course material
GET/course-patternsACADEMIC.PATTERNSList course patterns
POST/course-patternsACADEMIC.PATTERNSCreate a course pattern
POST/course-patterns/test_patternACADEMIC.PATTERNSCreate test pattern
DELETE/course-patterns/{patternID}ACADEMIC.PATTERNSDelete a course pattern
GET/course-patterns/{patternID}ACADEMIC.PATTERNSGet one course pattern
PATCH/course-patterns/{patternID}ACADEMIC.PATTERNSUpdate a course pattern
GET/course-patterns/{patternID}/previewACADEMIC.PATTERNSPreview for a course pattern
GET/course-requisitesACADEMIC.COURSESList course requisites
POST/course-requisitesACADEMIC.COURSESCreate a course requisite
DELETE/course-requisites/{requisiteID}ACADEMIC.COURSESDelete a course requisite
GET/course-requisites/{requisiteID}ACADEMIC.COURSESGet one course requisite
PATCH/course-requisites/{requisiteID}ACADEMIC.COURSESUpdate a course requisite
GET/course-substitutionsACADEMIC.COURSE_SUBSTITUTIONSList course substitutions
POST/course-substitutionsACADEMIC.COURSE_SUBSTITUTIONSCreate a course substitution
DELETE/course-substitutions/{substitutionID}ACADEMIC.COURSE_SUBSTITUTIONSDelete a course substitution
GET/course-substitutions/{substitutionID}ACADEMIC.COURSE_SUBSTITUTIONSGet one course substitution
PATCH/course-substitutions/{substitutionID}ACADEMIC.COURSE_SUBSTITUTIONSUpdate a course substitution
GET/coursesACADEMIC.COURSESList courses
POST/coursesACADEMIC.COURSESCreate a cours
GET/courses/credit-valuesACADEMIC.COURSESList credit values
GET/courses/searchACADEMIC.COURSESSearch
DELETE/courses/{courseID}ACADEMIC.COURSESDelete a cours
GET/courses/{courseID}ACADEMIC.COURSESGet one cours
PATCH/courses/{courseID}ACADEMIC.COURSESUpdate a cours
GET/courses/{courseID}/attributesACADEMIC.COURSESList the course's attributes
GET/courses/{courseID}/equivalentsACADEMIC.COURSESList the cours's equivalents
GET/courses/{courseID}/materialsACADEMIC.COURSESList the cours's materials
POST/courses/{courseID}/materialsACADEMIC.COURSESAdd materials to a cours
POST/courses/{courseID}/materials/pushACADEMIC.COURSESPush
GET/courses/{courseID}/sectionsREGISTRATION.SECTIONSList the cours's sections
GET/degree-blocksACADEMIC.DEGREESList degree blocks
POST/degree-blocksACADEMIC.DEGREESCreate a degree block
DELETE/degree-blocks/{degreeBlockID}ACADEMIC.DEGREESDelete a degree block
GET/degree-blocks/{degreeBlockID}ACADEMIC.DEGREESGet one degree block
PATCH/degree-blocks/{degreeBlockID}ACADEMIC.DEGREESUpdate a degree block
GET/degree-default-advisorsACADEMIC.DEGREESList degree default advisors
POST/degree-default-advisorsACADEMIC.DEGREESCreate a degree default advisor
GET/degree-default-advisors/for_degreeACADEMIC.DEGREESGet for degree
DELETE/degree-default-advisors/{advisorID}ACADEMIC.DEGREESDelete a degree default advisor
GET/degree-default-advisors/{advisorID}ACADEMIC.DEGREESGet one degree default advisor
PATCH/degree-default-advisors/{advisorID}ACADEMIC.DEGREESUpdate a degree default advisor
GET/degree-levelsACADEMIC.YEARSList degree levels
GET/degree-levels/{levelID}ACADEMIC.YEARSGet one degree level
GET/degreesACADEMIC.DEGREESList degrees
POST/degreesACADEMIC.DEGREESCreate a degree
DELETE/degrees/{degreeID}ACADEMIC.DEGREESDelete a degree
GET/degrees/{degreeID}ACADEMIC.DEGREESGet one degree
PATCH/degrees/{degreeID}ACADEMIC.DEGREESUpdate a degree
POST/degrees/{degreeID}/add_blockACADEMIC.DEGREESAdd block for a degree
GET/degrees/{degreeID}/blocksACADEMIC.DEGREESList the degree's blocks
POST/degrees/{degreeID}/copyACADEMIC.DEGREESAdd copy to a degree
DELETE/degrees/{degreeID}/remove_blockACADEMIC.DEGREESRemove block for a degree
GET/gradesADMIN.GRADING_SYSTEMSList grades
POST/gradesADMIN.GRADING_SYSTEMSCreate a grade
DELETE/grades/{gradeID}ADMIN.GRADING_SYSTEMSDelete a grade
GET/grades/{gradeID}ADMIN.GRADING_SYSTEMSGet one grade
PATCH/grades/{gradeID}ADMIN.GRADING_SYSTEMSUpdate a grade
GET/grading-systemsREGISTRATION.SECTIONSList grading systems
POST/grading-systemsADMIN.GRADING_SYSTEMSCreate a grading system
GET/grading-systems/defaultREGISTRATION.SECTIONSGet default
DELETE/grading-systems/{gradingSystemID}ADMIN.GRADING_SYSTEMSDelete a grading system
GET/grading-systems/{gradingSystemID}REGISTRATION.SECTIONSGet one grading system
PATCH/grading-systems/{gradingSystemID}ADMIN.GRADING_SYSTEMSUpdate a grading system
GET/major-default-advisorsACADEMIC.MAJORSList major default advisors
POST/major-default-advisorsACADEMIC.MAJORSCreate a major default advisor
GET/major-default-advisors/for_majorACADEMIC.MAJORSGet for major
DELETE/major-default-advisors/{advisorID}ACADEMIC.MAJORSDelete a major default advisor
GET/major-default-advisors/{advisorID}ACADEMIC.MAJORSGet one major default advisor
PATCH/major-default-advisors/{advisorID}ACADEMIC.MAJORSUpdate a major default advisor
GET/majorsACADEMIC.MAJORSList majors
POST/majorsACADEMIC.MAJORSCreate a major
DELETE/majors/{majorID}ACADEMIC.MAJORSDelete a major
GET/majors/{majorID}ACADEMIC.MAJORSGet one major
PATCH/majors/{majorID}ACADEMIC.MAJORSUpdate a major
POST/majors/{majorID}/add_blockACADEMIC.MAJORSAdd block for a major
POST/majors/{majorID}/add_campusACADEMIC.MAJORSAdd campus for a major
POST/majors/{majorID}/add_degreeACADEMIC.MAJORSAdd degree for a major
POST/majors/{majorID}/add_degree_levelACADEMIC.MAJORSAdd degree level for a major
GET/majors/{majorID}/blocksACADEMIC.MAJORSList the major's blocks
GET/majors/{majorID}/campusesACADEMIC.MAJORSList the major's campuses
GET/majors/{majorID}/emphasesACADEMIC.MAJORSList the major's emphases
POST/majors/{majorID}/emphasesACADEMIC.MAJORSAdd emphases to a major
DELETE/majors/{majorID}/emphases/{emphasisID}ACADEMIC.MAJORSDelete a emphas
GET/majors/{majorID}/emphases/{emphasisID}ACADEMIC.MAJORSGet one emphas
PATCH/majors/{majorID}/emphases/{emphasisID}ACADEMIC.MAJORSUpdate a emphas
POST/majors/{majorID}/emphases/{emphasisID}/blocksACADEMIC.MAJORSAdd blocks to a emphas
DELETE/majors/{majorID}/emphases/{emphasisID}/blocks/{emphasisBlockID}ACADEMIC.MAJORSDelete a block
DELETE/majors/{majorID}/remove_blockACADEMIC.MAJORSRemove block for a major
POST/majors/{majorID}/remove_campusACADEMIC.MAJORSRemove campus for a major
DELETE/majors/{majorID}/remove_degreeACADEMIC.MAJORSRemove degree for a major
DELETE/majors/{majorID}/remove_degree_levelACADEMIC.MAJORSRemove degree level for a major
GET/materialsACADEMIC.COURSESList materials
POST/materialsACADEMIC.COURSESCreate a material
DELETE/materials/{materialID}ACADEMIC.COURSESDelete a material
GET/materials/{materialID}ACADEMIC.COURSESGet one material
PATCH/materials/{materialID}ACADEMIC.COURSESUpdate a material
GET/minor-default-advisorsACADEMIC.MINORSList minor default advisors
POST/minor-default-advisorsACADEMIC.MINORSCreate a minor default advisor
GET/minor-default-advisors/for_minorACADEMIC.MINORSGet for minor
DELETE/minor-default-advisors/{advisorID}ACADEMIC.MINORSDelete a minor default advisor
GET/minor-default-advisors/{advisorID}ACADEMIC.MINORSGet one minor default advisor
PATCH/minor-default-advisors/{advisorID}ACADEMIC.MINORSUpdate a minor default advisor
GET/minorsACADEMIC.MINORSList minors
POST/minorsACADEMIC.MINORSCreate a minor
DELETE/minors/{minorID}ACADEMIC.MINORSDelete a minor
GET/minors/{minorID}ACADEMIC.MINORSGet one minor
PATCH/minors/{minorID}ACADEMIC.MINORSUpdate a minor
POST/minors/{minorID}/add_campusACADEMIC.MINORSAdd campus for a minor
GET/minors/{minorID}/blocksACADEMIC.MINORSList the minor's blocks
GET/minors/{minorID}/campusesACADEMIC.MINORSList the minor's campuses
POST/minors/{minorID}/remove_campusACADEMIC.MINORSRemove campus for a minor
GET/registration-windows/fieldsACADEMIC.REGISTRATION_WINDOWSFields a window rule may test
POST/registration-windows/rule-matchesACADEMIC.REGISTRATION_WINDOWSCount students an unsaved rule selects
GET/requirement-blocksACADEMIC.REQUIREMENTSList requirement blocks
POST/requirement-blocksACADEMIC.REQUIREMENTSCreate a requirement block
DELETE/requirement-blocks/{blockID}ACADEMIC.REQUIREMENTSDelete a requirement block
GET/requirement-blocks/{blockID}ACADEMIC.REQUIREMENTSGet one requirement block
PATCH/requirement-blocks/{blockID}ACADEMIC.REQUIREMENTSUpdate a requirement block
GET/requirement-blocks/{blockID}/childrenACADEMIC.REQUIREMENTSGet the requirement block's children
POST/requirement-blocks/{blockID}/copyACADEMIC.REQUIREMENTSAdd copy to a requirement block
GET/requirement-blocks/{blockID}/groupsACADEMIC.REQUIREMENTSList the requirement block's groups
GET/requirement-blocks/{blockID}/itemsACADEMIC.REQUIREMENTSList the requirement block's items
GET/requirement-group-rulesACADEMIC.REQUIREMENTSList requirement group rules
POST/requirement-group-rulesACADEMIC.REQUIREMENTSCreate a requirement group rule
DELETE/requirement-group-rules/{ruleID}ACADEMIC.REQUIREMENTSDelete a requirement group rule
GET/requirement-group-rules/{ruleID}ACADEMIC.REQUIREMENTSGet one requirement group rule
PATCH/requirement-group-rules/{ruleID}ACADEMIC.REQUIREMENTSUpdate a requirement group rule
GET/requirement-groupsACADEMIC.REQUIREMENTSList requirement groups
POST/requirement-groupsACADEMIC.REQUIREMENTSCreate a requirement group
DELETE/requirement-groups/{groupID}ACADEMIC.REQUIREMENTSDelete a requirement group
GET/requirement-groups/{groupID}ACADEMIC.REQUIREMENTSGet one requirement group
PATCH/requirement-groups/{groupID}ACADEMIC.REQUIREMENTSUpdate a requirement group
GET/requirement-itemsACADEMIC.REQUIREMENTSList requirement items
POST/requirement-itemsACADEMIC.REQUIREMENTSCreate a requirement item
DELETE/requirement-items/{itemID}ACADEMIC.REQUIREMENTSDelete a requirement item
GET/requirement-items/{itemID}ACADEMIC.REQUIREMENTSGet one requirement item
PATCH/requirement-items/{itemID}ACADEMIC.REQUIREMENTSUpdate a requirement item
GET/schedule-templatesACADEMIC.SCHEDULE_TEMPLATESList schedule templates
POST/schedule-templatesACADEMIC.SCHEDULE_TEMPLATESCreate a schedule template
GET/schedule-templates/dropdownACADEMIC.SCHEDULE_TEMPLATESList options for a picker
DELETE/schedule-templates/{templateID}ACADEMIC.SCHEDULE_TEMPLATESDelete a schedule template
GET/schedule-templates/{templateID}ACADEMIC.SCHEDULE_TEMPLATESGet one schedule template
PATCH/schedule-templates/{templateID}ACADEMIC.SCHEDULE_TEMPLATESUpdate a schedule template
GET/section-instructorsREGISTRATION.SECTIONSList section instructors
POST/section-instructorsREGISTRATION.SECTIONSCreate a section instructor
POST/section-instructors/set_grade_entryREGISTRATION.SECTIONSSet grade entry
DELETE/section-instructors/{instructorID}REGISTRATION.SECTIONSDelete a section instructor
GET/section-instructors/{instructorID}REGISTRATION.SECTIONSGet one section instructor
PATCH/section-instructors/{instructorID}REGISTRATION.SECTIONSUpdate a section instructor
DELETE/section-materials/{sectionMaterialID}REGISTRATION.SECTIONSDelete a section material
GET/section-materials/{sectionMaterialID}REGISTRATION.SECTIONSGet one section material
PATCH/section-materials/{sectionMaterialID}REGISTRATION.SECTIONSUpdate a section material
GET/sectionsREGISTRATION.SECTIONSList sections
POST/sectionsREGISTRATION.SECTIONSCreate a section
GET/sections/availableREGISTRATION.SECTIONSGet available
GET/sections/for_cohort_registrationREGISTRATION.COHORT_REGISTRATIONSections offered to cohort registration
GET/sections/for_registrationREGISTRATION.REGISTERSections offered to the registering student
DELETE/sections/{sectionID}REGISTRATION.SECTIONSDelete a section
GET/sections/{sectionID}REGISTRATION.SECTIONSGet one section
PATCH/sections/{sectionID}REGISTRATION.SECTIONSUpdate a section
GET/sections/{sectionID}/dependentsREGISTRATION.SECTIONSWhat depends on the section, so why it cannot be deleted or moved
GET/sections/{sectionID}/materialsREGISTRATION.SECTIONSList the section's materials
POST/sections/{sectionID}/materialsREGISTRATION.SECTIONSAdd materials to a section
GET/sections/{sectionID}/rosterREGISTRATION.SECTIONSGet the section's roster
DELETE/sections/{sectionID}/schedulingREGISTRATION.SECTIONSRemove scheduling from a section
GET/sections/{sectionID}/schedulingREGISTRATION.SECTIONSGet the section's scheduling
POST/sections/{sectionID}/schedulingREGISTRATION.SECTIONSAdd scheduling to a section
POST/sections/{sectionID}/scheduling/linkREGISTRATION.SECTIONSLink
POST/sections/{sectionID}/scheduling/unlinkREGISTRATION.SECTIONSUnlink
GET/student-course-substitutionsACADEMIC.COURSE_SUBSTITUTIONSList student course substitutions
POST/student-course-substitutionsACADEMIC.COURSE_SUBSTITUTIONSCreate a student course substitution
GET/student-course-substitutions/by_studentADVISING.AUDITList one student's course substitutions
DELETE/student-course-substitutions/{substitutionID}ACADEMIC.COURSE_SUBSTITUTIONSDelete a student course substitution
GET/student-course-substitutions/{substitutionID}ACADEMIC.COURSE_SUBSTITUTIONSGet one student course substitution
PATCH/student-course-substitutions/{substitutionID}ACADEMIC.COURSE_SUBSTITUTIONSUpdate a student course substitution
POST/student-course-substitutions/{substitutionID}/advisor-approveACADEMIC.COURSE_SUBSTITUTIONSAdd advisor approve to a student course substitution
POST/student-course-substitutions/{substitutionID}/deactivateACADEMIC.COURSE_SUBSTITUTIONSDeactivate for a student course substitution
POST/student-course-substitutions/{substitutionID}/registrar-approveACADEMIC.COURSE_SUBSTITUTIONSAdd registrar approve to a student course substitution
GET/sub-termsACADEMIC.TERMSList sub terms
POST/sub-termsACADEMIC.TERMSCreate a sub term
DELETE/sub-terms/{subTermID}ACADEMIC.TERMSDelete a sub term
GET/sub-terms/{subTermID}ACADEMIC.TERMSGet one sub term
PATCH/sub-terms/{subTermID}ACADEMIC.TERMSUpdate a sub term
GET/term-campus-offeringsACADEMIC.TERMSList term campus offerings
POST/term-campus-offeringsACADEMIC.TERMSCreate a term campus offering
DELETE/term-campus-offerings/{offeringID}ACADEMIC.TERMSDelete a term campus offering
GET/term-campus-offerings/{offeringID}ACADEMIC.TERMSGet one term campus offering
PATCH/term-campus-offerings/{offeringID}ACADEMIC.TERMSUpdate a term campus offering
GET/term-slotsACADEMIC.TERMSList term slots
POST/term-slotsACADEMIC.TERMSCreate a term slot
DELETE/term-slots/{slotID}ACADEMIC.TERMSDelete a term slot
GET/term-slots/{slotID}ACADEMIC.TERMSGet one term slot
PUT/term-slots/{slotID}ACADEMIC.TERMSReplace a term slot
GET/termsACADEMIC.TERMSList terms
POST/termsACADEMIC.TERMSCreate a term
GET/terms/available_for_registrationACADEMIC.TERMSGet available for registration
GET/terms/currentACADEMIC.TERMSGet the current record
GET/terms/for_cohort_registrationREGISTRATION.COHORT_REGISTRATIONTerms offered to cohort registration
GET/terms/latest_activeACADEMIC.TERMSGet the latest active term
GET/terms/open_for_registrationREGISTRATION.REGISTERTerms open for registration
DELETE/terms/{termID}ACADEMIC.TERMSDelete a term
GET/terms/{termID}ACADEMIC.TERMSGet one term
PATCH/terms/{termID}ACADEMIC.TERMSUpdate a term
GET/terms/{termID}/sectionsACADEMIC.TERMSList the term's sections
GET/terms/{termID}/registration-windowsACADEMIC.TERMSList the term's registration windows
POST/terms/{termID}/registration-windowsACADEMIC.REGISTRATION_WINDOWSCreate a registration window
GET/terms/{termID}/registration-windows/previewACADEMIC.TERMSPreview who each window lets in
DELETE/terms/{termID}/registration-windows/{windowID}ACADEMIC.REGISTRATION_WINDOWSDelete a registration window
PUT/terms/{termID}/registration-windows/{windowID}ACADEMIC.REGISTRATION_WINDOWSReplace a registration window

Student Information System Documentation