Single student walkthrough
POST /v1/calculate accepts a JSON document describing one student's degree status and term schedule, and returns a JSON document with the prorated annual eligibility and per-term distributions.
Endpoint
curl -X POST https://loanlimit.app/v1/calculate \
-H 'content-type: application/json' \
--data-binary @student.json
Request shape
The request body has three parts: student-level fields (dependency, degree, grade), financial-aid context (subsidized amount, legacy-borrower status, optional institutional limit), and terms (an ordered list of enrollment periods).
Student-level fields
| Field | Type | Required | Notes |
|---|---|---|---|
dependency_status |
"dependent" | "independent" |
yes | Use the dependency status applicable after any dependency-override determination. |
degree_level |
"undergraduate" | "graduate" | "professional" |
yes | Drives the loan-limit lookup. |
grade_level |
"first_year" | "second_year" | "third_year_and_beyond" | null |
required for undergraduate, must be null for graduate/professional |
|
subsidized_amount |
integer ≥ 0 | no (default 0) | The subsidized portion of the annual limit being claimed. Must not exceed the statutory subsidized max for the student's tier. |
plus_denied |
boolean | no (default false) |
Set true for dependent undergraduates whose parents were denied a PLUS loan — they receive independent-tier unsubsidized limits. |
is_legacy_borrower |
boolean | no (default false) |
Only valid for graduate/professional. Marks a student who borrowed before July 1, 2026 and remains within their expected time to credential per §685.203(b)(2)(iv)(B). |
cost_of_attendance |
integer or null |
required when is_legacy_borrower=true; must be null otherwise |
Used to derive legacy Grad PLUS max as COA - $20,500. Must be greater than $20,500. |
total_limit |
integer or null |
optional | If your institution has set a lower program limit under §685.203(m)(2), pass it here. The API uses the lower of this and the statutory max. |
Terms
A list of 1–4 Term objects in chronological order:
| Field | Type | Required | Notes |
|---|---|---|---|
label |
string | yes | E.g., "Fall", "Spring". Appears in the response. |
full_time_credits |
number > 0 | yes | Your institution's full-time credit standard for the term (usually 12 for undergrads). |
credits_enrolled |
number > 0 | yes | The student's enrolled credits (Title IV eligible) for the term. |
actual_final_credits |
number ≥ 0 or null |
no | Set when reconciling after an enrollment change — see Enrollment changes. |
prior_disbursement_sub |
integer ≥ 0 or null |
no | Dollar amount of subsidized loan actually disbursed for an already-disbursed term. |
prior_disbursement_unsub |
integer ≥ 0 or null |
no | Same for unsubsidized. |
prior_disbursement_grad_plus |
integer ≥ 0 or null |
no | Same for Grad PLUS (legacy borrowers only). |
Single-term mode
For single-term loans (one Term in the list), include the academic-year denominator:
| Field | Type | Required | Notes |
|---|---|---|---|
academic_year_terms |
integer 2–4 | yes when terms has length 1 |
The term fraction is 1 / academic_year_terms. Use 2 for semester, 3 for trimester, 4 for quarter. |
Must be null when there are 2+ terms.
Response shape
The top-level response contains:
annual_ft_credits— sum of full-time credits across all terms (the denominator for the reduced annual percentage).reduced_annual_pct— rounded enrollment-intensity percentage applied to the annual limit.annual_basic_eligibility_sub/..._unsub/..._grad_plus— the reduced annual limit in dollars for each loan type.terms— per-term breakdown (see below).total_equal/total_proportional— annual sums for each distribution method.show_both_options— whether equal and proportional differ meaningfully (false when there's a single eligible term or all eligible terms have identical credits).warnings— flat list of human-readable warning strings.
Each terms[i] carries label, credits_enrolled, full_time_credits, enrollment_intensity_pct, disbursement_pct, enrollment_status, equal, proportional, adjustment_sub, adjustment_unsub, adjustment_grad_plus, adjustment_explanation, adjustment_source_index, warning, and final_term_overdisbursement. See the API reference for full schemas.
Enrollment changes
When a student drops or adds credits mid-term, set actual_final_credits on the affected term. The engine recalculates the entire student's entitlement using actual enrollment, treating the original credits_enrolled as the projection.
Set prior_disbursement_* on already-disbursed terms to tell the engine what was actually given. If omitted, the engine assumes the full equal-distribution amount was disbursed.
If a prior disbursement exceeds the recalculated entitlement for that term, the carry is deducted from the next undisbursed term. The adjustment_* fields on the absorbing term report the deduction; adjustment_source_index points back to the term that caused it. If the over-disbursement is on the final term (no future term to absorb), final_term_overdisbursement: true is set; the school must seek reimbursement per regulatory process.
prior_disbursement_* values are validated against the pre-drop maximum. Submitting a value that exceeds what could have been disbursed at the original enrollment level returns a 422 with a field-level error such as terms_2_priorDisbursementSub: "Cannot exceed $4,500".
Error responses
See Error handling.