xAPI Learning Activity Webhooks
The Experience API (xAPI) is a learning technology interoperability specification that makes it easier for learning technology products to communicate with one another. In the context of LinkedIn Learning, xAPI can be used to track learning events in realtime. When an event takes place, LinkedIn will send an xAPI compliant HTTP POST payload to your webhook URL. The webhook URL & credentials are configured in LinkedIn Learning admin settings. To learn more about xAPI, review the Experience API (xAPI) Specification.
Authentication
LinkedIn Learning xAPI webhooks use two-legged OAuth 2.0 to send authenticated POST requests to your learning platform. Two-legged OAuth is also known as OAuth 2.0 Client Credentials Grant. Your Learning Platform is the authorization server and LinkedIn Learning is the client. LinkedIn Learning will authenticate with your Learning Platform directly in a system-to-system context. This section outlines the authentication request/response:
Access Token Request Reference
Request Details
URL | Verb | Headers |
---|---|---|
https://your-learning-platform.com/oauth2/token |
POST | Content-type=x-www-form-urlencoded |
Request Body Parameters
Parameter | Description | Required |
---|---|---|
grant_type | Value will always be client_credentials | Yes |
scope | Supported values are xapi:read, xapi:write and xapi:all. LinkedIn Learning will request the xapi:write scope. | Yes |
client_id | Value should be obtained from your learning platform | Yes |
client_secret | Value should be obtained from your learning platform | Yes |
Sample cURL Request
curl -X POST https://your-learning-platform/oauth2/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=client_credentials&client_id=dunder_mifflin&client_secret=abc123def45&scope=xapi:write'
Access Token Response Reference
Response Details
Status | Headers |
---|---|
200 | Content-Type: application/json;charset=UTF-8 |
Response Body
Item | Value |
---|---|
access_token | Valid access token string |
expires_in | Time to live (TTL) in seconds |
token_type | Value should always be "bearer" |
Sample Response
{
"access_token":"2YotnFZFEjr1zCsicMWpAA....",
"token_type":"bearer",
"expires_in":3600
}
Activity Statement
A learner activity webhook POST body follows an Actor, Verb, Object data model. This section describes each object in the data model. For additional details, review the Experience API Data section of the specification. LinkedIn will report the following two activities to your LMS system:
- COMPLETED -- sent when the learner/actor has completed a course.
- PROGRESSED -- sent when the learner/actor has completed a video in a course.
Completed Statement POST Body example
Here is an example COMPLETED
statement request POST body. This statement would be sent after actor dschrute@linkedin.com
completes course urn:li:lyndaCourse:563463
.
{
"actor": {
"mbox": "mailto:dschrute@dundermifflin.com",
"objectType": "Agent"
},
"result": {
"duration": "PT1M22S",
"completion": true
},
"verb": {
"display": {
"en-US": "COMPLETED"
},
"id": "http://adlnet.gov/expapi/verbs/completed"
},
"id": "e45018e3-e91f-47a1-b003-5938e4db4a8c",
"object": {
"definition": {
"type": "http://adlnet.gov/expapi/activities/course"
},
"id": "urn:li:lyndaCourse:563463",
"objectType": "Activity"
},
"timestamp": "2018-09-17T19:13:27.384Z"
}
Progressed Statement POST Body example
Here is an example PROGRESSED
statement request POST body. In this example a statement is sent after actor dschrute@linkedin.com
completes a video in the course urn:li:lyndaCourse:2822089
in LinkedIn Learning.
{
"actor": {
"account": {
"homePage": "https://example.com",
"name": "dschrute@linkedin.com"
},
"objectType": "Agent"
},
"id": "b2f642cb-5a65-4b15-a1ae-887f1099a4e1",
"object": {
"definition": {
"type": "http://adlnet.gov/expapi/activities/course"
},
"id": "urn:li:lyndaCourse:2822089",
"objectType": "Activity"
},
"result": {
"completion": false,
"extensions": {
"https://w3id.org/xapi/cmi5/result/extensions/progress": "28"
}
},
"timestamp": "2020-04-16T21:27:19.996Z",
"verb": {
"display": {
"en-US": "PROGRESSED"
},
"id": "http://adlnet.gov/expapi/verbs/progressed"
}
}
Activity Statement: Sample cURL
curl -X POST \
https://your-learning-platform.com/xAPI/statements \
-H 'Authorization: Bearer AyOtu...' \
-H 'Connection: close' \
-H 'Content-Type: application/json' \
-H 'X-Experience-API-Version: 1.0.0' \
-d '{
"actor": {
"mbox": "mailto:dschrute@dundermifflin.com",
"objectType": "Agent"
},
"result": {
"duration": "PT1M22S",
"completion": true
},
"verb": {
"display": {
"en-US": "COMPLETED"
},
"id": "http://adlnet.gov/expapi/verbs/completed"
},
"id": "e45018e3-e91f-47a1-b003-5938e4db4a8c",
"object": {
"definition": {
"type": "http://adlnet.gov/expapi/activities/course"
},
"id": "urn:li:lyndaCourse:563463",
"objectType": "Activity"
},
"timestamp": "2018-09-17T19:13:27.384Z"
}'
Actor
The actor object identifies the learner who performed an action in LinkedIn Learning. The functional identifier value used in activity statements is configurable in Linkedin Learning admin settings. There are two supported options:
- SAML SSO User Identifier: User identifier value included in SAML SSO authentication payload. This value can be an email address, username, employee number or any other unique and immutable user identifier. If your learning platform is configured as a SAML IdP select this option. If a third party identity management system is in use, this option can be used if both relying parties (LinkedIn Learning & your learning platform) are configured to receive the same user identifier from the SAML IdP.
- Email: A learner's work email address value.
Actor: SAML SSO User Identifier Example
"actor": {
"account": {
"name": "dpappas",
"homePage": "https://linkedin.com/learning"
},
"objectType": "Agent"
}
Actor: Email Identifier Example
"actor": {
"mbox": "mailto:mscott@dundermifflin.com",
"objectType": "Agent"
}
Result
The result object represents a measured learning outcome. The completion field indicates whether or not the LinkedIn Learning course was completed in full and duration is the period of time over which the completion took place. Durations are expressed using the format for Duration in ISO 8601:2004(E) section 4.4.3.2.
Example when course is completed
"result": {
"duration": "PT1M22S",
"completion": true
}
Example when course is not completed
"result": {
"completion": false,
"extensions": {
"https://w3id.org/xapi/cmi5/result/extensions/progress": "28"
}
}
Verb
The verb object identifies the event triggered in LinkedIn Learning. The supported verbs are COMPLETED
and PROGRESSED
. The events are fired when a user completes a LinkedIn Learning course for COMPLETED
statements and when a video is completed for PROGRESSED
statements.
Verb: Completed Example
"verb": {
"display": {
"en-US": "COMPLETED"
},
"id": "http://adlnet.gov/expapi/verbs/completed"
}
Verb: PROGRESSED Example
"verb": {
"display": {
"en-US": "PROGRESSED"
},
"id": "http://adlnet.gov/expapi/verbs/progressed"
}
Object
Object identifies a course on LinkedIn Learning. The object.id
URN value is a unique identifier whose value should be treated as opaque. The object.id
value is synonymous with course URN values returned in the /learningAssets API response body.
Object: LinkedIn Learning Course Example
"object": {
"definition": {
"type": "http://adlnet.gov/expapi/activities/course"
},
"id": "urn:li:lyndaCourse:563463",
"objectType": "Activity"
}
Retry Behavior for xAPI Events
Note
Retry behavior is only utilized for completion events, not progress statements.
In order to send an xAPI event to an external system, a multi-step process is initiated to request an OAuth2 access token and then send the xAPI event using the access token. If an error status code is encountered in either HTTP request, or any other failure is encountered at any time during this process, the event is enqueued and retried at a later time. Status codes 300 and above will result in a failed attempt, only 2XX
level status codes are considered successful. The retry cadence may change over time, but today the current behavior retries sending xAPI events that have failed every 12 hours for 5 days.