Skip to Content

Headless

Server-to-server endpoints for headless integrations: provision users, enroll learners and manage content programmatically. These endpoints require an lh_ API token.

Issue a user token

POST/api/v1/admin/{org_slug}/auth/token
API tokenrequired (no session fallback)

Issue a JWT access token on behalf of a user. The user must belong to the organization matching the org_slug. Requires `users.action_read` permission.

Path parameters

org_slugstringrequired

Request bodyapplication/jsonrequired

user_idintegerrequired

ID of the user to issue a token for

Returns

TokenResponse: Access token minted on behalf of the target user.

access_tokenstringrequired

JWT access token

token_typestring

Token type (always 'bearer')

user_idintegerrequired

ID of the user the token was issued for

user_uuidstringrequired

UUID of the user

Error responses
  • 403 API token lacks permission, user not in org, or org_slug mismatch
  • 404 User or organization not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "access_token": "string",
  "token_type": "bearer",
  "user_id": 1,
  "user_uuid": "string"
}

Check user course access

GET/api/v1/admin/{org_slug}/courses/{course_uuid}/access/{user_id}
API tokenrequired (no session fallback)

Check if a user can access a specific course. Returns enrollment status and whether the course is public. Requires `courses.action_read` permission.

Path parameters

org_slugstringrequired
course_uuidstringrequired
user_idintegerrequired

Returns

CourseAccessResponse: Access check result — whether the user can view the course.

has_accessbooleanrequired

True if the user can access the course (public or enrolled)

is_enrolledbooleanrequired

True if the user is enrolled in the course

is_publicbooleanrequired

True if the course is public

is_publishedbooleanrequired

True if the course is published

Error responses
  • 404 Course not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "has_access": false,
  "is_enrolled": false,
  "is_public": false,
  "is_published": false
}

Bulk unenroll users from a course

POST/api/v1/admin/{org_slug}/enrollments/bulk/unenroll
API tokenrequired (no session fallback)

Mirror of bulk enroll. Users not currently enrolled are reported in `not_enrolled`.

Path parameters

org_slugstringrequired

Request bodyapplication/jsonrequired

course_uuidstringrequired
user_idsinteger[]required

Returns

BulkUnenrollResponse: Per-user unenroll summary: unenrolled, not_enrolled.

unenrolledinteger[]required
not_enrolledinteger[]required
Error responses
  • 404 Course not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "unenrolled": [
    0
  ],
  "not_enrolled": [
    0
  ]
}

Enroll user in course

POST/api/v1/admin/{org_slug}/enrollments/{user_id}/{course_uuid}
API tokenrequired (no session fallback)

Enroll a user in a course on their behalf. Creates the learning trail and trail run. The user must belong to the organization. Requires `courses.action_read` permission.

Path parameters

org_slugstringrequired
user_idintegerrequired
course_uuidstringrequired

Returns

TrailRead: User enrolled — returns the user's updated trail with all runs.

idinteger | null
trail_uuidstring | null
org_idintegerrequired
user_idintegerrequired
creation_datestring | null
update_datestring | null
runsTrailRunRead[]required
Show child attributes
idinteger | null
dataData
statusStatusEnum
STATUS_IN_PROGRESSSTATUS_COMPLETEDSTATUS_PAUSEDSTATUS_CANCELLED
trail_idinteger | null
course_idinteger | null
org_idinteger | null
user_idinteger | null
courseCourse | null
creation_datestring | null
update_datestring | null
course_total_stepsinteger
stepsTrailStep[]
Show child attributes
idinteger | null
completebooleanrequired
teacher_verifiedbooleanrequired
gradestringrequired
dataData
trailrun_idintegerrequired
trail_idintegerrequired
activity_idintegerrequired
course_idintegerrequired
org_idintegerrequired
user_idintegerrequired
creation_datestringrequired
update_datestringrequired
Error responses
  • 400 User is already enrolled
  • 404 User or course not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "id": 1,
  "trail_uuid": "string",
  "org_id": 1,
  "user_id": 1,
  "creation_date": "string",
  "update_date": "string",
  "runs": [
    {
      "id": 1,
      "data": {},
      "status": "STATUS_IN_PROGRESS",
      "trail_id": 1,
      "course_id": 1,
      "org_id": 1,
      "user_id": 1,
      "course": {},
      "creation_date": "string",
      "update_date": "string",
      "course_total_steps": 0,
      "steps": [
        {
          "id": 1,
          "complete": false,
          "teacher_verified": false,
          "grade": "string",
          "data": {},
          "trailrun_id": 1,
          "trail_id": 1,
          "activity_id": 1,
          "course_id": 1,
          "org_id": 1,
          "user_id": 1,
          "creation_date": "string",
          "update_date": "string"
        }
      ]
    }
  ]
}

