Event Types

  • course.completed - Triggered when a learner completes a course.

  • course.submitted - Triggered when an author submits a course to be reviewed by an admin for publication.

  • enrollments.created - Triggered when users or groups are enrolled in either a course or learning path.

  • user.created - Triggered when a user is added to your Rise account.

Webhook Event Payload

Each webhook request's payload has a common structure shared by all webhook events. The body of the request contains the following properties:

  • id (string) - the unique identifier of the event

  • createdAt (string) - the time at which the event happened

  • type (string) - the webhook event type

  • webhookId (string) - the id of the webhook which resulted in the event being sent

  • apiVersion (string) - Rise API Version used when sending the webhook event. Will also be sent as a Rise-API-Version header in the request

  • data (object) - specific to the type of webhook event type (see examples)

Request Payload Examples

Each webhook event example below shows an example of what a webhook request to the target URL on your server would look like.

course.completed

Triggered when a learner completes a course.

{ 
"id": "example-course-completed-event-id",
"createdAt": "2020-07-02T03:39:18.991Z",
"type": "course.completed",
"webhookId": "example-webhook-id",
"apiVersion": "2020-07-16",
"data": {
"course": {
"authorUrl": "https://api.rise.com/users/example-author-id",
"coverImageUrl": null,
"id": "example-course-id",
"courseReportUrl": "https://api.rise.com/reports/courses/example-course-id",
"title": "Example Course",
"url": "https://api.rise.com/courses/example-course-id"
},
"user": {
"email": "foo@example.com",
"firstName": "Example First Name",
"groupsUrl": "https://api.rise.com/users/example-user-id/groups",
"id": "example-user-id",
"lastName": "Example Last Name",
"learnerReportUrl": "https://api.rise.com/reports/learners/example-user-id",
"role": "learner",
"url": "https://api.rise.com/users/example-user-id"
}
}
}

course.submitted

Triggered when an author submits a course to be reviewed by an admin for publication.

{ 
"id": "example-course-submitted-event-id",
"createdAt": "2020-09-14T05:47:28.951Z",
"type": "course.submitted",
"webhookId": "example-webhook-id",
"apiVersion": "2020-07-16",
"data": {
"isInitialSubmission": true,
"course": {
"authorUrl": "https://api.rise.com/users/example-author-id",
"coverImageUrl": null,
"id": "example-course-id",
"courseReportUrl": "https://api.rise.com/reports/courses/example-course-id",
"title": "Example Course",
"url": "https://api.rise.com/courses/example-course-id"
},
"submitter": {
"email": "author@example.com",
"firstName": "Example",
"groupsUrl": "https://api.rise.com/users/example-author-id/groups",
"id": "example-author-id",
"lastName": "Author",
"learnerReportUrl": "https://api.rise.com/reports/learners/example-author-id",
"role": "author",
"url": "https://api.rise.com/users/example-author-id"
},
"reviewer": {
"email": "admin@example.com",
"firstName": "Example",
"groupsUrl": "https://api.rise.com/users/example-admin-id/groups",
"id": "example-admin-id",
"lastName": "Admin",
"learnerReportUrl": "https://api.rise.com/reports/learners/example-admin-id",
"role": "admin",
"url": "https://api.rise.com/users/example-admin-id"
}
}
}

enrollments.created

Triggered when users or groups are enrolled in either a course or learning path.

This event's payload always contains the same property names, but which of those properties have values varies depending on the type of enrollments that were created.

For example, if one or more users are enrolled in a course, the data portion of the payload sent to your handler will include a users array property (an array of User Objects) and a course property. In this scenario the groups property will be an empty array and learningPath will be set to null.

Similarly, if one or more groups are enrolled in a learning path, the data object will have a groups array property (an array of Group Objects) and a learningPath property, while users will be an empty array and course will be null.

Event payload data properties:

  • course (object) - the Course Object for the related course or null if the enrollments are for a learning path.

  • learningPath (object) - the Learning Path Object for the related learning path or null if the enrollments are for a course.

  • enrolledBy (object) - The User Object of the user that created the enrollments or null if the enrollment was created through the Course Enrollments API or Learning Path Enrollments API.

  • groups (list of objects) - A list of Group Objects that were enrolled (may be empty).

  • users (list of objects) - A list of User Objects that were enrolled (may be empty).

