Courses

Available. Course management shipped in LMS-571: list/create/get/update/archive courses, list/add modules, and per-course enrollments. The Add Module endpoint covers content module types (video, audio, document, iframe, youtube_vimeo, quiz, html); SCORM/cmi5/AICC modules are added by uploading a package through the admin UI. Writes require the write scope (archive requires admin).

The Courses API lets you manage your course catalog — create courses, maintain modules, and retrieve enrollment lists per course.


The Course Object

{
  "id": "e7f6a5b4-8c9d-0123-efab-234567890123",
  "title": "Workplace Safety Fundamentals",
  "description": "An introduction to workplace health and safety regulations in Canada.",
  "short_description": "Workplace health and safety basics for Canadian workplaces.",
  "status": "published",
  "category_id": "1a2b3c4d-5e6f-7890-abcd-456789012345",
  "estimated_minutes": 45,
  "current_version_id": "5e6f7a8b-9c0d-1234-efab-567890123456",
  "published_at": "2026-01-12T15:00:00Z",
  "created_at": "2026-01-10T09:00:00Z",
  "updated_at": "2026-05-20T14:30:00Z",
  "enrollment_count": 14
}

Course status values:

StatusDescription
draftNot visible to learners
publishedAvailable for enrollment
archivedSoft-deleted; hidden from catalog; history preserved

Endpoints

List Courses

GET /api/v1/courses

Returns a paginated list of courses in the tenant’s catalog.

Authentication required: read scope

Query Parameters

ParameterTypeRequiredDescription
pageintegerNoPage number. Default: 1
per_pageintegerNoDefault: 50, max: 200
statusstringNoFilter: draft, published, archived. Default: excludes archived
categorystringNoFilter by category name (exact match)
searchstringNoCase-insensitive search on title and description
created_afterISO 8601NoFilter courses created after this timestamp
sort_bystringNocreated_at, title, updated_at. Default: created_at
sort_orderstringNoasc or desc. Default: desc

Example Request

curl "https://{your-subdomain}.embaylms.com/api/v1/courses?status=published&category=Compliance&per_page=20" \
  -H "Authorization: Bearer ems_live_0000000000000000000000000000"

Example Response

{
  "data": [
    {
      "id": "e7f6a5b4-8c9d-0123-efab-234567890123",
      "title": "Workplace Safety Fundamentals",
      "short_description": "Workplace health and safety basics for Canadian workplaces.",
      "status": "published",
      "category_id": "1a2b3c4d-5e6f-7890-abcd-456789012345",
      "estimated_minutes": 45,
      "published_at": "2026-01-12T15:00:00Z",
      "created_at": "2026-01-10T09:00:00Z",
      "updated_at": "2026-05-20T14:30:00Z",
      "enrollment_count": 14
    }
  ],
  "meta": {
    "page": 1,
    "per_page": 20,
    "total": 87
  },
  "error": null
}

Create Course

POST /api/v1/courses

Creates a new course in draft status.

Authentication required: write scope

Request Body

FieldTypeRequiredDescription
titlestringYesCourse title
descriptionstringNoCourse description (plain text or Markdown)
short_descriptionstringNoShort catalog blurb (max 500 characters)
estimated_minutesintegerNoEstimated completion time in minutes

An initial draft version is created alongside the course, so modules can be added right away.

Example Request

curl -X POST https://{your-subdomain}.embaylms.com/api/v1/courses \
  -H "Authorization: Bearer ems_live_0000000000000000000000000000" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "WHMIS 2015",
    "description": "Workplace Hazardous Materials Information System refresher course.",
    "short_description": "WHMIS refresher.",
    "estimated_minutes": 30
  }'

Example Response

{
  "data": {
    "id": "2b3c4d5e-6f7a-8901-bcde-901234567890",
    "title": "WHMIS 2015",
    "description": "Workplace Hazardous Materials Information System refresher course.",
    "short_description": "WHMIS refresher.",
    "status": "draft",
    "category_id": null,
    "estimated_minutes": 30,
    "created_at": "2026-06-05T10:15:00Z",
    "updated_at": "2026-06-05T10:15:00Z"
  },
  "meta": null,
  "error": null
}

HTTP Status: 201 Created


Get Course

GET /api/v1/courses/{id}

Returns a single course by UUID.

Authentication required: read scope

Path Parameters

ParameterTypeRequiredDescription
idUUIDYesCourse UUID

Example Request

curl "https://{your-subdomain}.embaylms.com/api/v1/courses/e7f6a5b4-8c9d-0123-efab-234567890123" \
  -H "Authorization: Bearer ems_live_0000000000000000000000000000"

Example Response

{
  "data": {
    "id": "e7f6a5b4-8c9d-0123-efab-234567890123",
    "title": "Workplace Safety Fundamentals",
    "description": "An introduction to workplace health and safety regulations in Canada.",
    "short_description": "Workplace health and safety basics for Canadian workplaces.",
    "status": "published",
    "category_id": "1a2b3c4d-5e6f-7890-abcd-456789012345",
    "estimated_minutes": 45,
    "current_version_id": "5e6f7a8b-9c0d-1234-efab-567890123456",
    "published_at": "2026-01-12T15:00:00Z",
    "created_at": "2026-01-10T09:00:00Z",
    "updated_at": "2026-05-20T14:30:00Z",
    "enrollment_count": 14
  },
  "meta": null,
  "error": null
}

