Stitchflow
LearnUpon logo

LearnUpon User Management API Guide

API workflow

How to automate user lifecycle operations through APIs with caveats that matter in production.

UpdatedMar 11, 2026

Summary and recommendation

LearnUpon exposes a REST API at `https://{subdomain}.learnupon.com/api/v1` authenticated via HTTP Basic Auth using a portal-specific API username and key - not admin login credentials. OAuth 2.0 and token-based auth are not supported. Every request body must wrap the resource in a named key (e.g., `{"user": {...}}`); bare JSON objects are rejected with no partial-success fallback.

Pagination is page-offset only, hard-capped at 50 records per page with no configurable page size. Full directory traversal requires iterating `?page=N` until an empty array is returned. Rate limit thresholds are not publicly documented; HTTP 429 is the only signal, and retry logic with exponential back-off is required.

Each LearnUpon portal subdomain carries independent API credentials, so multi-portal environments require separate auth contexts per portal - a meaningful consideration when building an identity graph across a multi-tenant deployment.

API quick reference

Has user APIYes
Auth methodHTTP Basic Authentication (API username + API key as password)
Base URLOfficial docs
SCIM availableNo
SCIM plan requiredEnterprise

Authentication

Auth method: HTTP Basic Authentication (API username + API key as password)

Setup steps

  1. Log in to LearnUpon as an admin.
  2. Navigate to Settings > Integrations > API.
  3. Enable the API and note the generated API Username and API Key.
  4. Use HTTP Basic Auth: set the API Username as the username and the API Key as the password in every request.
  5. All requests must be made over HTTPS.

User object / data model

Field Type Description On create On update Notes
id integer Unique internal user ID system-assigned read-only Use in URL path for update/delete
email string User's email address (unique identifier) required optional Must be unique per portal
first_name string User's first name required optional
last_name string User's last name required optional
password string User's password (plain text, write-only) optional optional If omitted on create, a welcome email with set-password link is sent
username string Username for login (if username login enabled) optional optional
role string User role: 'learner', 'manager', 'admin' optional optional Defaults to 'learner' if omitted
is_active boolean Whether the user account is active optional optional Set false to deactivate
send_invite boolean Send welcome/invite email on creation optional n/a Defaults to portal setting
custom_fields array Array of portal-defined custom user attributes optional optional Key-value pairs matching portal custom field names
group_ids array IDs of groups to assign the user to optional optional Separate group membership endpoint also available
manager_id integer User ID of the user's manager optional optional
locale string User's preferred language/locale code optional optional e.g., 'en', 'fr'
time_zone string User's time zone string optional optional Rails time zone format, e.g., 'Eastern Time (US & Canada)'
created_at datetime Timestamp of account creation system-assigned read-only ISO 8601
updated_at datetime Timestamp of last update system-assigned read-only ISO 8601

Core endpoints

List Users

  • Method: GET
  • URL: https://{subdomain}.learnupon.com/api/v1/users
  • Watch out for: Returns max 50 users per page. Iterate using ?page=N until an empty array is returned.

Request example

GET /api/v1/users?page=1
Authorization: Basic {base64(api_user:api_key)}

Response example

[
  {
    "id": 12345,
    "email": "jane@example.com",
    "first_name": "Jane",
    "last_name": "Doe",
    "is_active": true
  }
]

Get User by ID

  • Method: GET
  • URL: https://{subdomain}.learnupon.com/api/v1/users/{id}
  • Watch out for: Can also look up by email using GET /api/v1/users?email={email}.

Request example

GET /api/v1/users/12345
Authorization: Basic {base64(api_user:api_key)}

Response example

{
  "id": 12345,
  "email": "jane@example.com",
  "first_name": "Jane",
  "last_name": "Doe",
  "role": "learner",
  "is_active": true
}

Create User

  • Method: POST
  • URL: https://{subdomain}.learnupon.com/api/v1/users
  • Watch out for: Wrap the user object in a 'user' key. Duplicate email returns an error; check for existing users first.

Request example

POST /api/v1/users
Content-Type: application/json

{
  "user": {
    "email": "new@example.com",
    "first_name": "New",
    "last_name": "User"
  }
}

Response example

{
  "id": 12346,
  "email": "new@example.com",
  "first_name": "New",
  "last_name": "User",
  "is_active": true
}

Update User

  • Method: PUT
  • URL: https://{subdomain}.learnupon.com/api/v1/users/{id}
  • Watch out for: Uses PUT (full-style), but only supplied fields are changed. Setting is_active=false deactivates without deleting.

