Stitchflow
Skilljar logo

Skilljar User Management API Guide

API workflow

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

UpdatedMar 16, 2026

Summary and recommendation

Skilljar's REST API is versioned at /v1/ with token-based auth: pass the API key as `Token <api_key>` in the Authorization header, or via HTTP Basic Auth with the key as the username and an empty password.

All paths require a trailing slash - omitting it risks 301 redirects or 404s.

No official SDK is published;

all integrations use raw HTTP.

Rate limits are not publicly documented;

implement exponential backoff on 429 responses as a precaution.

Pagination is offset-based using a `page` parameter, with a hard max of 100 records per page.

Iterate the `next` URL in the response until it returns null.

User lookup by email is not a direct endpoint - filter via GET /v1/users/ or paginate results to resolve an internal ID before any user-scoped operation.

Custom user attributes (the `custom_attributes` object on the user record) must be pre-created in the dashboard before they can be written via API.

The `sso_id` and `groups` fields are key anchors for identity graph construction: `sso_id` maps the Skilljar user to an external IdP identity, while `groups` drives content entitlement logic downstream.

API quick reference

Has user APIYes
Auth methodAPI Key (Token-based) — passed as HTTP Basic Auth with the API key as the username and an empty password, or via Authorization header as a Bearer token.
Base URLOfficial docs
SCIM availableYes
SCIM plan requiredEnterprise

Authentication

Auth method: API Key (Token-based) - passed as HTTP Basic Auth with the API key as the username and an empty password, or via Authorization header as a Bearer token.

Setup steps

  1. Log in to the Skilljar Dashboard as an admin.
  2. Navigate to Settings > Integrations > API Keys.
  3. Click 'Generate API Key' and copy the key.
  4. Include the key in requests using HTTP Basic Auth: base64-encode ':' and set the Authorization header to 'Basic ', or use 'Token ' as the Authorization header value.

User object / data model

Field Type Description On create On update Notes
id string Unique Skilljar user identifier. system-generated immutable Used as path parameter in user endpoints.
email string User's email address; used as login identifier. required optional Must be unique across the domain.
first_name string User's first name. optional optional
last_name string User's last name. optional optional
username string Username for the user account. optional optional Defaults to email if not provided.
is_active boolean Whether the user account is active. optional optional Set to false to deactivate a user.
date_joined string (ISO 8601) Timestamp when the user registered. system-generated immutable
groups array List of group IDs the user belongs to. optional optional Used for access control and segmentation.
custom_attributes object Key-value pairs for custom user metadata fields defined in the dashboard. optional optional Attribute keys must be pre-configured in the Skilljar dashboard.
sso_id string External SSO identifier for the user. optional optional Used to map users from an IdP.
domain string The Skilljar domain/subdomain the user belongs to. system-assigned immutable

Core endpoints

List Users

  • Method: GET
  • URL: https://api.skilljar.com/v1/users/
  • Watch out for: Pagination is page-based; iterate 'next' URL until null. Default and max page size is 100.

Request example

GET /v1/users/?page=1 HTTP/1.1
Host: api.skilljar.com
Authorization: Token <api_key>

Response example

{
  "count": 250,
  "next": "https://api.skilljar.com/v1/users/?page=2",
  "previous": null,
  "results": [{"id": "usr_abc123", "email": "user@example.com", "first_name": "Jane"}]
}

Get User

  • Method: GET
  • URL: https://api.skilljar.com/v1/users/{user_id}/
  • Watch out for: Requires the Skilljar internal user ID, not email. Retrieve the ID via List Users first.

Request example

GET /v1/users/usr_abc123/ HTTP/1.1
Host: api.skilljar.com
Authorization: Token <api_key>

Response example

{
  "id": "usr_abc123",
  "email": "user@example.com",
  "first_name": "Jane",
  "last_name": "Doe",
  "is_active": true
}

Create User

  • Method: POST
  • URL: https://api.skilljar.com/v1/users/
  • Watch out for: Email must be unique within the domain. Duplicate email returns a 400 error.

Request example

POST /v1/users/ HTTP/1.1
Host: api.skilljar.com
Authorization: Token <api_key>
Content-Type: application/json

{"email": "newuser@example.com", "first_name": "John", "last_name": "Smith"}

Response example

{
  "id": "usr_xyz789",
  "email": "newuser@example.com",
  "first_name": "John",
  "last_name": "Smith",
  "is_active": true
}