Unenroll user from course

DELETE/api/v1/admin/{org_slug}/enrollments/{user_id}/{course_uuid}
API tokenrequired (no session fallback)

Unenroll a user from a course. Removes the enrollment and all associated progress (trail steps). Requires `courses.action_read` permission.

Path parameters

org_slugstringrequired
user_idintegerrequired
course_uuidstringrequired

Returns

UnenrollResponse: User unenrolled — trail steps for this course are deleted.

detailstringrequired
Error responses
  • 404 Enrollment not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "detail": "string"
}

Get user enrollments

GET/api/v1/admin/{org_slug}/enrollments/{user_id}
API tokenrequired (no session fallback)

Get all course enrollments for a user in the organization, including trail runs and steps. Requires `courses.action_read` permission.

Path parameters

org_slugstringrequired
user_idintegerrequired

Returns

TrailRead: The user's trail with every course enrollment and step.

idinteger | null
trail_uuidstring | null
org_idintegerrequired
user_idintegerrequired
creation_datestring | null
update_datestring | null
runsTrailRunRead[]required
Show child attributes
idinteger | null
dataData
statusStatusEnum
STATUS_IN_PROGRESSSTATUS_COMPLETEDSTATUS_PAUSEDSTATUS_CANCELLED
trail_idinteger | null
course_idinteger | null
org_idinteger | null
user_idinteger | null
courseCourse | null
creation_datestring | null
update_datestring | null
course_total_stepsinteger
stepsTrailStep[]
Show child attributes
idinteger | null
completebooleanrequired
teacher_verifiedbooleanrequired
gradestringrequired
dataData
trailrun_idintegerrequired
trail_idintegerrequired
activity_idintegerrequired
course_idintegerrequired
org_idintegerrequired
user_idintegerrequired
creation_datestringrequired
update_datestringrequired
Error responses
  • 404 User not found or not a member of this organization
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "id": 1,
  "trail_uuid": "string",
  "org_id": 1,
  "user_id": 1,
  "creation_date": "string",
  "update_date": "string",
  "runs": [
    {
      "id": 1,
      "data": {},
      "status": "STATUS_IN_PROGRESS",
      "trail_id": 1,
      "course_id": 1,
      "org_id": 1,
      "user_id": 1,
      "course": {},
      "creation_date": "string",
      "update_date": "string",
      "course_total_steps": 0,
      "steps": [
        {
          "id": 1,
          "complete": false,
          "teacher_verified": false,
          "grade": "string",
          "data": {},
          "trailrun_id": 1,
          "trail_id": 1,
          "activity_id": 1,
          "course_id": 1,
          "org_id": 1,
          "user_id": 1,
          "creation_date": "string",
          "update_date": "string"
        }
      ]
    }
  ]
}

Get user progress in course

GET/api/v1/admin/{org_slug}/progress/{user_id}/{course_uuid}
API tokenrequired (no session fallback)

Get a user's progress in a specific course including completion percentage and list of completed activity IDs. Requires `courses.action_read` permission.

Path parameters

org_slugstringrequired
user_idintegerrequired
course_uuidstringrequired

Returns

ProgressResponse: Progress summary (completion percentage + completed activity ids).

course_uuidstringrequired
user_idintegerrequired
total_activitiesintegerrequired

Total number of activities in the course

completed_activitiesintegerrequired

Number of activities the user has completed

completion_percentagenumberrequired

Completion percentage (0-100)

completed_activity_idsinteger[]required

IDs of completed activities

Error responses
  • 404 Course not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "course_uuid": "string",
  "user_id": 1,
  "total_activities": 0,
  "completed_activities": 0,
  "completion_percentage": 0,
  "completed_activity_ids": [
    0
  ]
}

Mark activity as completed

POST/api/v1/admin/{org_slug}/progress/{user_id}/activities/{activity_uuid}/complete
API tokenrequired (no session fallback)

Mark an activity as completed on behalf of a user. Automatically creates enrollment if needed. If this completes the entire course, a certificate is awarded (if configured). Requires `courses.action_read` permission.

Path parameters

org_slugstringrequired
user_idintegerrequired
activity_uuidstringrequired

Returns

ActivityCompletionResponse: Activity marked complete; includes whether this completed the course.

activity_uuidstringrequired
user_idintegerrequired
completedbooleanrequired
is_new_completionbooleanrequired

True if this was a new completion (not already completed)

course_completedbooleanrequired

True if this completion finished the entire course

Error responses
  • 404 Activity not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "activity_uuid": "string",
  "user_id": 1,
  "completed": false,
  "is_new_completion": false,
  "course_completed": false
}

