Enrolments and student progress
"Who's enrolled, and how far have they got?" is the question most schools eventually want answered in a spreadsheet, a CRM or a dashboard. For most schools, one request answers both halves.
Who's enrolled, and how far they've got
GET /v1/courses/{course_id}/enrollments
This lists the students enrolled in a course, a page at a time. Each entry
has the student's ID and their overall percent_complete, along
with when they enrolled and, if they have, when they finished.
With optio-teachable:
const { enrollments } = await teachable.v1.courses.getEnrolments(3033045);
enrollments[0].user_id; // who
enrollments[0].percent_complete; // how far, 0 to 100
const { users } = await teachable.v1.users.getByEmail('student@example.com');
const student = users[0];
getByEmail is handy on its own: most requests start with an email
address from somewhere else, and this turns it into a Teachable user. It
returns a list, so take the first match.
Putting them together
A whole course, every page of students, in a list ready for a spreadsheet:
async function courseProgress(courseId) {
const rows = [];
let page = 1, pages = 1;
do {
const { enrollments, meta } = await teachable.v1.courses.getEnrolments(courseId, page, 100);
for (const e of enrollments) {
rows.push({ user: e.user_id, percent: e.percent_complete ?? 0 });
}
pages = meta?.number_of_pages ?? 1;
page++;
} while (page <= pages);
return rows;
}
The paging is the same loop as the last lesson. That's one request per 100 students, so even a large course takes a handful of requests.
Lesson by lesson
GET /v1/courses/{course_id}/progress?user_id={user_id}
When you need more than the percentage, this gives one student's progress lesson by lesson: every section, and whether each lesson in it is complete.
const { course_progress } = await teachable.v1.courses.getProgress(3033045, student.id);
course_progress.percent_complete; // 0 to 100
course_progress.lecture_sections; // each section, with is_completed on every lesson
That's one request per student, so save it for the students you actually need detail on, not the whole course. Asking for every student at once is how a script runs into the rate limit in the next lesson.
Enrolling someone
V1 can enrol a student too:
POST /v1/enroll
It's how you'd give access after a purchase made somewhere other than Teachable. optio-teachable only reads, so this one is a plain request, sent the same way as the one in lesson 2. In V2, enrolments can be created, updated and removed, with the right scopes.
For keeping something up to date, don't poll every student every hour. Let
Enrollment.created and LectureProgress.created webhooks
tell you what changed, and use these requests to fill in detail and catch up
once a day.
In short
- /courses/{id}/enrollments lists who's in a course, with each student's percent_complete.
- /courses/{id}/progress?user_id= adds lesson-by-lesson detail, one student at a time.
- Use the enrolment list for the big picture, and let webhooks do the day-to-day work.