Update User

  • Method: PATCH
  • URL: https://api.skilljar.com/v1/users/{user_id}/
  • Watch out for: PATCH is partial update. Use PUT for full replacement if supported; PATCH is the documented method.

Request example

PATCH /v1/users/usr_xyz789/ HTTP/1.1
Host: api.skilljar.com
Authorization: Token <api_key>
Content-Type: application/json

{"first_name": "Jonathan", "is_active": false}

Response example

{
  "id": "usr_xyz789",
  "email": "newuser@example.com",
  "first_name": "Jonathan",
  "is_active": false
}

List Enrollments for User

  • Method: GET
  • URL: https://api.skilljar.com/v1/users/{user_id}/enrollments/
  • Watch out for: Returns enrollments scoped to the specific user. Pagination applies.

Request example

GET /v1/users/usr_abc123/enrollments/ HTTP/1.1
Host: api.skilljar.com
Authorization: Token <api_key>

Response example

{
  "count": 3,
  "results": [{"course_id": "crs_001", "status": "completed", "progress": 100}]
}

Enroll User in Course

  • Method: POST
  • URL: https://api.skilljar.com/v1/users/{user_id}/enrollments/
  • Watch out for: Course must exist and be published. Enrolling an already-enrolled user may return a 400 or idempotent 200 depending on version.

Request example

POST /v1/users/usr_abc123/enrollments/ HTTP/1.1
Host: api.skilljar.com
Authorization: Token <api_key>
Content-Type: application/json

{"course_id": "crs_001"}

Response example

{
  "id": "enr_111",
  "user_id": "usr_abc123",
  "course_id": "crs_001",
  "status": "enrolled"
}

List Groups

  • Method: GET
  • URL: https://api.skilljar.com/v1/groups/
  • Watch out for: Group IDs are needed to assign users to groups via the user update endpoint.

Request example

GET /v1/groups/ HTTP/1.1
Host: api.skilljar.com
Authorization: Token <api_key>

Response example

{
  "count": 5,
  "results": [{"id": "grp_001", "name": "Enterprise Customers"}]
}

Add User to Group

  • Method: POST
  • URL: https://api.skilljar.com/v1/groups/{group_id}/users/
  • Watch out for: Group must exist prior to this call. No bulk-add endpoint is documented; loop per user.

Request example

POST /v1/groups/grp_001/users/ HTTP/1.1
Host: api.skilljar.com
Authorization: Token <api_key>
Content-Type: application/json

{"user_id": "usr_abc123"}

Response example

{
  "group_id": "grp_001",
  "user_id": "usr_abc123",
  "status": "added"
}

Rate limits, pagination, and events

  • Rate limits: Skilljar's public documentation does not explicitly publish rate limit thresholds or tier-based limits as of the last known documentation review.

  • Rate-limit headers: No

  • Retry-After header: No

  • Rate-limit notes: No official rate limit figures or headers documented. Contact Skilljar support for current limits.

  • Pagination method: offset

  • Default page size: 100

  • Max page size: 100

  • Pagination pointer: page

  • Webhooks available: Yes

  • Webhook notes: Skilljar supports outbound webhooks that fire on learner activity events. Webhooks are configured in the Skilljar Dashboard under Settings > Integrations > Webhooks.

  • Alternative event strategy: For near-real-time user data without webhooks, poll the List Users or List Enrollments endpoints.

  • Webhook events: course.completed, course.started, lesson.completed, user.registered, enrollment.created, certificate.issued

SCIM API status

  • SCIM available: Yes

  • SCIM version: 2.0

  • Plan required: Enterprise

  • Endpoint: https://api.skilljar.com/scim/v2/

  • Supported operations: GET /Users, GET /Users/{id}, POST /Users, PUT /Users/{id}, PATCH /Users/{id}, DELETE /Users/{id}, GET /Groups, POST /Groups, PATCH /Groups/{id}, DELETE /Groups/{id}

Limitations:

  • SCIM provisioning requires an Enterprise plan.
  • Officially documented IdP integrations are Okta and Azure AD (Microsoft Entra ID); other IdPs may work but are not officially supported.
  • SCIM endpoint URL and bearer token are generated within the Skilljar dashboard; the token is IdP-specific.
  • Group push support may vary by IdP connector configuration.
  • Deprovisioning (DELETE) deactivates the user in Skilljar but may not permanently delete the record.

Common scenarios

Three scenarios cover the majority of lifecycle automation use cases:

Provision and enroll: POST /v1/users/ with email, first_name, and last_name.

Capture the returned id, then POST /v1/users/{id}/enrollments/ with the target course_id.

Guard the create call with a prior GET /v1/users/ email filter - duplicate email returns a 400 with no upsert behavior.

Deactivate on offboard: Resolve the internal user ID via GET /v1/users/ (email filter or pagination), then PATCH /v1/users/{id}/ with {"is_active": false}.

Optionally DELETE /v1/groups/{group_id}/users/{user_id}/ to remove group memberships.

Note: REST deactivation does not emit SCIM deprovision events - if SCIM is also active on the account, coordinate state to avoid conflicts.

SCIM sync on Enterprise: Generate a SCIM bearer token in Settings > Integrations > SCIM (this token is distinct from the REST API key - rotating one does not affect the other).

Configure the SCIM 2.0 connector in Okta or Azure AD with base URL https://api.skilljar.com/scim/v2/.

Officially supported IdPs are Okta and Azure AD;

others may function but are not documented.

Test with a single user assignment before broad rollout.

Provision a new user and enroll them in an onboarding course

  1. POST /v1/users/ with email, first_name, last_name to create the user account.
  2. Capture the returned 'id' field from the response.
  3. POST /v1/users/{id}/enrollments/ with the target course_id to enroll the user.

Watch out for: If the email already exists, the POST /users/ call returns a 400. Check for existing users via GET /v1/users/ with email filter before creating.

Deactivate a user when they leave an organization

  1. GET /v1/users/?email=user@example.com (or paginate) to find the user's internal ID.
  2. PATCH /v1/users/{id}/ with body {"is_active": false} to deactivate the account.
  3. Optionally, remove the user from relevant groups via DELETE /v1/groups/{group_id}/users/{user_id}/.

Watch out for: Deactivation via REST API does not trigger SCIM deprovision events. If SCIM is also configured, coordinate to avoid state conflicts.

Sync users from an IdP using SCIM on Enterprise plan

  1. Confirm the account is on the Enterprise plan.
  2. In the Skilljar Dashboard, navigate to Settings > Integrations > SCIM and generate a SCIM bearer token.
  3. In Okta or Azure AD, configure the SCIM 2.0 connector with base URL https://api.skilljar.com/scim/v2/ and the generated bearer token.
  4. Enable user provisioning (create, update, deactivate) and optionally group push in the IdP connector settings.
  5. Test with a single user assignment before enabling for all users.

Watch out for: The SCIM bearer token is separate from the REST API key. Rotating one does not affect the other. SCIM group push behavior depends on IdP connector capabilities.

Why building this yourself is a trap

The primary integration trap is the identity resolution gap: there is no GET /v1/users/by-email/ endpoint, so any system that receives an email address (from a webhook, an HR feed, or an identity graph node) must either maintain a local email-to-ID cache or accept the latency of a paginated list scan on every operation.

At 100 records per page with no documented rate limit ceiling, this becomes a meaningful bottleneck for orgs with large learner populations.

The second trap is the SCIM/REST state split. Both surfaces can modify is_active and group membership independently, with no documented reconciliation behavior. Teams building on top of an identity graph that routes some events through SCIM and others through REST must enforce a single write path per attribute or risk divergent state.

Webhooks fire on learner activity events (course.completed, user.registered, enrollment.created, etc.) and are the only near-real-time signal available - the REST API has no server-sent events or long-poll mechanism. Any identity graph that needs to react to completion or registration events must consume webhooks;

polling List Users or List Enrollments is the only fallback, and it carries the pagination cost described above.

Automate Skilljar 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 16, 2026

* Details sourced from official product documentation and admin references.

Keep exploring

Related apps

15Five logo

15Five

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

15Five uses a fixed role-based permission model with six predefined roles: Account Admin, HR Admin, Billing Admin, Group Admin, Manager, and Employee. No custom roles can be constructed. User management lives at Settings gear → People → Manage people p

1Password logo

1Password

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

1Password's admin console at my.1password.com covers the full user lifecycle — invitations, group assignments, vault access, suspension, and deletion — without any third-party tooling. Like every app that mixes role-based and resource-level permissions

8x8 logo

8x8

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

8x8 Admin Console supports full lifecycle user management — create, deactivate, and delete — across its X Series unified communications platform. Every app a user can access (8x8 Work desktop, mobile, web, Agent Workspace) is gated by license assignmen