Common Errors

HTTP StatusDescription
404No course with this ID in the tenant

Update Course

PATCH /api/v1/courses/{id}

Updates one or more fields on a course. Supports publishing a draft (status: "published"), unpublishing back to draft, or archiving (status: "archived", equivalent to DELETE).

Authentication required: write scope

Path Parameters

ParameterTypeRequiredDescription
idUUIDYesCourse UUID

Request Body

All fields are optional.

FieldTypeDescription
titlestringCourse title
descriptionstringCourse description
short_descriptionstringShort catalog blurb (max 500 characters)
statusstringdraft, published, or archived. "archived" is equivalent to the DELETE endpoint below

Example Request

curl -X PATCH "https://{your-subdomain}.embaylms.com/api/v1/courses/2b3c4d5e-6f7a-8901-bcde-901234567890" \
  -H "Authorization: Bearer ems_live_0000000000000000000000000000" \
  -H "Content-Type: application/json" \
  -d '{ "status": "published" }'

Example Response

Returns the updated course object (same structure as Get Course).


Archive Course

DELETE /api/v1/courses/{id}

Archives a course. This is a soft delete — the course is hidden from the catalog and no new enrollments can be created, but existing learner history and completions are preserved.

Authentication required: admin scope

Path Parameters

ParameterTypeRequiredDescription
idUUIDYesCourse UUID

Example Request

curl -X DELETE "https://{your-subdomain}.embaylms.com/api/v1/courses/e7f6a5b4-8c9d-0123-efab-234567890123" \
  -H "Authorization: Bearer ems_live_0000000000000000000000000000"

HTTP Status: 204 No Content


List Modules

GET /api/v1/courses/{id}/modules

Returns all modules for a course in display order.

Authentication required: read scope

Path Parameters

ParameterTypeRequiredDescription
idUUIDYesCourse UUID

Example Request

curl "https://{your-subdomain}.embaylms.com/api/v1/courses/e7f6a5b4-8c9d-0123-efab-234567890123/modules" \
  -H "Authorization: Bearer ems_live_0000000000000000000000000000"

Example Response

{
  "data": [
    {
      "id": "3c4d5e6f-7a8b-9012-cdef-012345678901",
      "title": "Introduction to WHMIS",
      "description": "Overview of hazard classes and labels.",
      "module_type": "video",
      "is_required": true,
      "order_index": 0,
      "created_at": "2026-01-10T09:00:00Z"
    },
    {
      "id": "4d5e6f7a-8b9c-0123-defa-123456789012",
      "title": "Final Assessment",
      "description": null,
      "module_type": "quiz",
      "is_required": true,
      "order_index": 1,
      "created_at": "2026-01-10T09:05:00Z"
    }
  ],
  "meta": null,
  "error": null
}

Add Module

POST /api/v1/courses/{id}/modules

Adds a new module to a course. The module is appended at the end of the module list by default.

Authentication required: write scope

Path Parameters

ParameterTypeRequiredDescription
idUUIDYesCourse UUID

Request Body

FieldTypeRequiredDescription
titlestringYesModule title
module_typestringYesvideo, audio, document, iframe, youtube_vimeo, quiz, or html. SCORM/cmi5/AICC modules are added by uploading a package through the admin UI
descriptionstringNoModule description (max 2000 characters)
is_requiredbooleanNoWhether completion is required for course completion. Default: true

Example Request

curl -X POST "https://{your-subdomain}.embaylms.com/api/v1/courses/e7f6a5b4-8c9d-0123-efab-234567890123/modules" \
  -H "Authorization: Bearer ems_live_0000000000000000000000000000" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Video: Hazardous Material Handling",
    "module_type": "video",
    "is_required": true
  }'

Example Response

{
  "data": {
    "id": "5e6f7a8b-9c0d-1234-efab-234567890123",
    "title": "Video: Hazardous Material Handling",
    "description": null,
    "module_type": "video",
    "is_required": true,
    "order_index": 2,
    "created_at": "2026-06-05T10:20:00Z"
  },
  "meta": null,
  "error": null
}

HTTP Status: 201 Created


List Course Enrollments

GET /api/v1/courses/{id}/enrollments

Returns all enrollments for a specific course.

Authentication required: read scope

Path Parameters

ParameterTypeRequiredDescription
idUUIDYesCourse UUID

Query Parameters

ParameterTypeRequiredDescription
statusstringNoFilter: active, completed, dropped, expired, waitlisted, pending_approval
pageintegerNoDefault: 1
per_pageintegerNoDefault: 50, max: 200

Example Request

curl "https://{your-subdomain}.embaylms.com/api/v1/courses/e7f6a5b4-8c9d-0123-efab-234567890123/enrollments?status=active" \
  -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": "api",
      "created_at": "2026-04-01T08:00:00Z"
    }
  ],
  "meta": { "page": 1, "per_page": 50, "total": 14 },
  "error": null
}