Summary and recommendation
Absorb LMS exposes a REST Integration API (base URL: rest.myabsorb.com for US; separate regional endpoints for CA, EU, AU) supporting full user lifecycle operations: create, read, update, deactivate, and batch provisioning up to 200 users per request.
Authentication requires a paid API Private Key add-on; tokens are obtained via POST /authentication and expire after 4 hours or immediately upon a new token request for the same username - whichever comes first.
For teams managing Absorb alongside a broader identity stack, Stitchflow's MCP server with ~100 deep IT/identity integrations provides a structured alternative to building and maintaining direct API connections per system. OAuth 2.0 Authorization Code flow (OpenID Connect) is also supported as an alternative auth method.
API quick reference
| Has user API | Yes |
| Auth method | API Token (short-lived bearer) + API Private Key header. OAuth 2.0 (Authorization Code / OpenID Connect) is also supported as an alternative auth method per official docs. |
| Base URL | Official docs |
| SCIM available | Yes |
| SCIM plan required | Enterprise (add-on); SSO is a separate paid prerequisite on all plans |
Authentication
Auth method: API Token (short-lived bearer) + API Private Key header. OAuth 2.0 (Authorization Code / OpenID Connect) is also supported as an alternative auth method per official docs.
Setup steps
- Purchase the Integration API add-on from Absorb; receive an API Private Key tied to your portal.
- POST to the authentication endpoint with your Private Key (x-api-key header) and Admin username/password in the request body to obtain a bearer token.
- Include the bearer token in the Authorization header and the Private Key in the x-api-key header on every subsequent request.
- Tokens expire after 4 hours OR when the same username requests a new token (whichever comes first); requesting a new token invalidates the previous one.
- For multi-workflow setups, create one dedicated Admin user per workflow to prevent token invalidation conflicts.
- Alternatively, use OAuth 2.0 Authorization Code flow (OpenID Connect): request an authorization code via browser redirect, exchange for access + refresh tokens, then use Bearer auth over HTTPS.
Required scopes
| Scope | Description | Required for |
|---|---|---|
| admin.v1 | Grants admin-level access to the Integration API (used in OAuth 2.0 flow example in official docs). | All user management operations via OAuth 2.0 flow |
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| id | string (UUID) | Absorb-generated unique user identifier. | system-generated | read-only | Used as path param for single-user endpoints. |
| departmentId | string (UUID) | ID of the department the user belongs to. | required | optional | Drives enrollment rule matching and availability. |
| firstName | string | User's first name. | required | optional | |
| middleName | string | User's middle name. | optional | optional | |
| lastName | string | User's last name. | required | optional | |
| username | string | Unique login username. | required | optional | Must be unique across the portal. |
| password | string | User's password. | required | optional | Required even when SSO is enabled; a default can be set via API. |
| emailAddress | string | Primary email address. | optional | optional | |
| externalId | string | External system identifier for the user (e.g., HRIS ID). | optional | optional | Useful for cross-system matching; filterable in GET /users. |
| ccEmailAddresses | array of strings | Additional CC email addresses. | optional | optional | |
| languageId | integer | Language preference ID. | optional | optional | |
| gender | integer (enum) | Gender enum value. | optional | optional | |
| jobTitle | string | User's job title. | optional | optional | |
| employeeNumber | string | Employee number. | optional | optional | |
| location | string | User's physical location. | optional | optional | |
| phone | string | Phone number. | optional | optional | |
| dateHired | string (ISO 8601) | Date the user was hired. | optional | optional | |
| dateTerminated | string (ISO 8601) | Date the user was terminated. | optional | optional | |
| activeStatus | string (enum) | Account active/inactive status (e.g., 'Active'). | optional | optional | Used to deactivate users; merged duplicate accounts are set to Inactive, not deleted. |
| customFields | object | Portal-defined custom fields (Bool1–5, DateTime1–5, Decimal1–5, String1+). | optional | optional | Schema varies per portal configuration. |
Core endpoints
Authenticate (get token)
- Method: POST
- URL:
https://rest.myabsorb.com/authentication - Watch out for: Requesting a new token immediately invalidates the previous token for that username. Use one Admin account per workflow.
Request example
POST /authentication
Headers: x-api-key: <privateKey>
Content-Type: application/json
{
"username": "admin@example.com",
"password": "adminpass"
}
Response example
{
"token": "eyJ...",
"expiresAt": "2025-02-25T08:00:00Z"
}
List Users
- Method: GET
- URL:
https://rest.myabsorb.com/users - Watch out for: Use _limit and _offset for pagination. Records modified during pagination may appear on multiple pages or be skipped.
Request example
GET /users?_limit=50&_offset=0&modifiedSince=2025-01-01
Headers: Authorization: <token>
x-api-key: <privateKey>
Response example
{
"totalItems": 120,
"limit": 50,
"offset": 0,
"returnedItems": 50,
"users": [{"id":"...","firstName":"Jane",...}]
}
Get User by ID
- Method: GET
- URL:
https://rest.myabsorb.com/users/{userId} - Watch out for: Returns 404 if user not found or not visible to the authenticated Admin's department scope.
Request example
GET /users/e46c9e94-d408-4c7c-86b9-f7f2e3b6a01d
Headers: Authorization: <token>
x-api-key: <privateKey>
Response example
{
"id": "e46c9e94-...",
"firstName": "Jane",
"lastName": "Doe",
"emailAddress": "jane@example.com",
"activeStatus": "Active"
}
Create User
- Method: POST
- URL:
https://rest.myabsorb.com/users - Watch out for: firstName, lastName, username, departmentId, and password are all required. Password is mandatory even if SSO is configured.
Request example
POST /users
Headers: Authorization: <token>, x-api-key: <key>
{
"firstName": "Jane",
"lastName": "Doe",
"username": "jane.doe",
"password": "Temp@1234",
"departmentId": "75916e81-...",
"emailAddress": "jane@example.com"
}
Response example
{
"id": "e46c9e94-...",
"firstName": "Jane",
"lastName": "Doe",
"username": "jane.doe"
}
Update User (full)
- Method: PUT
- URL:
https://rest.myabsorb.com/users/{userId} - Watch out for: Returns 404 if user not found; 422 on validation errors. Omitting fields may clear them depending on API version.
Request example
PUT /users/e46c9e94-...
Headers: Authorization: <token>, x-api-key: <key>
{
"firstName": "Jane",
"lastName": "Smith",
"jobTitle": "Manager"
}
Response example
{
"id": "e46c9e94-...",
"firstName": "Jane",
"lastName": "Smith",
"jobTitle": "Manager"
}
Batch Create/Update Users
- Method: POST
- URL:
https://rest.myabsorb.com/users/batch - Watch out for: Maximum of 200 users per batch request. Returns 422 if any user in the payload contains validation errors.
Request example
POST /users/batch
Headers: Authorization: <token>, x-api-key: <key>
{
"users": [{...}, {...}]
}
Response example
{
"succeeded": 198,
"failed": 2,
"errors": [{"index":5,"message":"..."}]
}
Deactivate User
- Method: PUT
- URL:
https://rest.myabsorb.com/users/{userId} - Watch out for: Absorb deactivates rather than hard-deletes users. Merged duplicate accounts are also set to Inactive, not deleted.
Request example
PUT /users/e46c9e94-...
Headers: Authorization: <token>, x-api-key: <key>
{
"activeStatus": "Inactive"
}
Response example
{
"id": "e46c9e94-...",
"activeStatus": "Inactive"
}
Get User Enrollments
- Method: GET
- URL:
https://rest.myabsorb.com/users/{userId}/enrollments - Watch out for: Filter by status (integer enum) and modifiedSince. Large result sets should use pagination parameters.
Request example
GET /users/e46c9e94-.../enrollments?status=0&modifiedSince=2025-01-01
Headers: Authorization: <token>, x-api-key: <key>
Response example
[
{"courseId":"...","status":0,"completedDate":null}
]
Rate limits, pagination, and events
- Rate limits: The Integration API enforces safeguards against traffic bursts. Exceeding limits returns HTTP 429 Too Many Requests.
- Rate-limit headers: No
- Retry-After header: No
- Rate-limit notes: A burst buffer of an additional 100 requests is available above the 200/sec steady-state limit. No rate-limit response headers are documented by Absorb; implement exponential backoff on 429 responses. Batch user upload endpoint caps at 200 users per request.
- Pagination method: offset
- Default page size: 0
- Max page size: 0
- Pagination pointer: _limit and _offset
| Plan | Limit | Concurrent |
|---|---|---|
| All API plans (single tier) | 200 requests per second | 0 |
- Webhooks available: Yes
- Webhook notes: Absorb supports webhooks that push HTTP notifications to a configured listener URL when LMS events occur. Payloads are intentionally lean (user ID, admin ID, client/correlation IDs) and are designed to trigger a follow-up Integration API call for full details. Webhook signatures can be validated with a secret key (added Q1 2025). Configuration is done by a System Administrator in Client Settings.
- Alternative event strategy: Poll GET /users?modifiedSince=
for user changes if webhooks are not configured. - Webhook events: User Created (Learner), Course Completed, Course Enrollment Created (added Q1 2025), Course Created (Admin), Competency Gained, Session Started
SCIM API status
SCIM available: Yes
SCIM version: 2.0
Plan required: Enterprise (add-on); SSO is a separate paid prerequisite on all plans
Endpoint: Tenant-specific SCIM endpoint URL generated in the Absorb Admin Console (Client Settings); format is not publicly documented but is provided during setup. Bearer token is generated in the Admin Console.
Supported operations: Create Users, Update User Attributes, Deactivate Users, Group Linking (via Okta OIN integration), Schema Discovery, Group Import
Limitations:
- SSO must be fully configured before SCIM can be enabled; SSO is a paid add-on on every plan tier.
- Native SCIM is only available on Enterprise plan (custom pricing).
- User provisioning only works on 'Absorb 5 – New Learner Experience'; older portal versions require migration.
- SAML JIT provisioning creates accounts on first login only and does not update existing user attributes.
- SCIM integration is currently available via Okta OIN; Microsoft Entra ID support exists via SAML SSO but SCIM endpoint configuration requires technical resources outside Absorb.
- Google Workspace users get JIT provisioning only, not full SCIM.
- SCIM Change Log maintained separately (last updated February 28, 2025); connector versions may lag behind LMS releases.
Common scenarios
Three integration patterns cover the majority of production use cases.
First, HRIS-driven provisioning: POST /authentication to obtain a token, then POST /users with firstName, lastName, username, password, departmentId, and externalId (mapped to the HRIS employee ID); store the returned Absorb user id for future lookups.
Note that password is required on every user creation even when SSO is active. Second, profile sync on attribute change: query HRIS for records modified since the last sync timestamp, resolve each to an Absorb user id via GET /users?
externalId=
Third, termination offboarding: receive the termination event, resolve the Absorb user id, and PUT /users/{userId} with activeStatus set to Inactive - Absorb does not hard-delete users, so deactivated records remain in the system and must be filtered explicitly in the Users Report.
Webhooks (User Created, Course Completed, Course Enrollment Created, and others) can supplement polling; payloads are intentionally lean and designed to trigger a follow-up API call for full record details. Webhook signature validation via secret key was added in Q1 2025.
Provision a new employee from an HRIS system
- POST to /authentication with Admin credentials + x-api-key to obtain a bearer token.
- POST to /users with required fields: firstName, lastName, username, password, departmentId, emailAddress, and externalId (set to HRIS employee ID for future matching).
- Store the returned Absorb user id mapped to the HRIS record.
- Optionally enroll the user in onboarding courses via POST /enrollments.
Watch out for: Password is required even if SSO is in use. Token expires in 4 hours; refresh before long-running sync jobs.
Sync user profile updates from HRIS (e.g., department transfer, job title change)
- Query HRIS for users modified since last sync timestamp.
- For each changed user, GET /users?externalId=
to resolve the Absorb user id.
- For each changed user, GET /users?externalId=
- PUT /users/{userId} with updated fields (departmentId, jobTitle, etc.).
- Update the last-sync timestamp to the current time for the next run.
Watch out for: Use modifiedSince filter on GET /users to reduce payload. Paginate with _limit/_offset for large user bases; records modified mid-scan may appear on multiple pages.
Offboard a terminated employee
- Receive termination event from HRIS.
- GET /users?externalId=
to resolve Absorb user id.
- GET /users?externalId=
- PUT /users/{userId} with { "activeStatus": "Inactive" } to deactivate the account.
- Optionally subscribe to the User Created webhook to detect re-hire scenarios and reactivate.
Watch out for: Absorb does not hard-delete users; deactivated accounts remain in the system. If using SCIM via Okta, deactivation is handled automatically by the IdP, but requires Enterprise plan + SSO add-on.
Why building this yourself is a trap
Several non-obvious constraints create integration risk at scale. The API add-on must be purchased separately - no Private Key means no API access regardless of plan tier.
Token invalidation on re-authentication is a hard operational constraint: in multi-workflow setups, a second process requesting a token for the same Admin username immediately invalidates the token in use by the first process; the documented mitigation is one dedicated Admin account per workflow.
The authenticated Admin's department scope applies equally to API responses - GET /users will silently omit users outside the Admin's assigned scope, which can cause provisioning logic to create duplicate accounts rather than update existing ones.
Rate limiting is set at 200 requests per second with a burst buffer of 100; no rate-limit headers are returned in responses, so exponential backoff on HTTP 429 must be implemented defensively.
The legacy v1 API (myabsorb.com/api/rest/v1/) remains accessible but is unsupported; use the x-api-version header to pin to a specific version of the current Integration API.
SCIM 2.0 is available but gated behind Enterprise tier plus a separately purchased SSO add-on, and only functions on Absorb 5 New Learner Experience - older portal implementations require migration before SCIM provisioning can be enabled.
Automate Absorb LMS workflows without one-off scripts
Stitchflow builds and maintains identity workflows for your exact setup. We cover every app, including the ones without APIs, and run deterministic trigger-to-report workflows with human approvals where they matter.