{ 
"id": "example-enrollments-created-event-id",
"type": "enrollments.created",
"createdAt": "2020-09-16T19:59:55.912Z",
"data": {
"course": {
"authorUrl": "https://api.rise.com/users/example-author-id",
"coverImageUrl": null,
"id": "example-course-id",
"courseReportUrl": "https://api.rise.com/reports/courses/example-course-id",
"title": "Example Course",
"url": "https://api.rise.com/courses/example-course-id"
},
"enrolledBy": {
"email": "admin@example.com",
"firstName": "Example",
"groupsUrl": "https://api.rise.com/users/example-admin-id/groups",
"id": "example-admin-id",
"lastName": "Admin",
"learnerReportUrl": "https://api.rise.com/reports/learners/example-admin-id",
"role": "admin",
"url": "https://api.rise.com/users/example-admin-id"
},
"groups": [],
"learningPath": null,
"users": [ {
"email": "learner1@example.com",
"firstName": "Foo",
"groupsUrl": "https://api.rise.com/users/example-learner-1/groups",
"id": "example-learner-1",
"lastName": "Learner",
"learnerReportUrl": "https://api.rise.com/reports/learners/example-learner-1",
"role": "learner",
"url": "https://api.rise.com/users/example-learner-1"
},
{
"email": "learner2@example.com",
"firstName": "Bar",
"groupsUrl": "https://api.rise.com/users/example-learner-2/groups",
"id": "example-learner-2",
"lastName": "Learner",
"learnerReportUrl": "https://api.rise.com/reports/learners/example-learner-2",
"role": "learner",
"url": "https://api.rise.com/users/example-learner-2"
},
{
"email": "learner3@example.com",
"firstName": "Baz",
"groupsUrl": "https://api.rise.com/users/example-learner-3/groups",
"id": "example-learner-3",
"lastName": "Learner",
"learnerReportUrl": "https://api.rise.com/reports/learners/example-learner-3",
"role": "learner",
"url": "https://api.rise.com/users/example-learner-3"
},
]
},
"apiVersion": "2020-07-16",
"webhookId": "example-webhook-id"
}

user.created

Triggered when a user is added to your Rise account.

Note: user.created events will be delayed for SSO users by 5-10 minutes.

Note: user.created events are NOT triggered for SAML users who are removed from your IDP and added again unless they are also removed from your Rise account.

{ 
"id": "example-user-created-event-id",
"createdAt": "2020-08-24T01:36:18.982Z",
"type": "user.created",
"webhookId": "example-webhook-id",
"apiVersion": "2020-07-16",
"data": {
"user": {
"email": "foo@example.com",
"firstName": "Example First Name",
"groupsUrl": "https://api.rise.com/users/example-user-id/groups",
"id": "example-user-id",
"lastName": "Example Last Name",
"learnerReportUrl": "https://api.rise.com/reports/learners/example-user-id",
"role": "learner",
"url": "https://api.rise.com/users/example-user-id"
}
}
}

Verifying Requests

When a webhook is created with a sharedSecret, Rise will include an X-Hook-Signature header in each request, allowing you to verify it came from Rise. To calculate the signature, Rise uses an HMAC-SHA1 hex digest with the sharedSecret and the body of the request.

Here's an example of what signature verification code might look like if you're using Node.js.

Note: the specifics may differ depending on the framework you're using, the version of Node you're on, and other factors.

const crypto = require('crypto') 

const signatureDigest = crypto.createHmac('sha1', process.env.WEBHOOK_SHARED_SECRET)
.update(Buffer.from(JSON.stringify(request.body)))
.digest('hex')

if (request.headers['x-hook-signature'] === signatureDigest) {
// OK: request came from Rise
} else {
// Error: request didn't come from Rise
}

Error Handling and Retries

Rise will send a POST request with JSON data to the configured targetUrl each time one of the configured events occurs. Your server acknowledges that it has received the payload by sending back a 200 response. Any response outside of the 200 range indicates an error. In that case, Rise will retry to send the request 14 more times over the next 48 hours.

Did this answer your question?