API ReferenceGetting Started

Getting Started

This guide walks through the most common API tasks in under 15 minutes. By the end you will have created an API key, listed your users, pulled enrollments with filters, and retrieved audit-grade completion records.

The public API covers reads and writes: Users (list, create, update, deactivate), Enrollments (list, create, update, cancel — including POST /enrollments/bulk), Courses and modules, Groups and membership, all five Reports (completions, enrollments, compliance, user activity, course performance) plus async CSV/XLSX export, Completions, the public GET /plans catalog, and the LTI 1.3 launch endpoints. A few surfaces remain planned — see What’s still planned below.

Prerequisites: Admin access to your EmbayLMS tenant.

Base URL: all requests go to your tenant’s subdomain:

https://{your-subdomain}.embaylms.com/api/v1/

Step 1: Create Your First API Key

  1. Sign in to your EmbayLMS tenant.
  2. Navigate to Settings -> Integrations -> API Keys (the API Keys tab of the unified Integrations menu).
  3. Click Create API Key.
  4. Name it Quickstart Test and select the read scope (available scopes are read, write, admin — the live read endpoints only need read).
  5. Click Create and copy the key — it is shown only once.

Your key looks like: ems_live_0000000000000000000000000000

Store it in an environment variable:

export EMBAYLMS_API_KEY=ems_live_0000000000000000000000000000

See Authentication for security best practices.

Prefer Postman? Import the ready-made Postman collection — every endpoint below with a pre-built environment, tests, and sample code in 20+ languages.


Step 2: Make Your First API Call — List Users

curl

curl "https://{your-subdomain}.embaylms.com/api/v1/users?role=learner&per_page=5" \
  -H "Authorization: Bearer $EMBAYLMS_API_KEY"

Node.js

const apiKey = process.env.EMBAYLMS_API_KEY;
 
const response = await fetch(
  'https://{your-subdomain}.embaylms.com/api/v1/users?role=learner&per_page=5',
  { headers: { 'Authorization': `Bearer ${apiKey}` } }
);
 
const { data, meta } = await response.json();
console.log(`Found ${meta.total} learners`);
data.forEach(user => console.log(`- ${user.first_name} ${user.last_name}`));

Example Response

{
  "data": [
    {
      "id": "a3f2c1d0-4e5b-6789-abcd-ef0123456789",
      "email": "jane.doe@acme.com",
      "first_name": "Jane",
      "last_name": "Doe",
      "role": "learner",
      "is_active": true,
      "external_id": "EMP-00412",
      "created_at": "2026-01-15T09:00:00Z"
    }
  ],
  "meta": { "page": 1, "per_page": 5, "total": 342 },
  "error": null
}

Every response uses the same { data, meta, error } envelope. Note a user’s id — you can use it to filter enrollments in Step 3.

See Users for the full endpoint reference.


Step 3: List Enrollments

Pull enrollments across the tenant, filtered by status and/or user:

curl

curl "https://{your-subdomain}.embaylms.com/api/v1/enrollments?status=active&user_id=YOUR_USER_ID" \
  -H "Authorization: Bearer $EMBAYLMS_API_KEY"

Supported filters: status (active, completed, dropped, expired, waitlisted, pending_approval), user_id, course_id, plus page / per_page pagination.

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-09-01T00:00:00Z",
      "completed_at": null,
      "source": "native",
      "created_at": "2026-05-01T08:00:00Z"
    }
  ],
  "meta": { "page": 1, "per_page": 50, "total": 23 },
  "error": null
}

See Enrollments for the full endpoint reference.


Step 4: Pull Completion Records

The Completions endpoint is the audit-grade record of who finished what and when — including historical completions imported from a previous LMS (source: "import"). Use it for compliance reporting and BI syncs.

curl

curl "https://{your-subdomain}.embaylms.com/api/v1/completions?per_page=100" \
  -H "Authorization: Bearer $EMBAYLMS_API_KEY"

Node.js — page through everything

async function fetchAllCompletions() {
  const all = [];
  let page = 1;
 
  while (true) {
    const response = await fetch(
      `https://{your-subdomain}.embaylms.com/api/v1/completions?page=${page}&per_page=200`,
      { headers: { 'Authorization': `Bearer ${process.env.EMBAYLMS_API_KEY}` } }
    );
    const { data, meta } = await response.json();
    all.push(...data);
    if (page * meta.per_page >= meta.total) break;
    page++;
  }
 
  return all;
}

See Completions for the full endpoint reference.


Bonus: The Public Plans Catalog

GET /api/v1/plans is the one endpoint that needs no authentication — it serves the canonical subscription-tier catalog (pricing, caps, capabilities):

curl "https://{your-subdomain}.embaylms.com/api/v1/plans"

See Plans.


What’s still planned

The write/management API (users, enrollments including bulk, courses, groups, and the full reports surface with async export) is live. The following surfaces are still planned and not yet implemented (calls to them return 404 today; their doc sections document the planned contract so you can design ahead — do not build production integrations against them until release):

  • User enrollments sub-resource: GET /users/{id}/enrollments (GET /users/{id}/transcript is live — see Users).
  • Bulk user import: POST /users/bulk.
  • OAuth-style token exchange: POST /auth/token.

Until then:


Versioning

Every endpoint lives under /api/v1/. We add to v1 (new endpoints, new optional parameters, new response fields) but never break it — anything breaking goes in a new prefix, and a deprecated endpoint gets at least 12 months of Deprecation / Sunset headers first.

Two things to build in from the start: ignore response fields you do not recognise, and log the Deprecation header. Full rules in Versioning & Deprecation.


Next Steps