Skip to content
This repository has been archived by the owner on Sep 2, 2020. It is now read-only.

Awarding Badges

SueSmith edited this page Sep 28, 2014 · 14 revisions

In this guide we will work through the process of actually issuing a badge via BadgeKit API. As you will have seen if you followed the Application Review Webhooks guide, a notification is sent to a URL of your choice when an application is reviewed in BadgeKit. At this point you can communicate with the earner, offering them the badge if their application was successful. The code in this document will show how you can build on what we did in the application review webhook guide to go ahead and award the badge when the user chooses to accept it.

For an explanation of how assessment works in BadgeKit, see Assessment with BadgeKit.

If you aren't using assessment, you should still be able to use the guidance below to issue badges via BadgeKit API.

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.

Contents

Overview

Below is a detailed guide to using the API in the context of a node.js app - here's the short version!

Creating Badge Instances

Create Instance Request Endpoints

POST /systems/:slug/badges/:slug/instances
POST /systems/:slug/issuers/:slug/badges/:slug/instances
POST /systems/:slug/issuers/:slug/programs/:slug/badges/:slug/instances

See the API docs for more on the badge issuing endpoints.

Expected Post Data Example

{
    "email": "[email protected]"
}
Issuing Parameters

All you need to issue a badge is the earner email address - BadgeKit API will retrieve the badge data from the endpoint path you request. Here are the data items you can post:

NAME VALUE
email required - earner email address
slug optional - instance slug (API will generate if not provided)
issuedOn optional - date issued (API will generate if not provided)
expires optional - expiry date (unix time)
claimCode optional - use only when issuing via claim code

Example Instance Created Response

The API returns status and instance objects when a badge instance is successfully created:

{
    "status": "created",
    "instance": 
    {
        "slug": "abcde12345",
        "email": "[email protected]",
        "expires": null,
        "issuedOn": "2014-05-13T16:29:13.911Z",
        "assertionUrl": "http://issuersite.com/public/assertions/abcde12345"
    }
}

When you create a badge instance for an earner email address, BadgeKit will NOT communicate with the earner. Instead, the API sends notification to your webhook URL - you can then contact the earner regarding their badge.

Processing an Application

Application Processed Request Endpoints

PUT /systems/:slug/badges/:slug/applications/:slug
PUT /systems/:slug/issuers/:slug/badges/:slug/applications/:slug
PUT /systems/:slug/issuers/:slug/programs/:slug/badges/:slug/applications/:slug

See the API docs for more on the application update endpoints.

Expected Put Data Example

{
    "processed": "processed date" 
}
Application Update Parameters

All you need to process an application is the processed field - BadgeKit API will retrieve the application data from the endpoint path you request. You can optionally also include an evidence array or alternatively the application object itself (which can include both the processed and evidence values together with other application data items).

Example Application Processed Response

The API returns status and application objects when an application is successfully marked as processed:

{
    "status": "updated",
    "application": 
    {
        "id": 1,
        "slug": "abcdef123456",
        "learner": "[email protected]",
        "created": "2014-05-06T12:24:45.000Z",
        "assignedTo": null,
        "assignedExpiration": null,
        "badge": 
        {
            "id": 1,
            "slug": "great-badge",
            "name": "Great Badge",
            "strapline": "General greatness.",
            "earnerDescription": "This badge shows how great you are.",
            "consumerDescription": "Earners of this badge are 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": "systemsite.com",
                "name": "Excellent System",
                "email": null,
                "imageUrl": null
            },

            "criteriaUrl": "http://issuersite.com/system/badgekit/badge/great-badge/criteria",
            "criteria": 
            [
                {
                    "id": 1,
                    "description": "Is really great.",
                    "required": 1,
                    "note": ""
                },

                {
                    "id": 2,
                    "description": "Demonstrates greatness.",
                    "required": 1,
                    "note": ""
                }
            ],

            "categories": 
            [

            ]
        },

        "processed": null,
        "evidence": 
        [
            {
                "url": null,
                "mediaType": null,
                "reflection": "I did great stuff."
            }
        ]
    }
}

Authentication

Requests should be signed using your BadgeKit API secret and a JWT token in the Authorization header. See the Authorization doc for more.

