Most HRIS-to-LMS integrations fail not during architecture – they fail at the field-mapping stage, the token refresh edge case, or when a terminated employee’s account stays active in the LMS for 72 hours. This guide closes those gaps. Whether you’re building a native REST integration between Workday and Docebo, implementing SCIM 2.0 provisioning through Okta, or debugging a broken xAPI 1.0.3 statement pipeline, the specifics are here.
The Integration Stack: Protocols, Standards, and Where They Actually Apply
Before touching configuration, it’s critical to separate the concerns: authentication, user provisioning, content tracking, and tool interoperability are solved by different standards and should not be conflated.
| Layer | What It Solves | Primary Standards |
|---|---|---|
| Authentication | Who can call the API | OAuth 2.0, API Keys, JWT |
| User Provisioning | Syncing employee records to LMS | SCIM 2.0, REST API (HRIS vendor), CSV/SFTP |
| Identity Federation | SSO across systems | SAML 2.0, OpenID Connect, LTI 1.3 |
| Content Tracking | Learning event capture | SCORM 1.2 / 2004, xAPI 1.0.3, cmi5 |
| Tool Interoperability | Embedding external tools in LMS | LTI 1.3 + LTI Advantage |
| Completion Writeback | Pushing training data to HRIS | REST webhook, HRIS proprietary API |
Most content on this topic conflates all of these as “integration.” In practice, each layer has its own failure modes, versioning concerns, and vendor support caveats.
Core Technical Concepts: Data Flow and Protocol Architecture
The HRIS-to-LMS Data Pipeline
The canonical integration flow operates in one direction at provisioning time and bidirectionally for completion data:
HRIS (System of Record)
│
├─► [Trigger: Employee Create / Role Change / Termination]
│ │
│ ▼
│ SCIM 2.0 or REST API Call ──► LMS User Provisioning Endpoint
│ │ │
│ │ ├─ Create account
│ │ ├─ Assign role/group
│ │ └─ Enroll in curriculum
│
└─► [Completion Writeback]
▲
│
LMS Webhook ──► HRIS Custom Field / Training Record
A concrete SCIM 2.0 POST /Users payload from Workday to a SCIM-compliant LMS looks like this:
{
“schemas”: [“urn:ietf:params:scim:schemas:core:2.0:User”],
“userName”: “jsmith@company.com“,
“name”: {
“givenName”: “Jane”,
“familyName”: “Smith”
},
“emails”: [{ “value”: “jsmith@company.com“, “primary”: true }],
“active”: true,
“urn:ietf:params:scim:schemas:extension:enterprise:2.0:User”: {
“employeeNumber”: “EMP-00432”,
“department”: “Product Engineering”,
“manager”: {
“value”: “mlee@company.com“,
“$ref”: “https://hris.company.com/scim/v2/Users/789“
}
}
}
The LMS SCIM endpoint responds with 201 Created and a location header. The employeeNumber value becomes the canonical linking key between systems – this is what gets written into the LMS custom_field and referenced in completion writebacks.
xAPI 1.0.3 Statement Structure
When the LMS sends learning events to a Learning Record Store (LRS) – whether internal or external – each event is an xAPI statement. The ADL specification (xAPI 1.0.3, released December 2013, maintained at adlnet.gov) defines the Actor–Verb–Object pattern. A compliant completion statement for an onboarding module looks like:
{
“actor”: {
“mbox”: “mailto:jsmith@company.com“,
“name”: “Jane Smith”,
“objectType”: “Agent”
},
“verb”: {
“id”: “http://adlnet.gov/expapi/verbs/completed“,
“display”: { “en-US”: “completed” }
},
“object”: {
“id”: “https://lms.company.com/courses/onboarding-2026“,
“definition”: {
“name”: { “en-US”: “New Hire Onboarding – Q1 2026” },
“type”: “http://adlnet.gov/expapi/activities/course“
},
“objectType”: “Activity”
},
“result”: {
“success”: true,
“completion”: true,
“score”: { “scaled”: 0.92, “raw”: 92, “min”: 0, “max”: 100 },
“duration”: “PT45M30S”
},
“timestamp”: “2026-03-15T14:22:00Z”,
“authority”: {
“mbox”: “mailto:lrs-admin@company.com“,
“objectType”: “Agent”
}
}
The actor.mbox must match a consistent identifier across your HRIS and LMS – ideally the corporate email, not an LMS-internal UUID. Inconsistent actor identifiers are the single most common cause of broken analytics in multi-tool LRS environments.
Standards and LMS Compatibility Matrix
The following matrix reflects the current (Q1 2026) feature support posture across major enterprise LMS platforms. “Native” means vendor-documented support; “Partial” means functional with configuration caveats; “Via Middleware” means requires an iPaaS (Workato, MuleSoft, Zapier) or identity provider (Okta, Azure AD Entra) in the chain.
| LMS | SCIM 2.0 | xAPI 1.0.3 | LTI 1.3 + Advantage | SAML 2.0 | Native HRIS Connectors | REST API (Rate Limit) | Webhook Events |
|---|---|---|---|---|---|---|---|
| Workday Learning | Native | Native | Native | Native | Workday HCM (embedded) | ✓ (undisclosed) | ✓ |
| SAP SuccessFactors | Native | Native | Native | Native | SAP HCM / EC | ✓ (600/min) | ✓ |
| Docebo | Native | Native | Native | Native | Workday, BambooHR, ADP | ✓ (500/hr) | ✓ |
| Cornerstone OnDemand | Via IdP | Native | Partial (1.1 + 1.3) | Native | Workday, ADP, Oracle HCM | ✓ (300/hr) | Limited |
| CYPHER Learning | Native | Native | Native | Native | Multiple via REST | ✓ (600/hr) | ✓ |
| TalentLMS | Via IdP | Native | Partial | Native | BambooHR, ADP | ✓ (200/hr) | Limited |
| Litmos (SAP) | Native (via SAP EC) | Native | LTI 1.1 only | Native | BambooHR, ADP, Workday | ✓ (500/hr) | ✓ |
| Absorb LMS | Via IdP (SAML 2.0) | Native | Native | Native | Major HRIS via REST | ✓ (rate-limited) | Limited |
| Sana Learn | Native | Native | Native | Native | Workday, BambooHR, Personio, Hibob | ✓ (GraphQL + REST) | ✓ |
| Bridge (Instructure) | Via IdP | Native | Native | Native | Workday, ADP, SAP, BambooHR | ✓ | ✓ |
Implementation Steps: HRIS-to-LMS Integration (Workday → Docebo as Reference Architecture)
These steps apply conceptually to any REST-based integration. Workday + Docebo is used as the reference pair because it’s among the most common enterprise pairings and both expose well-documented APIs.
Step 1: Establish OAuth 2.0 Client Credentials
In Workday: Register an integration system user (ISU) with the System > ISU > SCIM 2.0 Outbound domain. Generate a client ID and client secret. Set the token endpoint to:
POST https://wd2-impl-services1.workday.com/ccx/oauth2/{tenant}/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
Access tokens expire in 3,600 seconds (1 hour). Your middleware must implement token refresh logic – polling without refresh will fail silently after the first hour.
Step 2: Configure the SCIM Endpoint in Docebo
In Docebo Admin: API & SSO → SCIM Provisioning → Enable SCIM. Copy the generated Bearer token and SCIM base URL (format: https://yourcompany.docebosaas.com/scim/v2/). In Workday’s integration configuration, paste these as the outbound SCIM target.
Map the following Workday fields to Docebo SCIM attributes:
| Workday Field | SCIM Attribute | Docebo User Field |
|---|---|---|
| Worker ID | externalId | External ID |
| Primary Email | userName + emails[0].value | Username / Email |
| Legal Name | name.givenName + name.familyName | First / Last Name |
| Supervisory Org | enterprise.department | Branch/Group |
| Position | enterprise.organization | Additional Field |
| Employment Status | active | Active flag |
Step 3: Configure Trigger Events in Workday
Use Workday’s Business Process Framework to configure SCIM triggers on:
- Hire → POST /Users
- Job Change (role, department, location) → PATCH /Users/{id}
- Terminate → PATCH /Users/{id} with “active”: false
Do not use the “full sync” option in production – a daily full-sync for large orgs (10,000+ users) will consume your API rate limit budget and delay incremental events.
Step 4: Implement Completion Writeback
For the reverse flow – pushing LMS completion data back to Workday – use Docebo webhooks. In Docebo: Admin → Webhooks → Add New.
Configure the payload to fire on course.completion events, targeting Workday’s REST inbound endpoint or a middleware service. A minimal writeback payload:
{
“event”: “course.completion”,
“user”: {
“email”: “jsmith@company.com“,
“external_id”: “EMP-00432”
},
“course”: {
“id”: 1042,
“name”: “HIPAA Compliance 2026”,
“completion_date”: “2026-03-15”,
“score”: 92
}
}
Workday receives this via a custom REST API integration (Workday Studio or EIB inbound) and writes to the employee’s Learning record in Talent.
Step 5: Test in Sandbox Before Production
Run the full provisioning cycle in Workday’s Implementation Tenant and Docebo’s Sandbox environment. Verify:
- New hire creation creates an LMS account within the expected SLA (typically under 15 minutes for event-driven triggers)
- Role change fires a PATCH, not a DELETE + POST (which would orphan completion records)
- Termination sets active: false and deactivates, not deletes, the LMS account (critical for audit trail preservation)
Common Issues and Fixes
Error 1: “Unable to Acquire LMS API” (SCORM Runtime)
Symptom: Learner launches a SCORM package; browser displays a dialog – “Unable to find API adapter” or “LMSInitialize failed.”
Root cause: The SCORM API discovery algorithm traverses parent frames looking for the API object (SCORM 1.2) or API_1484_11 (SCORM 2004). A cross-origin iframe restriction or incorrect launch window mode blocks the traversal.
Fix: Verify the SCO Launch Type in course properties. If content is launched in a new window and the LMS player is a frameset, the API is unreachable. Switch both to frameset, or test in SCORM Cloud (cloud.scorm.com) to isolate whether the issue is in the package or the LMS. If SCORM Cloud succeeds, the LMS’s iframe security policy is the problem – whitelist the content CDN domain.
Error 2: SCIM Provisioning Silently Drops Events After Hour 1
Symptom: New hires created after the first hour of a sync session don’t appear in the LMS. No error surfaced in the HRIS.
Root cause: OAuth 2.0 access token expired (default TTL: 3,600s). The HRIS integration continues firing SCIM calls with the expired bearer token, receiving 401 Unauthorized, but the error is swallowed if middleware doesn’t log 4xx responses.
Fix: Implement proactive token refresh. Subtract 60 seconds from the expires_in value and refresh at expires_in – 60. Log all 4xx responses from the SCIM endpoint – never silently suppress them.
Error 3: Duplicate User Accounts on Role Change
Symptom: An employee changes departments and now has two LMS accounts – one active, one orphaned.
Root cause: The HRIS integration is configured to fire a DELETE + POST on job change events rather than a PATCH. This happens when the HRIS system creates a new worker record for position changes (common in ADP Workforce Now).
Fix: Use externalId as the idempotency key, not email. Configure the LMS SCIM receiver to perform an upsert: if externalId exists, PATCH; if not, POST. In Docebo, this is the “External ID Matching” option in SCIM settings. For ADP integrations, map the associateOID (not positionID) as the stable externalId.
Error 4: xAPI Statements Not Appearing in LRS / Completion Not Registering
Symptom: Learners complete courses; xAPI statements are sent but don’t appear in the LRS dashboard or don’t trigger grade passback.
Root cause (most common): The actor.mbox in the xAPI statement (mailto:userid@lms.internal) doesn’t match the actor identifier expected by the LRS (mailto:jsmith@company.com). The LRS indexes statements by actor, so unmatched actors create orphaned records.
Fix: Enforce a consistent actor identification strategy across all tools that write to the LRS. The ADL specification recommends using corporate email (mbox) or an HRIS employee ID passed as account.name with a homePage of your HRIS instance URL. Document and enforce the chosen pattern in your content authoring standards.
Error 5: LTI 1.3 Launch Fails with “Invalid State” or JWT Signature Error
Symptom: External LTI 1.3 tool returns an error on launch. Browser console shows a CSRF or JWT validation failure.
Root cause: The LTI 1.3 security model requires that the platform (LMS) and tool exchange a state parameter and validate a signed JWT. If the tool’s Deployment ID or Client ID is misconfigured in either system, the signature verification fails. This is especially common after migrating from LTI 1.1.
Fix: In the LMS, verify the Deployment ID matches exactly what the tool provider configured – this is case-sensitive and whitespace-sensitive. Confirm the LMS’s public JWK Set URL is accessible from the tool’s server (firewall rules often block this). For Moodle-based LMSes, regenerate the key pair under Site admin → Plugins → LTI → Manage tools and re-register with the tool provider.
Error 6: Webhook Delivery Failures Causing Missed Completion Writebacks
Symptom: Some completions are not written back to the HRIS. Spot checks reveal the LMS fired the webhook but the HRIS never received it.
Root cause: Webhooks use fire-and-forget delivery. If the receiving endpoint returns a non-2xx response (e.g., the HRIS middleware is temporarily unavailable), the event is lost – most LMS platforms do not retry failed webhooks more than 3 times, and retry windows are short (often under 10 minutes).
Fix: Build a durable message queue (AWS SQS, Azure Service Bus, or Google Cloud Pub/Sub) between the LMS webhook and the HRIS write operation. The queue absorbs transient failures and guarantees at-least-once delivery. Additionally, implement a nightly reconciliation job that queries the LMS API for completions in the past 48 hours and compares against HRIS records, writing any gaps.
💡Map externalId Before Anything Else
The single most impactful thing you can do before writing a single line of integration code is to define and lock down your stable identifier strategy. Every system involved – HRIS, LMS, IdP, LRS – needs to agree on one immutable, non-recycled employee identifier. Use the HRIS-assigned employee ID (not email, not username, not SSO subject claim – these all change). Map it as externalId in SCIM, as account.name in xAPI, and as a custom attribute in your SAML assertion. When an employee changes their name, gets married, switches email domains, or moves to a subsidiary, the externalId remains constant. Every integration issue traced back to “wrong user” or “duplicate account” roots in this not being set up correctly from day one. Retrofitting this after go-live requires a full user re-provisioning event and is extraordinarily disruptive.
FAQ
Q1. Should I use SCIM or a direct REST API integration between my HRIS and LMS?
Use SCIM 2.0 where both systems support it natively – it provides a standardized schema, predictable event types (Create, Patch, Delete), and is IdP-compatible (Okta, Azure AD Entra). Direct REST API integrations offer more flexibility for custom field mapping and completion writeback, but require you to maintain the integration logic as APIs evolve. Many production architectures use SCIM for provisioning and direct REST/webhooks for completion data, since SCIM was not designed for bidirectional learning data.
Q2. Do I need a standalone LRS if my LMS supports xAPI internally?
It depends on your analytics requirements. If you’re tracking learning events only from within the LMS and reporting through the LMS’s built-in dashboards, an embedded LRS is sufficient. If you’re capturing xAPI statements from outside the LMS (mobile apps, simulations, VR environments, manager observations), you need a standalone LRS (SCORM Cloud LRS, Learning Locker, WATERSHED, or Veracity) to serve as the central aggregation point. The LMS-embedded LRS typically doesn’t expose an external query API at the statement level, limiting cross-system analytics.
Q3. How do we handle employee termination in a way that preserves audit compliance but revokes LMS access?
The correct sequence for termination is: (1) Set active: false via SCIM PATCH – this deactivates the account without deleting records. Never hard-delete LMS users on termination; completion records, certificates, and audit trails are destroyed. (2) Revoke SSO sessions immediately through your IdP (Okta universal logout, Azure AD session revocation). (3) If your LMS platform supports it, archive (soft-delete) the account after a configurable retention period (typically 90 days post-termination). Regulated industries (healthcare, finance, government) often have 7-year training record retention requirements – confirm your LMS’s data retention policy and whether soft-deleted records are included in compliance exports before configuring any automated deletion.