mobieusCore API — mobieusLearn
The Learn surface of the public REST API. Manage courses, modules, lessons, activities, enrollments, attempts, certificates, certificate templates, and SCORM packages.
Added in API version 1.3.0 (2026-06-02).
Scopes
| Scope | Grants |
|---|---|
learn:read |
List + read every Learn resource (courses, enrollments, attempts, certificates, templates, SCORM packages, nested entities). |
learn:write |
Create / update / publish / archive courses, enroll users, cancel enrollments, revoke + regenerate certificates. |
Generate a key at /admin/api-keys, tick the scopes you need.
Pro / Creator Plus / Sovereign plans only — same plan gate as the
rest of the public API.
Quick start
curl https://YOUR-TENANT.mobieus.io/api/v1/learn/courses \
-H 'Authorization: Bearer mc_live_...'
Returns up to 50 courses ordered by id desc. Use ?cursor=...&limit=N
(max 100) to page; next_cursor is null on the last page.
Resources
Courses
| Method | Path | Scope | What |
|---|---|---|---|
GET |
/api/v1/learn/courses |
learn:read |
List courses (cursor-paginated). |
GET |
/api/v1/learn/courses/{id} |
learn:read |
Get a single course (with credit info, version status, owner author). |
POST |
/api/v1/learn/courses |
learn:write |
Create a course. Required: slug, title. Optional: subtitle, summary, language, completion_rule, estimated_minutes, credit_hours, credit_kind, credit_expires_after_months. |
POST |
/api/v1/learn/courses/{id} |
learn:write |
Update. Any field from create is acceptable; omitted fields keep their value. |
POST |
/api/v1/learn/courses/{id}/publish |
learn:write |
Move to published. |
POST |
/api/v1/learn/courses/{id}/unpublish |
learn:write |
Revert to draft. |
POST |
/api/v1/learn/courses/{id}/archive |
learn:write |
Archive (hides from learners; preserves enrollments). |
Example: enroll-on-purchase flow
# 1. Create a course
curl -X POST https://YOUR-TENANT.mobieus.io/api/v1/learn/courses \
-H 'Authorization: Bearer mc_live_...' -H 'Content-Type: application/json' \
-d '{"slug":"intro-to-mobieus","title":"Intro to Mobieus","completion_rule":"all_required","credit_hours":2.5,"credit_kind":"CEU"}'
# 2. After a Stripe checkout completes, enroll the buyer
curl -X POST https://YOUR-TENANT.mobieus.io/api/v1/learn/enrollments \
-H 'Authorization: Bearer mc_live_...' -H 'Content-Type: application/json' \
-d '{"user_id":123,"course_id":42,"source":"stripe_purchase"}'
Nested entities (read-only)
| GET | /api/v1/learn/courses/{id}/modules | learn:read | Modules in a course. |
| GET | /api/v1/learn/modules/{mid}/lessons | learn:read | Lessons in a module. |
| GET | /api/v1/learn/lessons/{lid}/activities | learn:read | Activities in a lesson. |
Writes for modules / lessons / activities go through the admin UI; they enforce per-course team membership (see M9-2 in the changelog). Per-course capability scoping for the API key model lands in a future minor version.
Enrollments
| GET | /api/v1/learn/enrollments?course_id=&user_id= | learn:read | List, optionally filtered. |
| GET | /api/v1/learn/enrollments/{id} | learn:read | Get one. |
| POST | /api/v1/learn/enrollments | learn:write | Enroll a user. Body: {"user_id", "course_id", "source"?, "expires_at"?}. |
| POST | /api/v1/learn/enrollments/{id}/cancel | learn:write | Cancel (status flips to cancelled). |
Attempts
| GET | /api/v1/learn/attempts?enrollment_id=&activity_id= | learn:read | List. |
| GET | /api/v1/learn/attempts/{id} | learn:read | Get one (includes score_raw, score_scaled, passed, status, time_started_at, time_ended_at, total_time_seconds). |
Certificates
| GET | /api/v1/learn/certificates?user_id=&course_id= | learn:read | List. |
| GET | /api/v1/learn/certificates/{id} | learn:read | Get one. |
| GET | /api/v1/learn/certificates/verify/{vid} | learn:read | Look up by the 40-char verification id. Returns is_revoked: true|false. |
| POST | /api/v1/learn/certificates/{id}/revoke | learn:write | Revoke. Body: {"reason": "..."}. Required. |
| POST | /api/v1/learn/certificates/{id}/regenerate-pdf | learn:write | Rebuild the PDF (after editing a template). Verification URL unchanged. |
Certificate templates
| GET | /api/v1/learn/cert-templates | learn:read | List templates (per-tenant brand identity for certs). |
| GET | /api/v1/learn/cert-templates/{id} | learn:read | Get one. |
SCORM packages
| GET | /api/v1/learn/scorm-packages | learn:read | List packages (any status). |
| GET | /api/v1/learn/scorm-packages/{id} | learn:read | Get one with its SCO list. |
Importing a SCORM package via API isn't supported in 1.3.0 — use the
admin UI at /admin/learn/scorm/new. The endpoint is on the roadmap.
Response envelope
Every endpoint returns:
{
"data": ...,
"next_cursor": "...",
"request_id": "req_..."
}
next_cursor is null when there's no more data.
Errors
{
"error": "course_not_found",
"message": "Course not found.",
"request_id": "req_..."
}
Common codes for the Learn surface:
| Code | When |
|---|---|
404 course_not_found |
id doesn't match any row. |
404 enrollment_not_found |
Same for enrollments. |
404 certificate_not_found |
Same for certs (including /verify/{vid} misses). |
400 invalid_argument |
CourseService rejected the payload — message explains. |
400 missing_field |
A required body field was empty / absent. |
403 insufficient_scope |
Key doesn't have learn:read (or learn:write). |
What's not in 1.3.0 (defer to a future minor)
- Import SCORM packages via API (use the admin UI today).
- Assessment item authoring + question-bank CRUD via API.
- Question pool CRUD via API.
- Per-course team membership for API keys (today they get tenant-wide admin-equivalent capabilities).
# mobieusCore API — mobieusLearn
The Learn surface of the public REST API. Manage courses, modules,
lessons, activities, enrollments, attempts, certificates,
certificate templates, and SCORM packages.
Added in API version **1.3.0** (2026-06-02).
## Scopes
| Scope | Grants |
|---|---|
| `learn:read` | List + read every Learn resource (courses, enrollments, attempts, certificates, templates, SCORM packages, nested entities). |
| `learn:write` | Create / update / publish / archive courses, enroll users, cancel enrollments, revoke + regenerate certificates. |
Generate a key at **`/admin/api-keys`**, tick the scopes you need.
Pro / Creator Plus / Sovereign plans only — same plan gate as the
rest of the public API.
## Quick start
```bash
curl https://YOUR-TENANT.mobieus.io/api/v1/learn/courses \
-H 'Authorization: Bearer mc_live_...'
```
Returns up to 50 courses ordered by id desc. Use `?cursor=...&limit=N`
(max 100) to page; `next_cursor` is null on the last page.
## Resources
### Courses
| Method | Path | Scope | What |
|---|---|---|---|
| `GET` | `/api/v1/learn/courses` | `learn:read` | List courses (cursor-paginated). |
| `GET` | `/api/v1/learn/courses/{id}` | `learn:read` | Get a single course (with credit info, version status, owner author). |
| `POST` | `/api/v1/learn/courses` | `learn:write` | Create a course. Required: `slug`, `title`. Optional: subtitle, summary, language, completion_rule, estimated_minutes, credit_hours, credit_kind, credit_expires_after_months. |
| `POST` | `/api/v1/learn/courses/{id}` | `learn:write` | Update. Any field from create is acceptable; omitted fields keep their value. |
| `POST` | `/api/v1/learn/courses/{id}/publish` | `learn:write` | Move to published. |
| `POST` | `/api/v1/learn/courses/{id}/unpublish` | `learn:write` | Revert to draft. |
| `POST` | `/api/v1/learn/courses/{id}/archive` | `learn:write` | Archive (hides from learners; preserves enrollments). |
**Example: enroll-on-purchase flow**
```bash
# 1. Create a course
curl -X POST https://YOUR-TENANT.mobieus.io/api/v1/learn/courses \
-H 'Authorization: Bearer mc_live_...' -H 'Content-Type: application/json' \
-d '{"slug":"intro-to-mobieus","title":"Intro to Mobieus","completion_rule":"all_required","credit_hours":2.5,"credit_kind":"CEU"}'
# 2. After a Stripe checkout completes, enroll the buyer
curl -X POST https://YOUR-TENANT.mobieus.io/api/v1/learn/enrollments \
-H 'Authorization: Bearer mc_live_...' -H 'Content-Type: application/json' \
-d '{"user_id":123,"course_id":42,"source":"stripe_purchase"}'
```
### Nested entities (read-only)
| `GET` | `/api/v1/learn/courses/{id}/modules` | `learn:read` | Modules in a course. |
| `GET` | `/api/v1/learn/modules/{mid}/lessons` | `learn:read` | Lessons in a module. |
| `GET` | `/api/v1/learn/lessons/{lid}/activities` | `learn:read` | Activities in a lesson. |
Writes for modules / lessons / activities go through the admin UI;
they enforce per-course team membership (see M9-2 in the changelog).
Per-course capability scoping for the API key model lands in a
future minor version.
### Enrollments
| `GET` | `/api/v1/learn/enrollments?course_id=&user_id=` | `learn:read` | List, optionally filtered. |
| `GET` | `/api/v1/learn/enrollments/{id}` | `learn:read` | Get one. |
| `POST` | `/api/v1/learn/enrollments` | `learn:write` | Enroll a user. Body: `{"user_id", "course_id", "source"?, "expires_at"?}`. |
| `POST` | `/api/v1/learn/enrollments/{id}/cancel` | `learn:write` | Cancel (status flips to `cancelled`). |
### Attempts
| `GET` | `/api/v1/learn/attempts?enrollment_id=&activity_id=` | `learn:read` | List. |
| `GET` | `/api/v1/learn/attempts/{id}` | `learn:read` | Get one (includes score_raw, score_scaled, passed, status, time_started_at, time_ended_at, total_time_seconds). |
### Certificates
| `GET` | `/api/v1/learn/certificates?user_id=&course_id=` | `learn:read` | List. |
| `GET` | `/api/v1/learn/certificates/{id}` | `learn:read` | Get one. |
| `GET` | `/api/v1/learn/certificates/verify/{vid}` | `learn:read` | Look up by the 40-char verification id. Returns `is_revoked: true|false`. |
| `POST` | `/api/v1/learn/certificates/{id}/revoke` | `learn:write` | Revoke. Body: `{"reason": "..."}`. Required. |
| `POST` | `/api/v1/learn/certificates/{id}/regenerate-pdf` | `learn:write` | Rebuild the PDF (after editing a template). Verification URL unchanged. |
### Certificate templates
| `GET` | `/api/v1/learn/cert-templates` | `learn:read` | List templates (per-tenant brand identity for certs). |
| `GET` | `/api/v1/learn/cert-templates/{id}` | `learn:read` | Get one. |
### SCORM packages
| `GET` | `/api/v1/learn/scorm-packages` | `learn:read` | List packages (any status). |
| `GET` | `/api/v1/learn/scorm-packages/{id}` | `learn:read` | Get one with its SCO list. |
Importing a SCORM package via API isn't supported in 1.3.0 — use the
admin UI at `/admin/learn/scorm/new`. The endpoint is on the roadmap.
## Response envelope
Every endpoint returns:
```json
{
"data": ...,
"next_cursor": "...",
"request_id": "req_..."
}
```
`next_cursor` is null when there's no more data.
## Errors
```json
{
"error": "course_not_found",
"message": "Course not found.",
"request_id": "req_..."
}
```
Common codes for the Learn surface:
| Code | When |
|---|---|
| `404 course_not_found` | `id` doesn't match any row. |
| `404 enrollment_not_found` | Same for enrollments. |
| `404 certificate_not_found` | Same for certs (including `/verify/{vid}` misses). |
| `400 invalid_argument` | CourseService rejected the payload — message explains. |
| `400 missing_field` | A required body field was empty / absent. |
| `403 insufficient_scope` | Key doesn't have `learn:read` (or `learn:write`). |
## What's not in 1.3.0 (defer to a future minor)
- Import SCORM packages via API (use the admin UI today).
- Assessment item authoring + question-bank CRUD via API.
- Question pool CRUD via API.
- Per-course team membership for API keys (today they get tenant-wide
admin-equivalent capabilities).