GET /v2/courses/{course_id}/progress
Course progress
Returns chapter-by-chapter status while a course is being built. Cheap to poll — designed for a 1–3s loop until progress_pct === 100.
If you’d rather not poll, register a webhook for course.completed and course.failed instead. See Register webhook.
Request
Headers
| Header | Required | Notes |
|---|---|---|
X-API-Key | yes | |
X-External-User-Id | yes (or X-User-Id) | Must own the course |
Path parameters
course_id string (UUID) required The course’s ID. |
Returns
{
"course_id": "8fa640c0-22e6-436b-becd-bf2cfc86741a",
"course_status": "generating",
"job_id": "j_01HW0XYZ…",
"job_status": "running",
"progress_pct": 60,
"expected_chapters": 5,
"completed_chapters": 3,
"chapters": [
{ "order": 0, "title": "Sunlight & Chlorophyll", "status": "completed", "completed_at": "2026-05-19T14:02:51Z" },
{ "order": 1, "title": "The Calvin Cycle", "status": "completed", "completed_at": "2026-05-19T14:03:12Z" },
{ "order": 2, "title": "Light-dependent rxns", "status": "completed", "completed_at": "2026-05-19T14:03:30Z" },
{ "order": 3, "title": "C4 plants", "status": "running", "completed_at": null },
{ "order": 4, "title": "Field photosynthesis", "status": "pending", "completed_at": null }
],
"error": null
}
If generation fails, course_status becomes "failed", job_status becomes "failed", and error carries the structured reason.
progress_pct is computed as completed_chapters / expected_chapters * 100, capped at 99 until the job itself reports completion. It hits 100 only when the entire course (including auto-generated study guide) is committed.
Errors
- 404 — No course with that ID for the calling user.