LearnUpon technical documentation
Set up Webhooks to connect to LearnUpon, to keep your records of learner activity up to date.
Webhooks guide
This guide explains how to set up and configure LearnUpon webhooks.
Webhooks let you "listen" for specific events that occur on your LearnUpon portal, like a learner completing a course or a manager enrolling a learner. Once you set up the webhook feature, LearnUpon sends event notices (the hooks) to a defined URL, as a JSON data POST, with defined data schematics. You can use these notices in your third-party site or applications.
Configuration
When you set up webhooks as a feature, your destination URL receives all the webhooks, for all event triggers that apply to your LearnUpon content and users. You can't turn on a single webhook type.
Contact the support team to turn on webhooks for your portal.
When you have access to the feature, you set it up through your portal interface, following the instructions in the LearnUpon Knowledge Base.
Webhook types
LearnUpon sends webhook messages for the following events on your portal.
Webhook type | Description of event |
---|---|
course_cloning_complete |
an admin finishes cloning a course |
course_completion |
a learner completes a course |
course_updated |
someone updates a course |
module_complete |
a learner completes a module within a course |
exam_completion |
a learner compeletes an exam |
survey_completion |
a learner completes a survey |
learning_path_updated |
someone updates a learning path |
learning_path_completion |
a learner completes a learning path |
purchase_completion |
a customer completes a purchase of courses on the portal |
badge_awarded |
the portal awards a badge associated with a course, learning path, activity or level |
badge_revoked |
an admin removes a badge from a learner |
Receiving a webhook on your servers
Configuring your server to receive a webhook is no different from creating any page on your website. For example:
- with PHP, you might create a new .php file on your server
- with a framework like Sinatra, you can add a new route with the desired URL
Remember, with webhooks, your server is the server receiving the request.
LearnUpon sends its webhook data as JSON in the request's body. If security is a concern, or if it's important to confirm that LearnUpon sent the webhook, see the Setup tips section for replay-attack prevention and signature verification.
Receiving webhooks with a CSRF-protected server
If you use Rails, Django, or another web framework, your server may automatically check that POST request bodies it receives contain a CSRF token. This security feature helps protect you and your users from cross-site request forgery(external link). However, it may also prevent your server from receiving legitimate webhooks. You may need to exempt the CSRF protection on the Rails route or Django view you use to receive webhooks.
Verifying the received webhook
MD5 Hash in ruby
{
MD5.hexdigest( JSON_DATA_FROM_HOOK + ":" + secret_key )
}
If you have specified a secret key in your LearnUpon webhook settings, each webhook contains a signature
in the header section of the JSON payload. That signature is the MD5 hash of the entire JSON payload, minus the signature element itself, with your secret key appended, including a colon separator.
To verify the JSON is valid, LearnUpon recommends the following workflow in your code. Using a JSON parser to parse the received JSON:
- Search for the
signature
key in theheader
section, and remove the element (key/value pair). - Store the parsed JSON (minus the signature) as a string, taking care not to alter the whitespace or quotes. LearnUpon use minimal whitespace, and valid strict JSON quoting: so key names use double quotes, not single quotes, for example.
- Append a colon (
:
) to the string, and then append your secret key with no quotes or formatting. - Get the MD5 hash of that entire string: match it to the signature value you received (and subsequently removed) from the JSON.
Troubleshooting
If the MD5 hash doesn't match the returned signature value, make sure:
- The secret key is correctly set up in LearnUpon: if you pasted it in to LearnUpon, did a trailing space get included?
- Your JSON parser is not altering the whitespace of the JSON payload. Some parsers, for example, have "pretty print" options to nicely format the JSON for printing/debug.
- You have no quotes, whitespace, or formatting when appending your secret key. Also, don't forget the colon, with no whitespace either side of it.
If you still have no success, contact the support team with a sample for further assistance.
Responding to a Webhook
To acknowledge you received the webhook successfully, your server should return a 2xx HTTP status code. LearnUpon's system ignores any other information you return in the request headers or request body.
Any response code outside the 2xx range indicates to LearnUpon that you did not receive/process the webhook successfully. When a webhook is not received for whatever reason, LearnUpon continues trying to send the webhook for 2 more hours.
If your server returns a 4XX HTTP status code, LearnUpon logs a response inside the Error Message section of webhook status.
Make sure responses are no longer than 2 seconds. LearnUpon will timeout the connection, and mark the hook as failed, if the system gets no response within 2+ seconds. If you need to process data, or have any time-consuming operation in your webhook handler, return a status and then finish your processing, either in a background process, or after sending the response and closing the socket.
Webhook content
A typical JSON header
{
"header": {
"source": "LearnUpon",
"version": 1,
"signature": "6d8275f37584e888167c40e100abffcd",
"webhookId": 1234,
"attempt": 1,
"lastAttemptAt": "2012-12-18T15:30:09Z",
"webHookType": "course_completion"
},
"user": {
"userId": 12,
"lastName": "Doe",
"firstName": "John",
"email": "john.doe@somewhere.com",
"username": "john.doe",
"customData": {
"customerId": 124124
}
}
}
HTTP headers
Each webhook contains custom HTTP headers.
Header | Description |
---|---|
X-Powered-By | LearnUpon set for any webhook from LearnUpon |
X-LearnUpon-Version | 1 - or the current version that is associated with the webhook API source |
X-LearnUpon-TimeStamp | Unix Epoch Time when LearnUpon servers generated this webhook |
Webhook header and user attributes
After the HTTP headers, each webhook contains a header
and user
section in the JSON body.
Most of the LearnUpon webhooks describe user actions, like completing a course or earning a badge. Events prompted by changes to courses or learning paths don't include user data.
The
header
section lists metadata such as the webhook version, and webhookId for the hook.The
user
section describes the user/learner who prompted the webhook: for example, a user completing a course, or purchasing a course in the store.
Attribute | Type | Description |
---|---|---|
source | string | All webhooks use a source of LearnUpon . The source provides a neat way for you to filter webhooks on your endpoints, if needed! |
version | integer | The webhook API version for the webhook being received |
webhookId | integer | Unique numeric identifier of this event or webhook |
signature | string | MD5 Hash of the JSON Data you receive (without the signature attribute), with a secret key that is set on your webhook configuration settings. You can use this signature to verify if the data sent has been manipulated or not. This step is optional, but recommended. See Verifying the received Webhook |
attempt | integer | The number of times that LearnUpon attempted to send this webhook |
lastAttemptAt | date/time | The last time that LearnUpon failed to send the webhook to you, in UTC date format. Use this data to determine when an error last occurred, and LearnUpon could not send you the webhook data |
webHookType | string | Indicates the type of webhook that you are receiving. See Webhook types |
userId | integer | Unique numeric identifier for the user, whose action has triggered the webhook |
lastName | string | The last name of the user |
firstName | string | The first name of the user |
string | The email of the user. Email is the unique identifier for the user in LearnUpon, and is a required field to create users (unless you implement usernames as unique identifier, instead of email, in your initial setup) | |
username | string | If you implement usernames (in place of email) in your portals, this node appears in data. It is the username implemented for logins and user "lookups" in the API |
customData | object | Any custom user data fields that you create on your portals for a user. For example, if you use a custom data field called Customer ID it appears in this data payload section |
Course Clone Completion
Sample course cloning completion webhook
{
"header": {
"source": "LearnUpon",
"version": 1,
"webhookId": 178134,
"attempt": 2,
"lastAttemptAt": "2022-03-07T18:36:02Z",
"webHookType": "course_cloning_complete",
"signature": "6d8275f37584e888167c40e100abffcd"
},
"clonedFromPortalId": 2000,
"clonedToPortalId": 15001,
"newCourseId": 126002,
"originalCourseId": 126000,
"ownerId": 1341
}
The course clone completion hook is a JSON payload sent to your designated URL end point whenever LearnUpon successfully clones, aka makes a copy of, a course, from either the user interface or by using the API.
Course clone completion attributes
Attribute | Type | Description |
---|---|---|
clonedFromPortalId | integer | Source portal of the original course |
clonedToPortalId | integer | Destination portal for the new cloned course |
originalCourseId | integer | The course id for the original course |
newCourseId | integer | The course id for the newly cloned course |
ownerId | integer | Unique identifier of the course owner |
Course Completion
Sample course completion webhook
{
"header": {
"source": "LearnUpon",
"version": 1,
"signature": "6d8275f37584e888167c40e100abffcd",
"webhookId": 1234,
"attempt": 1,
"lastAttemptAt": "2012-12-18T15:30:09Z",
"webHookType": "course_completion"
},
"user": {
"userId": 12,
"lastName": "Doe",
"firstName": "John",
"email": "john.doe@somewhere.com",
"username": "john.doe",
"customData": {
"customerId": 124124
}
},
"enrollmentId": 12345,
"courseId": 12345,
"courseName": "Webhooks 101",
"courseReferenceCode": "XYZ123",
"modules": [{
"id": 12345,
"name": "Pre Test",
"type": "exam",
"status": "passed",
"percentage": 95
}],
"credits": [{
"name": "cpd",
"number": "11.0"
},{
"name": "cme",
"number": "0.0"
}],
"certification": true,
"certificationName": "Webhook Certification 2015",
"certExpiresAt": "2013-12-18T15:30:09Z",
"wasRecertified": false,
"courseAccessExpiresAt": null,
"dateEnrolled": "2012-12-16T15:30:09Z",
"dateStarted": "2012-12-17T15:30:09Z",
"dateCompleted": "2012-12-18T15:30:09Z",
"enrollmentStatus": "passed",
"percentage": 95,
"hasAttemptsRemaining": false,
"manuallyMarkedComplete": true,
"manuallyMarkedCompleteById": 11
}
The course completion hook is a JSON payload of completion data sent to your designated URL end point, every time a learner completes a course.
This webhook's details about modules are different from the module completion webhook. See Module Completion.
Course completion user attributes
Attribute | Type | Description |
---|---|---|
enrollmentId | integer | Unique numeric identifier for the enrollment |
courseId | integer | Unique numeric identifier for the course |
courseName | string | The title of the course |
courseReferenceCode | string | If you enable course reference codes on your portal, this field contains the references and data from that attribute |
certification | boolean | Indicates if the learner achieved a certificate or not by completing this course |
certificationName | string | The name of the certificate awarded, if any |
certExpiresAt | string | Set to a date (UTC) when the learner's certificate will expire: null indicates no expiry |
wasRecertified | boolean | If you have set up recertification policies on your course certificate, and the user was awarded a certificate, this value is set to true when the user was automatically recertified by LearnUpon on the course |
courseAccessExpiresAt | string | The date (UTC) that the learner's access to this course expires, if set |
dateEnrolled | string | The date (UTC) that the learner enrolled on the course |
dateStarted | string | The date and time (UTC) that the learner started the course |
dateCompleted | string | The date and time (UTC) that the learner completed the course |
enrollmentStatus | string | Indicates the status of the learner on the course having completed it: values are completed , passed or failed |
percentage | integer | The percentage scored for the learner on the course: this value is the learner's average score across all modules with scores in the course. |
hasAttemptsRemaining | boolean | Indicates if the learner has more attempts on the course: this value appears if a learner reaches a failed status, but they have an exam that allows them to re-attempt the course |
manuallyMarkedComplete | boolean | Indicates if the completion was marked complete manually by an authorized user |
manuallyMarkedCompleteById | integer | Unique numeric identifier of the person who manually marked the learner as complete |
courseMetaData | array | Contains custom course data values for courses. Contents returned depend on what custom course data is set up in the portal |
credits | array | If you issue credits for your course, the credits appear here in a listed/embedded object |
modules | array | The list of modules and related statuses in the course: for each module in your course, you get a status, a date the status was set, and scores where relevant |
Credits data attributes
attribute | type | description |
---|---|---|
name | string | The name of the credit that was awarded, like "CPD" |
number | float | The number of credits that were awarded to the learner by completing the course, like 5.0 |
Module object attributes
attribute | type | description |
---|---|---|
id | integer | Unique id of the module in LearnUpon |
type | string | The type of the module: values include page , exam , scorm , tincan , assignment , ilt , survey , checklist |
name | string | The name of the module in LearnUpon |
status | string | The status of the module at the time the learner completed the course, with one of the following statuses: not_started , in_progress , completed , passed , failed , pending_review , attended , no_show , cancelled |
percentage | float | The score that the learner achieved, if the module included a test, such as an exam or assignment. Normally an integer, but can be a float in some particular modules (e.g. SCORM Module) |
dateCompleted | string | Date/time in UTC format when the user completed this module |
attempts | integer | The number of attempts by the learner, on the module, assuming this module is exam-based |
isKnowledgeCheck | boolean | If the module is an exam, indicates if the exam was a knowledge test only (true ) or formal exam (false ) |
Course Update
Sample course update webhook
{
"header": {
"source": "LearnUpon",
"version": 1,
"webhookId": 16011,
"attempt": 2,
"lastAttemptAt": "2020-02-26T14:52:29Z",
"webHookType": "course_updated",
"signature": "453ace7ececfcbaa5647fc20d0e279a6"
},
"courseId": 14874,
"courseName": "Health and Safety 101",
"courseReferenceCode": "HS101",
"courseKeywords": "health and safety, health, safety",
"courseShortDescription": "Occupational safety and health (OSH), also commonly referred to as occupational health and safety (OHS), occupational health, or workplace health and safety (WHS), is a multidisciplinary field concerned with the safety, health, and welfare of people at work. These terms also refer to the goals of this field, so their use in the sense of this article was originally an abbreviation of occupational safety and health program/department etc.\n\nThe goals of occupational safety and health programs include to foster a safe and healthy work environment. OSH may also protect co-workers, family members, employers, customers, and many others who might be affected by the workplace environment.",
"datePublished": "2019-06-17T16:31:56Z",
"courseVersion": 1,
"courseSourceId": 14874,
"courseStatus": "Published",
"cataloged": true,
"thumbnailImageUrl": "https://s3.eu-west-1.amazonaws.com/learnupondev/courseimages/1293/large/pixel77-free-vector-medical-logo-0512-400.jpg",
"difficulty": "Basic",
"courseLength": 30,
"courseLengthUnit": "Minutes",
"modules": [
{
"id": 17925,
"type": "Module",
"name": "Health and Safety Video Tutorial",
"isKnowledgeCheck": false
},
{
"id": 17926,
"type": "Exam",
"name": "Health and Safety Knowledge Check",
"isKnowledgeCheck": true
}
],
"courseIsSellable": true,
"price": 0,
"membershipPricing": [
{
"name": "memberPrice",
"price": 40
},
{
"name": "nonMemberPrice",
"price": 100
}
],
"dueDate": {
"numOfDaysAfterEnrollment": null,
"setDate": null
},
"accessExpires": {
"numOfDaysAfterEnrollment": null,
"setDate": null
},
"certificate": {
"certificateName": "Health and Safety 101",
"certExpiresNumDaysAfterAward": 365,
"autoReenroll": true,
"autoReenrollNumDaysBeforeCertExpires": 300
},
"credits": [
{
"name": "CPE",
"number": "100.0"
}
],
"badges": [
{
"name": "Gold Course Completion",
"number": 2,
"points": 80,
"achieved": "On course completion"
},
{
"name": "Strong Skills",
"number": 2,
"points": 80,
"achieved": "On course completion"
}
]
}
The course update webhook is a JSON payload of course change data sent to your designated URL end point, every time an admin, manager or instructor updates a course.
Courses must have a status of published, under revision, archived or deleted to trigger a webhook. Creating and editing a draft course does not prompt a webhook.
For a deleted course status, LearnUpon sends a webhook noting the deletion, and won't send further webhooks for that course.
Once published, any change to the course attributes listed triggers a webhook. Webhooks are designed to send after 1 minute. So multiple updates you make in 1 minute can appear within a single webhook, and it contains the most up to date information available.
For custom course data, creating or deleting a new custom course data field doesn't trigger a webhook. You need to add new data to the field to prompt the webhook.
Course Update does not pass any user information: course information only.
Course update attributes
Attribute | Type | Description |
---|---|---|
courseId | integer | Unique identifier numeric for the course |
courseName | string | The title of the course |
courseReferenceCode | string | If you have course reference codes enabled on your portal, this attribute contains the references and data from that attribute |
courseKeywords | string | If you have keywords added to your course, they appear here |
courseShortDescription | string | The short description, which appears on the My Courses page or the catalog |
datePublished | string | The date that the course was first published, in UTC format |
courseVersion | integer | The version of the course |
courseSourceId | integer | This is the source course_id for each version of a course. For example: for 3 courses, A, B, C (versions 1, 2, 3 respectively) each of these courses use the same courseSourceId value, the id of the first course. This attribute lets you group together courses that stem from the same root course, in their version tree |
courseStatus | string | The status of the course at the time LearnUpon sends the webhook, for courses with a status of Published , Under Revision , Archived or Deleted |
thumbnailImageUrl | string | The main thumbnail image URL for the course |
catalogued | boolean | Indicates if the course is available in the catalogue (true ). Default value is false |
modules | array | The list of modules and module types in the course |
courseIsSellable | boolean | Notes if the course is available on the storefront. Default value is false , for not sellable |
price | integer | The price of the course |
membershipPricing | array | If you use associations in your portal, the pricing for each type of member is in a listed/embedded object |
dueDate | object | The course due date, or set number of days to complete the course after an enrollment for a learner |
accessExpires | object | The course expiry date, or set number of days before an enrollment expires after an enrollment for a learner |
difficulty | string | Indicates the difficulty level on your course |
courseLength | integer | The course length if specified |
courseLengthUnit | string | Indicates the length unit for your course, hours or minutes |
certificate | object | If learners can get a certificate on this course, this attribute contains the information |
credits | array | If you issue credits for your course, the credits appear here in a listed/embedded object |
badges | array | Describes the badges learners can receive, in a listed/embedded object |
courseMetaData | array | Contains custom course data values for courses. Contents returned depend on what custom course data you set up in the portal |
dueDate object attributes
Attribute | Type | Description |
---|---|---|
numOfDaysAfterEnrollment | integer | The number of days after enrollment on this course, for completing the course |
setDate | string | The date/time when this course is due for completion in UTC format |
accessExpires object attributes
Attribute | Type | Description |
---|---|---|
numOfDaysAfterEnrollment | integer | The number of days learners can access this course before it expires |
setDate | string | The set expiry date for this course in UTC format. If set, learners cannot access after this date |
certificate object attributes
Attribute | Type | Description |
---|---|---|
certificateName | string | The name of the certificate awarded to a learner, on successful completion of the course |
certExpiresNumDaysAfterAward | integer | The set number of days before a certificate expires after awarding |
autoReenroll | boolean | |
autoReenrollNumDaysBeforeCertExpires | integer | If the learner is expected to renew their certificate before it expires, this attribute lists the number of days before the expiry, to auto re-enroll the learner |
modules array attributes
Attribute | Type | Description |
---|---|---|
id | integer | Unique id of the module in LearnUpon |
type | string | The type of the module: values include page , exam , scorm , tincan , assignment , ILT Session , survey , checklist , training |
name | string | The name of the module in LearnUpon |
isKnowledgeCheck | boolean | If the module is an exam, indicates if the exam was a knowledge test only (true ) or formal exam (false ) |
startAt | string | ILT modules only: start date and time that the ILT session is scheduled, in UTC format |
endAt | string | ILT modules only: end date and time that the ILT is scheduled to complete, in UTC format |
maxCapacity | integer | ILT modules only: the maximum number of learners allowed to attend the ILT session |
membershipPricing array attributes
Attribute | Type | Description |
---|---|---|
name | string | The name provided as the membership type in your portal |
price | integer | The course price for the specific membership type |
credits array attributes
Attribute | Type | Description |
---|---|---|
name | string | The name of the credit that was awarded, like "CPD" |
number | float | The number of credits that were awarded to the learner by completing the course, like 5.0 |
badges array attributes
Attribute | Type | Description |
---|---|---|
name | string | The name of the badge |
type | string | The type of badge |
points | integer | The number of points awarded |
achieved | string | Notes when learner will receive the badge: for example, on completion of the course |
Module Complete
Sample module completion webhook
{
"header" : {
"webhookId" : 1721016,
"lastAttemptAt" : "2022-12-13T16:34:16Z",
"signature" : "no_secret_key_set",
"source" : "LearnUpon",
"webHookType" : "module_complete",
"attempt" : 1,
"version" : 1
},
"courseId" : 925689,
"enrollmentId" : 15977495,
"sequence" : 1,
"dateStarted" : "2022-12-13 16:28:34 UTC",
"userId" : 291235,
"moduleId" : 747130,
"percentage" : 100,
"portalId" : 123456,
"type" : "scorm",
"markedComplete" : false,
"additionalData" : null,
"dateCompleted" : "2022-12-13 16:34:16 UTC",
"status" : "passed"
}
The module complete hook is a JSON payload of completion data sent to your designated URL end point, every time a learner completes a module.
This webhook is different from the course completion webhook, that contains module data. See Course Completion.
For exam and survey modules, LearnUpon sends both the exam_completion
or survey_completion
*and the module_complete
webhook.
This webhook handles ILT Center training differently from legacy ILT modules:
- ILT Center training sessions are "conditional scorable" and can generate a
failed
status - legacy ILT modules never generate a
failed
status
Module completion attributes
Attribute | Type | Description |
---|---|---|
portalId | integer | Unique numeric identifier for your portal |
enrollmentId | integer | Unique numeric identifier for the enrollment |
courseId | integer | Unique numeric identifier for the course |
moduleId | integer | Unique numeric identifier for the module the learner completed |
sequence | integer | Describes the order that the modules appear in the course |
dateStarted | string | The date and time (UTC) that the learner started the module |
dateCompleted | string | The date and time (UTC) that the learner completed the module |
markedComplete | boolean | Indicates if the completion was marked complete manually by an authorized user. Default is false |
type | string | Type of module the learner completed: one of page , exam , scorm , tincan , assignment , ILT Session , survey , checklist , training |
status | string | Indicates the status of the learner on the module having completed it: values are completed , failed , or pending_review |
percentage | integer | The percentage of the module completed |
additionalData | Object | Null : reserved for future development |
Exam Submitted
Sample exam submitted webhook
{
"header": {
"source": "LearnUpon",
"version": 1,
"signature": "6d8275f37584e888167c40e100abffcd",
"webhookId": 1234,
"attempt": 1,
"lastAttemptAt": "2012-12-18T15:30:09Z",
"webHookType": "exam_completion"
},
"user": {
"userId": 12,
"lastName": "Doe",
"firstName": "John",
"email": "john.doe@somewhere.com",
"username": "john.doe",
"customData": {
"customerId": 124124
}
},
"enrollmentId": 12345,
"courseId": 12345,
"courseName": "Webhooks 101",
"courseReferenceCode": "XYZ123",
"examId": 12345,
"examName": "Pre Test",
"isKnowledgeTest": false,
"status": "passed",
"percentage": 95,
"dateCompleted": "2012-12-18T15:30:09Z",
"attemptsTaken": 2,
"attemptsAllowed": null,
"unlimitedAttemptsAllowed": true,
"timedExam": true,
"timeAllowed": 60,
"timeTaken": 867.03,
"wasAutoSubmitted": false,
"passMark": null,
"passPercentage": 90
}
The exam submitted hook is a JSON payload of exam submitted details. Submitting an exam indicates that a learner completed an exam.
Exam user attributes
attribute | type | description |
---|---|---|
enrollmentId | integer | Unique id of the enrollment in LearnUpon |
courseId | integer | Unique id of the course in LearnUpon |
courseName | string | The title of the course |
courseReferenceCode | string | If you enable course reference codes on your portal, this field contains the references and data from that attribute |
examId | integer | Unique numeric identifier of the exam in LearnUpon |
examName | string | The name of the exam in LearnUpon |
isKnowledgeTest | boolean | Indicates if the exam is a knowledge test (true ) only or formal exam (false ) |
status | string | The status of the user on the exam, passed or failed |
percentage | integer | The score that the learner achieved on on the exam |
dateCompleted | string | Date and time when the user completed this exam, in UTC format |
attemptsTaken | integer | The number of attempts on this exam by the learner so far |
attemptsAllowed | integer | The number of attempts permitted, assuming attempts are limited (see unlimitedAttemptsAllowed attribute) |
unlimitedAttemptsAllowed | boolean | Set to true if the exam has unlimited attempts permitted: otherwise false . When set, this attribute overrides attemptsAllowed |
timedExam | boolean | Set to true when the exam is a timed exam |
timeAllowed | integer | The number of minutes allocated to complete the exam |
timeTaken | float | The number of seconds taken by the learner to complete the exam |
wasAutoSubmitted | boolean | Set to true if LearnUpon automatically submitted the exam, when the allocated time (timeAllowed) elapsed in full |
passMark | integer | The number of correct answers required to pass the exam, if you do not use passPercentage attribute |
passPercentage | integer | The passing percentage required for this exam. When set, this value overrides passMark |
Survey submitted
Sample survey submitted webhook
{
"header": {
"source": "LearnUpon",
"version": 1,
"signature": "6d8275f37584e888167c40e100abffcd",
"webhookId": 1234,
"attempt": 1,
"lastAttemptAt": "2012-12-18T15:30:09Z",
"webHookType": "survey_completion"
},
"user": {
"userId": 12,
"lastName": "Doe",
"firstName": "John",
"email": "john.doe@somewhere.com",
"username": "john.doe",
"customData": {
"customerId": 124124
}
},
"enrollmentId": 12345,
"courseId": 12345,
"courseName": "Webhooks 101",
"courseReferenceCode": "XYZ123",
"surveyId": 123456,
"surveyName": "Pre Test",
"dateCompleted": "2012-12-18T15:30:09Z"
}
The survey submitted hook is a JSON payload of survey submitted details sent to your designated URL end point. Submitting a survey indicates that a learner completed a survey, within one of their courses.
Survey submitted attributes
Attribute | Type | Description |
---|---|---|
enrollmentId | integer | Unique numeric identifier of the enrollment |
courseId | integer | Unique numeric identifier of the course |
courseName | string | The title of the course |
courseReferenceCode | string | If you enable course reference codes on your portal, this field contains the references and data from that attribute |
surveyId | integer | Unique numeric identifier of the survey |
surveyName | string | The name of the survey |
dateCompleted | string | Date and time UTC when the user completed this survey |
Learning Path update
Sample learning path update webhook
{
"header": {
"source": "LearnUpon",
"attempt": 1,
"webHookType": "learning_path_updated",
"signature": "453ace7ececfcbaa5647fc20d0e279a6",
"version": 1,
"lastAttemptAt": "2021-06-28T09:21:13Z",
"webhookId": 249609
},
"learningPathId": 13550,
"learningPathName": "Growing a positive company culture",
"learningPathKeywords": "culture, growth, inclusion, business, company",
"learningPathShortDescription": "In this learning path, we have organized a host of courses which best showcase growing a positive company culture.",
"learningPathStatus": "Published",
"cataloged": true,
"learningPathLength": 45,
"learningPathLengthUnit": "Minutes",
"thumbnailImageUrl": "https://s3.eu-west-1.amazonaws.com/learnupon/lpimages/16597/large/teams.jpeg",
"difficulty": "Not Applicable"
}
The learning path update webhook is a JSON payload of learning path data sent to your designated URL end point, every time an admin, manager or instructor updates a learning path. This webhook helps you keep up to date of changes to learning paths.
You need to turn on learning paths in your portal, and create and publish a learning path with courses before any learning path updates appear as webhooks.
See Learning paths: create a path, add courses, set progression and publish in the LearnUpon Knowledge Base.
Learning paths must have a status of published, archived or deleted to trigger a webhook. Creating and editing a draft learning path does not prompt a webhook.
For a deleted learning path status, LearnUpon sends a webhook noting the deletion, and won't send further webhooks for that learning path.
Once published, any change to the learning path attributes listed triggers a webhook. Webhooks are designed to send after 1 minute. So multiple updates you make in 1 minute can appear within a single webhook, and it contains the most up to date information available.
Like the Course Update webhook, Learning Path Update does not pass any user information: learning path information only.
Learning path update attributes
Attribute | Type | Description |
---|---|---|
learningPathId | integer | Unique numeric identifier for the learning path |
learningPathName | string | The title of the learning path |
learningPathKeywords | string | If you have keywords added to your learning path, they appear here |
learningPathShortDescription | string | The short description, which appears on the My Courses page or the catalog |
datePublished | string | The date that the course was first published, in UTC format |
learningPathStatus | string | The status of the learning path at the time LearnUpon sends the webhook, for learning paths with a status of Published , Archived or Deleted |
thumbnailImageUrl | string | The main thumbnail image URL for the learning path |
catalogued | boolean | Indicates if the learning path is available in the catalog (true ). Default value is false |
difficulty | string | Indicates the difficulty level on your learning path |
learningPathLength | integer | The learning path length if specified |
learningPathLengthUnit | string | Indicates the length unit for your course, hours or minutes |
Learning Path completions
Sample learning path completion webhook
{
"header": {
"source": "LearnUpon",
"version": 1,
"signature": "6d8275f37584e888167c40e100abffcd",
"webhookId": 1234,
"attempt": 1,
"lastAttemptAt": "2012-12-18T15:30:09Z",
"webHookType": "learning_path_completion"
},
"user": {
"userId": 12,
"lastName": "Doe",
"firstName": "John",
"email": "john.doe@somewhere.com",
"username": "john.doe",
"customData": {
"customerId": 124124
}
},
"learningPathUserId": 12345,
"learningPathId": 12345,
"learningPathName": "Webhooks 101",
"courses": [{
"id": 12345,
"name": "Pre Test",
"status": "passed",
"percentage": 95
}],
"credits": [{
"name": "cpd",
"number": "11.0"
},{
"name": "cme",
"number": "0.0"
}
],
"certification": true,
"certificationName": "Webhook Certification 2015",
"certExpiresAt": "2013-12-18T15:30:09Z",
"wasRecertified": false,
"dateEnrolled": "2012-12-16T15:30:09Z",
"dateStarted": "2012-12-17T15:30:09Z",
"dateCompleted": "2012-12-18T15:30:09Z",
"percentage": 95,
"numberCompletedCourses": 1
}
The path completion hook is a JSON payload of completion data sent to your designated URL end point, every time a learner completes a Learning Path.
Learning Path completed user attributes
attribute | type | description |
---|---|---|
learningPathUserId | integer | Unique id of the learning path enrollment for the user in LearnUpon |
learningPathId | integer | Unique id of the path in LearnUpon |
learningPathName | string | The title of the path |
certification | boolean | Indicates if the learner achieved a certificate or not by completing this path |
certificationName | string | The name of the certificate awarded, if any |
certExpiresAt | string | Set to a date (UTC) when the learner's certificate will expire: null indicates no expiry |
wasRecertified | boolean | If you have recertification policies set up on your path certificate, and the user was awarded a certificate, this value is set to true if the user was automatically recertified by LearnUpon on the path. |
dateEnrolled | string | The date (UTC) that the learner was enrolled on the path |
dateStarted | string | The date and time (UTC) that the learner started the path |
dateCompleted | string | The date and time (UTC) that the learner completed the path |
percentage | integer | The percentage scored for the learner on the path: the average score across all scorable courses which the learner completes in the path |
numberCompletedCourses | integer | The number of courses the learner completes on this path |
credits | array | If you issue credits for your path, the credits appear here in a listed/embedded object |
courses | array | The list of courses and related statuses in the course: for each course in your path, you get a status, date of status, scores where relevant |
Path credits data attributes
attribute | type | description |
---|---|---|
name | string | The name of the credit that was awarded, like "CPD" |
number | float | The number of credits that were awarded to the learner by completing the path, like 5.0 |
Course object attributes
attribute | type | description |
---|---|---|
id | integer | Unique id of the course in LearnUpon |
name | string | The name of the course in LearnUpon |
status | string | The status of the course at the time the learner completed the path, with one of the following statuses: not_started , in_progress , completed , passed , failed , pending_review |
percentage | integer | The average score that the learner achieved on this course, if the course contained scoring modules |
dateCompleted | string | Date and time UTC when the user completed this course |
Purchase completion
Sample purchase completion webhook (bulk purchase)
{
"header": {
"source": "LearnUpon",
"version": 1,
"signature": "6d8275f37584e888167c40e100abffcd",
"webhookId": 1234,
"attempt": 1,
"lastAttemptAt": "2012-12-18T15:30:09Z",
"webHookType": "purchase_completion"
},
"user": {
"userId": 12,
"lastName": "Doe",
"firstName": "John",
"email": "john.doe@somewhere.com",
"username": "john.doe",
"customData": {
"customerId": 124124
}
},
"orderId": 1234,
"currency": "usd",
"country": "United States",
"state": "California",
"paymentGateway": "stripe",
"paymentId": "jh_CHRHKeugje",
"discount": null,
"coupon": null,
"dateCompleted": "2012-12-18T15:30:09Z",
"bulkCodes": "JGUHT353, JFHHHGYEHEH, JHJGHEF78",
"orderTotal": 33.00,
"amountPaid": 33.00,
"orderDiscount": 1.00,
"salesTaxAmount": 1.00,
"lineItems": [{
"lineItemId": 1353,
"name": "JSON For Developers",
"courseReferenceCode": "json_123",
"type": "course",
"listPrice": 11.00,
"discount": 1.00,
"coupon": "LEARNUPONJSON",
"salesTaxRate": 10,
"salesTaxAmount": 1.00,
"taxRateLocation": "store",
"amountPaid": 11.00,
"quantity": 1
}]
}
If you enable LearnUpon’s eCommerce module, you can listen for purchase completion actions happening on your storefront. LearnUpon sends a webhook for every successful sale on your store, including the customer details, the courses/paths/bundles purchased and any taxes, discounts and pricing applied for the sale.
Purchase completion user attributes
Attribute | Type | Description |
---|---|---|
orderId | integer | Unique numeric identifier of the order or cart in LearnUpon. |
currency | string | The currency code for this purchase: options are usd , eur , gbp , cad , aud , nzd |
country | string | The country the customer selected while purchasing |
state | string | The state, if applicable, that the customer selected while purchasing |
paymentGateway | string | The gateway that the customer used in this purchase, assuming it was not a free purchase: options are paypal , stripe , or shopify |
paymentId | string | Unique Payment ID for the purchase: the PayPal, Stripe, or Shopify payment ID/token. If the purchase is a free purchase and no gateway is involved, then this value is LearnUpon's own internal ID for free purchases |
coupon | string | The coupon code used if there was a discount applied and it was a cart wide coupon |
dateCompleted | string | The date and time (UTC) that the customer completed the purchase |
bulkCodes | string | List of Bulk Purchase codes associated with the purchase, if applicable. Learners can use these codes to redeem a purchase in the case of bulk or purchasing on behalf of other users |
orderTotal | float | The total cost of the order, without discounts applied or taxes |
amountPaid | float | The actual total amount paid by the customer, including discounts applied and taxes |
orderDiscount | float | The discount applied to the order if any, by way of a coupon |
salesTaxAmount | float | The amount of sales tax applied on the purchase if any |
lineItems | array | The list of items the customer bought: courses, learning paths and/or bundles |
Order line items data attributes
Attribute | Type | Description |
---|---|---|
lineItemId | integer | Unique numeric identifier of the item sold in LearnUpon, for a Course, Learning Path or a Bundle |
name | string | The name of the item purchased in LearnUpon |
courseReferenceCode | string | If you enable course reference codes on your portal, this field contains the references and data from that attribute |
type | string | Indicates the type of the item purchased: course , path or bundle |
listPrice | float | The list price of the course in the store, without discounts or coupons applied |
discount | float | Discount applied to the line_item , if any |
coupon | string | The coupon code used, if there was a discount applied |
salesTaxRate | float | The sales tax rate applied to the line item |
salesTaxAmount | float | The amount of sales tax applied if any to this line_item : applies to all purchases where sales tax is applicable. |
taxRateLocation | string | Indicates if the tax paid was the store tax rate, or the local tax rate of the purchase. The local tax rate applies only for EU based sales. Options are store or local |
amountPaid | float | The cost of this line_item in relation to the overall cart, including discounts removed |
quantity | integer | The number or quantity of this item purchased: invariably this is just 1 but can be more for a bulk purchase. |
Badge Awarded
Sample badge awarded webhook
{
"header" : {
"source" : "LearnUpon",
"version" : 1,
"webhookId" : 10033043,
"attempt" : 2,
"lastAttemptAt" : "2019-12-16T22:24:20Z",
"webHookType" : "badge_awarded",
"signature" : "5819cb303fd80d4f3d1d6a6ea7608b68"
},
"user" : {
"id" : 6138780,
"lastName" : "test1",
"firstName" : "test1",
"email" : "test1@luptest.com",
"username" : null,
"numberOfPoints" : 25,
"numberOfBadges" : 3
},
"badge" : {
"id" : 104597
"points" : 0,
"name" : "Level 1 novice badge",
},
"awardedBy" : {
"gamificationLevel" : {
"id" : 29011,
"achievedOverOrEqual" : 0,
"name" : "Level 1"
}
}
}
If you enable the LearnUpon's gamification module, then you can listen for badge-related actions. When learners complete actions (typically completing a course) which trigger awarding a badge, LearnUpon sends a JSON payload with user details.
Badge Awarded user attributes
Attribute | Type | Description |
---|---|---|
awardedBy | object | Describes the gamification system linked to the action: in this example, taking a course |
badge | object | Describes the badge awarded to the user |
awardedBy attributes
Attribute | Type | Description |
---|---|---|
gamificationLevel | object | Details about the gamification level achieved by the learner |
order | object | Attributes for the purchase order in the online store |
learningResource | object | Details about the learning resource used by the learner |
course | object | Details about the course the learner is taking |
learningPath | object | Details about the learning path linked to the gamification |
externalTrainingRecord | object | Details about the user's external training record |
GamificationLevel attributes
Attribute | Type | Description |
---|---|---|
id | integer | Unique numeric identifier of the gamification level |
achievedOverOrEqual | integer | Indicates how many points required to achieve this level |
name | string | Name of the level the user has achieved: for example, Level 1, 2, 3 |
Order attributes
Attribute | Type | Description |
---|---|---|
id | integer | Unique numeric identifier of the purchase order in the online store |
LearningResource attributes
Attribute | Type | Description |
---|---|---|
id | integer | Unique numeric identifier of the learning resource |
title | string | Title of the learning resource |
Course attributes
Attribute | Type | Description |
---|---|---|
id | integer | Unique numeric identifier of the course |
name | string | Course name |
LearningPath attributes
Attribute | Type | Description |
---|---|---|
id | integer | Unique numeric identifier of the learning path |
name | string | Learning path name |
ExternalTrainingRecord attributes
Attribute | Type | Description |
---|---|---|
id | integer | Unique numeric identifier of the external training record |
activity | string | Name of the external training activity |
Badge attributes
Attribute | Type | Description |
---|---|---|
points | integer | Number of points associated with this badge |
name | string | Name of the badge the user has achieved: for example, Level 1 novice badge , Level 2 beginner badge , |
id | integer | Unique numeric identifier associated of the badge awarded to this user |
Badge Revoked
Sample badge revoked webhook
{
"header" : {
"source" : "LearnUpon",
"version" : 1,
"webhookId" : 10033124,
"attempt" : 2,
"lastAttemptAt" : "2019-12-16T22:32:13Z",
"webHookType" : "badge_revoked",
"signature" : "b1acfe18b94803bb06c6a8e62140723b"
},
"user" : {
"id" : 6138780,
"lastName" : "test1",
"firstName" : "test1",
"email" : "test1@luptest.com",
"username" : null,
"numberOfPoints" : 5,
"numberOfBadges" : 2
},
"badge" : {
"id" : 104601,
"name" : "Bronze Course Completion",
"points" : 20
}
}
If you enable the gamification module, LearnUpon sends the Badge Revoked webhook when a portal admin revokes (deletes) a badge from the list of badges a learner has received.
Badge Revoked user attributes
Attribute | Type | Description |
---|---|---|
badge | object | List of attributes which describe the badge revoked from the user |
Badge attributes
Attribute | Type | Description |
---|---|---|
points | integer | Number of points associated with this badge |
name | string | Name of the badge the user has achieved: for example, Level 1 novice badge , Level 2 beginner badge , |
id | integer | Unique numeric identifier associated of the badge awarded to this user |
Setup tips
Each webhook has an ID associated with it (header.webhookId). This ID helps you ensure that your store successfully processed webhooks in your application, and you can block repeat posts of the same ID to your application. This ID can help you prevent replay attacks on your servers.
To verify that the JSON payload sent to you is not manipulated externally, verify the signatures that LearnUpon sends in the header. This check demonstrates that no tampering happened to the data in transit.
Each webhook event has a header section, containing user information, and webhook attempts information. You can use this information to track errors in your own service. For example if the number of attempts was 4 and the
last_attempt_at
is set, that indicates that a problem occurred when LearnUpon last tried to send you this webhook. You can get specific error messages from the Settings >> Webhook Configuration panel of your LearnUpon portal: search using a specific webhook ID or user, or filter by those webhooks that have errors.LearnUpon supports sending of data over non-SSL Connections, but recommends that your listening agent looks for webhooks on an SSL connection.