AllureLMS SCORM API Documentation

Complete documentation for the AllureLMS SCORM Player API - a production-ready REST API for managing SCORM 1.2/2004 packages, sessions, analytics, and xAPI telemetry.

Table of Contents

Quick Start

Base URL

Production: https://connect.allurelms.com
Development: http://localhost:3001

API Version

Current: v1 All endpoints are prefixed with /api/v1/ except health checks.

Quick Example

// Upload a SCORM package
const formData = new FormData();
formData.append('file', scormZipFile);
formData.append('uploaded_by', 'user-123');

const response = await fetch('https://connect.allurelms.com/api/v1/packages', {
  method: 'POST',
  headers: {
    'X-API-Key': 'your-api-key-here',
  },
  body: formData,
});

const { package_id, launch_url } = await response.json();
console.log(`Package uploaded: ${package_id}`);
console.log(`Launch URL: ${launch_url}`);

Authentication

All API requests (except /api/health) require authentication using API keys.

API Key Authentication

Include your API key in the X-API-Key header:

X-API-Key: scorm_abc123...

Example

curl -H "X-API-Key: scorm_abc123..." \
  https://connect.allurelms.com/api/v1/packages

API Key Scopes

API keys have different permission scopes:

  • read: List and view resources
  • write: Create and update resources
  • delete: Delete resources

Obtaining API Keys

Contact your administrator or use the admin portal to generate API keys.

See: API Authentication Guide

Rate Limiting

Rate limits prevent abuse and ensure fair usage across all tenants.

Limits

  • Read operations: 1000 requests per minute
  • Write operations: 100 requests per minute
  • Upload operations: 10 requests per minute

Rate Limit Headers

Responses include rate limit information:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 995
X-RateLimit-Reset: 1640995200

Exceeded Rate Limit

HTTP/1.1 429 Too Many Requests
{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded"
  }
}

Solution: Wait until the reset time or implement exponential backoff.

Endpoints

Health Check

GET /api/health

Check service health status.

Authentication: None required

Response:

{
  "status": "healthy",
  "service": "scorm-api",
  "version": "1.5.0",
  "timestamp": "2025-01-01T12:00:00Z",
  "checks": {
    "database": true
  }
}

Packages

List Packages

GET /api/v1/packages

List all SCORM packages for the authenticated tenant.

Query Parameters:

  • page (integer, default: 1) - Page number
  • limit (integer, default: 20, max: 100) - Results per page

Example:

curl -H "X-API-Key: scorm_abc123..." \
  "https://connect.allurelms.com/api/v1/packages?page=1&limit=20"

Response:

{
  "packages": [
    {
      "id": "pkg-123",
      "tenant_id": "tenant-456",
      "title": "Workplace Safety Essentials",
      "version": "1.2",
      "launch_url": "https://connect.allurelms.com/content/...",
      "manifest_url": "https://connect.allurelms.com/content/.../imsmanifest.xml",
      "file_size_bytes": 5242880,
      "created_at": "2025-01-01T00:00:00Z",
      "updated_at": "2025-01-01T00:00:00Z"
    }
  ],
  "count": 42
}

Upload Package

POST /api/v1/packages

Upload a new SCORM package.

Content-Type: multipart/form-data

Form Fields:

  • file (required) - SCORM package ZIP file (max 10GB)
  • uploaded_by (optional) - User ID

Example:

const formData = new FormData();
formData.append('file', scormZipFile);
formData.append('uploaded_by', 'user-123');

const response = await fetch('https://connect.allurelms.com/api/v1/packages', {
  method: 'POST',
  headers: { 'X-API-Key': apiKey },
  body: formData,
});

Response:

{
  "package_id": "pkg-123",
  "title": "Course Title",
  "version": "1.2",
  "launch_url": "https://connect.allurelms.com/content/...",
  "manifest_url": "https://connect.allurelms.com/content/.../imsmanifest.xml"
}

Get Package

GET /api/v1/packages/{id}

Get details of a specific package.

Response:

{
  "id": "pkg-123",
  "tenant_id": "tenant-456",
  "title": "Course Title",
  "version": "1.2",
  "launch_url": "https://connect.allurelms.com/content/...",
  "manifest_url": "https://connect.allurelms.com/content/.../imsmanifest.xml",
  "file_size_bytes": 5242880,
  "metadata": {
    "description": "Course description",
    "sco_count": 5
  },
  "created_at": "2025-01-01T00:00:00Z",
  "updated_at": "2025-01-01T00:00:00Z"
}