Undo activity completion

DELETE/api/v1/admin/{org_slug}/progress/{user_id}/activities/{activity_uuid}/complete
API tokenrequired (no session fallback)

Remove a user's activity completion. Does not revoke certificates. Requires `courses.action_read` permission.

Path parameters

org_slugstringrequired
user_idintegerrequired
activity_uuidstringrequired

Returns

ActivityUncompletionResponse: Activity completion removed.

activity_uuidstringrequired
user_idintegerrequired
completedboolean
Error responses
  • 404 Activity not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "activity_uuid": "string",
  "user_id": 1,
  "completed": false
}

Mark entire course as completed

POST/api/v1/admin/{org_slug}/progress/{user_id}/{course_uuid}/complete
API tokenrequired (no session fallback)

Mark all activities in a course as completed for a user. Skips activities that are already completed. Awards a certificate if configured. Requires `courses.action_read` permission.

Path parameters

org_slugstringrequired
user_idintegerrequired
course_uuidstringrequired

Returns

CourseCompletionResponse: All activities marked complete; indicates whether a certificate was awarded.

course_uuidstringrequired
user_idintegerrequired
completed_countintegerrequired

Number of newly completed activities

already_completed_countintegerrequired

Number of activities that were already completed

total_activitiesintegerrequired
course_completedbooleanrequired
certificate_awardedbooleanrequired

True if a certificate was awarded as a result

Error responses
  • 404 Course not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "course_uuid": "string",
  "user_id": 1,
  "completed_count": 0,
  "already_completed_count": 0,
  "total_activities": 0,
  "course_completed": false,
  "certificate_awarded": false
}

Get all user progress

GET/api/v1/admin/{org_slug}/progress/{user_id}
API tokenrequired (no session fallback)

Get a progress summary across all courses a user is enrolled in. Returns completion percentage and status for each enrollment. Requires `courses.action_read` permission.

Path parameters

org_slugstringrequired
user_idintegerrequired

Returns

ProgressSummaryItem[]: One row per course enrollment with completion percentage and status.

course_uuidstringrequired
course_namestringrequired
statusstringrequired

Enrollment status (STATUS_IN_PROGRESS, STATUS_COMPLETED, etc.)

total_activitiesintegerrequired
completed_activitiesintegerrequired
completion_percentagenumberrequired
enrolled_atstringrequired
Error responses
  • 404 User not found or not a member of this organization
  • 422 Validation Error: HTTPValidationError
Request
Response
[
  {
    "course_uuid": "string",
    "course_name": "Example name",
    "status": "string",
    "total_activities": 0,
    "completed_activities": 0,
    "completion_percentage": 0,
    "enrolled_at": "string"
  }
]

Get user trail with full progress breakdown

GET/api/v1/admin/{org_slug}/trails/{user_id}
API tokenrequired (no session fallback)

Return the user's trail in the organization with a full chapter-by-chapter and activity-by-activity progress breakdown for every course they are enrolled in. Each activity carries its completion state, teacher verification flag, grade, and completion timestamp. Requires `courses.action_read` permission.

Path parameters

org_slugstringrequired
user_idintegerrequired

Returns

UserTrailDetail: Full trail breakdown grouped by course → chapter → activity.

trail_uuidstring | null

Null if the user has never started a trail in this org

user_idintegerrequired
org_idintegerrequired
creation_datestring | null
update_datestring | null
coursesTrailCourseProgress[]required
Show child attributes
course_uuidstringrequired
course_idintegerrequired
course_namestringrequired
statusstring | null

TrailRun status (STATUS_IN_PROGRESS, STATUS_COMPLETED, …); null when there is no enrollment row

enrolled_atstring | null

ISO timestamp the user was enrolled; null when there is no enrollment row

total_activitiesintegerrequired
completed_activitiesintegerrequired
completion_percentagenumberrequired
chaptersTrailChapterProgress[]required
Show child attributes
chapter_uuidstringrequired
chapter_idintegerrequired
namestringrequired
orderintegerrequired
total_activitiesintegerrequired
completed_activitiesintegerrequired
activitiesTrailActivityProgress[]required
Show child attributes
activity_uuidstringrequired
activity_idintegerrequired
namestringrequired
activity_typestringrequired
activity_sub_typestringrequired
orderintegerrequired

Order of this activity within its chapter

publishedbooleanrequired
completedbooleanrequired
teacher_verifiedboolean

Whether a teacher has verified the completion (assignments)

gradestring

Grade/feedback recorded on the trail step, when set

completed_atstring | null

ISO timestamp when the activity was marked complete; null if not completed

