Courses

Training content employees complete. A course holds ordered chapters; each chapter owns an article carrying its title and content, and may also have a CMS-managed quiz — employees pass a chapter by completing its article and passing its quiz (when one exists). Flow: create the course (draft by default), add chapters, fill each chapter's article, publish.

Required scope: read:courses for the GET endpoints, write:courses for the rest. A chapter's content is read and written through the articles endpoints, which take read:articles / write:articles plus the course scope: reading a chapter's article takes read:courses or write:courses, writing it takes write:courses, otherwise 403.

Courses are a feature that is switched on per company. While it is off, every endpoint on this page, and the articles endpoints for a course chapter's article, return 403 with the message The courses feature is not enabled., even with the right scope. For completion figures and per-employee progress, see Academy Statistics.

Endpoints

GET
/api/open/v1/courses

List courses (published by default, paginated)

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

Get a course incl. ordered chapter summaries

POST
/api/open/v1/courses

Create a course (draft by default)

PATCH
/api/open/v1/courses/{id}

Update a course; publish via is_published

DELETE
/api/open/v1/courses/{id}

Delete a course and its chapters (returns 204)

GET
/api/open/v1/courses/{id}/chapters

List chapters (position order, paginated)

POST
/api/open/v1/courses/{id}/chapters

Create a chapter — its article is created automatically

GET
/api/open/v1/course-chapters/{id}

Get a single chapter

PATCH
/api/open/v1/course-chapters/{id}

Update title/subtitle, position, is_published

DELETE
/api/open/v1/course-chapters/{id}

Delete a chapter (and its quiz)

Both lists take ?status=published|draft|all (default published; any other value returns 422) and page / per_page (max 50). GET /courses also takes ?since= (created at or after); the chapter list does not. Courses and chapters are listed in the order set in the CMS (position). GET /courses/{id} and GET /course-chapters/{id} return drafts too.

Course response

GET, POST and PATCH on a course return this object. chapters — the ordered chapter summaries — is only included by GET /courses/{id}; the list, create and update leave it out.

{
  "data": {
    "id": 9,
    "title": "Food Safety",
    "subtitle": "Annual training",
    "translations": {
      "title": { "en": "Food Safety", "sv": "Livsmedelssäkerhet" },
      "subtitle": { "en": "Annual training" }
    },
    "groups": [
      { "id": 1, "name": "Kitchen", "type": "department", "created_at": "2025-09-01T10:00:00+02:00" }
    ],
    "is_published": false,
    "published_at": null,
    "chapters_count": 1,
    "chapters": [
      { "id": 61, "title": "Food Safety Basics", "subtitle": "Module one", "position": 0, "is_published": true, "article_id": 95 }
    ],
    "created_at": "2026-07-01T09:00:00+02:00",
    "updated_at": "2026-07-01T09:00:00+02:00"
  }
}

groups is the course's targeting, empty for a global course. chapters_count counts the chapters, drafts included.

Create a course

curl -X POST https://customer.monotree.com/api/open/v1/courses \
  -H "Authorization: Bearer mono_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{ "title": "Food Safety", "subtitle": "Annual training", "groups": [1, 3] }'
FieldTypeNotes
titlestringRequired. Max 255 characters. Stored in the default content locale.
subtitlestringOptional. Max 512 characters.
groupsint[]Optional group targeting; omit for a global course. An unknown group id returns 422.
is_publishedbooleanOptional, default false (draft).
translationsobjectOptional — the course's own title/subtitle in other locales: { "title": { "sv": "…" }, "subtitle": { "sv": "…" } }. Same semantics as article translations. A locale that is not activated for the company returns 422.

Returns 201 with the course object.

PATCH /courses/{id} accepts the same fields — all optional — and only changes what you send; groups replaces the targeting. Publishing a course that has no title in the default content locale returns 422. Chapter titles and content are translated through their articles; the translations field here covers only the course's own title and subtitle.

DELETE /courses/{id} deletes the course together with its chapters and returns 204.

Add a chapter

Creating a chapter automatically creates its article — the response carries the article_id for the articles endpoints. Chapters are published by default (visibility is governed by the course); pass is_published: false for a draft. Chapter title/subtitle live on the article.

curl -X POST https://customer.monotree.com/api/open/v1/courses/9/chapters \
  -H "Authorization: Bearer mono_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{ "title": "Food Safety Basics", "subtitle": "Module one" }'
FieldTypeNotes
titlestringRequired. Max 255 characters.
subtitlestringOptional. Max 512 characters.
is_publishedbooleanOptional, default true.

Returns 201 with the chapter object. PATCH /course-chapters/{id} takes the same fields, all optional, plus position (integer, 0 or more) to reorder the chapter within its course.

Chapter response

{
  "data": {
    "id": 61,
    "course_id": 9,
    "article_id": 95,
    "quiz_id": null,
    "title": "Food Safety Basics",
    "subtitle": "Module one",
    "position": 0,
    "is_published": true,
    "published_at": "2026-07-01T09:00:00+02:00",
    "created_at": "2026-07-01T09:00:00+02:00",
    "updated_at": "2026-07-01T09:00:00+02:00"
  }
}
  • quiz_id is read-only — quizzes are created and managed in the CMS.
  • DELETE /course-chapters/{id} returns 204. Deleting a course chapter also deletes its quiz; the article is left in place.
  • Unpublishing a course keeps it in its onboarding flow and journeys as a draft — hidden from employees until it is republished. Only deleting the course removes it from them.
  • Chapter title/subtitle in responses are the default content locale — their translations are read and written through the chapter's article, see translations.