Request example

PUT /api/v1/users/12346
Content-Type: application/json

{
  "user": {
    "first_name": "Updated",
    "is_active": false
  }
}

Response example

{
  "id": 12346,
  "email": "new@example.com",
  "first_name": "Updated",
  "is_active": false
}

Delete User

  • Method: DELETE
  • URL: https://{subdomain}.learnupon.com/api/v1/users/{id}
  • Watch out for: Deletion is permanent and removes all associated enrollment/progress data. Prefer deactivation (is_active=false) for audit retention.

Request example

DELETE /api/v1/users/12346
Authorization: Basic {base64(api_user:api_key)}

Response example

HTTP 200 OK
{}

Enroll User in Course

  • Method: POST
  • URL: https://{subdomain}.learnupon.com/api/v1/enrollments
  • Watch out for: Enrolling an already-enrolled user returns an error. Check existing enrollments before calling.

Request example

POST /api/v1/enrollments
Content-Type: application/json

{
  "enrollment": {
    "user_id": 12345,
    "course_id": 99
  }
}

Response example

{
  "id": 5001,
  "user_id": 12345,
  "course_id": 99,
  "status": "not_started"
}

Add User to Group

  • Method: POST
  • URL: https://{subdomain}.learnupon.com/api/v1/groups/{group_id}/memberships
  • Watch out for: Group membership can trigger auto-enrollment rules configured on the group. Verify group rules before bulk-adding users.

Request example

POST /api/v1/groups/77/memberships
Content-Type: application/json

{
  "membership": {
    "user_id": 12345
  }
}

Response example

{
  "id": 3001,
  "group_id": 77,
  "user_id": 12345
}

Get User Enrollments

  • Method: GET
  • URL: https://{subdomain}.learnupon.com/api/v1/enrollments?user_id={id}
  • Watch out for: Paginated at 50 per page. Filter by status (not_started, in_progress, passed, failed) using ?status= param.

Request example

GET /api/v1/enrollments?user_id=12345&page=1
Authorization: Basic {base64(api_user:api_key)}

Response example

[
  {
    "id": 5001,
    "user_id": 12345,
    "course_id": 99,
    "status": "passed",
    "score": 85
  }
]

Rate limits, pagination, and events

  • Rate limits: LearnUpon enforces API rate limits but does not publicly document specific numeric thresholds per plan. Requests exceeding limits receive HTTP 429 responses.

  • Rate-limit headers: Unknown

  • Retry-After header: Unknown

  • Rate-limit notes: Specific per-plan rate limit numbers are not publicly documented. Contact LearnUpon support for current limits. Implement exponential back-off on 429 responses.

  • Pagination method: offset

  • Default page size: 50

  • Max page size: 50

  • Pagination pointer: page

  • Webhooks available: Yes

  • Webhook notes: LearnUpon supports webhooks (called 'Notifications' in the UI) that POST JSON payloads to a configured URL when specific events occur.

  • Alternative event strategy: Poll GET /api/v1/users and GET /api/v1/enrollments with updated_at filters for systems that cannot receive inbound webhooks.

  • Webhook events: user.created, user.updated, enrollment.created, enrollment.completed, enrollment.passed, enrollment.failed, course.completed, certificate.issued

SCIM API status

  • SCIM available: No
  • SCIM version: Not documented
  • Plan required: Enterprise
  • Endpoint: Not documented

Limitations:

  • LearnUpon does not offer a native SCIM 2.0 endpoint as of the latest available documentation.
  • User provisioning from IdPs (Okta, Entra ID, Google Workspace) is handled via SAML 2.0 JIT (Just-In-Time) provisioning, not SCIM.
  • Bulk provisioning outside of JIT requires use of the REST API or CSV import.
  • Enterprise plan is required for SAML SSO and JIT provisioning.

Common scenarios

Three primary automation scenarios are well-supported by the API:

  • Provision and enroll: POST /api/v1/users to create the account (capture returned id), then POST /api/v1/groups/{group_id}/memberships to assign to the onboarding group. If the group has auto-enrollment rules configured, the group membership call may already trigger course enrollment - calling POST /api/v1/enrollments afterward for the same course will return a duplicate-enrollment error.

  • Deactivate a departing employee: GET /api/v1/users?email={email} to resolve the internal id, then PUT /api/v1/users/{id} with {"user": {"is_active": false}}. This preserves all enrollment and completion history. DELETE /api/v1/users/{id} is permanent and purges all associated data - avoid unless data removal is explicitly required and policy-compliant.

  • Bulk HR sync: Paginate GET /api/v1/users to build an email-to-ID map, then iterate HR records to create or update as needed. There is no bulk-upsert endpoint; every user requires an individual API call. For directories exceeding 1,000 users, schedule sync jobs during off-peak hours to reduce 429 exposure.