Delete Package

DELETE /api/v1/packages/{id}

Delete a SCORM package and all associated sessions.

Response:

{
  "success": true,
  "package_id": "pkg-123"
}

Sessions

List Sessions

GET /api/v1/sessions

List learner sessions with optional filtering.

Query Parameters:

  • package_id (UUID) - Filter by package
  • user_id (UUID) - Filter by user
  • completion_status (string) - Filter by completion (not_attempted, incomplete, completed)
  • success_status (string) - Filter by success (unknown, passed, failed)
  • page (integer, default: 1)
  • limit (integer, default: 20, max: 100)

Example:

curl -H "X-API-Key: scorm_abc123..." \
  "https://connect.allurelms.com/api/v1/sessions?package_id=pkg-123&completion_status=completed"

Response:

{
  "sessions": [
    {
      "id": "session-789",
      "package_id": "pkg-123",
      "tenant_id": "tenant-456",
      "user_id": "user-abc",
      "completion_status": "completed",
      "success_status": "passed",
      "score": {
        "scaled": 0.95,
        "raw": 95,
        "min": 0,
        "max": 100
      },
      "attempts": 1,
      "time_spent_seconds": 3600,
      "session_time": "PT1H",
      "created_at": "2025-01-01T00:00:00Z",
      "updated_at": "2025-01-01T01:00:00Z",
      "package": {
        "title": "Course Title",
        "version": "1.2"
      }
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 150,
    "total_pages": 8
  }
}

Get Session

GET /api/v1/sessions/{id}

Get detailed session information including full CMI data.

Response:

{
  "session": {
    "id": "session-789",
    "package_id": "pkg-123",
    "user_id": "user-abc",
    "completion_status": "completed",
    "success_status": "passed",
    "score": {
      "scaled": 0.95,
      "raw": 95,
      "min": 0,
      "max": 100
    },
    "cmi_data": {
      "cmi.core.lesson_status": "completed",
      "cmi.core.score.raw": "95",
      "cmi.suspend_data": "..."
    },
    "package": {
      "title": "Course Title"
    }
  }
}

Update Session

PUT /api/v1/sessions/{id}

Update session CMI data (learner progress).

Request Body:

{
  "cmi_data": {
    "cmi.core.lesson_status": "completed",
    "cmi.core.score.raw": "95"
  },
  "completion_status": "completed",
  "success_status": "passed",
  "score": {
    "scaled": 0.95,
    "raw": 95,
    "min": 0,
    "max": 100
  },
  "session_time": "PT1H",
  "suspend_data": "..."
}

Response:

{
  "success": true,
  "session_id": "session-789",
  "updated_at": "2025-01-01T01:00:00Z"
}

Dispatches

Create Dispatch

POST /api/v1/dispatches

Create a dispatch for external SCORM package distribution.

Request Body:

{
  "package_id": "pkg-123",
  "dispatch_name": "Partner Training",
  "registration_limit": 100,
  "expires_in_hours": 720,
  "allowed_domains": ["partner.com", "*.partner.com"]
}

Response:

{
  "dispatch": {
    "id": "dispatch-456",
    "tenant_id": "tenant-789",
    "package_id": "pkg-123",
    "dispatch_name": "Partner Training",
    "registration_limit": 100,
    "registration_count": 0,
    "expires_at": "2025-02-01T00:00:00Z",
    "status": "active",
    "token": "eyJhbGciOiJIUzI1NiIs...",
    "launch_url": "https://connect.allurelms.com/player/dispatch/eyJhbGciOiJIUzI1NiIs...",
    "created_at": "2025-01-01T00:00:00Z"
  }
}

List Dispatches

GET /api/v1/dispatches

List all dispatches for the authenticated tenant.

Query Parameters:

  • page (integer, default: 1)
  • limit (integer, default: 20, max: 100)

Response:

{
  "dispatches": [
    {
      "id": "dispatch-456",
      "package_id": "pkg-123",
      "dispatch_name": "Partner Training",
      "registration_limit": 100,
      "registration_count": 25,
      "expires_at": "2025-02-01T00:00:00Z",
      "status": "active",
      "created_at": "2025-01-01T00:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 5,
    "total_pages": 1
  }
}

Revoke Dispatch

DELETE /api/v1/dispatches/{id}

Revoke a dispatch and prevent further access.

Response:

{
  "status": "revoked",
  "dispatch_id": "dispatch-456"
}

Generate Dispatch ZIP

POST /api/v1/dispatches/{id}/generate

Trigger background generation of the offline dispatch ZIP file.

Response:

{
  "success": true,
  "message": "Dispatch generation queued.",
  "dispatch_id": "dispatch-456"
}

xAPI (Experience API)

Store xAPI Statements

POST /api/v1/xapi/statements

Store one or more xAPI statements.

Request Body (Single):

{
  "actor": {
    "name": "John Doe",
    "mbox": "mailto:john@example.com"
  },
  "verb": {
    "id": "http://adlnet.gov/expapi/verbs/completed",
    "display": { "en-US": "completed" }
  },
  "object": {
    "id": "https://connect.allurelms.com/packages/pkg-123",
    "definition": {
      "name": { "en-US": "Course Title" },
      "type": "http://adlnet.gov/expapi/activities/course"
    }
  },
  "result": {
    "score": { "scaled": 0.95, "raw": 95, "min": 0, "max": 100 },
    "success": true,
    "completion": true,
    "duration": "PT1H30M"
  },
  "timestamp": "2025-01-01T12:00:00Z"
}

Request Body (Multiple):

[
  { /* statement 1 */ },
  { /* statement 2 */ }
]

Response (Single):

"550e8400-e29b-41d4-a716-446655440000"

Response (Multiple):

[
  "550e8400-e29b-41d4-a716-446655440000",
  "660f9511-f3ac-52e5-b827-557766551111"
]

Query xAPI Statements

GET /api/v1/xapi/statements

Query xAPI statements with filters.

Query Parameters:

  • statementId (UUID) - Get specific statement
  • verb (URL) - Filter by verb IRI
  • activity (URL) - Filter by activity IRI
  • registration (UUID) - Filter by registration
  • since (ISO 8601) - Statements stored since
  • until (ISO 8601) - Statements stored until
  • page (integer, default: 1)
  • limit (integer, default: 20, max: 100)

Example:

curl -H "X-API-Key: scorm_abc123..." \
  "https://connect.allurelms.com/api/v1/xapi/statements?verb=http://adlnet.gov/expapi/verbs/completed"

Response:

{
  "statements": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "actor": { /* ... */ },
      "verb": { /* ... */ },
      "object": { /* ... */ },
      "result": { /* ... */ },
      "timestamp": "2025-01-01T12:00:00Z",
      "stored": "2025-01-01T12:00:00.123Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 250,
    "total_pages": 13
  }
}

Get xAPI Statement

GET /api/v1/xapi/statements/{id}

Retrieve a specific xAPI statement.

Response:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "actor": { /* ... */ },
  "verb": { /* ... */ },
  "object": { /* ... */ },
  "result": { /* ... */ },
  "timestamp": "2025-01-01T12:00:00Z"
}

