> For the complete documentation index, see [llms.txt](https://docs.stellic.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.stellic.com/stellic-partner-api/student/read-a-student-s-progress-summary.md).

# Read a student's progress summary

Use this endpoint for a student's completion percentages: overall, for each credential, and for each declared program. The numbers come from the student's graded and registered courses against their declared programs, computed when you call. `completion_percentage` is `(taken + in_progress + registered) / (taken + in_progress + registered + remaining) × 100`, rounded to two decimals, and `0.0` when there's nothing to count.

## GET /student/{student\_username}/progress/summary

>

```json
{"openapi":"3.0.0","info":{"title":"Stellic for Developers","version":"1.0"},"tags":[{"name":"Student"}],"servers":[{"url":"https://{institution}.stellic.com/partnerapi/v1","variables":{"institution":{"default":"{institution}","description":"Your institution's Stellic subdomain: the part before `.stellic.com` in the URL you use to sign in. It becomes the host in every request, as in `https://{institution}.stellic.com/partnerapi/v1/...`. Replace the `{institution}` placeholder with your subdomain before sending."}}}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Personal Access Token issued by your Stellic integration partner. Send it as `Authorization: Bearer <token>` on every request. One token per institution; do not share across environments."}},"schemas":{"ProgressSummaryResponse":{"type":"object","properties":{"success":{"type":"boolean"},"progress_last_computed":{"type":"string","description":"When Stellic last saved the audit for the student's default plan (the one students and advisors see in Stellic), in UTC, formatted `MM/DD/YYYY HH:MM:SS`. Not the time of this response: the progress numbers are computed on every call, while this timestamp moves only when that saved audit is updated.\n\n`null` when no audit has been saved for the default plan yet.","nullable":true},"progress_dict":{"type":"object","properties":{"overall":{"type":"object","description":"Overall progress across all credentials and programs.","properties":{"courses":{"description":"Overall course/unit progress. The key name is `courses` on course-counting universities; on unit-counting universities it is renamed to the unit term (for example `credits` or `hours`). The rename applies at every level of the response.","allOf":[{"$ref":"#/components/schemas/CoursesProgressEntry"}]},"milestones":{"$ref":"#/components/schemas/MilestonesProgressEntry"}}},"credentials":{"type":"object","description":"Per-credential (diploma) progress. Outer keys are the student's credential-enrollment IDs, which no other endpoint uses, not the catalog credential IDs; the inner `id` field on each entry is the catalog credential ID. Credentials appear only at institutions that track degree requirements; elsewhere this object is empty.","additionalProperties":{"$ref":"#/components/schemas/CredentialProgress"}},"programs":{"type":"object","description":"Per-program progress. Outer keys are the student's program-enrollment IDs, which no other endpoint uses, not the catalog program IDs; the inner `id` field on each entry is the catalog program ID.","additionalProperties":{"$ref":"#/components/schemas/ProgramProgress"}}}}}},"CoursesProgressEntry":{"type":"object","description":"Progress data for courses (or units, depending on university configuration).","properties":{"completion_percentage":{"type":"number","format":"float","description":"Percentage of completion, rounded to 2 decimal places. Always returned as a JSON float (e.g., `0.0`, `62.5`, `80.0`), never a bare integer.\n\nFormula: `(taken + in_progress + registered) / (taken + in_progress + registered + remaining) * 100`. Returns `0.0` when total is 0. `unmatched` is excluded from the formula."},"taken":{"type":"number","description":"Count of courses or units already taken."},"in_progress":{"type":"number","description":"Count of courses or units currently in progress."},"registered":{"type":"number","description":"Count of courses or units registered for a future term."},"remaining":{"type":"number","description":"Count of courses or units still required to satisfy the audit."},"unmatched":{"type":"number","description":"Count of courses or units that did not match any requirement, plus withdrawn courses or units. Excluded from the completion percentage formula. Only `overall` carries a real count; on credential and program entries this is always `0`."}}},"MilestonesProgressEntry":{"type":"object","description":"Progress data for milestones. Counts are returned as JSON numbers (for example `4.0`), not integers. Milestone entries do not include an `unmatched` field; that field exists only on the courses/units entry.","properties":{"completion_percentage":{"type":"number","format":"float","description":"Percentage of completion, rounded to 2 decimal places. Always returned as a JSON float."},"taken":{"type":"number","description":"Number of milestones taken."},"in_progress":{"type":"number","description":"Number of milestones in progress."},"registered":{"type":"number","description":"Number of milestones registered."},"remaining":{"type":"number","description":"Number of milestones remaining."}}},"CredentialProgress":{"type":"object","description":"Progress data for a credential (diploma).","properties":{"id":{"type":"integer","description":"Catalog ID of the credential. The outer key of this entry in `credentials` is the plan-credential link ID, a different number."},"name":{"type":"string","description":"Name of the credential."},"sis_id":{"type":"string","description":"Partner-supplied SIS identifier for the credential. (Programs use `external_id` for the equivalent identifier; same idea, different field name per entry type.)"},"courses":{"description":"Course or unit progress for this credential. The key name is `courses` on course-counting universities; on unit-counting universities it is renamed to the unit term (for example `credits` or `hours`).","allOf":[{"$ref":"#/components/schemas/CoursesProgressEntry"}]},"milestones":{"$ref":"#/components/schemas/MilestonesProgressEntry"}}},"ProgramProgress":{"type":"object","description":"Progress data for a program.","properties":{"id":{"type":"integer","description":"Catalog ID of the program. The outer key of this entry in `programs` is the plan-program link ID, a different number."},"name":{"type":"string","description":"Name of the program."},"external_id":{"type":"string","description":"Partner-supplied external identifier for the program. (Credentials use `sis_id` for the equivalent identifier; same idea, different field name per entry type.)"},"program_type":{"type":"string","description":"Type of the program (for example, Major, Minor). `null` when the program has no type assigned.","nullable":true},"shared_requirement":{"type":"object","description":"Present only when the program is a general requirement.","properties":{"id":{"description":"ID of the general requirement. The string `\"ERR\"` when the program is marked as a general requirement but has none attached.","oneOf":[{"type":"integer"},{"type":"string"}]}}},"courses":{"description":"Course or unit progress for this program. The key name is `courses` on course-counting universities; on unit-counting universities it is renamed to the unit term (for example `credits` or `hours`).","allOf":[{"$ref":"#/components/schemas/CoursesProgressEntry"}]},"milestones":{"$ref":"#/components/schemas/MilestonesProgressEntry"}}}}},"paths":{"/student/{student_username}/progress/summary":{"get":{"tags":["Student"],"parameters":[{"name":"student_username","in":"path","description":"Student's Stellic username. Matched exactly; not lowercased.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProgressSummaryResponse"}}}},"400":{"description":"The body reads `Audit Cache has not been populated for this student yet`.","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"array","items":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"401":{"description":"Unauthorized."},"403":{"description":"Your IP address isn't on the allowlist for this endpoint. Contact Stellic to add it; the response includes the `client_ip` Stellic saw.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"},"client_ip":{"type":"string"}}}}}},"404":{"description":"Three paths trigger this:\n\n- Student not found: `Student with username '<username>' not found`.\n- Student without a default plan: `Student with username '<username>' does not have a plan`.\n- Stellic couldn't produce an audit for the student's default plan: `'Audit not found or Audit progress has not been populated for this student'`. The literal single quotes around the message are part of the JSON string; strip them on your side if you display the message.","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"array","items":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"500":{"description":"Unhandled error. Body is `{\"errors\": []}` (empty array), not a parseable message. Treat any `500` as opaque and log the HTTP code.","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"array","description":"Always an empty array on this endpoint.","items":{"type":"object"}}}}}}}}}}}}
```

#### Notes

* **Expect slow responses for students with several programs.** Each call runs a full audit.
* **The numbers can differ from the in-app audit.** General requirements count only when they're declared.
* **`programs` and `credentials` are keyed by the student's program-enrollment and credential-enrollment IDs,** which no other endpoint uses. Match entries by the `external_id` (programs) or `sis_id` (credentials) inside each one; the `id` there is the program's or credential's own ID. Credentials appear only at institutions that track degree requirements.
* **At institutions that count units, the `courses` key is named after the unit** (for example `credits`) at every level.
* **Only `overall` has a real `unmatched` count**, and it includes withdrawn courses. On credential and program entries, `unmatched` is always 0.
* **`progress_last_computed` isn't the time of this response.** It's when Stellic last saved the student's audit, in UTC, as `MM/DD/YYYY HH:MM:SS`.
* **Archived students get a new computation, not their audit as saved at archive.** Use [`GET /student/{student_username}/gpas`](/stellic-partner-api/student/read-a-student-s-gpas.md) or the in-app audit for the saved version.

#### Related APIs

* [`GET /student/{student_username}/audit/official/{course_filter}/{property}`](/stellic-partner-api/student/read-a-student-s-official-degree-audit.md) for the full audit behind these numbers.
* [`GET /student/{student_username}/gpas`](/stellic-partner-api/student/read-a-student-s-gpas.md) for the student's GPAs.
