API ReferencePagination & Filtering

Pagination and Filtering

All list endpoints in the EmbayLMS API are paginated with page / per_page parameters. This guide covers standard pagination, the filters each live endpoint supports, and the planned pagination/filtering extensions.


Standard Pagination

Use page and per_page query parameters on any list endpoint.

GET /api/v1/users?page=2&per_page=100
ParameterTypeDefaultMaximumDescription
pageinteger1Page number (1-indexed)
per_pageinteger50200Number of results per page

Out-of-range values are clamped (e.g. per_page=1000 behaves as 200, page=0 as 1).

Pagination Metadata

Every list response includes a meta object:

{
  "data": [...],
  "meta": {
    "page": 2,
    "per_page": 100,
    "total": 1482
  },
  "error": null
}
FieldDescription
pageCurrent page number
per_pageResults per page as requested (after clamping)
totalTotal number of records matching the query

Compute the page count as ceil(total / per_page); there is no separate total_pages field. When page is past the end of the result set, data is an empty array (not an error).

Full Iteration Example (Node.js)

async function fetchAllUsers(apiKey) {
  const allUsers = [];
  let page = 1;
 
  while (true) {
    const url = new URL('https://{your-subdomain}.embaylms.com/api/v1/users');
    url.searchParams.set('page', String(page));
    url.searchParams.set('per_page', '200');
 
    const response = await fetch(url.toString(), {
      headers: { 'Authorization': `Bearer ${apiKey}` },
    });
    const { data, meta } = await response.json();
 
    allUsers.push(...data);
    if (page * meta.per_page >= meta.total) break;
    page++;
  }
 
  return allUsers;
}

Live Filter Parameters

Filters are endpoint-specific. The live list endpoints support:

EndpointFilters
GET /api/v1/usersrole (learner, author, manager, admin), is_active (true/false), group_id, created_after, created_before
GET /api/v1/enrollmentsstatus (active, completed, dropped, expired, waitlisted, pending_approval), user_id, course_id, group_id, due_after, due_before, created_after
GET /api/v1/coursesstatus, category (exact category name), search (title + description, case-insensitive), created_after
GET /api/v1/groupssearch (group name, case-insensitive)
GET /api/v1/completionsuser_id

Unknown parameters are ignored. UUID filters take the resource’s id exactly as returned by the API. Timestamps are ISO 8601 with UTC offset: 2026-06-05T00:00:00Z or 2026-06-05T00:00:00-04:00.

Example

GET /api/v1/enrollments?status=completed&course_id=e7f6a5b4-8c9d-0123-efab-234567890123&per_page=100

Sorting (Live)

The main list endpoints accept sort_by and sort_order:

Endpointsort_by optionsDefault
GET /api/v1/userscreated_at, last_name, emailcreated_at desc
GET /api/v1/enrollmentsenrolled_at, due_date, completed_atenrolled_at desc
GET /api/v1/coursescreated_at, title, updated_atcreated_at desc
GET /api/v1/groupscreated_at, namecreated_at asc

sort_order is asc or desc. An invalid sort_by / sort_order value returns 400. Completions are always ordered completed_at descending.


Planned Extensions

⚠️ Planned — not yet available. The extensions below are not yet implemented — these parameters are ignored today. They are documented here as the intended contract.

Cursor-Based Pagination

For high-volume exports, cursor pagination will guarantee consistency even when records are created or updated during iteration:

GET /api/v1/users?per_page=200&cursor=eyJpZCI6ImEzZjJjMWQwIn0=
{
  "data": [...],
  "meta": {
    "per_page": 200,
    "next_cursor": "eyJpZCI6ImI0YzNkMmUxIn0=",
    "has_more": true
  },
  "error": null
}

Field Selection

The fields parameter will let you request only specific fields to reduce payload size:

GET /api/v1/users?fields=id,email,role