Actor Performance Analytics

GET /api/v1/xapi/analytics/actors

Get aggregated performance metrics by learner.

Query Parameters:

  • actor_mbox (email) - Filter by actor email
  • min_activities (integer) - Minimum unique activities
  • sort (string) - Sort field (total_statements, avg_score_scaled, etc.)
  • order (asc/desc, default: desc)
  • page (integer, default: 1)
  • limit (integer, default: 20, max: 100)

Response:

{
  "actors": [
    {
      "actor_mbox": "john@example.com",
      "actor_name": "John Doe",
      "total_statements": 45,
      "unique_activities": 12,
      "completed_count": 10,
      "passed_count": 9,
      "failed_count": 1,
      "avg_score_scaled": 0.87,
      "first_activity": "2025-01-01T00:00:00Z",
      "last_activity": "2025-01-15T14:30:00Z"
    }
  ],
  "pagination": { /* ... */ }
}

Activity Performance Analytics

GET /api/v1/xapi/analytics/activities

Get aggregated performance metrics by activity.

Query Parameters:

  • activity_id (URL) - Filter by activity IRI
  • activity_type (URL) - Filter by activity type
  • package_id (UUID) - Filter by SCORM package
  • min_learners (integer) - Minimum unique learners
  • sort (string) - Sort field
  • order (asc/desc, default: desc)
  • page (integer, default: 1)
  • limit (integer, default: 20, max: 100)

Response:

