Enrollments
An enrollment represents a single learner assigned to a single course. Reading
(GET), creating (POST), bulk-creating (POST /enrollments/bulk), fetching one
(GET /enrollments/{id}), reading its progress (GET /enrollments/{id}/progress),
updating (PATCH /enrollments/{id}, e.g. the due date), and unenrolling
(DELETE /enrollments/{id}) are all available. Reads need the read scope,
creates and updates the write scope, and unenroll the admin scope.
The Enrollment Object
{
"id": "d6e5f4a3-7b8c-9012-defa-123456789012",
"user_id": "a3f2c1d0-4e5b-6789-abcd-ef0123456789",
"course_id": "e7f6a5b4-8c9d-0123-efab-234567890123",
"status": "active",
"due_date": "2026-07-01T00:00:00Z",
"completed_at": null,
"source": "native",
"created_at": "2026-05-01T08:00:00Z"
}| Field | Type | Notes |
|---|---|---|
id | uuid | Enrollment UUID |
user_id | uuid | The enrolled learner |
course_id | uuid | The course |
status | string | See status values below |
due_date | ISO 8601 | null | Deadline for completion, if set |
completed_at | ISO 8601 | null | When the course was completed |
source | string | native or import (Switcher historical data) |
created_at | ISO 8601 | When the enrollment was created |
Enrollment status values:
| Status | Description |
|---|---|
active | Enrollment is in effect — the learner can take the course |
completed | Course finished |
dropped | Learner was unenrolled / dropped the course |
expired | Enrollment validity window has passed |
waitlisted | Waiting for a seat (session/capacity-limited courses) |
pending_approval | Awaiting manager approval |
Endpoints
List Enrollments
GET /api/v1/enrollmentsReturns a paginated list of enrollments across the tenant, most recently created first.
Authentication required: API key with the read scope
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Default: 1 |
per_page | integer | No | Default: 50, max: 200 |
user_id | UUID | No | Filter by user |
course_id | UUID | No | Filter by course |
status | string | No | Filter: active, completed, dropped, expired, waitlisted, pending_approval |
Example Request
curl "https://{your-subdomain}.embaylms.com/api/v1/enrollments?status=active&course_id=e7f6a5b4-8c9d-0123-efab-234567890123" \
-H "Authorization: Bearer ems_live_0000000000000000000000000000"Example Response
{
"data": [
{
"id": "d6e5f4a3-7b8c-9012-defa-123456789012",
"user_id": "a3f2c1d0-4e5b-6789-abcd-ef0123456789",
"course_id": "e7f6a5b4-8c9d-0123-efab-234567890123",
"status": "active",
"due_date": "2026-05-01T00:00:00Z",
"completed_at": null,
"source": "native",
"created_at": "2026-04-01T08:00:00Z"
}
],
"meta": { "page": 1, "per_page": 50, "total": 23 },
"error": null
}Common Errors
Errors use the standard envelope with a numeric error.code matching the HTTP
status — see Errors.
| HTTP Status | Description |
|---|---|
401 | Missing or invalid API key |
403 | Key lacks the read scope, or the API is not included in your plan |
429 | Rate limit or monthly usage cap exceeded — see Rate Limits |
Available.
POST /enrollments(create),POST /enrollments/bulk,GET /enrollments/{id}, andDELETE /enrollments/{id}(unenroll) shipped in the first LMS-539 write tranche.PATCH /enrollments/{id}(change due date),GET /enrollments/{id}/progress, and the additionalGET /enrollmentslist filters (group_id,due_before,due_after,created_after,sort_by,sort_order) shipped inLMS-574and are now live.
Additional List Filters
The following GET /api/v1/enrollments query parameters are available:
| Parameter | Type | Description |
|---|---|---|
group_id | UUID | Filter enrollments for users in a specific group |
due_before | ISO 8601 | Filter enrollments with due date before this timestamp |
due_after | ISO 8601 | Filter enrollments with due date after this timestamp |
created_after | ISO 8601 | Filter enrollments created after this timestamp |
sort_by | string | enrolled_at, due_date, completed_at. Default: enrolled_at |
sort_order | string | asc or desc. Default: desc |
The write API also extends the Enrollment object with progress_percent,
score, pass_fail, enrolled_at, started_at, certificate_id, and
updated_at fields, as shown in the examples below.
Create Enrollment
POST /api/v1/enrollmentsEnrolls a user in a course through the same enrollment engine as the in-app flow: the enrollment window, seat cap (waitlisting when enabled), manager-approval requirement (status pending_approval), and prerequisites are all enforced. The course must be published. A live enrollment (active, completed, waitlisted, or pending approval) returns 409; a previously dropped or expired enrollment is reactivated with a clean slate. A confirmation notification is always sent to the learner.
Authentication required: write scope
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
user_id | UUID | Yes | User to enroll |
course_id | UUID | Yes | Course to enroll the user in |
due_date | ISO 8601 | No | Deadline for completion |
Example Request
curl -X POST https://{your-subdomain}.embaylms.com/api/v1/enrollments \
-H "Authorization: Bearer ems_live_0000000000000000000000000000" \
-H "Content-Type: application/json" \
-d '{
"user_id": "a3f2c1d0-4e5b-6789-abcd-ef0123456789",
"course_id": "e7f6a5b4-8c9d-0123-efab-234567890123",
"due_date": "2026-09-01T00:00:00Z"
}'Example Response
{
"data": {
"id": "5e6f7a8b-9c0d-1234-efab-234567890123",
"user_id": "a3f2c1d0-4e5b-6789-abcd-ef0123456789",
"course_id": "e7f6a5b4-8c9d-0123-efab-234567890123",
"status": "active",
"due_date": "2026-09-01T00:00:00Z",
"created_at": "2026-06-05T10:30:00Z"
},
"meta": null,
"error": null
}HTTP Status: 201 Created
status is active, pending_approval (the course requires manager approval), or waitlisted (the course is full and has a waitlist). Progress and completion details live on Get Enrollment Progress.
Common Errors
| HTTP Status | Description |
|---|---|
404 | User or course does not exist |
409 | User already has a live enrollment (active/completed/waitlisted/pending approval) in this course |
422 | Enrollment rejected: window closed, course full with no waitlist, prerequisites incomplete, or an ILT series selection is required (enroll in-app) |
422 | Course is not in published status |
Get Enrollment
GET /api/v1/enrollments/{id}Returns a single enrollment by UUID.
Authentication required: read scope
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Enrollment UUID |
Example Request
curl "https://{your-subdomain}.embaylms.com/api/v1/enrollments/d6e5f4a3-7b8c-9012-defa-123456789012" \
-H "Authorization: Bearer ems_live_0000000000000000000000000000"Example Response
Returns the full enrollment object (see The Enrollment Object).
Update Enrollment
PATCH /api/v1/enrollments/{id}Updates mutable fields on an enrollment. Currently supports updating the due date.
Authentication required: write scope
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Enrollment UUID |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
due_date | ISO 8601 or null | No | New due date. Pass null to remove the due date |
Example Request
curl -X PATCH "https://{your-subdomain}.embaylms.com/api/v1/enrollments/d6e5f4a3-7b8c-9012-defa-123456789012" \
-H "Authorization: Bearer ems_live_0000000000000000000000000000" \
-H "Content-Type: application/json" \
-d '{ "due_date": "2026-10-01T00:00:00Z" }'Example Response
Returns the updated enrollment object.
Unenroll
DELETE /api/v1/enrollments/{id}Unenrolls a user from a course. If the course has been completed, the enrollment cannot be deleted — it becomes a permanent part of the user’s transcript. Use this only to remove enrollments that have not yet been completed.
Authentication required: admin scope
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Enrollment UUID |
Example Request
curl -X DELETE "https://{your-subdomain}.embaylms.com/api/v1/enrollments/d6e5f4a3-7b8c-9012-defa-123456789012" \
-H "Authorization: Bearer ems_live_0000000000000000000000000000"HTTP Status: 204 No Content
Common Errors
| HTTP Status | Description |
|---|---|
422 | Enrollment is already completed and cannot be deleted |
Bulk Enroll
POST /api/v1/enrollments/bulkEnrolls up to 500 users in one or more courses in a single request. Every row runs the full enrollment engine independently; rows that fail (already enrolled, course full, prerequisites, etc.) are reported per-row in errors[] with the batch returning 207 Multi-Status — the remaining rows still succeed. Confirmation notifications are sent per enrollment.
Authentication required: write scope
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
enrollments | Enrollment[] | Yes | Array of enrollment objects (max 500) |
Each item in enrollments:
| Field | Type | Required | Description |
|---|---|---|---|
user_id | UUID | Yes | User to enroll |
course_id | UUID | Yes | Course to enroll in |
due_date | ISO 8601 | No | Deadline for completion |
Example Request
curl -X POST https://{your-subdomain}.embaylms.com/api/v1/enrollments/bulk \
-H "Authorization: Bearer ems_live_0000000000000000000000000000" \
-H "Content-Type: application/json" \
-d '{
"enrollments": [
{
"user_id": "a3f2c1d0-4e5b-6789-abcd-ef0123456789",
"course_id": "e7f6a5b4-8c9d-0123-efab-234567890123",
"due_date": "2026-09-01T00:00:00Z"
},
{
"user_id": "c5d4e3f2-6a7b-8901-cdef-012345678901",
"course_id": "e7f6a5b4-8c9d-0123-efab-234567890123",
"due_date": "2026-09-01T00:00:00Z"
}
]
}'Example Response
{
"data": {
"created": 2,
"skipped": 0,
"errors": []
},
"meta": null,
"error": null
}HTTP Status: 207 Multi-Status on partial errors; 201 when all succeed.
Get Enrollment Progress
GET /api/v1/enrollments/{id}/progressReturns detailed progress data for an enrollment — module-level completion, scores, and time spent.
Authentication required: read scope
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | UUID | Yes | Enrollment UUID |
Example Request
curl "https://{your-subdomain}.embaylms.com/api/v1/enrollments/d6e5f4a3-7b8c-9012-defa-123456789012/progress" \
-H "Authorization: Bearer ems_live_0000000000000000000000000000"Example Response
{
"data": {
"enrollment_id": "d6e5f4a3-7b8c-9012-defa-123456789012",
"overall_progress_percent": 65,
"time_spent_seconds": 1842,
"last_activity_at": "2026-06-04T11:20:00Z",
"modules": [
{
"module_id": "3c4d5e6f-7a8b-9012-cdef-012345678901",
"module_title": "Introduction to WHMIS",
"status": "completed",
"score": null,
"time_spent_seconds": 920,
"completed_at": "2026-05-10T10:15:00Z"
},
{
"module_id": "4d5e6f7a-8b9c-0123-defa-123456789012",
"module_title": "Final Assessment",
"status": "not_started",
"score": null,
"time_spent_seconds": 0,
"completed_at": null
}
]
},
"meta": null,
"error": null
}