Provision a new employee and enroll in onboarding course

  1. POST /api/v1/users with email, first_name, last_name, and role='learner'; capture returned user id.
  2. POST /api/v1/groups/{onboarding_group_id}/memberships with the new user_id to assign to the onboarding group (triggers group auto-enrollments if configured).
  3. Optionally POST /api/v1/enrollments with user_id and specific course_id if direct enrollment is needed beyond group rules.
  4. Verify enrollment via GET /api/v1/enrollments?user_id={id}.

Watch out for: If the group has auto-enrollment rules, adding the user to the group may already enroll them; calling the enrollment endpoint again will return a duplicate-enrollment error.

Deactivate a departing employee

  1. GET /api/v1/users?email={email} to retrieve the user's internal id.
  2. PUT /api/v1/users/{id} with {"user": {"is_active": false}} to deactivate the account.
  3. Optionally remove from groups via DELETE /api/v1/groups/{group_id}/memberships/{membership_id} to prevent future auto-enrollments.

Watch out for: Deactivation prevents login but preserves all enrollment and completion history. Do not use DELETE unless permanent data removal is intended and compliant with your data retention policy.

Bulk-sync users from an external HR system

  1. Paginate GET /api/v1/users (page=1, 2, … until empty array) to build a local map of email → learnupon_id.
  2. For each HR record: if email not in map, POST /api/v1/users to create; if present and attributes differ, PUT /api/v1/users/{id} to update.
  3. For employees marked inactive in HR, PUT /api/v1/users/{id} with is_active=false.
  4. Implement exponential back-off on HTTP 429 responses throughout the sync loop.

Watch out for: LearnUpon has no bulk-upsert endpoint; each user requires an individual API call. For large directories (1,000+ users), rate limiting is a practical concern - batch jobs should be run during off-peak hours.

Why building this yourself is a trap

The most significant architectural caveat is the absence of native SCIM 2.0. IdP integrations (Okta, Entra ID, Google Workspace) rely on SAML JIT provisioning, which creates or updates user records on login but performs no deprovisioning.

A user disabled in your IdP will not be deactivated in LearnUpon until an explicit API call or manual action is taken - this is a hard gap in any identity graph that assumes IdP state is authoritative for downstream app access.

Webhooks (called 'Notifications' in the UI) are available for key events including user.created, enrollment.completed, and certificate.issued, and can reduce polling overhead for event-driven pipelines. For systems that cannot receive inbound webhooks, polling GET /api/v1/enrollments with updated_at filters is the documented alternative, though it adds latency and API call volume.

The combination of no SCIM, no OAuth, and undocumented rate limits makes LearnUpon a higher-integration-effort target compared to SCIM-native LMS platforms.

Automate LearnUpon workflows without one-off scripts

Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.

Every app coverage, including apps without APIs
60+ app integrations plus browser automation for apps without APIs
IT graph reconciliation across apps and your IdP
Less than a week to launch, maintained as APIs and admin consoles change
SOC 2 Type II. ~2 hours of your team's time

UpdatedMar 11, 2026

* Details sourced from official product documentation and admin references.

Keep exploring

Related apps

Abnormal Security logo

Abnormal Security

API Only
AutomationAPI only
Last updatedMar 2026

Abnormal Security is an enterprise email security platform focused on detecting and investigating threats such as phishing, account takeover (ATO), and vendor email compromise. It does not support SCIM provisioning, which means every app in your stack

ActiveCampaign logo

ActiveCampaign

API Only
AutomationAPI only
Last updatedFeb 2026

ActiveCampaign uses a group-based permission model: every user belongs to exactly one group, and all feature-area access (Contacts, Campaigns, Automations, Deals, Reports, Templates) is configured at the group level, not per individual. The default Adm

ADP logo

ADP

API Only
AutomationAPI only
Last updatedFeb 2026

ADP Workforce Now is a mid-market to enterprise HCM platform that serves as the HR source of record for employee data — payroll, benefits, time, and talent. User access is governed by a hybrid permission model: predefined security roles (Security Maste