{
  "activities": [
    {
      "activity_id": "https://connect.allurelms.com/packages/pkg-123",
      "activity_type": "http://adlnet.gov/expapi/activities/course",
      "package_id": "pkg-123",
      "total_statements": 250,
      "unique_learners": 50,
      "completed_count": 45,
      "passed_count": 42,
      "failed_count": 3,
      "avg_score_scaled": 0.82,
      "first_activity": "2025-01-01T00:00:00Z",
      "last_activity": "2025-01-15T16:00:00Z"
    }
  ],
  "pagination": { /* ... */ }
}

Error Handling

All errors follow a consistent format:

{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error message",
    "details": {}
  },
  "request_id": "correlation-id"
}

Common Error Codes

Status Code Description
400 BAD_REQUEST Invalid request format
400 VALIDATION_ERROR Failed validation
401 UNAUTHORIZED Missing/invalid API key
403 FORBIDDEN Insufficient permissions
403 QUOTA_EXCEEDED Quota limit exceeded
404 NOT_FOUND Resource not found
404 PACKAGE_NOT_FOUND SCORM package not found
404 SESSION_NOT_FOUND Session not found
409 CONFLICT State conflict
429 RATE_LIMIT_EXCEEDED Too many requests
500 INTERNAL_ERROR Server error
500 DATABASE_ERROR Database operation failed

Error Response Examples

Validation Error:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "details": {
      "fieldErrors": {
        "email": ["Invalid email format"],
        "age": ["Must be greater than 0"]
      }
    }
  }
}

Quota Exceeded:

{
  "error": {
    "code": "QUOTA_EXCEEDED",
    "message": "Package limit exceeded",
    "details": {
      "limit": 100,
      "current": 100
    }
  }
}

Best Practices

1. Always Check Response Status

const response = await fetch(url, options);

if (!response.ok) {
  const error = await response.json();
  console.error(`API Error [${error.error.code}]: ${error.error.message}`);
  throw new Error(error.error.message);
}

const data = await response.json();

2. Implement Retry Logic

async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url, options);

      // Don't retry on client errors (4xx)
      if (response.status >= 400 && response.status < 500) {
        return response;
      }

      if (response.ok) {
        return response;
      }

      // Retry on server errors (5xx)
      if (i < maxRetries - 1) {
        await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, i)));
      }
    } catch (error) {
      if (i === maxRetries - 1) throw error;
    }
  }
}

3. Handle Rate Limiting

async function fetchWithRateLimit(url, options) {
  const response = await fetch(url, options);

  if (response.status === 429) {
    const resetTime = response.headers.get('X-RateLimit-Reset');
    const waitTime = (parseInt(resetTime!) - Date.now() / 1000) * 1000;

    await new Promise(resolve => setTimeout(resolve, waitTime));
    return fetchWithRateLimit(url, options); // Retry
  }

  return response;
}

4. Use Pagination

async function fetchAllPackages(apiKey) {
  const allPackages = [];
  let page = 1;
  let hasMore = true;

  while (hasMore) {
    const response = await fetch(
      `https://connect.allurelms.com/api/v1/packages?page=${page}&limit=100`,
      { headers: { 'X-API-Key': apiKey } }
    );

    const { packages, count } = await response.json();
    allPackages.push(...packages);

    hasMore = packages.length === 100;
    page++;
  }

  return allPackages;
}

5. Monitor API Usage

Track your API usage to avoid hitting limits:

const response = await fetch(url, options);

const rateLimitRemaining = response.headers.get('X-RateLimit-Remaining');
const rateLimitReset = response.headers.get('X-RateLimit-Reset');

console.log(`Remaining requests: ${rateLimitRemaining}`);
console.log(`Reset time: ${new Date(parseInt(rateLimitReset!) * 1000)}`);

SDKs & Tools

Official SDKs

Coming Soon:

  • Node.js SDK
  • Python SDK
  • PHP SDK
  • .NET SDK

OpenAPI Specification

Download the OpenAPI 3.1 specification:

  • YAML: https://connect.allurelms.com/api/docs/openapi.yaml
  • JSON: https://connect.allurelms.com/api/docs/openapi.json

Use with tools like:

  • Postman
  • Insomnia
  • Swagger UI
  • OpenAPI Generator

Postman Collection

Import our Postman collection for quick testing:

https://connect.allurelms.com/api/docs/postman-collection.json

Additional Resources

Documentation

Specifications

Support

Community


Last Updated: 2025-11-11 API Version: v1.5.0 OpenAPI Version: 2025-10-27