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| Parameter | Type | Default | Maximum | Description |
|---|---|---|---|---|
page | integer | 1 | — | Page number (1-indexed) |
per_page | integer | 50 | 200 | Number 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
}| Field | Description |
|---|---|
page | Current page number |
per_page | Results per page as requested (after clamping) |
total | Total 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:
| Endpoint | Filters |
|---|---|
GET /api/v1/users | role (learner, author, manager, admin), is_active (true/false), group_id, created_after, created_before |
GET /api/v1/enrollments | status (active, completed, dropped, expired, waitlisted, pending_approval), user_id, course_id, group_id, due_after, due_before, created_after |
GET /api/v1/courses | status, category (exact category name), search (title + description, case-insensitive), created_after |
GET /api/v1/groups | search (group name, case-insensitive) |
GET /api/v1/completions | user_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=100Sorting (Live)
The main list endpoints accept sort_by and sort_order:
| Endpoint | sort_by options | Default |
|---|---|---|
GET /api/v1/users | created_at, last_name, email | created_at desc |
GET /api/v1/enrollments | enrolled_at, due_date, completed_at | enrolled_at desc |
GET /api/v1/courses | created_at, title, updated_at | created_at desc |
GET /api/v1/groups | created_at, name | created_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