- Print
- DarkLight
- PDF
Webhook
Webhooks enable Cirrus to push information to other systems when certain events occur. This contrary to the rest of the REST API where a system will have to call Cirrus' API for information,
At the moment Cirrus offers one webhook: Exam results ready.
Use this webhook to be notified when new results become available (so your system does not need to fall back on polling which is not permitted under Cirrus' Fair Use policy).
Trigger / Retries
The Exam results ready is triggered when results are published within Cirrus. Since September 2021 if results are updated (e.g. through rescoring) the Exam results ready will be triggered again.
Since October 2021 you can configure to only trigger the Exam results ready webhook Only when result is SATISFACTORY, i.e. only when the candidate passed the exam, e.g. useful when the receiving system generates a certificate or badge.
If the receiving server is down, Cirrus will retry for a total of 10 attempts with a randomized exponential delay between each attempt calculated thus:
var random = new Random();
return (int)Math.Round(Math.Pow(attempt - 1, 4) + 15 + random.Next(30) * attempt);
Your service should always return 200 for valid (including properly authenticated) messages, except if a consequent call to the Cirrus API (i.e. /results
) fails. See Response.
If the processing fails on your end, please return 200 (OK), and enqueue the processing on your end. This to prevent unnecessary load and triggering alerts on Cirrus servers.
Create webhook
Create webhook via the cirrus user interface. You must fill following fields
Step 1: Go to Admin > Webservices Group > Webhooks
Step 2: Create webhook
Field | Description |
---|---|
Active | An inactive webhook will not trigger request. NOTE that any requests not send will not be send after (re)activation. |
Title | Title of webhook with a short description |
Payload URL | URL of the endpoint on your server that will receive the webhook POST requests |
Content type | Content type that will be used for requests |
Authorization type | See Authorization Types for Integrity Check below |
Secret key | For X-Cirrus-Signature, see Authorization Types for Integrity Check below |
Username/Password | For Basic Authentication, see Authorization Types for Integrity Check below |
Token | For Bearer token, see Authorization Types for Integrity Check below |
Events | See Triggers / Retries above. |
Payload template | See Custom Payload Template below |
Response
Webhook response should have http status 200 OK, or any other 2## status, for the successfully received webhook. Other statuses will be considered as an error, and will trigger another attempt.
Your service should always return 200 for valid (including properly authenticated) messages, except if consequent calls to the Cirrus API fail (1).
E.g. if you receive a result for an unknown schedule as it was manually created in Cirrus do not return an error as it will trigger retries and clog our queues.
(1) if consequent calls to the Cirrus API fail, like /results
is the only appropriate scenario to return an error response in order to leverage Cirrus' retry mechanism.
Authorization Types for Integrity Check
If an optional authentication secret is supplied with an webhook endpoint, Cirrus offers several authorization types:
Authorization Type | Header | Value | Remarks |
---|---|---|---|
Basic Authentication | Authorization | login:password or Base64 token | If the Secret Key contains a : Cirrus will first Base64 encode⧉ it, else it will be added verbatim |
Bearer token | Bearer | token | Cirrus will added the Secret verbatim (if required by your system you need to Base64 encode⧉ it beforehand.) |
X-Cirrus-Signature | X-Cirrus-Signature | SHA-1 hash | Validation of message contents. Default for existing customers. See "X-Cirrus-Signature Specification" further down. |
Custom Payload Template
When providing a custom Payload Template you must provide a complete valid JSON template, including surrounding {}. You can check your template using online JSON validators (e.g. jsonformatter.org⧉
Supported Fields
Field | Token | Description/Remarks |
---|---|---|
Timestamp | {{timestamp}} | ISO timestamp (in UTC) that this result was published |
Exam Submission Date | {{submissiondate}} | ISO timestamp (in UTC) that candidate submitted the exam |
Candidate User ID | {{candidate_id}} | |
Assessment External ID | {{assessment_id}} | |
Schedule External ID | {{schedule_id}} | |
Schedule HierarchyExternal ID | {{schedule_hierarchy_id}} | |
Attempt External ID | {{attempt_id}} | |
Is Remarked | {{is_remarked}} | |
Webhook URL | {{webhook_url}} | The URL you configured to receive the events of this webhook. Added mostly for backward compatibility. |
Candidate First or Given name | {{candidate_first_name}} | |
Candidate Last or Family name | {{candidate_last_name}} | |
Candidate Email | {{candidate_email}} | |
Candidate Username | {{candidate_username}} | |
Candidate Language | {{candidate_lang_code}} | 2-letter ISO code |
Event Key | {{webhook_event}} | Added mostly for backward compatibility. |
Event Title | {{webhook_title}} | Added mostly for backward compatibility. |
Default template
{
"result":
{
"student_id":"{{candidate_id}}",
"exam_id":"{{assessment_id}}",
"schedule_id":"{{schedule_id}}",
"attempt_id":"{{attempt_id}}"
},
"event":"{{webhook_event}}",
"title": "{{webhook_title}}",
"created":"{{timestamp}}",
"url":"{{webhook_url}}"
}
Credly
This information is provided for your information only. Credly's documentation⧉ is authoratitive for the workings of the Credly API and system: https://sandbox.credly.com/docs⧉
Prequisites:
- A contract with Credly so you have a valid Credly Organisation ID and Credly Authorization Token
- Authentication Type "Basic Authentication" and "Username" "
*credly-auth-token*
" i.e. your Credly Authorization Token; e.g. "2yfzJINVALIDxEXAMPLEdRCKI
". Leave the "Password" field blank. - Credly Template for each Assessment. And the Assessment's External ID is filled with the Credly Template ID.
As External IDs must be unique so each Assessment requires its own External ID, for this reason you must create a Credly template per Assessment.
An Assessment can of course be (re)used in many times in different Schedules.
Credly URLs
System | URL | Remarks |
---|---|---|
Live for normal login | Contact Credly | |
Live Webhook URL | Contact Credly | |
Test for normal login | https://sandbox.credly.com | Do not use for web hooks. |
Test Webhook URL | https://sandbox-api.youracclaim.com/v1/organizations/aecb0222-c7f1-4fca-a2fa-37a42e14afcb/badges | Replace aecb0222-c7f1-4fca-a2fa-37a42e14afcb with your Credly Organisation ID |
Credly Payload template
- "suppress_badge_notification_email" if true Credly will NOT send a notification to the Candidate's email.
- "expires_at" null means the Credly certification will not expire.
{
"recipient_email": "{{candidate_email}}",
"badge_template_id": "{{assessment_id}}",
"issued_at": "{{submissiondate}}",
"issued_to_first_name": "{{candidate_first_name}}",
"issued_to_last_name": "{{candidate_last_name}}",
"expires_at": null,
"issuer_earner_id": "{{candidate_id}}",
"locale": "en",
"suppress_badge_notification_email": false
}
Example Request Headers
"X-Cirrus-Signature": "sha1=ee499df566fcdf8b20c3948d0264f79e4c5644da",
"Connection": "Keep-Alive",
"Content-Length": 240,
"Content-Type": "application/json",
"Expect": "100-continue",
"Host": "http://cirrus.com" - Your Host which you provided
Example Response Body
It’s by design that the response contains only IDs. They can be used in appropriate additional calls for additional information of interest. E.g. '/get-assessment-results' for the result details.
{
"result":
{
"student_id":"student_1", //userId
"exam_id":"exam_1", //Assessment externalId
"schedule_id":"schedule_1" //Schedule externalId
"attempt_id":"attempt_1" //Attempt externalId
},
"event":"exam-results-ready",
"title": "results_hook",
"created":"2019-09-12T05:31:01.2833776Z", // UTC Time
"url":"http://cirrus.com/results" // Your url which you provided
}
X-Cirrus-Signature Specification
This header is of the format:
X-Cirrus-Signature: sha1=f7000d3a2fd51f8f53d91e0085fae1423dfbab8e
Where the above hash is calculated by (OSX and Linux)
echo -n 'request body' | openssl dgst -sha1 -hmac "authentication secret"
This header can be used to detect malicious payloads sent to your endpoint.
How to get data, compute signature and validate is best shown with example code, see the following C# example.
X-Cirrus-Signature C# Example Code
static void Main(string[] args)
{
var server = new HttpListener();
server.Prefixes.Add("http://<yourdomain.com>/results"); //your url for webhook
server.Start();
var context = server.GetContext();
var request = context.Request;
var response = context.Response;
//get request body
var body = new StreamReader(context.Request.InputStream).ReadToEnd();
//validate data, optional step, can don't do that
var sign = string.Concat("sha1=", SignatureSha1.Sign("your secret key", body));
var isValid = request.Headers["X-Cirrus-Signature"] == sign;
if (!isValid)
return; // do something if invalid
response.StatusCode = (int)HttpStatusCode.OK;
response.StatusDescription = "OK";
response.Close();
}
public static class SignatureSha1 // class for sign a data
{
public static string Sign(string key, string body)
{
var byteKey = Encoding.UTF8.GetBytes(key);
var byteBody = Encoding.UTF8.GetBytes(body);
using (var hmac = new HMACSHA1(byteKey))
{
var result = hmac.ComputeHash(byteBody);
var stringResult = result.Aggregate("", (s, e) => s + $"{e:x2}", s => s);
return stringResult;
}
}
}
TROUBLESHOOTING
Webhook issues
In order to troubleshoot Webhook issues you need technical expertise and sysadmin access to the detailed logs of the receiving system.
Before you contact support, please:
- Carefully check your Webhook configuration in Cirrus, in particular is it "Active", is your "Payload URL" and "Payload template" correct, but also the other fields.
- Check in Cirrus if the results for your (test) attempt have been published (or else the Webhook won't have been triggered).
- Check the "External ID"s in Cirrus of your Candidate (User ID), Assessment (External ID), and Schedule (External ID)
In case, you must contact our Service Desk for help, please ensure you provide the following:
- At least one Webhook request as send by Cirrus including URL (your URL), HTTP Headers, and Body;
- The Cirrus URL, URL of the Cirrus environment, and
- Exact date and time of Webhook (e.g. when you triggered it by publishing a result in Cirrus).
- A screenshot of your Webhook Configuration settings screen in Cirrus;
- The User ID of the candidate and External IDs of both Schedule and Assessment.
- A screenshot of your published attempt;
Empty Fields
When following steps of Webhook issues, in particular check the "Payload Template" for errors, e.g. tokens misspelled or missing a {
or }
, and check the related objects in Cirrus if the information is correctly filled in there.
.