Error responses
  • 403 API token lacks access to this organization
  • 404 User not found or not a member of this organization
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "trail_uuid": "string",
  "user_id": 1,
  "org_id": 1,
  "creation_date": "string",
  "update_date": "string",
  "courses": [
    {
      "course_uuid": "string",
      "course_id": 1,
      "course_name": "Example name",
      "status": "string",
      "enrolled_at": "string",
      "total_activities": 0,
      "completed_activities": 0,
      "completion_percentage": 0,
      "chapters": [
        {
          "chapter_uuid": "string",
          "chapter_id": 1,
          "name": "Example name",
          "order": 0,
          "total_activities": 0,
          "completed_activities": 0,
          "activities": [
            "…"
          ]
        }
      ]
    }
  ]
}

Get user trail breakdown for a single course

GET/api/v1/admin/{org_slug}/trails/{user_id}/courses/{course_uuid}
API tokenrequired (no session fallback)

Return the user's full chapter-by-chapter and activity-by-activity progress breakdown for a single course. Surfaces progress even when the user has no explicit enrollment row (status will be null in that case). Requires `courses.action_read` permission.

Path parameters

org_slugstringrequired
user_idintegerrequired
course_uuidstringrequired

Returns

UserTrailDetail: Full breakdown for the requested course only.

trail_uuidstring | null

Null if the user has never started a trail in this org

user_idintegerrequired
org_idintegerrequired
creation_datestring | null
update_datestring | null
coursesTrailCourseProgress[]required
Show child attributes
course_uuidstringrequired
course_idintegerrequired
course_namestringrequired
statusstring | null

TrailRun status (STATUS_IN_PROGRESS, STATUS_COMPLETED, …); null when there is no enrollment row

enrolled_atstring | null

ISO timestamp the user was enrolled; null when there is no enrollment row

total_activitiesintegerrequired
completed_activitiesintegerrequired
completion_percentagenumberrequired
chaptersTrailChapterProgress[]required
Show child attributes
chapter_uuidstringrequired
chapter_idintegerrequired
namestringrequired
orderintegerrequired
total_activitiesintegerrequired
completed_activitiesintegerrequired
activitiesTrailActivityProgress[]required
Show child attributes
activity_uuidstringrequired
activity_idintegerrequired
namestringrequired
activity_typestringrequired
activity_sub_typestringrequired
orderintegerrequired

Order of this activity within its chapter

publishedbooleanrequired
completedbooleanrequired
teacher_verifiedboolean

Whether a teacher has verified the completion (assignments)

gradestring

Grade/feedback recorded on the trail step, when set

completed_atstring | null

ISO timestamp when the activity was marked complete; null if not completed

Error responses
  • 403 API token lacks access to this organization
  • 404 Course or user not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "trail_uuid": "string",
  "user_id": 1,
  "org_id": 1,
  "creation_date": "string",
  "update_date": "string",
  "courses": [
    {
      "course_uuid": "string",
      "course_id": 1,
      "course_name": "Example name",
      "status": "string",
      "enrolled_at": "string",
      "total_activities": 0,
      "completed_activities": 0,
      "completion_percentage": 0,
      "chapters": [
        {
          "chapter_uuid": "string",
          "chapter_id": 1,
          "name": "Example name",
          "order": 0,
          "total_activities": 0,
          "completed_activities": 0,
          "activities": [
            "…"
          ]
        }
      ]
    }
  ]
}

Get user certificates

GET/api/v1/admin/{org_slug}/certifications/{user_id}
API tokenrequired (no session fallback)

Get all certificates awarded to a user in the organization. Includes certification details and course information. Requires `certifications.action_read` permission.

Path parameters

org_slugstringrequired
user_idintegerrequired

Returns

CertificateItem[]: All certificates awarded to the user in this org.

certificate_userCertificate Userrequired
certificationCertificationrequired
courseCertificateCourseInforequired
Show child attributes
idinteger | null
course_uuidstringrequired
namestringrequired
descriptionstring | null
thumbnail_imagestring | null
Error responses
  • 404 User not found or not a member of this organization
  • 422 Validation Error: HTTPValidationError
Request
Response
[
  {
    "certificate_user": {},
    "certification": {},
    "course": {
      "id": 1,
      "course_uuid": "string",
      "name": "Example name",
      "description": "An example description",
      "thumbnail_image": "string"
    }
  }
]

Provision a user

POST/api/v1/admin/{org_slug}/users
API tokenrequired (no session fallback)

Create a user and attach them to the organization in one call. Designed for SSO/JIT provisioning — the user's email is auto-verified and the normal email-verification flow is skipped. If a user with the given email already exists in another organization, they are attached to this org (idempotent); the password/username/name fields in the request are ignored in that case.