For a more detailed overview of awarding a badge by creating a badge instance and marking an application as processed, read on.

Badge Issuing Flow

BadgeKit API is designed to let you choose an issuing flow that suits your own community of earners. The following is a typical overview, although you may not need to implement all of these stages in your own situation:

  • earner applies for badge
  • badge application is reviewed
  • review data is sent to webhook URL
  • webhook emails earner, offering badge if application was a success
  • earner chooses to accept the badge via the issuer site*
  • issuer site awards the badge:
  • creates a badge instance*
  • marks the application as processed*
  • award data is sent to the webhook
  • issuer communicates with the earner
    • for example offering to push their new badge to a backpack

*In this guide we will demonstrate these parts of the process.

Webhook Configuration

If you have not done so already, you need to configure a webhook for your BadgeKit instance by inserting a record in the API webhooks table. Include the address at which you plan on processing the webhook notification, a secret to carry out authentication and the ID for the system the webhook is associated with. See the following example:

INSERT INTO 'webhooks' ('id', 'url', 'secret', 'systemId') VALUES (null, 'http://issuersite.com/hook', 'asecret', 1);

If you followed the application review webhook guide, you will be able to build what we do in this guide into your existing code. The samples below require the following resources:

var http = require("http");
var jws = require('jws');
var bodyParser = require('body-parser');
app.use(bodyParser.json());
var crypto = require("crypto");
var qs = require("qs");

Accepting Badges

When an application review assesses an earner as having met the criteria to earn a badge, BadgeKit classifies the application as approved. At this point in the review webhook code, we offered the earner the badge by including a link in their email message - you can opt to carry this out any way you prefer, for example within your own site. The link we included in the email had the following structure:

http://issuersite.com/accept?badge=a-great-badge&[email protected]&application=1a2b3c4d5e6f7g8h9i0j

For simplicity, we will process the data in the node app by retrieving the URL parameters in the accept function. To issue the badge, we need the badge slug, earner email and application slug. With the badge slug and earner email, we can create a badge instance to represent the specific instance badge awarded to the earner. With the application slug, we will mark the earner's application for the badge as processed. This will stop the application from appearing in the Applications > Pending list in the BadgeKit Web app if you are using it.

Creating the badge instance and marking the application as processed both involve BadgeKit API endpoints.

Creating a Badge Instance

Let's start by creating a badge instance when the earner has chosen to accept the badge. In our node app, we represent the URL included in the earner's email message as follows (ending /accept):

app.get('/accept', function(req, res) {
//issue the badge
});

Inside this function, first retrieve the parameters we included in the URL:

var badgeSlug=req.param("badge");
var earner=req.param("earner");
var application=req.param("application");

The endpoints for creating a badge instance are as follows:

POST /systems/system-slug/badges/badge-slug/instances
POST /systems/system-slug/issuers/issuer-slug/badges/badge-slug/instances
POST /systems/system-slug/issuers/issuer-slug/programs/program-slug/badges/badge-slug/instances

See the API docs for more on the badge issuing endpoints.

In the sample code, the badge simply belongs to a system, so we can define the path as follows:

var awardPath = "/systems/badgekit/badges/"+badgeSlug+"/instances";

This would apply where the system slug is badgekit.

BadgeKit API will deduce the badge details from the endpoint path, so the only data item we need to pass to create a badge instance is the earner email:

var awardData = qs.stringify({
	email: earner 
});

Making a Request

We can prepare the request data to call on the API as follows:

var claimData = {
	header: {typ: 'JWT', alg: 'HS256'},
	payload: {
		key: 'master',
		exp: Date.now() + (1000 * 60),
		method: 'POST',
		path: awardPath,
		body: {
			alg: "SHA256",
			hash: crypto.createHash('SHA256').update(awardData).digest('hex')
		}
	},
	secret: 'yoursecret'
};

var requestOptions = {
	host : 'yourapilocation.com', 
	path : awardPath, 
	method : 'POST', 
	headers: { 'Authorization': 'JWT token="' + jws.sign(claimData) + '"',
		'Content-Type': 'application/x-www-form-urlencoded',
		'Content-Length': Buffer.byteLength(awardData)
	}
};

