Motivate Cloud API
Introduction
Motivate Cloud provides multiple ways to receive information from and send information to other systems. A REST API allows registered applications to access and modify Motivate Cloud data whenever those applications desire, usually on a schedule. Webhooks allow applications to receive data in real time when events occur. This page will help you understand how to use these features to integrate your application with Motivate Cloud.
Table of Contents
Using the REST API
Basic API Rules
- All API access is over HTTPS to https://www.motivate Cloud.com/api/
- For POST and PUT requests, send the content in JSON format with the content-type set to application/json
- All API responses will be provided in JSON format except for specific APIs that also have an option for CSV files
- When errors occur, the API will return a status code 4xx and the response body will be a JSON object like { “Message”: “Description of error here” }
- POST and PUT requests will include a “Location” header that give the URL to access the new/updated object
- Timestamps should be sent and will be returned in ISO 8601 format, UTC time zone.
Application and User Configuration
Motivate Cloud only allows API access to applications that have been registered. An Administrator can register an application by logging into the Motivate Cloud Administration Portal and going to the Settings -> Developer menu. There the Administrator can create an application, which will provide a client ID that will be needed in API calls.
Each API call also needs to be performed by a registered Motivate Cloud user that has API access and the appropriate roles within Motivate Cloud. An administrator should create the user, and under Permissions grant the needed permissions, including “Access API”. Under that permission is the option to “Generate Secret Key.” Follow those instructions to create a secret key and remember it for use in the API calls.
Authentication
The Motivate Cloud API uses an OAuth2.0 Username and Password flow for authorization. This flow is a two-step process where the application first sends credentials to request a token, and then uses this token in subsequent requests to the API.
The first step is to POST to the Authorization method (/oauth2/authorize) providing the following:
{ "grant_type": "password", "client_id": (Client ID for the application from the Developer Settings), "username": (User's login ID), "password": (User's secret key and/or password + | + secret key) }
The value of the password field will depend on the way the application was setup in the Developer Settings. If only a Secret Key is required for the application, the password should be the Secret Key. If the application requires password as well, the password should be the user’s Password + “|” + the user’s Secret Key.
If successful, this will return a 200 (OK) with a JSON object that includes some information about the user, including the access_token. This token is good for 2 hours and needs to be remembered for future API calls.
Sending Authenticated Requests
All calls to the APIs need to include the Token received from the authentication process. There are different possible ways to send it (replace {auth_token} with the token you received):
1. (Preferred) Send token in an authorization header with Bearer followed by a space and the auth_token
curl https://motivatecloud.com/api/services/v1.0/users -H "Authorization: Bearer [auth_token]"
2. Send the token in as a query string parameter named “access_token”, URL encoded (not recommended since the query string can be sniffed over the network)
curl https://motivatecloud.com/api/services/v1.0/user?access_token=[auth_token]
If the token is missing or invalid, the API will return a 401 (Unauthorized). If the token is valid, the API will return in the format specified for that API.
Pagination
Requests that return multiple items will be paginated to 10 items by default. You can set a custom per-page amount with the ?pageSize parameter.
The result of a paginated result will provide the information in two ways. The result object will include a “meta” property with page_size, page_num, total_count, and page_count, and the actual list of results will be in the “data” property. A “Link” header will also be returned with the URLs as shown below:
<http://{url}?page_num=2&page_size=10&additional...> rel="current", <http://{url}?page_num=1&page_size=10&additional...> rel="first", <http://{url}?page_num=1&page_size=10&additional...> rel="prev", <http://{url}?page_num=3&page_size=10&additional...> rel="next", <http://{url}?page_num=4&page_size=10&additional...> rel="last"
These links will be absolute urls that include all parameters necessary to retrieve the desired current, next, previous, first, or last page. The one exception is that if an access_token parameter is sent for authentication, it will not be included in the returned links, and must be re-appended.
REST API Explorer
Motivate Cloud has an interactive API Explorer that allows you to examine all the available APIs and even try them out. Click the button below to open the Explorer in a new browser tab.
Rest API ExplorerUsing Webhooks
Setting up a Webhook
An administrator sets up a Webhook by logging into the Motivate Cloud Administration Portal and going to the Settings -> Developer menu. There the Adminstrator can create as many webhooks as desired by entering the URL. The administrator can also say which events should trigger the webhook call. Webhooks on this page will be active until they are deleted, though a webhook can be temporarily disabled by deselecting all events.
From that page, the administrator can also send test messages to the webhook by clicking on the “Test this webhook” link under the URL.
Webhook Messages
Motivate Cloud will post a JSON object to the webhook’s URL. Regardless of the event, this object will have the following fields:
{ "timestamp": Integer number of seconds passed since January 1, 1970, "token": Randomly generated string with length 50, "signature": See section "Validating Messages" for information on how this is computed, "event_type": Specifies the type of event. See below for the possible values, "message_id": Unique ID of the message for tracking purposes (string), "event_time": Date/Time that the event occurred, "employee_id": The employee ID of the user who did the event, "login_id": Login ID of the user, "first_name": First name of the user, "last_name": Last name of the user, "nick_name": Nick name of the user, "is_test_message": True if this is being called from Tester in the admin portal (otherwise the field isn't included), "event_data": JSON object with data specific to the event (see below) }
The following event_type values may be sent to the webhook, and the event_data will contain the corresponding fields:
badge_earned
{ "badge_id": The unique ID of the badge, "badge_name": The name of the badge, "description": The description of the badge }
course_completed
{ "course_id": The unique ID of the course, "course_name": The name of the course, "score_is_known": Whether the course reported a score (true/false), "score": If the score is known, the score 0-100 (decimal), "completion_date": The most recent date the learner completed the course, "compliant_until": The date until which the learner will still be compliant }
course_pack_completed
{ "course_pack_id": The unique ID of the course pack, "course_pack_name": The name of the course pack, "earned_certificate": Whether this completion earned the user a certificate (true/false) }
level_up
{ "level_id": The ID of the Level (first level is always 1), "level_name": The name of the level }
reward_redeemed
{ "reward_id": The unique ID of the reward, "title": The title of the reward, "price": The price, in coins, per reward, "quantity": The number of rewards redeemed }
ftp_job_completed
{ "ftp_log_id": The ID of this FTP job (can be used in the REST API to get more details about the job), "file_type": 'U' for User or 'O' for Org Chart, "received_date_utc": The date/time the file was received (in UTC time), "status": 'Success' if the file was able to be processed (even if some rows had errors) or 'Error' if the file could not be processed, "message": If the status is 'Error', more details about the error, "orig_file_name": The file name as it was placed on the FTP server, "processed_file_name": The file name as it was archived on the FTP server, "row_count": The number of rows in the file that were processed (includes those in error but not those that were skipped), "added_count": The number of records added, "updated_count": The number of records updated (if the record matched, it's considered an update even if no data actually changed), "deleted_count": The number of records deleted, "reactivated_count": The number or records reactivated, "error_count": The number of rows with errors (use the REST API to get more details), "skipped_count": The number of rows in the input file that were skipped because of an exclusion rule with errors }
Validating Messages
Motivate Cloud will post to whatever URL is configured for the URL, including any query-string parameters that are part of that URL. In many cases, using a complex URL for the webhook is enough to secure the endpoint. If you want additional validation, however, Motivate Cloud will also compute a signature on every post using a 36-character company-specific Webhook Key that you can find on the screen where you configure the webhook. You can see if this signature is valid to prove it came from Motivate Cloud.
The signature is computed as follows:
- Concatenate the timestamp and token values from the message (which change for each call)
- Compute the SHA256 HMAC Hash of the above value using the Webhook Key
- Convert the result to Hex format (without any hyphens) and uppercase the result
The webhook should compute the signature using the above approach, then compare it to the signature provided by Motivate Cloud. The code for computing this will vary by language, but a couple examples are provided below.
Javascript
<script src='https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/hmac-sha256.js' type='text/javascript'></script> <script src='https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/enc-base64-min.js' type='text/javascript'></script> var timestamp = "value_from_message"; var token = "value_from_message"; var key = "from_admin_portal"; var hash = CryptoJS.HmacSHA256( timestamp + token, key); var signature = hash.toString(CryptoJS.enc.Hex).toUpperCase();
C#
using System.Security.Cryptography; string timestamp = "value_from_message"; string token = "value_from_message"; string key = "from_admin_portal"; var hmac = new HMACSHA256(System.Text.Encoding.ASCII.GetBytes(key)); var bytes = hmac.ComputeHash(System.Text.Encoding.ASCII.GetBytes(timestamp + token)); string signature = BitConverter.ToString(bytes).Replace("-", "");
You can also just validate that these signatures work like you expect by using https://caligatio.github.io/jsSHA/. On this screen, use the HMAC Demo and set the following:
- Input Text: timestamp + token from the message
- Input Type: TEXT
- Key: Webhook Key from admin portal
- Key Type: TEXT
- SHA Variant: SHA-256
- Output Type: HEX
The signature will appear in Output Hash. Note that it will be lowercase but Motivate Cloud will use uppercase.
Additional steps can be included to avoid abuse of your webhook:
- Cache the token value locally and not honor any subsequent request with the same token. This will prevent replay attacks.
- Check if the timestamp is not too far from the current time
Error Handling
Motivate Cloud expects to receive an HTTP result code of 200, 201, 202, or 204 when a webhook successfully accepts a message. If there is a problem, Motivate Cloud will try again after 1 minute. If that fails will try after another 2, 5, 10, 15, 30 and 60 minutes. If it still fails, the message will be canceled and an email will be sent to your Support email address.
If you’d like to receive posts from Motivate Cloud but don’t have an endpoint ready yet, try setting up a mock bin. There are multiple free services on the web, such as RequestBin. At this site you can click to get an address to a bin just for you. Configure your Motivate Cloud webhook to use this URL, then you can just refresh the RequestBin page to see what data it received.