Path parameters

org_slugstringrequired

Request bodyapplication/jsonrequired

emailstringrequired
usernamestringrequired
first_namestring
last_namestring
passwordstring | null

Optional — if omitted, treated as SSO user with empty password

role_idinteger

Role id for the org membership (default 4 = student)

extra_metadataExtra Metadata | null

Optional arbitrary JSON metadata attached to the user for headless integrations

Returns

UserRead: User created or attached to the org. Returns the user.

usernamestringrequired
first_namestringrequired
last_namestringrequired
emailstringrequired
avatar_imagestring | null
biostring | null
detailsDetails | null
profileProfile | null
extra_metadataExtra Metadata | null
idintegerrequired
user_uuidstringrequired
email_verifiedboolean
last_login_atstring | null
signup_methodstring | null
is_superadminboolean
Error responses
  • 400 Email already in this org, duplicate username, weak password, or invalid role_id
  • 403 Member limit reached, feature disabled, role belongs to another org, role is elevated (Admin/Maintainer), or token creator lacks privilege
  • 422 Validation Error: HTTPValidationError
  • 429 Too many provisioning requests for this token
Request
Response
{
  "username": "string",
  "first_name": "Example name",
  "last_name": "Example name",
  "email": "ada@example.com",
  "avatar_image": "string",
  "bio": "string",
  "details": {},
  "profile": {},
  "extra_metadata": {},
  "id": 1,
  "user_uuid": "string",
  "email_verified": false,
  "last_login_at": "string",
  "signup_method": "string",
  "is_superadmin": false
}

Update a user's profile

PATCH/api/v1/admin/{org_slug}/users/{user_id}
API tokenrequired (no session fallback)

Update profile fields of an org member. Supports partial updates — only fields present in the request body are changed. Duplicate email/username is rejected.

Path parameters

org_slugstringrequired
user_idintegerrequired

Request bodyapplication/jsonrequired

usernamestring | null
first_namestring | null
last_namestring | null
emailstring | null
avatar_imagestring | null
biostring | null
detailsDetails | null
profileProfile | null

Returns

UserRead: Updated user profile.

usernamestringrequired
first_namestringrequired
last_namestringrequired
emailstringrequired
avatar_imagestring | null
biostring | null
detailsDetails | null
profileProfile | null
extra_metadataExtra Metadata | null
idintegerrequired
user_uuidstringrequired
email_verifiedboolean
last_login_atstring | null
signup_methodstring | null
is_superadminboolean
Error responses
  • 400 Duplicate email or username
  • 404 User not in org
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "username": "string",
  "first_name": "Example name",
  "last_name": "Example name",
  "email": "ada@example.com",
  "avatar_image": "string",
  "bio": "string",
  "details": {},
  "profile": {},
  "extra_metadata": {},
  "id": 1,
  "user_uuid": "string",
  "email_verified": false,
  "last_login_at": "string",
  "signup_method": "string",
  "is_superadmin": false
}

Remove a user from the organization

DELETE/api/v1/admin/{org_slug}/users/{user_id}
API tokenrequired (no session fallback)

Remove a user's organization membership. The user account itself is preserved (it may belong to other orgs). Blocks removing the last admin.

Path parameters

org_slugstringrequired
user_idintegerrequired

Returns

RemoveUserResponse: Membership removed. The user account is preserved.

detailstringrequired
Error responses
  • 400 User is the last admin
  • 404 User not in org
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "detail": "string"
}

Look up a user by email

GET/api/v1/admin/{org_slug}/users/by-email/{email}
API tokenrequired (no session fallback)

Find a user by email within the organization. Returns 404 if the user does not exist or is not a member of this org.

Path parameters

org_slugstringrequired
emailstringrequired

URL-encoded email address

Returns

UserRead: The user matching the given email within this org.

usernamestringrequired
first_namestringrequired
last_namestringrequired
emailstringrequired
avatar_imagestring | null
biostring | null
detailsDetails | null
profileProfile | null
extra_metadataExtra Metadata | null
idintegerrequired
user_uuidstringrequired
email_verifiedboolean
last_login_atstring | null
signup_methodstring | null
is_superadminboolean
Error responses
  • 404 User not found in this organization
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "username": "string",
  "first_name": "Example name",
  "last_name": "Example name",
  "email": "ada@example.com",
  "avatar_image": "string",
  "bio": "string",
  "details": {},
  "profile": {},
  "extra_metadata": {},
  "id": 1,
  "user_uuid": "string",
  "email_verified": false,
  "last_login_at": "string",
  "signup_method": "string",
  "is_superadmin": false
}

Issue a magic sign-in link

POST/api/v1/admin/{org_slug}/auth/magic-link
API tokenrequired (no session fallback)