As usual, your path and method must match in these two objects or authentication will fail. Include your own API location and secret. When you attempt to create a badge instance, the response data will have the following structure:

{
	"status": "created",
	"instance": 
	{
		"slug": "abcdefghijk1234567890",
		"email": "[email protected]",
		"expires": null,
		"issuedOn": "2014-05-13T16:29:13.911Z",
		"assertionUrl": "http://issuersite.com/public/assertions/abcdefghijk1234567890"
	}
}

You can therefore detect success by checking the status field includes created. You can make the post request as follows:

var postRequest = http.request(requestOptions, function(acceptResponse) {
	var response = [];
	acceptResponse.setEncoding('utf8');

	acceptResponse.on('data', function (responseData) {					
		response.push(responseData);
	});

	acceptResponse.on('end', function(){
		var awardData=JSON.parse(response.join('')); 
		console.log('accept response: ' + response.join(''));//output all at once
		if(awardData.status==="created"){ //status created
			res.send("<html>"+
				"<head>"+
				"<title>Badge Accepted</title>"+
				"<style type='text/css'>"+
				"//add some css"+
				"</style>"+
				"</head>"+
				"<body>"+
				"<h1>You've accepted your badge!</h1>"+
				"<p>Thanks! We'll be in touch.</p>"+
				"</body>"+
				"</html>"
			);
			//mark application as processed
			processApplication(badgeSlug, application);//we will add this next
		}
		else {
			res.send("Whoops! Something went wrong with your badge.");
		}
	});
});

postRequest.on('error', function(e) {
	console.error(e);
});
// post the data
postRequest.write(awardData);
postRequest.end();

We check the status is created and output a confirmation to the user - here is the simple page with a little CSS added:

Badge Accepted

Issuing Multiple Badges

Note that you can issue a particular badge to multiple earner email addresses at one time using the bulk issuing route:

POST /systems/system-slug/badges/badge-slug/instances/bulk
POST /systems/system-slug/issuers/issuer-slug/badges/badge-slug/instances/bulk
POST /systems/system-slug/issuers/issuer-slug/programs/program-slug/badges/badge-slug/instances/bulk

See the API docs for more on the bulk issuing endpoints.

Your post data should include an array of the earner email addresses you are awarding the badge to:

var awardData = qs.stringify({
	emails: ['[email protected]', '[email protected]'] 
});

The API will only create instances for email addresses that do not already have an awarded instance of the badge. Any duplicate email addresses will only be awarded the badge once. The API responds to calls at the bulk issuing route with an array of the created badge instances.

Processing the Application

Now we've created the badge instance, but we still have to mark the application in the API database as processed. If you use the BadgeKit Web app, you will notice that pending applications persist even after review - applications continue to appear until they are marked as processed. Notice that in the above code we included the following line:

processApplication(badgeSlug, application);

Let's add this method next:

function processApplication(bdgSlug, appSlug){
//process application
}

We pass the badge and application slug, so inside the function we can build these into the path:

var processPath = "/systems/badgekit/badges/"+bdgSlug+"/applications/"+appSlug;

The endpoint for updating an application is as follows:

PUT /systems/system-slug/badges/badge-slug/applications/application-slug
PUT /systems/system-slug/issuers/issuer-slug/badges/badge-slug/applications/application-slug
PUT /systems/system-slug/issuers/issuer-slug/programs/program-slug/badges/badge-slug/applications/application-slug

See the API docs for more on the application update endpoints.

All we need to pass as data to this endpoint is a processed field, which will be a date:

var proc = new Date();
var processData = qs.stringify({
	processed: proc 
});

Now we can prepare the request data as before:

var claimData = {
	header: {typ: 'JWT', alg: 'HS256'},
	payload: {
		key: 'master',
		exp: Date.now() + (1000 * 60),
		method: 'PUT',
		path: processPath,
		body: {
			alg: "SHA256",
			hash: crypto.createHash('SHA256').update(processData).digest('hex')
		}
	},
	secret: 'yoursecret'
};

