Overview
Elumio's Developer API lets your systems read training enrollments and certificate status for people in your Elumio organisation.
Use it when an HRIS, ops tool, or internal dashboard needs to answer: Did this person complete this training — and can someone re-check the credential?
Elumio is a proof layer for courses you already run (BYO curriculum): measured completion, gated assessments where required, and certificates anyone can verify by QR or link — valid, revoked, or expired. It is not a content LMS catalog inside your HR system, and it does not replace payroll, attendance, or people records.
Typical flow:
- People train and earn certificates in Elumio.
- Your app calls the API with your organisation's API key.
- You receive enrollment progress plus certificate serial, status, dates, a public verify URL, and a short-lived PDF download URL.
- You show that status in your own UI — or share the verify link with a client or auditor.
Share this page with your HRIS vendor or internal integrator when you want Elumio as the proof engine beside your HR stack.
Start here
- Mint a key at Organisation → API keys ( /trainer/organization/api-keys ) — owner or trainer; Business or Scale.
- Call
GET /api/v1/coursesto read each course'sidandtitle. - Call
POST /api/v1/enrollments/lookupwithAuthorization: Bearer va_prod_…and optionalcourseId. - Read
results[].enrollments[]+ nestedcertificate.verifyUrl/ short-livedpdfUrl.
Authentication
All requests require an organisation API key.
Send the key in the Authorization header:
Authorization: Bearer va_prod_... Keys you mint start with va_prod_. There is no separate test environment — a key reads your organisation's live enrollments and certificates. Keys minted earlier with the va_test_ prefix still authenticate until you revoke them.
The secret is shown once at mint time; Elumio stores only a hash. Revoked keys are rejected immediately.
Who can mint and revoke keys
- Organisation owner or trainer (managers cannot mint).
- In the app: Organization → API keys at
/trainer/organization/api-keys.
Treat keys like passwords. Do not commit them to source control or share them outside your integration.
Plan gate: API access requires Business or Scale. Other plans receive 402.
Tenancy
One API key belongs to exactly one Elumio organisation.
- The key only returns data for that org's trainees and certificates.
- There is no partner multi-org key in v1.
- To connect a second customer org, they mint their own key in their Elumio account.
Endpoint: list courses
This is how you get the courseId that lookup accepts. Returns every course in the key's organisation, including drafts and archived courses — lookup already accepts those ids.
GET /api/v1/courses
Authorization: Bearer va_prod_...Response (example — JSON camelCase)
{
"courses": [
{
"id": "3f2a0c1e-7b44-4c8a-9e2d-0b1c2d3e4f50",
"title": "Refresher Training for Virtual Assistants",
"status": "published"
}
]
}| Field | What you get |
|---|---|
id | UUID. Pass this as lookup's courseId. |
title | Course title. Same string lookup returns as courseTitle. |
status | draft, published, or archived. |
An organisation with no courses returns { "courses": [] } and 200, not 404.
Endpoint: batch lookup by email
Look up enrollments and certificates for a list of email addresses in your organisation.
POST /api/v1/enrollments/lookup
Content-Type: application/json
Authorization: Bearer va_prod_...Request
{
"emails": [
"alex@example.com",
"bailey@example.com"
],
"courseId": "optional-uuid",
"includeRevoked": false,
"page": 1,
"perPage": 50
}| Field | Type | Rules |
|---|---|---|
emails | string[] | Required. Max 500 addresses per request. Matched case-insensitively. Duplicates are de-duped. |
courseId | string (uuid) | Optional. If set, only enrollments for that course (must belong to the key's org). Get ids from GET /api/v1/courses. |
includeRevoked | boolean | Optional. Default false. When true, include revoked certificates. |
page | number | Optional. Offset pagination; default 1. |
perPage | number | Optional. Default 100, max 200 per page. |
Response (example — JSON camelCase)
{
"results": [
{
"email": "alex@example.com",
"enrollments": [
{
"id": "uuid",
"courseId": "uuid",
"courseTitle": "Refresher Training for Virtual Assistants",
"status": "completed",
"enrolledAt": "2026-09-01T12:00:00Z",
"completedAt": "2026-09-08T15:30:00Z",
"dueAt": "2026-09-08T15:59:59Z",
"completedOnTime": true,
"progressSummary": {
...- Unknown / no-enrollment emails still appear with
"enrollments": []. - Progress is a summary only (no lecture-by-lecture breakdown in v1).
- Exam:
examPassed+ best/latestexamScorewhen available.
Response fields
| Area | What you get |
|---|---|
| Enrollments | Course id/title + status / progressSummary for that email in your org |
| dueAt | Enrollment due date as an ISO timestamp, or null when no deadline is set. |
| completedOnTime | Stored result for the current enrollment cycle: true when completed on time, false when completed late, or null when unfinished or completed without a deadline. This result is saved at completion and is not recalculated when settings change. Earlier cycles are not included. |
| Certificates | Nested under the enrollment when issued · serial (display) · verifyCode (random code for URL) · status (valid / revoked / expired) · issued / expiry dates when applicable |
| verifyCode | Random code used in verify URL path. Not the serial (which is sequential and for display only). |
| verifyUrl | Public page at https://www.elumio.io/verify/{verifyCode}. No Elumio login required for the checker. |
| pdfUrl | Pre-signed Supabase Storage URL · TTL ~1 hour · pdfUrlExpiresAt (ISO timestamp) included |
Lookup key: Public verify uses a random verifyCode in the path (example: https://www.elumio.io/verify/a1b2c3d4e5f6). The certificate serial is for humans and records only — do not put the serial in the verify URL.
verifyUrl is safe to show clients and auditors. pdfUrl expires — fetch or cache the file before TTL if you need a durable copy in your system.
Errors
| Code | Meaning | What to do |
|---|---|---|
| 401 | Missing or invalid API key | Check Bearer key + prefix (va_prod_) |
| 403 | Key valid but missing scope / revoked / not allowed | Confirm key not revoked; owner/trainer mint path |
| 402 | Plan does not include API access (api_access is Business and Scale only) | Upgrade to Business or Scale |
| 400 | Bad request (e.g. more than 500 emails, malformed payload, courseId not in org) | Cap emails ≤500; validate payload / courseId in org |
| 429 | Rate limited | Back off; limit 60 req/min/key |
Rate limits: 60 requests / minute / API key. Retry with exponential backoff on 429.
What's not in v1
v1 is read-only: list your courses, then batch-lookup enrollments, with per-organisation API keys.
Not available in this version (roadmap ideas for later partner work — no dates):
- Outbound webhooks (completed / issued / expired / revoked)
external_employee_id(HRIS ID) alongside email- Partner multi-org keys / OAuth marketplace install
- Single-employee GET by id
- Enroll / write APIs
- SSO / SCIM
Do not assume these ship with v1.