Generate a short-lived URL that, when opened in a browser, will log the target user in and optionally redirect them to a specific path. Token lifetime is clamped to 60–900 seconds.

Path parameters

org_slugstringrequired

Request bodyapplication/jsonrequired

user_idintegerrequired
redirect_tostring | null

Path to redirect to after the user lands on the consume endpoint

ttl_secondsinteger

Token lifetime in seconds (60–900)

Returns

MagicLinkResponse: Magic sign-in URL and underlying JWT. Token lifetime is already clamped.

urlstringrequired

Clickable URL to deliver to the user

tokenstringrequired

Raw JWT (for integrations that prefer to build their own URL)

expires_atstringrequired

ISO8601 timestamp when the token expires

Error responses
  • 400 redirect_to is not a same-origin path
  • 403 User not in this org
  • 404 User not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "url": "https://example.com",
  "token": "string",
  "expires_at": "string"
}

Consume a magic sign-in link (browser-facing)

GET/api/v1/admin/{org_slug}/auth/magic-consume
API tokenrequired (no session fallback)

Public endpoint — no API token required. Validates the magic-link JWT from the query string, sets authentication cookies, and redirects to the target path. On error, renders a friendly HTML page with a support link instead of a raw JSON error.

Path parameters

org_slugstringrequired

Query parameters

tokenstringrequired

Magic-link JWT

Error responses
  • 302 Success — cookies set and redirect to target
  • 410 Token invalid, expired, or user no longer a member (HTML page)
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "detail": [
    {
      "loc": [
        "string"
      ],
      "msg": "string",
      "type": "string",
      "input": null,
      "ctx": {}
    }
  ]
}

Bulk enroll users in a course

POST/api/v1/admin/{org_slug}/enrollments/bulk
API tokenrequired (no session fallback)

Enroll a batch of users into a single course. Users who are already enrolled are reported in `already_enrolled`. Users who are not members of the org are reported in `skipped`.

Path parameters

org_slugstringrequired

Request bodyapplication/jsonrequired

course_uuidstringrequired
user_idsinteger[]required

List of user ids to enroll (max 500)

Returns

BulkEnrollResponse: Per-user enrollment summary: enrolled, already_enrolled, skipped.

enrolledinteger[]required

User ids that were newly enrolled

already_enrolledinteger[]required

User ids that already had an enrollment

skippedinteger[]required

User ids that were not members of the org

Error responses
  • 404 Course not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "enrolled": [
    0
  ],
  "already_enrolled": [
    0
  ],
  "skipped": [
    0
  ]
}

List users enrolled in a course

GET/api/v1/admin/{org_slug}/courses/{course_uuid}/enrollments
API tokenrequired (no session fallback)

Reverse lookup: get all users currently enrolled in a course, with pagination. Returns enrollment status and enrolled_at per user.

Path parameters

org_slugstringrequired
course_uuidstringrequired

Query parameters

pageinteger
limitinteger

Returns

CourseEnrollmentItem[]: One row per enrolled user in this course, with status and enrolled_at.

userUserrequired
enrolled_atstringrequired
statusstringrequired
Error responses
  • 404 Course not found
  • 422 Validation Error: HTTPValidationError
Request
Response
[
  {
    "user": {},
    "enrolled_at": "string",
    "status": "string"
  }
]

Reset a user's progress in a course

POST/api/v1/admin/{org_slug}/progress/{user_id}/{course_uuid}/reset
API tokenrequired (no session fallback)

Delete all of a user's trail steps for a course, keeping the enrollment intact. The user can retake the course from scratch.

Path parameters

org_slugstringrequired
user_idintegerrequired
course_uuidstringrequired

Returns

ResetProgressResponse: Returns the number of trail steps deleted for this user/course.

course_uuidstringrequired
user_idintegerrequired
steps_deletedintegerrequired
Error responses
  • 404 User or course not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "course_uuid": "string",
  "user_id": 1,
  "steps_deleted": 0
}

Manually award a certificate

POST/api/v1/admin/{org_slug}/certifications/{user_id}/{course_uuid}/award
API tokenrequired (no session fallback)

Award a certificate to a user bypassing the normal completion gate. Useful for migrations and manual overrides. The course must have a certification configured.

Path parameters

org_slugstringrequired
user_idintegerrequired
course_uuidstringrequired

Returns

AwardCertificateResponse: Certificate awarded; returns the new user_certification_uuid.

user_certification_uuidstringrequired
user_idintegerrequired
course_uuidstringrequired
Error responses
  • 400 User already has a certificate for this course
  • 404 Course or certification not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "user_certification_uuid": "string",
  "user_id": 1,
  "course_uuid": "string"
}