var requestOptions = {
	host : 'yourapilocation.com', 
	path : processPath, 
	method : 'PUT', 
	headers: { 'Authorization': 'JWT token="' + jws.sign(claimData) + '"',
		'Content-Type': 'application/x-www-form-urlencoded',
		'Content-Length': Buffer.byteLength(processData)
	}
};

This time it is a put request as we are updating the data for an existing application. Now we can make the request:

var putRequest = http.request(requestOptions, function(processResponse) {
	var response = [];
	processResponse.setEncoding('utf8');

	processResponse.on('data', function (responseData) {					
		response.push(responseData);
	});

	processResponse.on('end', function(){
		console.log("process response: "+response.join(''));
	});
});

putRequest.on('error', function(e) {
	console.error(e);
});
// post the data
putRequest.write(processData);
putRequest.end();

We simply write the result to the console - in your own site you may wish to carry out additional steps. The response has the following structure:

{
	"status": "updated",
	"application": 
	{
		"id": 11,
		"slug": "abcdefghijk1234567890",
		"learner": "[email protected]",
		"created": "2014-05-14T19:11:19.000Z",
		"assignedTo": null,
		"assignedExpiration": null,
		"badge": 
		{
			"id": 11,
			"slug": "dowell-and-co-new-group-leader",
			"name": "DoWell and Co New Group Leader",
			"strapline": "The Group Leader badge acknowledges dynamic, effective leadership amongst peers in the realm of program facilitation.",
			"earnerDescription": "The Group Leader badge communicates that you are a leader amongst your peers. With it you demonstrate that you have effectively performed at least four of the following skills at DoWell and Co - communication, delegation, organization, responsibility & ownership, and passionate commitment.",
			"consumerDescription": "The DoWell & Co Group Leadership badge communicates important leadership values that we hold dear at DoWell & Co. Values that will serve an earner throughout their life. This badge represents breadth and depth of commitment to at least four of the five necessary leadership skills: communication, delegation, organization, responsibility & ownership, and passionate commitment. Along with the other DoWell & Co badges, particularly Group Management and Time Management, the earning of this badge acknowledges exemplary achievement of the highest sort at DoWell & Co for groups of 7-12 members.",
			"issuerUrl": "dowellandco.co",
			"rubricUrl": "",
			"timeValue": 0,
			"timeUnits": "minutes",
			"limit": 0,
			"unique": 0,
			"created": "2014-05-14T17:34:16.000Z",
			"imageUrl": "http://issuersite.com/images/badge/251",
			"type": "",
			"archived": false,
			"system": 
			{
				"id": 1,
				"slug": "badgekit",
				"url": "http://systemsite.com",
				"name": "Best System",
				"email": null,
				"imageUrl": null,
				"issuers": 
				[
					
				]
			},

			"criteriaUrl": "http://issuersite.com/system/badgekit/badge/dowell-and-co-new-group-leader/criteria",
			"criteria": 
			[
				{
					"id": 31,
					"description": "The Group Leader badge recognizes achievement in the realm of program facilitation. It acknowledges dynamic, effective interaction with peers in the completion of a group project. Group Leaders possess some form of at least four of the following five skills: superior communication skills, effective delegation skills, advanced organization skills, personal responsibility & ownership skills, passionate commitment.",
					"required": 1,
					"note": ""
				},

				{
					"id": 41,
					"description": "This badge illustrates expertise in reaching goals involving complex collaborative environments of groups ranging in size between 7 and 12 members.",
					"required": 0,
					"note": ""
				}
			],

			"categories": 
			[
				
			],

			"tags": 
			[
				
			]
		},

		"processed": "2014-05-14T19:11:53.000Z",
		"evidence": 
		[
			{
				"url": null,
				"mediaType": null,
				"reflection": "I lead people and stuff."
			},

			{
				"url": "http://mysites.com/app/uploads/picture.png",
				"mediaType": "image",
				"reflection": "picture"
			},

			{
				"url": "http://site.com/myevidence.html",
				"mediaType": "link",
				"reflection": null
			}
		]
	}
}

As you can see, the status is updated and the processed field has a date in it.

Award Hook

When you create a badge instance as we do above, another notification is sent to the webhook. You can configure your webhook code to again follow up with the earner when this occurs - see Badge Issued Webhooks for an overview of how to do that.