-
Notifications
You must be signed in to change notification settings - Fork 42
Application Review Webhooks
This guide will demonstrate how you can configure a webhook to receive notification of badge application reviews being submitted via BadgeKit API. If you haven't seen it already, you may want to check out the guide to Submitting Applications first. We will add our webhook URL to the BadgeKit database so that it receives notification of badging events. After that we will process the data BadgeKit API sends when an application review is submitted, building the data into an email to send to the badge earner.
For an explanation of how assessment works in BadgeKit, see Assessment with BadgeKit.
The API guides use node.js examples to demonstrate the key processes you need to connect BadgeKit to your own earner-facing site. If you're using other languages/ platforms, you should be able to see how you can use BadgeKit to deliver your implementation.
- Overview
- Config
- Authentication
- Example Data Received
- Configuring a Webhook
- Verifiying the Data
- Processing the Data
- Communicating with the Earner
- BadgeKit Web App
- Next Steps
Below is a detailed guide to using the API in the context of a node.js app - here's the short version!
See the API docs for more detail on the webhook.
To receive data at a webhook URL, you first need to add it to your BadgeKit API database, in the webhooks table. You need an entry including your webhook URL and a secret you will use to decode the data sent there from the API.
You can authenticate data received from the API at your webhook URL as follows:
- Verify the JWT token sent in the Authorization header - use the secret you included in the API
webhookstable. - Check the hash sent in the Authorization header token against a hash of the received body data.
See the Authorization document for more.
Data sent to the webhook on application review includes the action, application, review and approved objects:
{
"action": "review",
"application":
{
"id": 1,
"slug": "abcdefg1234567",
"learner": "earner@adomain.com",
"created": "2014-05-12T15:13:07.000Z",
"assignedTo": null,
"assignedExpiration": null,
"badge":
{
"id": 1,
"slug": "great-badge",
"name": "Great Badge",
"strapline": "Does great stuff.",
"earnerDescription": "This badge shows how great you are.",
"consumerDescription": "The earner of this badge is great.",
"issuerUrl": "issuersite.com",
"rubricUrl": "",
"timeValue": 0,
"timeUnits": "minutes",
"limit": 0,
"unique": 0,
"created": "2014-05-05T14:17:46.000Z",
"imageUrl": "http://issuersite.com/images/badge/1",
"type": "",
"archived": false,
"system":
{
"id": 1,
"slug": "badgekit",
"url": "http://systemsite.com",
"name": "Excellent System",
"email": null,
"imageUrl": null
},
"criteriaUrl": "http://issuersite.com/system/badgekit/badge/great-badge/criteria",
"criteria":
[
{
"id": 1,
"description": "Does great things often.",
"required": 1,
"note": ""
},
{
"id": 2,
"description": "Is generally great.",
"required": 1,
"note": ""
}
],
"categories":
[
]
},
"processed": null,
"evidence":
[
]
},
"review":
{
"id": 1,
"slug": "1234567abcdefg",
"author": "reviewer@adomain.com",
"comment": "Fantastic job on your application.",
"reviewItems":
[
{
"criterionId": 1,
"satisfied": 1,
"comment": "Exactly right."
},
{
"criterionId": 2,
"satisfied": 1,
"comment": "Perfect."
}
]
},
"approved": true
}For a more detailed overview of handling the application review webhook, read on.
You can allow people to earn the badges you publish via BadgeKit in various ways, one of which involves applications. With this approach, as an issuer, you can list available badges on your site, allowing potential earners to submit applications, supplying supporting evidence. If you're using the BadgeKit Web app, submitted applications will appear in the Applications > Pending section.
When a reviewer assesses a pending application and submits their review, your site can receive notification of this event. This allows you to communicate with the earner, informing them whether or not their application was successful and optionally forwarding feedback from the reviewer. You can configure how you deliver the information (i.e. via your site or via email) to suit your own community.
Note that when an application is assessed as meeting the criteria for a badge, in which case the application status is approved, this does not mean that the badge is automatically issued to the earner. Instead, your site must create a badge instance following a successful review - optionally after offering the badge to the earner and awaiting their confirmation. This allows you to manage cases where permissions may be required for younger earners. When you do use the API endpoints to create the badge instance, you can receive another notification at your webhook URL. At this point you can follow up with the earner, for example offering to push their new badge to a backpack.
The following represents a typical flow for this process:
- Earner applies for a badge.
- Reviewer assesses badge application.
- Webhook receives application review submitted notification.*
- Webhook communicates with earner, informing them of the review.*
- If the application was approved, the earner is offered the badge.*
- If the earner chooses to accept the badge, issuer site creates a badge instance.
- Webhook receives badge issued notification.
- Issuer site follows up with earner, e.g. offering to push badge to backpack.
*In this guide we will demonstrate the following parts of this process: configuring a webhook in the API database; receiving the application review notification in the webhook; processing the application review data and including it in an email to the earner.
Even if you do not plan on using the process as it is outlined above, the code examples below will demonstrate how to receive and process the application review webhook data. You can see a more complete working example of this process in the Open Badges - Badges code.
Your BadgeKit API instance database contains a webhooks table. To receive notification of badging events, insert a record in the table, including:
- the URL at which you are going to process the received data
- a secret you will use to decode the data
- the ID for the system your webhook is going to be associated with.
The following sample SQL demonstrates:
INSERT INTO 'webhooks' ('id', 'url', 'secret', 'systemId') VALUES (null, 'http://issuersite.com/hook', 'asecret', 1);At the URL you specified in your webhook table, you can process the data sent from the API when an application is reviewed. To demonstrate the process in a node.js app, we will use the following resources:
var jws = require('jws');
var bodyParser = require('body-parser');
app.use(bodyParser.json());
var crypto = require("crypto");You will need these installed (locally or included in a package.json file as dependencies if you're pushing to a service such as Heroku). The following function will receive the webhook data (with a URL ending /hook listed in the database table example above):
app.post('/hook', function(req, res) {
//process notifications
});The code inside the function will execute when the webhook data is received from the API. We will authenticate the data before we process it, so we begin inside the function by retrieving the authorization header and verifying it:
var token = req.headers.authorization;
token = token.slice(token.indexOf('"')+1, -1);
if (!jws.verify(token, 'asecret')) { //use your secret
console.log("verification failed");
}
else{
//process the data
}The API sends an authorization token in the header, so we check it using the secret we set in the webhook database table. The remainder of the code will be placed in the else block, so that we don't process the data unless verification is successful. See the Authorization doc for more details.
Inside the else block, we can carry out another verification check, this time on the body data received:
var decodedToken;
try {
decodedToken = jws.decode(token);
if (decodedToken.payload.body.hash !== crypto.createHash('sha256').update(JSON.stringify(req.body)).digest('hex')) {
console.log("body hash does not match token hash");
}
else {
//process review data
}
} catch(err) {
console.log("error decoding the data");
}Here we check the hash of the received body against the hash sent along with it in the authorization header token - this way we know the data received is what the API sent. We will only proceed to communicate with the earner if this verification is also successful, so the rest of the code will be placed in this new else block.
Now that we've verified the data, we can go ahead and find out what's in there. The API will send data to the webhook URL when various actions occur, but in this case we're only interested in the review event - this occurs when a review is submitted to the API (either via the BadgeKit Web app or another method). We can find out what action has caused the webhook to execute by checking the action field in the data.
We will use a switch statement in the code example as you may later add support for the other webhook notifications. We are going to build a text string to include as the body of an email we will send to the earner, so we start it as an empty string. The data sent to the hook from the API includes many items you may wish to retrieve - the following demonstrates a relatively simple case.
var action = req.body.action;
var info="";
var emailTo="";
switch(action) {
//review event
case 'review':
//earner email
emailTo=req.body.application.learner;
//build badge name into email
info+="<p>Your application for the following badge was reviewed:"+
"<strong>"+req.body.application.badge.name+"</strong></p>";
//respond differently if approved or not
if(req.body.approved){
info+="<p>Great news - your application was approved!</p>";
//include link to accept the badge
// - alter for your url
info+="<p><a href="+
"'http://issuersite.com/accept?badge="+
req.body.application.badge.slug+
"&earner="+req.body.application.learner+
"&application="+req.body.application.slug+
"'>Accept your badge</a></p>";
}
else{
info+="<p>Unfortunately your application was unsuccessful this time. "+
"You can re-apply for the badge any time though!</p>";
}
//review includes multiple feedback and comment items
info+="<p>The reviewer included feedback for you:</p>";
info+="<ul>";
//comment field includes everything in the Finish page in BadgeKit Web app
info+="<li><em>"+req.body.review.comment+"</em></li>";
//review items array, one per criteria - build into list
var reviewItems = req.body.review.reviewItems;
var r;
for(r=0; r<reviewItems.length; r++){
info+="<li><em>"+reviewItems[r].comment+"</em></li>";
//can also include whether each criteria item was satisfied
}
info+="</ul>";
info+="<p><strong><em>Thanks for applying!</em></strong></p>";
break;
}We use a few of the data items sent to the webhook, which includes the action, application, review and approved fields. The application and review objects provide you with various other pieces of information related to the badge application.
The review sent to the webhook includes multiple data items - the following is a slightly simplified example of the data the webhook URL may receive for an application review:
{
"action": "review",
"application":
{
"id": 123,
"slug": "abcdefg1234567",
"learner": "earner@adomain.com",
"created": "2014-05-12T15:13:07.000Z",
"assignedTo": null,
"assignedExpiration": null,
"badge":
{
"id": 61,
"slug": "mozilla-webmaker-basic-digital-mentor",
"name": "Mozilla Webmaker Basic Digital Mentor",
"strapline": "A commitment to exploring, encouraging and shepherding the development of digital expertise in the Mozilla Webmaker community and beyond.",
"earnerDescription": "This badge acknowledges your commitment to exploring, encouraging, and shepherding community members inthe development of digital expertise in the Webmaker community. You earn this badge by working with the Mozilla Webmaker Team during 2014.",
"consumerDescription": "Webmaking is an essential component to the sustainability of the worldwide web. This badge represents a personal commitment to exploring, encouraging, and shepherding community members in the development of digital expertise in the Mozilla Webmaker community. It involves any of the following activities: creating a teaching resource; hosting a webmaker event; or making and sharing through the Teach the Web online community. This badge is issued by the Mozilla Webmaker Team during 2014.",
"issuerUrl": "www.webmaker.org",
"rubricUrl": "",
"timeValue": 0,
"timeUnits": "minutes",
"limit": 0,
"unique": 0,
"created": "2014-05-05T14:17:46.000Z",
"imageUrl": "http://issuersite.com/images/badge/123",
"type": "",
"archived": false,
"system":
{
"id": 1,
"slug": "badgekit",
"url": "http://systemsite.com",
"name": "Excellent System",
"email": null,
"imageUrl": null
},
"criteriaUrl": "http://issuersite.com/system/badgekit/badge/mozilla-webmaker-basic-digital-mentor/criteria",
"criteria":
[
{
"id": 221,
"description": "This badge demonstrates the earner has met Mozilla's stringent requirements for Basic Digital Mentor. This badge represents commitment to exploring, encouraging, and shepherding community members in developing digital expertise. It acknowledges the combined community building aspects of teaching and learning. Webmaker Mentors are an essential aspect to Mozilla's mission of making the web.",
"required": 1,
"note": ""
},
{
"id": 231,
"description": "The Basic Digital Mentor has taken one of our training courses and effectively completed one of the following requirements. Create a teaching resource. Create a hackable teaching kit using one of our handy templates. Submit your kit, activity, teaching guide or other teaching resource to help others teach the web or digital literacy to webmaker.org. Host a Webmaker event. Organize a hack jam, learning party or classroom event. Then document and share outcomes with the community. Our handy event guides make it easy. Make and share through the Teach the Web online community. Connect and learn other mentors around the world through remixing, making and discussion.",
"required": 1,
"note": ""
},
{
"id": 241,
"description": "This badge is issued by the Mozilla Webmaker Team during 2014. Mozilla Webmaker helps people teach digital and web literacy, learn new coding skills and make amazing things using digital tools.",
"required": 1,
"note": ""
}
],
"categories":
[
]
},
"processed": null,
"evidence":
[
]
},
"review":
{
"id": 456,
"slug": "1234567abcdefg",
"author": "reviewer@adomain.com",
"comment": "Fantastic job on your application.\n\nBest. Application. Ever.\n\nEverything incredible.\n\n\n\n",
"reviewItems":
[
{
"criterionId": 221,
"satisfied": 1,
"comment": "Exactly right."
},
{
"criterionId": 231,
"satisfied": 1,
"comment": "Perfect."
},
{
"criterionId": 241,
"satisfied": 1,
"comment": "Amazing."
}
]
},
"approved": true
}You can choose whichever data items you need to proceed with the earner's application. In the sample code above, we include the badge slug plus earner email, in a URL the earner will be able to click on in the email. When this happens you could create a badge instance through the API, at which point another webhook notification will be sent.
You can send an email or communicate with the earner using a method of your choice. The following simplified code demonstrates a basic email function:
var mail = require("nodemailer").mail;
mail({
from: "Badge Issuer <badges@issuer.com>", //your email
to: emailTo,
subject: "Badge", //your subject
generateTextFromHTML: true,
html: info
});The code retrieves the earner email from the review data received, sending the email to the address associated with the badge application. You can of course configure how much information you want to include in the email and how much you want to keep on your own site.
If you're using the BadgeKit Web app, you can see how the data items within an application review are packaged in the webhook data. For example, the following screenshots show the two parts of the review interface in which the assessor includes feedback:

The data in both of these sections is included in the review object sent to the webhook. The Criteria section data is included in reviewItems and the feedback in the Finish section is included in the comment field. Here is the simple email the sample code above produces:

Next up we will build on the process outlined above to create a new badge instance when the earner confirms that they want to accept the badge. See Awarding Badges for an overview of how to do that. This will cause another notification to fire at the webhook, at which point you can again contact the earner, for example if you wish to let them carry out follow-up tasks such as pushing their badge to a backpack.
For support working with BadgeKit or Open Badges, use any of the following channels:
- Post general questions in our Community Google Group and post technical questions in our Dev Google Group.
- Reach members of the Open Badges team directly on IRC (irc.mozilla.org) on the #badges channel.
- Email questions directly to badges@mozillafoundation.org and a member of the team will follow-up.
- Follow or tweet the Open Badges team @OpenBadges.
- Get involved or submit issues via the GitHub repos - feedback is always appreciated!