Revoke a user's certificate

DELETE/api/v1/admin/{org_slug}/certifications/{user_id}/{user_certification_uuid}
API tokenrequired (no session fallback)

Delete a certificate row. Does not affect course enrollment or progress.

Path parameters

org_slugstringrequired
user_idintegerrequired
user_certification_uuidstringrequired

Returns

RevokeCertificateResponse: Certificate revoked. The cert row is hard-deleted.

detailstringrequired
user_certification_uuidstringrequired
Error responses
  • 404 Certificate not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "detail": "string",
  "user_certification_uuid": "string"
}

Add a user to a user group

POST/api/v1/admin/{org_slug}/usergroups/{usergroup_uuid}/members/{user_id}
API tokenrequired (no session fallback)

Add a user to a cohort/group. Both must belong to the token's org.

Path parameters

org_slugstringrequired
usergroup_uuidstringrequired
user_idintegerrequired

Returns

UserGroupMemberResponse: User added to the cohort.

detailstringrequired
usergroup_uuidstringrequired
user_idintegerrequired
Error responses
  • 400 User is already in this group
  • 404 User or group not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "detail": "string",
  "usergroup_uuid": "string",
  "user_id": 1
}

Remove a user from a user group

DELETE/api/v1/admin/{org_slug}/usergroups/{usergroup_uuid}/members/{user_id}
API tokenrequired (no session fallback)

Remove a user's membership from a cohort/group. The user account itself is preserved.

Path parameters

org_slugstringrequired
usergroup_uuidstringrequired
user_idintegerrequired

Returns

UserGroupMemberResponse: User removed from the cohort.

detailstringrequired
usergroup_uuidstringrequired
user_idintegerrequired
Error responses
  • 404 User, group, or membership not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "detail": "string",
  "usergroup_uuid": "string",
  "user_id": 1
}

Change a user's org role

PATCH/api/v1/admin/{org_slug}/users/{user_id}/role
API tokenrequired (no session fallback)

Change the user's role within the organization. Blocks demoting the last admin. The target role must belong to this org or be a global role.

Path parameters

org_slugstringrequired
user_idintegerrequired

Request bodyapplication/jsonrequired

role_idintegerrequired

Target role id

Returns

ChangeRoleResponse: User role updated.

user_idintegerrequired
role_idintegerrequired
Error responses
  • 400 Cannot demote the last admin
  • 403 Role does not belong to this organization
  • 404 User or role not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "user_id": 1,
  "role_id": 1
}

Create a user group

POST/api/v1/admin/{org_slug}/usergroups
API tokenrequired (no session fallback)

Create a cohort/user group owned by the organization.

Path parameters

org_slugstringrequired

Request bodyapplication/jsonrequired

namestringrequired
descriptionstring

Returns

UserGroupResponse: The newly created cohort.

idintegerrequired
org_idintegerrequired
usergroup_uuidstringrequired
namestringrequired
descriptionstringrequired
creation_datestringrequired
update_datestringrequired
Error responses
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "id": 1,
  "org_id": 1,
  "usergroup_uuid": "string",
  "name": "Example name",
  "description": "An example description",
  "creation_date": "string",
  "update_date": "string"
}

Delete a user group

DELETE/api/v1/admin/{org_slug}/usergroups/{usergroup_uuid}
API tokenrequired (no session fallback)

Delete a user group and all its memberships and course links. The underlying users and courses are untouched.

Path parameters

org_slugstringrequired
usergroup_uuidstringrequired

Returns

DeleteUserGroupResponse: Cohort and all its memberships/course links deleted.

detailstringrequired
usergroup_uuidstringrequired
Error responses
  • 404 UserGroup not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "detail": "string",
  "usergroup_uuid": "string"
}

List members of a user group

GET/api/v1/admin/{org_slug}/usergroups/{usergroup_uuid}/members
API tokenrequired (no session fallback)

Reverse lookup: list users belonging to a cohort, with pagination.

Path parameters

org_slugstringrequired
usergroup_uuidstringrequired

Query parameters

pageinteger
limitinteger

Returns

UserGroupMemberListItem[]: Members of the cohort, paginated.

userUserrequired
added_atstringrequired
Error responses
  • 404 UserGroup not found
  • 422 Validation Error: HTTPValidationError
Request
Response
[
  {
    "user": {},
    "added_at": "string"
  }
]

List user groups a user belongs to

GET/api/v1/admin/{org_slug}/users/{user_id}/groups
API tokenrequired (no session fallback)

Reverse lookup: which cohorts is this user a member of?

Path parameters

org_slugstringrequired
user_idintegerrequired

Returns

