cmi5 API Reference
cmi5 launch protocol integration for Creatiq. Enables standards-compliant content delivery with xAPI-based tracking, following the cmi5 specification for assignable unit (AU) registration, launch, and session lifecycle management.
Base path: /api/cmi5
Endpoints
POST /api/cmi5/register
Register content for a cmi5 launch.
| Property | Value |
|---|---|
| Auth | JWT Bearer token (authMiddleware) |
| Feature gate | cmi5-launch |
Description
Creates a cmi5 content registration binding a specific content item to a learner. Uses upsert logic -- if a registration for the same contentId + learnerId pair exists, it updates the updated_at timestamp. The registration starts in initialized status with Normal launch mode.
Request
{
"contentId": "h5p-content-abc123",
"learnerId": "user-12345",
"actorAccount": {
"homePage": "https://lms.example.com",
"name": "user-12345"
}
}
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
contentId | string | Yes | 1--500 chars | H5P content identifier |
learnerId | string | Yes | 1--255 chars | Learner user identifier |
actorAccount.homePage | string | Yes | URL, max 500 | xAPI actor account home page |
actorAccount.name | string | Yes | 1--255 chars | xAPI actor account name |
Response (201 Created)
{
"success": true,
"data": {
"id": "uuid",
"contentId": "h5p-content-abc123",
"learnerId": "user-12345",
"actorAccount": {
"homePage": "https://lms.example.com",
"name": "user-12345"
},
"status": "initialized",
"sessionId": null,
"score": null,
"launchMode": "Normal",
"createdAt": "2025-01-15T10:00:00.000Z",
"updatedAt": "2025-01-15T10:00:00.000Z"
}
}
Errors
| Status | Error | Condition |
|---|---|---|
| 400 | Validation error: ... | Zod schema validation failure |
| 401 | Unauthorized | Missing or invalid JWT |
| 403 | Feature not available | cmi5-launch feature not enabled |
GET /api/cmi5/launch/:registrationId
Generate a cmi5 launch URL for a registration.
| Property | Value |
|---|---|
| Auth | JWT Bearer token (authMiddleware) |
| Feature gate | cmi5-launch |
Description
Generates a cmi5-compliant launch URL for the specified registration. The process:
- Looks up the registration record.
- Creates a one-time fetch token (cached in memory, 1-hour TTL).
- Generates a new
sessionIdand sets registration status tolaunched. - Builds the launch URL with cmi5 query parameters.
The returned URL contains all parameters required by the cmi5 specification for AU launch.
Path Parameters
| Param | Type | Description |
|---|---|---|
registrationId | string | UUID of the cmi5 registration |
Response
{
"success": true,
"data": {
"launchUrl": "https://app.creatiq.com/h5p/play/abc123?endpoint=https%3A%2F%2Fapp.creatiq.com%2Fapi%2Fxapi%2Fstatements&fetch=https%3A%2F%2Fapp.creatiq.com%2Fapi%2Fcmi5%2Ffetch%2F{token}®istration={id}&activityId=https%3A%2F%2Fapp.creatiq.com%2Fh5p%2Fcontent%2Fabc123&actor=%7B%22objectType%22%3A%22Agent%22%2C%22account%22%3A%7B%22homePage%22%3A%22...%22%2C%22name%22%3A%22...%22%7D%7D"
}
}
Launch URL Query Parameters (cmi5 spec)
| Param | Description |
|---|---|
endpoint | xAPI statements endpoint ({appUrl}/api/xapi/statements) |
fetch | Fetch URL for token exchange ({appUrl}/api/cmi5/fetch/{token}) |
registration | Registration UUID |
activityId | Activity IRI ({appUrl}/h5p/content/{contentId}) |
actor | JSON-encoded xAPI Agent with account |
Errors
| Status | Error | Condition |
|---|---|---|
| 400 | Registration ID required | Missing path parameter |
| 500 | Registration not found: {id} | No registration with that ID |
POST /api/cmi5/fetch/:token
Exchange a fetch token for an xAPI auth token (AU fetch endpoint).
| Property | Value |
|---|---|
| Auth | None (token is self-authenticating) |
| Feature gate | None |
Description
Called by the Assignable Unit (AU) during launch to obtain an xAPI authentication token. The fetch token is single-use -- it is deleted from the cache after exchange. Returns a JWT signed with JWT_SECRET containing the registrationId and purpose claim, valid for 1 hour.
Path Parameters
| Param | Type | Description |
|---|---|---|
token | string | One-time fetch token from launch URL |
Response
{
"auth-token": "eyJhbGciOiJIUzI1NiIs..."
}
The returned JWT payload:
{
"registrationId": "uuid",
"purpose": "cmi5-xapi-auth",
"iat": 1705312800,
"exp": 1705316400
}
Errors
| Status | Error | Condition |
|---|---|---|
| 400 | Token required | Missing path parameter |
| 401 | Invalid or expired fetch token | Token not found in cache |
| 401 | Fetch token expired | Token exists but past its 1-hour TTL |
GET /api/cmi5/sessions/:registrationId
Get the session status for a cmi5 registration.
| Property | Value |
|---|---|
| Auth | JWT Bearer token (authMiddleware) |
| Feature gate | cmi5-launch |
Description
Returns the current session state for a registration, including status, score, and launch mode.
Path Parameters
| Param | Type | Description |
|---|---|---|
registrationId | string | UUID of the cmi5 registration |
Response
{
"success": true,
"data": {
"id": "uuid",
"contentId": "h5p-content-abc123",
"learnerId": "user-12345",
"actorAccount": {
"homePage": "https://lms.example.com",
"name": "user-12345"
},
"status": "completed",
"sessionId": "uuid",
"score": {
"scaled": 0.85,
"raw": 85,
"min": 0,
"max": 100
},
"launchMode": "Normal",
"createdAt": "2025-01-15T10:00:00.000Z",
"updatedAt": "2025-01-15T11:30:00.000Z"
}
}
Errors
| Status | Error | Condition |
|---|---|---|
| 400 | Registration ID required | Missing path parameter |
| 500 | Registration not found: {id} | No registration with that ID |
PUT /api/cmi5/sessions/:registrationId
Update the session status for a cmi5 registration.
| Property | Value |
|---|---|
| Auth | JWT Bearer token (authMiddleware) |
| Feature gate | None (auth only) |
Description
Updates the status and optionally the score for a cmi5 session. Used internally by the platform to reflect AU state transitions. If a score is provided, it is merged with any existing score (COALESCE -- does not overwrite with null).
Path Parameters
| Param | Type | Description |
|---|---|---|
registrationId | string | UUID of the cmi5 registration |
Request
{
"status": "completed",
"score": {
"scaled": 0.85,
"raw": 85,
"min": 0,
"max": 100
}
}
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
status | string | Yes | Enum (see below) | New session status |
score | object | No | Score data | |
score.scaled | number | No | 0--1 | Normalized score |
score.raw | number | No | Raw score value | |
score.min | number | No | Minimum possible score | |
score.max | number | No | Maximum possible score |
Valid Status Values
| Status | Description |
|---|---|
initialized | Registration created, not yet launched |
launched | AU has been launched |
completed | Learner completed the content |
passed | Learner passed (met mastery criteria) |
failed | Learner failed (did not meet mastery criteria) |
abandoned | Learner left without completing |
waived | Requirement waived by instructor |
terminated | Session explicitly terminated |
Response
{
"success": true,
"data": {
"id": "uuid",
"contentId": "h5p-content-abc123",
"learnerId": "user-12345",
"status": "completed",
"sessionId": "uuid",
"score": { "scaled": 0.85, "raw": 85, "min": 0, "max": 100 },
"launchMode": "Normal",
"createdAt": "2025-01-15T10:00:00.000Z",
"updatedAt": "2025-01-15T11:30:00.000Z"
}
}
Errors
| Status | Error | Condition |
|---|---|---|
| 400 | Registration ID required | Missing path parameter |
| 400 | Validation error: ... | Invalid status or score format |
| 500 | Registration not found: {id} | No registration with that ID |
Session Lifecycle
initialized --> launched --> completed
--> passed
--> failed
--> abandoned
--> terminated
--> waived
The typical flow:
- Register content for a learner (
POST /register-- status:initialized). - Generate launch URL (
GET /launch/:id-- status changes tolaunched). - AU opens in browser, calls fetch endpoint to get xAPI auth token.
- AU sends xAPI statements to
/api/xapi/statementsusing the auth token. - Session terminates with a final status update (
PUT /sessions/:id).
cmi5 Verb Constants
| Verb | IRI |
|---|---|
| Initialized | http://adlnet.gov/expapi/verbs/initialized |
| Completed | http://adlnet.gov/expapi/verbs/completed |
| Passed | http://adlnet.gov/expapi/verbs/passed |
| Failed | http://adlnet.gov/expapi/verbs/failed |
| Abandoned | https://w3id.org/xapi/adl/verbs/abandoned |
| Waived | https://w3id.org/xapi/adl/verbs/waived |
| Satisfied | https://w3id.org/xapi/adl/verbs/satisfied |
| Terminated | http://adlnet.gov/expapi/verbs/terminated |
Database Table
cmi5_registrations
| Column | Type | Description |
|---|---|---|
id | UUID (PK) | Auto-generated |
content_id | VARCHAR(500) | H5P content identifier |
learner_id | VARCHAR(255) | Learner user identifier |
actor_account | JSONB | xAPI agent account { homePage, name } |
status | VARCHAR(50) | Current session status (default: initialized) |
session_id | VARCHAR(255) | Active session UUID (set on launch) |
score | JSONB | Score object { scaled, raw, min, max } |
launch_mode | VARCHAR(20) | Launch mode (default: Normal) |
created_at | TIMESTAMP | Creation time |
updated_at | TIMESTAMP | Last update time |
Unique constraint: (content_id, learner_id).
Indexes: content_id, learner_id.