Skip to main content
A Course in Cativa is a sequence of lessons organized into modules. It lives inside a Group and issues a certificate when the student completes it. Course access is gated by a badge, and every certificate carries a code that anyone can verify publicly, with no key, which is ideal for “validate certificate” pages. Think of a course as a book: the module is the chapter, the lesson is the page. The student turns page by page, and progress is simply how many pages they have read. The library card (the badge) is what lets them check the book out: without it, they can’t even open it.

The hierarchy

A Course groups Modules, each Module groups Lessons. The student advances lesson by lesson, and progress is measured by the share of completed lessons. When the course is completed, the certificate is issued.
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.
The partner does not configure the access rule, but triggers the transition: by assigning the badge to the user, they gain access to the course and can enroll. In practice, access delivery almost always comes from a badge tied to a purchase or subscription. See the Grant access via purchase guide.
Do not treat enrollment as the access mechanism. Access belongs to the badge. Enrolling without the matching badge returns 403 forbidden. Always model unlocking through the badge, never by creating one course per customer.

Base URL and authentication

Every call uses the public API base:
Authenticate with an API Key in the header, except the public certificate validation endpoint (covered below):
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.
To edit course metadata, use 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.
Illustrative progress response (the authoritative schema is in the API Reference, tag Course). progressPercentage derives from completedLessons / totalLessons:
The student is always the user tied to the authenticated credential. Do not send 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.
Illustrative response (full schema in the API Reference, tag Certificate). The 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

Don’t create one course per incoming customer. Courses are static content entities, not per-user containers. To customize who has access, use badges: a single course and the badge assigned to the right students. Enrollment and the certificate follow the badge, not a copy of the course.

Common errors and questions

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.
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.
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.
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).
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.