UserUserGroupItem[]: Cohorts the user belongs to within this org.

usergroupUsergrouprequired
added_atstringrequired
Error responses
  • 404 User not in org
  • 422 Validation Error: HTTPValidationError
Request
Response
[
  {
    "usergroup": {},
    "added_at": "string"
  }
]

Grant a cohort access to a course

POST/api/v1/admin/{org_slug}/usergroups/{usergroup_uuid}/courses/{course_uuid}
API tokenrequired (no session fallback)

Link a course to a user group — all members of the group gain the access rights configured for that group.

Path parameters

org_slugstringrequired
usergroup_uuidstringrequired
course_uuidstringrequired

Returns

UserGroupCourseResponse: Course linked to the cohort.

detailstringrequired
usergroup_uuidstringrequired
course_uuidstringrequired
Error responses
  • 400 Course already linked to this group
  • 404 Group or course not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "detail": "string",
  "usergroup_uuid": "string",
  "course_uuid": "string"
}

Revoke a cohort's access to a course

DELETE/api/v1/admin/{org_slug}/usergroups/{usergroup_uuid}/courses/{course_uuid}
API tokenrequired (no session fallback)

Unlink a course from a user group. Members of the cohort lose access unless granted through another path.

Path parameters

org_slugstringrequired
usergroup_uuidstringrequired
course_uuidstringrequired

Returns

UserGroupCourseResponse: Course unlinked from the cohort.

detailstringrequired
usergroup_uuidstringrequired
course_uuidstringrequired
Error responses
  • 404 Group or link not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "detail": "string",
  "usergroup_uuid": "string",
  "course_uuid": "string"
}

Full GDPR data export for a user

GET/api/v1/admin/{org_slug}/users/{user_id}/export
API tokenrequired (no session fallback)

Return a JSON bundle containing the user's profile, org memberships, trails, runs, steps, certificates, and cohort memberships. Intended for GDPR Article 15 (Right of Access) compliance. All sub-collections are scoped to the caller's org.

Path parameters

org_slugstringrequired
user_idintegerrequired

Returns

UserDataExportResponse: Bundle of all user data scoped to this org.

profileProfilerequired

The user's profile (scrubbed of sensitive fields)

membershipsobject[]required

Org memberships scoped to the caller's org

trailsobject[]required

Learning trails in the caller's org

trail_runsobject[]required

Course enrollments / trail runs

trail_stepsobject[]required

Activity completions

certificatesobject[]required

Certificates awarded in the caller's org

user_groupsobject[]required

Cohort memberships in the caller's org

exported_atstringrequired

ISO8601 timestamp when the export was generated

Error responses
  • 404 User not in org
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "profile": {},
  "memberships": [
    {}
  ],
  "trails": [
    {}
  ],
  "trail_runs": [
    {}
  ],
  "trail_steps": [
    {}
  ],
  "certificates": [
    {}
  ],
  "user_groups": [
    {}
  ],
  "exported_at": "string"
}

GDPR right-to-be-forgotten

POST/api/v1/admin/{org_slug}/users/{user_id}/anonymize
API tokenrequired (no session fallback)

Scrub a user's PII (email, name, avatar, bio, details, profile, password). Delete API tokens the user created. Keeps trails and certificates so course analytics remain accurate. Invalidates session cache.

Path parameters

org_slugstringrequired
user_idintegerrequired

Returns

AnonymizeUserResponse: User PII scrubbed; reports how many API tokens were revoked.

detailstringrequired
user_idintegerrequired
anonymized_emailstringrequired
api_tokens_revokedintegerrequired
Error responses
  • 404 User not in org
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "detail": "string",
  "user_id": 1,
  "anonymized_email": "ada@example.com",
  "api_tokens_revoked": 0
}

Aggregate stats for a course

GET/api/v1/admin/{org_slug}/courses/{course_uuid}/analytics
API tokenrequired (no session fallback)

Returns enrollment/completion counts, average completion percentage across all enrollees, and total certificates awarded.

Path parameters

org_slugstringrequired
course_uuidstringrequired

Returns

CourseAnalyticsResponse: Aggregate course stats: enrollment, completion, certificates, etc.

course_uuidstringrequired
enrollment_countintegerrequired
completed_countintegerrequired
in_progress_countintegerrequired
total_activitiesintegerrequired
average_completion_percentagenumberrequired
certificate_countintegerrequired
Error responses
  • 404 Course not found
  • 422 Validation Error: HTTPValidationError
Request
Response
{
  "course_uuid": "string",
  "enrollment_count": 0,
  "completed_count": 0,
  "in_progress_count": 0,
  "total_activities": 0,
  "average_completion_percentage": 0,
  "certificate_count": 0
}