Registration API
Base URL: /api/v1/registration
Manage course enrollment, registration transactions, waitlists, holds, and degree planning.
Endpoints Overview
Enrollments
| Method | Endpoint | Description |
|---|---|---|
| GET | /enrollments | List enrollments |
| POST | /enrollments | Create enrollment |
| GET | /enrollments/{id} | Get enrollment details |
| PATCH | /enrollments/{id} | Update enrollment |
| DELETE | /enrollments/{id} | Delete enrollment |
| POST | /enrollments/register | Register for a section |
| POST | /enrollments/quick_register | Quick register with validation |
| GET | /enrollments/by_student | Get enrollments by student |
| GET | /enrollments/by_section | Get enrollments by section |
| POST | /enrollments/drop | Drop or withdraw from a section (or request it, when advisor approval applies) |
| GET | /enrollments/drop_preview | What a drop would do today |
| POST | /enrollments/enter_grade | Enter grade for enrollment |
| GET | /enrollment-history | A student's enrollment status changes |
Term Enrollments
| Method | Endpoint | Description |
|---|---|---|
| GET | /term-enrollments | List term enrollment summaries |
| GET | /term-enrollments/{id} | Get term enrollment details |
Waitlists
| Method | Endpoint | Description |
|---|---|---|
| GET | /waitlists | List waitlist entries (staff) |
| POST | /waitlists | Join a waitlist |
| GET | /waitlists/for_student | A student's own waitlist entries |
| POST | /waitlists/{waitlistID}/leave | Leave a waitlist (student) |
| DELETE | /waitlists/{waitlistID} | Remove from waitlist (staff) |
Holds
| Method | Endpoint | Description |
|---|---|---|
| GET | /hold-types | List hold types |
| POST | /hold-types/{holdTypeID}/run_auto_create | Run auto-create for one hold type |
| GET | /student-holds | List student holds |
| POST | /student-holds | Create hold |
| GET | /student-holds/my_holds | Holds on the caller's own record |
| POST | /student-holds/bulk_create | Place holds on many students |
| POST | /student-holds/bulk_create_from_list | Place holds from a student list |
| GET | /student-holds/my_holds | Get current user's holds |
| POST | /student-holds/check_holds | Check holds for a student |
| POST | /student-holds/bulk_create | Bulk create holds |
| POST | /student-holds/{holdID}/clear | Clear one hold |
GPA & Class Standing
| Method | Endpoint | Description |
|---|---|---|
| GET | /gpa | Calculate GPA |
| GET | /class-standing | Get class standing |
| POST | /gpa/bulk-recalculate | Recalculate GPA for multiple students |
Degree Planning
| Method | Endpoint | Description |
|---|---|---|
| GET | /planning | List planned courses |
| POST | /planning | Add planned course |
| DELETE | /planning/{plannedID} | Remove planned course |
| POST | /planning/check_prerequisites | Prerequisite check (with minimum grades) |
| POST | /planning/check_corequisites | Corequisite check |
| POST | /planning/check_credit_limit | Credit load and overload check |
| POST | /planning/check_repeat | Repeat-limit check |
| POST | /planning/convert_to_registration | Submit a term's plans as a registration request |
| POST | /students/{studentID}/failed-course-cascade | Remove plans stranded by a failed course |
Transactions
| Method | Endpoint | Description |
|---|---|---|
| GET | /transactions/mine | The caller's own transactions |
| POST | /transactions | Create registration transaction |
| DELETE | /transactions/{transactionID} | Cancel a transaction |
| POST | /transactions/{transactionID}/validate | Validate transaction |
| POST | /transactions/{transactionID}/submit | Submit transaction |
| POST | /transactions/{transactionID}/complete | Complete transaction |
| POST | /transactions/{transactionID}/add_item | Add an item to a transaction |
| DELETE | /transactions/{transactionID}/items/{itemID} | Remove an item |
| POST | /transactions/{transactionID}/transition | Move the transaction to another step |
| POST | /transactions/{transactionID}/override | Apply a registration override |
| GET | /transactions/{transactionID}/history | Transaction history |
| GET / POST | /transactions/{transactionID}/notes | Read / add notes (student, registrar) |
Approvals
| Method | Endpoint | Description |
|---|---|---|
| GET | /approvals | Requests waiting for the caller's decision |
| GET | /approvals/{transactionID} | One request, as the approver sees it |
| POST | /transactions/{transactionID}/approve | Approve |
| POST | /transactions/{transactionID}/reject | Reject with a reason |
| GET / POST | /approvals/{transactionID}/notes | Read / add notes (advisor, registrar) |
Hold Evaluation Logs
| Method | Endpoint | Description |
|---|---|---|
| GET | /hold-evaluation-logs | List hold evaluation logs |
Enrollments
List Enrollments
GET /api/v1/registration/enrollmentsQuery Parameters
| Parameter | Type | Description |
|---|---|---|
student | integer | Filter by student ID |
student_id | integer | Filter by student ID (alias) |
section | integer | Filter by section ID |
section_id | integer | Filter by section ID (alias) |
term_id | integer | Filter by term ID |
status_id | integer | Filter by status |
grade_id | integer | Filter by grade |
is_audit | boolean | Filter audit enrollments |
is_pass_fail | boolean | Filter pass/fail enrollments |
search | string | Search by student number, course code |
Success Response (200 OK)
{
"count": 25000,
"results": [
{
"enrollment_id": 1,
"student_id": 1001,
"student_number": "STU001234",
"section_id": 512,
"course_code": "MATH 101",
"course_title": "College Algebra",
"section_code": "001",
"term_code": "FA2024",
"status_code": "REGISTERED",
"status_display": "Registered",
"registration_date": "2024-04-15",
"grade": null,
"is_graded": false,
"credits_attempted": 3.0,
"credits_earned": 0.0,
"is_audit": false,
"is_pass_fail": false
}
]
}Get Enrollment Details
GET /api/v1/registration/enrollments/{id}Success Response (200 OK)
{
"enrollment_id": 1,
"student_id": 1001,
"student_number": "STU001234",
"student_name": "John Smith",
"section_id": 512,
"course_code": "MATH 101",
"course_title": "College Algebra",
"section_code": "001",
"term_id": 8,
"term_code": "FA2024",
"term_name": "Fall 2024",
"status_id": 1,
"status_code": "REGISTERED",
"status_display": "Registered",
"registration_date": "2024-04-15",
"drop_date": null,
"grade_id": null,
"grade": null,
"grade_display": null,
"grade_date": null,
"is_graded": false,
"credits_attempted": 3.0,
"credits_earned": 0.0,
"is_audit": false,
"is_pass_fail": false,
"notes": null,
"created_at": "2024-04-15T10:30:00Z",
"updated_at": "2024-04-15T10:30:00Z"
}TypeScript Types
interface Enrollment {
enrollment_id: number
student_id: number
student_number: string
student_name?: string
section_id: number
course_code: string
course_title: string
section_code: string
term_id: number
term_code: string
term_name?: string
status_id: number
status_code: string
status_display: string
registration_date: string
drop_date: string | null
grade_id: number | null
grade: string | null
grade_display: string | null
grade_date: string | null
is_graded: boolean
credits_attempted: number
credits_earned: number
is_audit: boolean
is_pass_fail: boolean
notes: string | null
}Create Enrollment
POST /api/v1/registration/enrollmentsRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
student_id | integer | Yes | Student ID |
section_id | integer | Yes | Section ID |
is_audit | boolean | No | Audit enrollment |
is_pass_fail | boolean | No | Pass/fail grading |
notes | string | No | Enrollment notes |
Register for Section
POST /api/v1/registration/enrollments/registerRegister a student for a course section with full validation.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
student_id | integer | Yes | Student ID |
section_id | integer | Yes | Section ID |
is_audit | boolean | No | Audit enrollment |
is_pass_fail | boolean | No | Pass/fail option |
credits | number | No | The chosen credits on a variable-credit section (migration 279). Must lie within the section's range, on its credit_increment grid from the minimum (the maximum is always allowed). Defaults to the minimum; ignored on a fixed section. Recorded as credits_attempted |
allow_repeat | boolean | No | Register despite a repeat restriction. Needs REGISTRATION.OVERRIDE.DUPLICATE |
override_sequence, sequence_override_reason | boolean, string | No | Bypass a sequencing deadline. Needs REGISTRATION.OVERRIDE.SEQUENCE |
override_capacity, capacity_override_reason | boolean, string | No | Enroll into a full section. Needs REGISTRATION.OVERRIDE.CAPACITY |
Validations Performed
- Section availability and capacity
- The term's registration period and the student's registration window. A caller holding
REGISTRATION.OVERRIDE.DEADLINEis not held to the window - Repeat limits (
COURSE_REPEAT) - Sequencing deadlines
- Hold checks
Credit limits are not checked on this route. They apply to registration transactions.
Success Response (201 Created)
{
"enrollment_id": 150,
"student_id": 1001,
"section_id": 512,
"course_code": "MATH 101",
"status_code": "REGISTERED",
...
}Error Response (400 Bad Request)
{
"error": "Section MATH 101-001 is full. Enrollment: 30/30"
}Quick Register
POST /api/v1/registration/enrollments/quick_registerRegister with full prerequisite validation and optional override.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
student_id | integer | Yes | Student ID |
section_id | integer | Yes | Section ID |
override_prerequisites | boolean | No | Skip prerequisite check |
override_reason | string | Conditional | Reason for override |
Error Response with Prerequisites
{
"success": false,
"error": "Prerequisites not met",
"prerequisites": [
{
"course_code": "MATH 095",
"min_grade": "C",
"status": "NOT_COMPLETED"
}
],
"can_override": true
}Enrollments by Student
GET /api/v1/registration/enrollments/by_studentGet all enrollments for a specific student.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
student_id | integer | Student ID |
term_id | integer | Filter by term |
Enrollments by Section
GET /api/v1/registration/enrollments/by_sectionGet all enrollments for a specific section.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
section_id | integer | Section ID |
Drop Enrollment
POST /api/v1/registration/enrollments/dropDrop a student from an enrolled section. Whether it is a drop or a withdrawal is decided by the section's term deadlines (see Drops and Withdrawals).
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
student_id | integer | Yes | Student ID |
section_id | integer | Yes | Section ID |
reason | string | No | Reason, recorded in the enrollment history (and as the first note when the drop becomes a request) |
Outcomes
| Status | outcome | When |
|---|---|---|
| 200 | DROPPED | On or before drop_deadline: status DROPPED, off the transcript |
| 200 | WITHDRAWN | After drop_deadline, on or before withdrawal_deadline: status WITHDRAWN, a W |
| 202 | PENDING_APPROVAL | The caller is the student and DROP_REQUIRES_ADVISOR_APPROVAL / WITHDRAWAL_REQUIRES_ADVISOR_APPROVAL is on: a one-item transaction was created and submitted; nothing changed yet |
| 409 | — | After withdrawal_deadline (no override on this route: use a transaction with override_deadline), or the enrollment is already dropped or withdrawn |
| 404 | — | The student has no enrollment in the section |
{
"success": true,
"message": "Your withdrawal request was sent to your advisor for approval.",
"outcome": "PENDING_APPROVAL",
"phase": "WITHDRAW",
"transaction_id": 4812
}phase is DROP or WITHDRAW. A completed drop sets drop_date, offers the seat to the waitlist and emails the student and their advisors (COURSE_DROP_* templates).
Drop Preview
GET /api/v1/registration/enrollments/drop_preview?student_id={id}§ion_id={id}What dropping the section would do today, for the confirmation dialog. Writes nothing.
{
"phase": "WITHDRAW",
"drop_deadline": "2026-09-30",
"withdrawal_deadline": "2026-11-13",
"appears_on_transcript": true,
"requires_advisor_approval": false
}| Field | Description |
|---|---|
phase | DROP, WITHDRAW or CLOSED (too late without a registrar override) |
drop_deadline, withdrawal_deadline | The term's dates; omitted when unset (an unset deadline is not enforced) |
appears_on_transcript | True for a withdrawal |
requires_advisor_approval | True when this caller's request would wait for the primary advisor |
Enter Grade
POST /api/v1/registration/enrollments/enter_gradeEnter or update a grade for an enrollment.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
enrollment_id | integer | Yes | Enrollment ID |
grade_id | integer | Yes | Grade lookup ID |
grade_date | date | No | Date grade was assigned |
Waitlists
List Waitlist Entries
GET /api/v1/registration/waitlistsQuery Parameters
| Parameter | Type | Description |
|---|---|---|
section | integer | Filter by section ID |
student | integer | Filter by student ID |
Waitlist entry
Every waitlist route returns entries in this shape:
{
"waitlist_id": 1,
"section_id": 512,
"student_id": 1001,
"position": 1,
"added_at": "2026-04-15T11:00:00Z",
"status_id": 2,
"status_code": "NOTIFIED",
"status_display": "Notified",
"is_waiting": false,
"is_notified": true,
"notified_at": "2026-04-20T09:12:00Z",
"notification_expires_at": "2026-04-22T09:12:00Z",
"student_number": "STU001234",
"student_name": "John Smith",
"course_code": "MATH 101",
"course_title": "College Algebra",
"section_code": "001",
"term_code": "2026FA",
"term_name": "Fall 2026",
"created_at": "2026-04-15T11:00:00Z",
"updated_at": "2026-04-20T09:12:00Z"
}| Field | Description |
|---|---|
status_code | WAITING, NOTIFIED, EXPIRED, ENROLLED or REMOVED |
position | Place in line among the entries still open (closes up as others leave) |
is_notified | A seat has been offered and the offer has not lapsed. False once notification_expires_at has passed, even before the row is marked EXPIRED |
notification_expires_at | 48 hours after the offer |
removed_at, removal_reason | Set when the entry closes (Enrolled, Offer expired, ...) |
A freed seat (drop, withdrawal, cancelled request, cascade, an offer-holder leaving) is offered to the next WAITING entry. The offer is a notice only: the seat is not held, and no email is sent. See Waitlist.
Join a Waitlist
POST /api/v1/registration/waitlistsGated on REGISTRATION.REGISTER, so a student can join for themselves.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
student_id | integer | Yes | Student ID |
section_id | integer | Yes | Section ID |
Returns 201 with the entry. Refused with 409 when the section still has open seats, its positive waitlist_capacity is reached, the student is already on the list or enrolled. Also refused by a hold that blocks everything, or before the student's registration window opens.
A Student's Waitlists
GET /api/v1/registration/waitlists/for_student?student_id={id}
POST /api/v1/registration/waitlists/{waitlistID}/leaveThe student-facing pair, on REGISTRATION.REGISTER and limited to the caller's own record. for_student returns a paginated envelope of entries. leave closes the entry as REMOVED (204) and offers any seat the student held on offer to the next in line. Staff remove an entry with DELETE /waitlists/{waitlistID} (REGISTRATION.WAITLISTS).
POST /waitlists/{waitlistID}/convert_to_transaction (REGISTRATION.WAITLISTS) is the staff screen's Promote. It adds the entry's section as an ADD item to the student's IN_PROGRESS transaction for the section's term, creating one when none is open, and returns that transaction (200, the same shape as GET /transactions/{id}). The body is optional: {"campus_id": n} is used only when a transaction is created.
| Status | When |
|---|---|
| 404 | No such entry, or outside the caller's student scope |
| 409 | The entry is closed; the student's transaction for the term is SUBMITTED; or the section is already in it |
The entry stays open until the enrollment is written, when it is closed as ENROLLED.
Holds
List Hold Types
GET /api/v1/registration/hold-typesSuccess Response (200 OK)
{
"count": 10,
"results": [
{
"hold_type_id": 1,
"hold_type_code": "FINANCIAL",
"name": "Financial Hold",
"description": "Outstanding balance due",
"prevents_registration": true,
"prevents_transcript": true,
"prevents_graduation": true,
"is_active": true
}
]
}Auto-Create Hold Types
POST /api/v1/registration/hold-types/{holdTypeID}/run_auto_createAutomatically create standard hold types based on system defaults.
List Student Holds
GET /api/v1/registration/student-holdsQuery Parameters
| Parameter | Type | Description |
|---|---|---|
student | integer | Filter by student ID |
hold_type | integer | Filter by hold type |
is_active | boolean | Filter active holds |
Success Response (200 OK)
{
"count": 25,
"results": [
{
"hold_id": 1,
"student_id": 1001,
"student_number": "STU001234",
"student_name": "John Smith",
"hold_type_id": 1,
"hold_type_code": "FINANCIAL",
"hold_type_name": "Financial Hold",
"reason": "Outstanding tuition balance",
"placed_date": "2024-11-01",
"placed_by": "bursar@university.edu",
"release_date": null,
"released_by": null,
"is_active": true,
"prevents_registration": true,
"prevents_transcript": true
}
]
}Create Hold
POST /api/v1/registration/student-holdsRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
student_id | integer | Yes | Student ID |
hold_type_id | integer | Yes | Hold type ID |
reason | string | No | Reason for hold |
placed_date | date | No | Date placed (default: today) |
Release Hold
POST /api/v1/registration/student-holds/{holdID}/clearHolds are cleared, not edited: there is no PATCH or DELETE on /student-holds. Clearing end-dates the hold and leaves the record in place, so the history of why a student was held survives.
My Holds
GET /api/v1/registration/student-holds/my_holdsGet holds for the currently authenticated student.
Check Holds
POST /api/v1/registration/student-holds/check_holdsCheck if a student has any active holds that prevent registration.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
student_id | integer | Student ID to check |
Bulk Create Holds
POST /api/v1/registration/student-holds/bulk_createCreate holds for multiple students at once.
Request Body
{
"student_ids": [1001, 1002, 1003],
"hold_type_id": 1,
"reason": "Outstanding balance"
}Clear Holds
POST /api/v1/registration/student-holds/{holdID}/clearClear (release) holds for a student or set of students.
Request Body
{
"student_ids": [1001, 1002],
"hold_type_id": 1
}Transactions
Create Transaction
POST /api/v1/registration/transactionsCreate a new registration transaction.
Validate Transaction
POST /api/v1/registration/transactions/{transactionID}/validateValidate a registration transaction before submission.
Submit Transaction
POST /api/v1/registration/transactions/{transactionID}/submitSubmit a registration transaction for processing.
Complete Transaction
POST /api/v1/registration/transactions/{transactionID}/completeMark a registration transaction as complete.
Transition Transaction
POST /api/v1/registration/transactions/{id}/transitionTransition a transaction to a new state.
Override Transaction
POST /api/v1/registration/transactions/{transactionID}/overrideExcuse specific validation failures. Needs REGISTRATION.OVERRIDE.
| Field | Type | Required | Description |
|---|---|---|---|
reason | string | Yes | Max 1,000 characters. Also written to the notes thread as an OVERRIDE note |
override_prereqs | boolean | No | Unmet prerequisites |
override_deadline | boolean | No | REGISTRATION_CLOSED (the term's period or the student's registration window) and DROP_DEADLINE (a drop after the withdrawal deadline) |
override_credit_limit | boolean | No | CREDIT_LIMIT (over the normal load) |
override_campus | boolean | No | CAMPUS_MISMATCH |
override_sequence | boolean | No | SEQUENCE_DEADLINE |
override_repeat | boolean | No | COURSE_REPEAT. Also needs REGISTRATION.OVERRIDE.DUPLICATE (403 otherwise) |
At least one flag is required. Overrides accumulate and are never cleared by a later call. A closed (completed or cancelled) transaction is refused with 409. Validation messages that an override covers drop to INFO severity with "(overridden)" appended. The validation state reports needs_*_override and applied_*_override for each kind.
Overload requests (migration 296) also carry is_overload_request, overload_reason, overload_credits, overload_advisor_approved_at and overload_advisor_name.
Approvals
GET /api/v1/registration/approvals
GET /api/v1/registration/approvals/{transactionID}
POST /api/v1/registration/transactions/{transactionID}/approve
POST /api/v1/registration/transactions/{transactionID}/rejectOn REGISTRATION.APPROVALS. Which role may decide is the PENDING_APPROVAL step's role list. An advisor decides only for students they are primary advisor to.
reject takes {"reason": "..."} (required, max 1,000). The transaction returns to DRAFT with its seats, and the reason is also written as a REJECT note.
approve enrolls every item together or none. Possible outcome values include COMPLETED, BOUNCED (nothing enrolled, returned to the student), APPROVED_PENDING_CLEARANCE (a blocks-completion hold), and OVERLOAD_ADVISOR_APPROVED. The last means the primary advisor's signature on an overload request was recorded and the request waits for the registrar. The registrar approving an overload before the advisor gets 409, unless the student has no current primary advisor.
Transaction Notes
GET /api/v1/registration/transactions/{transactionID}/notes
POST /api/v1/registration/transactions/{transactionID}/notes
GET /api/v1/registration/approvals/{transactionID}/notes
POST /api/v1/registration/approvals/{transactionID}/notesOne append-only thread per transaction (migration 278). The /transactions/... pair is on REGISTRATION.REGISTER (student, registrar) and the /approvals/... pair on REGISTRATION.APPROVALS (advisor, registrar). Both apply the same row-level visibility.
POST body: {"note_text": "..."}, 1 to 2,000 characters. There is no edit or delete route, and the database refuses UPDATE, DELETE and TRUNCATE on the table.
{
"note_id": 912,
"transaction_id": 4812,
"note_kind": "NOTE",
"note_text": "Please confirm the lab section works with your job.",
"step_id": 40,
"step_name": "Pending Approval",
"author_person_id": "8b0c...",
"author_name": "Dana Advisor",
"author_role_code": "ADVISOR",
"created_at": "2026-10-20T14:03:00Z"
}note_kind is NOTE, OVERRIDE or REJECT. The list is oldest first.
Hold Evaluation Logs
List Hold Evaluation Logs
GET /api/v1/registration/hold-evaluation-logsView logs of hold evaluation runs.
GPA Calculation
Calculate GPA
GET /api/v1/registration/gpaQuery Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
student_id | integer | Yes | Student ID |
term_id | integer | No | Specific term (cumulative if omitted) |
Success Response (200 OK)
{
"student_id": 1001,
"gpa_type": "cumulative",
"gpa": 3.45,
"credits_attempted": 48.0,
"credits_earned": 45.0,
"quality_points": 165.6,
"courses_completed": 16
}Class Standing
GET /api/v1/registration/class-standingQuery Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
student_id | integer | Yes | Student ID |
Success Response (200 OK)
{
"student_id": 1001,
"class_standing": "Sophomore",
"credits_earned": 45.0,
"thresholds": {
"freshman": { "min": 0, "max": 29 },
"sophomore": { "min": 30, "max": 59 },
"junior": { "min": 60, "max": 89 },
"senior": { "min": 90, "max": null }
}
}Degree Planning
List Planned Courses
GET /api/v1/registration/planningQuery Parameters
| Parameter | Type | Description |
|---|---|---|
student | integer | Filter by student ID |
term | integer | Filter by planned term |
status | string | Filter by status (PLANNED, COMPLETED, DROPPED) |
Success Response (200 OK)
{
"count": 8,
"results": [
{
"planned_course_id": 1,
"student_id": 1001,
"course_id": 201,
"course_code": "CS 201",
"course_title": "Data Structures",
"credits": 3,
"planned_term_id": 9,
"planned_term_code": "SP2025",
"status": "PLANNED",
"notes": "Required for major",
"created_at": "2024-11-15T10:00:00Z"
}
]
}Add Planned Course
POST /api/v1/registration/planningRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
student_id | integer | Yes | Student ID |
section_id | integer | Yes | Section to plan (the term comes from it) |
requirement_item_id, requirement_block_id | integer | No | The requirement this plan is for |
credits_selected | number | No | Chosen credits on a variable-credit section; validated against the section's range and increment, ignored otherwise |
override_prereq, prereq_override_reason | boolean, string | No | Plan despite an unmet prerequisite. Needs REGISTRATION.OVERRIDE.PREREQ |
override_sequence, sequence_override_reason | boolean, string | No | Needs REGISTRATION.OVERRIDE.SEQUENCE |
override_capacity, capacity_override_reason | boolean, string | No | Reserve a seat in a full section. Needs REGISTRATION.OVERRIDE.CAPACITY |
override_repeat, repeat_override_reason | boolean, string | No | Plan a course the student may not take again. Needs REGISTRATION.OVERRIDE.DUPLICATE and a reason of at least 10 characters; the override is kept on the plan |
override_conflict, override_reason | boolean, string | No | Schedule-conflict override (recorded) |
notes | string | No | Planning notes |
Sequencing and repeat limits are enforced on this route. A repeat refusal comes back as a COURSE_REPEAT error with the reason. The other checks are the advisory endpoints below, which the planning dialog calls first.
Planning Checks
All POST, all on REGISTRATION.REGISTER, all read-only.
| Endpoint | Body | Returns |
|---|---|---|
/planning/check_prerequisites | student_id, course_id, term_id | is_satisfied, messages (MISSING_PREREQ, with the minimum grade and the grade earned when that is why), and prerequisites that are only planned |
/planning/check_corequisites | student_id, course_id, term_id | has_coreqs and a message naming any corequisite not arranged for the term |
/planning/check_credit_limit | student_id, section_id, credits (optional, for a variable section) | See below |
/planning/check_repeat | student_id, section_id | blocked, message, attempts, max_attempts (0 = none), limit_source (course, major <code> or institution), can_override |
/planning/check_sequence | student_id, section_id | Sequencing verdict |
/planning/check_conflicts | student_id, section_id | Overlapping meetings |
Prerequisites are read from Colleague's requisite rules (course_requisite_links, migration 285): timing P must be met in an earlier term, E in an earlier or the same term, and C rules are corequisites. A pass below the rule's minimum grade (migration 286) does not meet it.
Credit limit check
{
"is_within_limit": false,
"current_term_credits": 15,
"section_credits": 4,
"max_credits": 17.5,
"overload_ceiling": 21,
"is_overload": true,
"credits_after_adding": 19,
"message": "Adding this course would bring your total to 19 credits, above the normal 17.5-credit load. ...",
"can_override": true
}max_credits is the student's normal load (MAX_CREDITS_UNDERGRAD or MAX_CREDITS_GRADUATE) and overload_ceiling the matching *_OVERLOAD setting. is_overload means past the normal load but within the ceiling. can_override is false past the ceiling. See Credit Load and Overloads.
Submit Plans for Registration
POST /api/v1/registration/planning/convert_to_registrationSubmits every PLANNED course the student has in a term as one transaction at PENDING_APPROVAL.
| Field | Type | Required | Description |
|---|---|---|---|
student_id | integer | Yes | Student ID |
term_id | integer | Yes | Term |
overload_reason | string | Conditional | Required when the term would pass the normal load (max 1,000 characters) |
- Past the overload ceiling: refused (400) with the total.
- Past the normal load without
overload_reason: a validation error onoverload_reason. Resubmit with the reason. - Past the normal load with a reason: submitted as an overload request (
is_overload_request: truein the response and on the transaction). The primary advisor approves first, then the registrar. - Before the student's registration window opens: refused.
{
"success": true,
"transaction_id": 4812,
"plans_converted": 6,
"plans_not_eligible": 0,
"is_overload_request": true,
"pending_clearance_hold": null
}Failed-Course Cascade
POST /api/v1/registration/students/{studentID}/failed-course-cascade[?preview=1]On REGISTRATION.APPROVALS. Cancels the student's PLANNED courses whose prerequisites a failed course, or a pass below a prerequisite's minimum, has made unreachable, down the dependency chain. Plans inside a transaction, plans with a prerequisite override and live enrollments are reported, not touched. preview=1 writes nothing. The same code runs on grade entry, on final-grade release and hourly. This route is for repair and backfill.
The response lists failed_courses, below_minimum_courses and what was (or would be) removed and reported.
Enrollment Status History
GET /api/v1/registration/enrollment-historyA student's section-enrollment status changes, newest first. A drop is not on the transcript, but it is here. On REGISTRATION.REGISTER, limited to records the caller may see, so a student reads their own.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
student_id | integer | Required |
term_id | integer | Narrow to one term |
page, page_size | integer | Pagination |
Success Response (200 OK)
{
"count": 2,
"results": [
{
"history_id": 2,
"student_section_enrollment_id": "5f0c...",
"section_id": 512,
"course_code": "MATH 101",
"course_title": "College Algebra",
"term_code": "2026FA",
"term_name": "Fall 2026",
"old_status_code": "REGISTERED",
"old_status_display": "Registered",
"new_status_code": "WITHDRAWN",
"new_status_display": "Withdrawn",
"changed_at": "2026-10-14T14:00:00Z",
"changed_by_person_id": "8b0c...",
"reason": "Dropped after the drop deadline; recorded as a withdrawal (W)",
"appears_on_transcript": true
}
]
}GET /enrollment-history/{historyID} is a stub that always returns 404.
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/registration. 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.
| Method | Endpoint | Permission node | Description |
|---|---|---|---|
| GET | /approvals | REGISTRATION.APPROVALS | List requests awaiting the caller's decision |
| GET | /approvals/{transactionID} | REGISTRATION.APPROVALS | Get one request (approver view) |
| GET | /approvals/{transactionID}/notes | REGISTRATION.APPROVALS | List the request's notes |
| POST | /approvals/{transactionID}/notes | REGISTRATION.APPROVALS | Add a note |
| GET | /class-standing | REGISTRATION | Get class standing |
| POST | /class-standing | REGISTRATION | Create class standing |
| GET | /cohort/cohorts | REGISTRATION.COHORT_REGISTRATION | Cohorts the caller may register |
| POST | /cohort/plan | REGISTRATION.COHORT_REGISTRATION.PLAN | Plan sections for cohort members |
| POST | /cohort/register | REGISTRATION.COHORT_REGISTRATION | Register cohort members |
| POST | /cohort/validate_section | REGISTRATION.COHORT_REGISTRATION (VIEW) | Each member's verdict for one section |
| GET | /cohort/{cohortID}/members | REGISTRATION.COHORT_REGISTRATION | List cohort members |
| GET | /enrollment-history | REGISTRATION.REGISTER | A student's enrollment status changes |
| GET | /enrollment-history/{historyID} | REGISTRATION | Get one enrollment history |
| GET | /enrollments | REGISTRATION | List enrollments |
| POST | /enrollments | REGISTRATION | Create a enrollment |
| GET | /enrollments/by_section | REGISTRATION | Get by section |
| GET | /enrollments/by_student | REGISTRATION | Get by student |
| POST | /enrollments/drop | REGISTRATION.REGISTER | Drop or withdraw (202 when sent for advisor approval) |
| GET | /enrollments/drop_preview | REGISTRATION.REGISTER | What a drop would do today |
| POST | /enrollments/enter_grade | GRADING.ROSTER | Create enter grade |
| POST | /enrollments/quick_register | REGISTRATION.REGISTER | Create quick register |
| POST | /enrollments/register | REGISTRATION.REGISTER | Create register |
| DELETE | /enrollments/{enrollmentID} | REGISTRATION | Delete a enrollment |
| GET | /enrollments/{enrollmentID} | REGISTRATION | Get one enrollment |
| PATCH | /enrollments/{enrollmentID} | REGISTRATION | Update a enrollment |
| GET | /gpa | GRADING.GPA | Get GPA |
| POST | /gpa | GRADING.GPA | Create GPA |
| POST | /gpa/bulk-recalculate | GRADING.GPA | Bulk recalculate |
| GET | /hold-evaluation-logs | REGISTRATION.HOLDS | List hold evaluation logs |
| GET | /hold-evaluation-logs/{logID} | REGISTRATION.HOLDS | Get one hold evaluation log |
| GET | /hold-types | ADMIN.HOLD_TYPES | List hold types |
| POST | /hold-types | ADMIN.HOLD_TYPES | Create a hold type |
| DELETE | /hold-types/{holdTypeID} | ADMIN.HOLD_TYPES | Delete a hold type |
| GET | /hold-types/{holdTypeID} | ADMIN.HOLD_TYPES | Get one hold type |
| PATCH | /hold-types/{holdTypeID} | ADMIN.HOLD_TYPES | Update a hold type |
| POST | /hold-types/{holdTypeID}/run_auto_create | ADMIN.HOLD_TYPES | Run auto create for a hold type |
| POST | /holds | REGISTRATION.HOLDS | Create a hold |
| GET | /holds/check/{studentID} | REGISTRATION.HOLDS | Get one check |
| GET | /holds/student/{studentID} | REGISTRATION.HOLDS | Get one student |
| POST | /holds/{holdID}/release | REGISTRATION.HOLDS | Add release to a hold |
| POST | /planned-courses | REGISTRATION.REGISTER | Create a planned cours |
| DELETE | /planned-courses/{plannedID} | REGISTRATION.REGISTER | Delete a planned cours |
| PATCH | /planned-courses/{plannedID} | REGISTRATION.REGISTER | Update a planned cours |
| GET | /planned-courses/{studentID} | REGISTRATION.REGISTER | Get one planned cours |
| GET | /planning | REGISTRATION.REGISTER | Get planning |
| POST | /planning | REGISTRATION.REGISTER | Create planning |
| POST | /planning/check_conflicts | REGISTRATION.REGISTER | Check conflicts |
| POST | /planning/check_corequisites | REGISTRATION.REGISTER | Check corequisites |
| POST | /planning/check_credit_limit | REGISTRATION.REGISTER | Check credit limit |
| POST | /planning/check_prerequisites | REGISTRATION.REGISTER | Check prerequisites |
| POST | /planning/check_repeat | REGISTRATION.REGISTER | Check repeat limits |
| POST | /planning/check_sequence | REGISTRATION.REGISTER | Check sequence |
| POST | /planning/convert_to_registration | REGISTRATION.REGISTER | Convert to registration |
| GET | /planning/courses_for_pattern | REGISTRATION.REGISTER | Get courses for pattern |
| GET | /planning/search_courses | REGISTRATION.REGISTER | List search courses |
| GET | /planning/sections_for_course | REGISTRATION.REGISTER | Get sections for course |
| GET | /planning/suggest_prereq_plans | REGISTRATION.REGISTER | Suggest prereq plans |
| DELETE | /planning/{plannedID} | REGISTRATION.REGISTER | Delete a planning |
| GET | /planning/{plannedID} | REGISTRATION.REGISTER | Get one planning |
| GET | /student-holds | REGISTRATION.HOLDS | List student holds |
| POST | /student-holds | REGISTRATION.HOLDS | Create a student hold |
| POST | /students/{studentID}/failed-course-cascade | REGISTRATION.APPROVALS | Remove plans stranded by a failed course (?preview=1) |
| POST | /student-holds/bulk_create | REGISTRATION.HOLDS | Bulk create |
| POST | /student-holds/bulk_create_from_list | REGISTRATION.HOLDS | Bulk create from list |
| POST | /student-holds/check_holds | REGISTRATION.HOLDS | Check holds |
| GET | /student-holds/my_holds | REGISTRATION.MY_HOLDS | List my holds |
| GET | /student-holds/{holdID} | REGISTRATION.HOLDS | Get one student hold |
| POST | /student-holds/{holdID}/clear | REGISTRATION.HOLDS | Clear for a student hold |
| GET | /term-enrollments | REGISTRATION | List term enrollments |
| POST | /term-enrollments | REGISTRATION | Create a term enrollment |
| DELETE | /term-enrollments/{enrollmentID} | REGISTRATION | Delete a term enrollment |
| GET | /term-enrollments/{enrollmentID} | REGISTRATION | Get one term enrollment |
| PATCH | /term-enrollments/{enrollmentID} | REGISTRATION | Update a term enrollment |
| GET | /transactions | REGISTRATION.ALL_TRANSACTIONS | List transactions |
| POST | /transactions | REGISTRATION.REGISTER | Create a transaction |
| GET | /transactions/mine | REGISTRATION.MY_TRANSACTIONS (VIEW) | The caller's own transactions |
| DELETE | /transactions/{transactionID} | REGISTRATION.REGISTER | Cancel a transaction |
| GET | /transactions/{transactionID} | REGISTRATION.REGISTER | Get one transaction |
| POST | /transactions/{transactionID}/add_item | REGISTRATION.REGISTER | Add item for a transaction |
| POST | /transactions/{transactionID}/approve | REGISTRATION.APPROVALS | Approve a request |
| POST | /transactions/{transactionID}/complete | REGISTRATION.REGISTER | Complete for a transaction |
| GET | /transactions/{transactionID}/history | REGISTRATION.REGISTER | Get the transaction's history |
| DELETE | /transactions/{transactionID}/items/{itemID} | REGISTRATION.REGISTER | Delete a item |
| GET | /transactions/{transactionID}/notes | REGISTRATION.REGISTER | List the transaction's notes |
| POST | /transactions/{transactionID}/notes | REGISTRATION.REGISTER | Add a note |
| POST | /transactions/{transactionID}/override | REGISTRATION.OVERRIDE | Override for a transaction |
| POST | /transactions/{transactionID}/reject | REGISTRATION.APPROVALS | Reject a request with a reason |
| POST | /transactions/{transactionID}/submit | REGISTRATION.REGISTER | Submit for a transaction |
| POST | /transactions/{transactionID}/transition | REGISTRATION.REGISTER | Transition for a transaction |
| POST | /transactions/{transactionID}/validate | REGISTRATION.REGISTER | Validate for a transaction |
| POST | /waitlist | REGISTRATION.REGISTER | Create waitlist |
| GET | /waitlist/section/{sectionID} | REGISTRATION.WAITLISTS | Get one section |
| GET | /waitlist/student/{studentID} | REGISTRATION.WAITLISTS | Get one student |
| POST | /waitlist/{waitlistID}/cancel | REGISTRATION.WAITLISTS | Cancel for a waitlist |
| GET | /waitlists | REGISTRATION.WAITLISTS | List waitlists |
| POST | /waitlists | REGISTRATION.REGISTER | Join a waitlist |
| GET | /waitlists/for_student | REGISTRATION.REGISTER | A student's own waitlist entries |
| DELETE | /waitlists/{waitlistID} | REGISTRATION.WAITLISTS | Remove from a waitlist |
| GET | /waitlists/{waitlistID} | REGISTRATION.WAITLISTS | Get one waitlist entry (stub: always 404) |
| POST | /waitlists/{waitlistID}/convert_to_transaction | REGISTRATION.WAITLISTS | Promote: add the section to the student's registration transaction |
| POST | /waitlists/{waitlistID}/leave | REGISTRATION.REGISTER | Leave a waitlist |