The hierarchy
A Course is a static entity defined by the tenant admin, in the same spirit as Groups and Spaces. Creating structure (course, module, lesson) requires admin scope. See Communities and Spaces for the full rule on who creates what.
Course access: the badge gates it
Just like Groups, a Course is unlocked by a badge. A student can only enroll and consume lessons if they hold the badge the course requires. This is configured in the admin dashboard, not through the partner API.Base URL and authentication
Every call uses the public API base:IDs are ULIDs (e.g.
01HQ5ABCDEF1234567890XYZ). Do not infer response payload shapes from the examples here. For the exact schema of each field, check the API Reference tab and filter by the Course and Certificate tags.Read courses
Create a course
Creating a course requires admin scope. Partner keys with default scope cannot reach this category. The natural flow is the admin building the structure in the dashboard, but the endpoint exists for administrative automations.PUT /education/courses/{courseId} (general update) or PATCH /admin/courses/{courseId} (targeted admin adjustment). To remove it, DELETE /admin/courses/{courseId}.
Modules and lessons (admin)
The course’s internal structure is managed under the/admin/education/courses/{courseId} prefix:
From an empty course to an enrolled student
1
Create the course (admin)
POST /education/courses with groupId and a title. Keep the returned courseId.2
Add modules and lessons (admin)
POST /admin/education/courses/{courseId}/modules creates the module; then POST .../modules/{moduleId}/lessons creates each lesson. Repeat until the track is built.3
Unlock access via a badge
Student access comes from the badge the course requires (configured in the dashboard). Assign that badge to the user (typically via a purchase or subscription). See Grant access via purchase.
4
Enroll and complete (student)
With the badge, the user calls
POST .../enroll, advances by marking PUT .../lessons/{lessonId}/complete, and receives the certificate once every lesson is done.Enrollment and progress (student)
On the student side, the cycle is enroll, track progress, and complete lesson by lesson.progressPercentage derives from completedLessons / totalLessons:
userId in the body. If the user lacks the badge the course requires, enrollment returns 403 forbidden.
When every lesson is complete, the course counts as finished and the certificate is issued. The student can download the course certificate PDF:
Certificates
On course completion, a certificate is issued to the student. Each certificate carries a verification code.Public verification by code (anonymous)
This is the only endpoint in the family that needs no key. It confirms a certificate’s authenticity by its code, ideal for a public “validate certificate” page where anyone pastes a code and checks whether it is legitimate.url points to the certificate PDF, and code is the same validated code:
Because it is anonymous, wire this flow straight into your site without passing the API Key to the browser. The code is the only input needed.
Other certificate reads
Certificate administration (admin)
The template and manual issuance live under/admin/certificates:
We do not lay out each certificate response field here. Check the API Reference tab under the Certificate tag for the exact issuance, template and validation contracts.
Anti-pattern: one course per customer
Common errors and questions
403 forbidden when enrolling the student
403 forbidden when enrolling the student
The badge the course requires is missing. Enrollment is not the access mechanism: access belongs to the badge. Assign the badge configured on the course to the user (typically via a purchase/subscription) and retry
enroll. See Grant access via purchase.I enrolled the same student twice
I enrolled the same student twice
Enrollment is idempotent per user and course: enrolling again does not create a second enrollment or reset progress. You can safely retry it in sync jobs.
All lessons complete but no certificate was issued
All lessons complete but no certificate was issued
The certificate is issued when progress reaches 100% (every lesson marked
complete). Check the user’s progress: if completedLessons is below totalLessons, a lesson is still pending. Lessons added to the course later count too and can reopen the pending state.Do I need the API Key to validate a certificate on my site?
Do I need the API Key to validate a certificate on my site?
No.
GET /certificates/validate/{code} is the only endpoint in the family that needs no key. Call it straight from the browser on your “validate certificate” landing page. Never put the API Key in the frontend for the other endpoints (those are server-side).Should I create one course per customer who buys?
Should I create one course per customer who buys?
No. A course is static content, not a per-user container. A single course serves everyone; the badge assigned to the right students is what customizes access. One course per customer becomes dead duplication and breaks enrollment.
Next steps
Badges as Permissions
How course access is gated by a badge, without creating new structure.
Grant access via purchase
The typical flow: an external purchase assigns the badge that enrolls the student.
Events
How events and lives sit alongside courses in the community.
