Before you’ll be taking your first steps developing a Speakap Application, let’s familiarize ourselves with some key concepts:
Now that that’s off of our chests, let’s digg in...
Assuming that you already have a Speakap Network at your disposal; let’s start writing a manifest. The most simple manifest contains the application’s name in just one language:
{ "name": { "en-US": "Hello World", "permissions": [], "entries": [] } }
The two empty arrays permissions
and entries
are there to satisfy our manifest validator. They will be
discussed later on in this tutorial.
It’s speaks for itself that this can be extended with many more languages or translations:
{
"name": {
"en-US": "Hello World",
"nl-NL": "Hallo Wereld",
"de-DE": "Hallo Welt",
"fr-FR": "Bonjour Monde"
},
"permissions": [],
"entries": []
}
When your app is listed in the Speakap Market the name is preceded with an icon image. The icon can be any publicly available web image (preferably PNG or GIF).
{
"name": {
"en-US": "Hello World"
},
"permissions": [],
"icon": "http://developer.speakap.io/world-icon.png",
"entries": []
}
To make the application available from Speakap we need to create an entry. The most common entry points are:
main
Large iframe that opens after clicking the app icon from the main navigation.network-timeline-widget
Widget on the right-hand side of the network timeline.Let’s add both these positions:
{
"name": {
"en-US": "Hello World"
},
"permissions": [],
"icon": "http://developer.speakap.io/world-icon.png",
"entries": [
{
"position": "main",
"responsive": false,
"devices": "all",
"icon": "\uf0ac",
"label": {
"en-US": "Hello World"
}
},
{
"position": "network-timeline-widget",
"devices": "all",
"label": {
"en-US": "Hello World"
}
}
]
}
The icon we use in the main navigation is one of the Font Awesome icons. By default a limited set of these icons is available within Speakap. Contact our Support department to request an additional icon.
The observant reader may have noticed the devices
property. This allows you to have your entry target specific
devices, one of: desktop, phone, tablet or all.
One important property is still missing from the entries, namely the actual URL to your application. We’ll save that for a bit later.
As you can imagine, one of the most important things to consider is security. But first let’s distinguish two areas of Speakap Applications:
client-side: | The client-side is the front-end of your application, i.e., everything that operates within a browser’s context. This part of an app must use the JavaScript API to communicate with both the Speakap Client and Speakap API. |
---|---|
server-side: | From your servers you are able to do requests directly to the Speakap API, i.e. back-end requests. Because no client is involved you are allowed to use a special App Access Token to authorize these requests. |
The above makes clear that you have two options to communicate with our API: client-to-server and server-to-server. The first restricts you to the authorization level, i.e. privileges, of the logged-in user as it compels you to do all requests on its behalf. Not only that, but you are also bound by the endpoints whitelisted by us. The second offers no restrictions on specific resources, but you are, however, limited to permissions we make available for apps.
In most cases you wil probably use a combination of the two and in case of a single-page application you might even write your own API or web service capable of delivering data to your front-end.
Now let’s start coding our Hello World app:
<html>
<head>
<title>Hello World</title>
</head>
<body>
<p>Hello Speakap user!</p>
</body>
</html>
If you would upload a file like this to a public-facing web folder you just finished your first, kinda useless, Speakap Application.
But wait...
We still need to finalize the manifest with the correct URL and complete the upload and install process. Assuming you
picked the filename helloworld.html
the manifest will now read:
{
"name": {
"en-US": "Hello World"
},
"icon": "http://developer.speakap.io/world-icon.png",
"entries": [
{
"position": "main",
"responsive": false,
"devices": "all",
"url": "https://yourdomain.com/app/folder/helloworld.html",
"icon": "\uf0ac",
"label": {
"en-US": "Hello World"
}
},
{
"position": "network-timeline-widget",
"url": "https://yourdomain.com/app/folder/helloworld.html",
"devices": "all",
"label": {
"en-US": "Hello World"
}
}
]
}
Upload your manifest to the same location as the app, so that it becomes publicly accessible as well. Then go to the Speakap Market of your Speakap Network and click the “+ Application” button. This opens the list of available apps. Next click “Add application to market” and you will be presented with an input field. Fill in the URL to the manifest and press “Install”.
Once successfully added, your application will be the first entry in the list containing an App ID and Secret. We recommend creating a screenshot or at least writing down both these values, especially the secret.
Combine these two values and you’ve got your application’s Access Token:
[App ID]_[Secret]
The app is only available from the App Market of your Speakap Network and nowhere else. To install click anywhere on or around the app’s name or to uninstall simply click the trash can. The app can be deleted by clicking the trash can from the available apps list. The whole flow of add-install-uninstall-delete can be repeated as often as needed. Contact Speakap if you would like your application to be published to the public App Market.
Now that we have our App ID we can start using the Speakap API. Let’s update the HTML-file and add some scripts.
<html>
<head>
<title>Hello World</title>
<script type="text/javascript">
var Speakap = { appId: "...", signedRequest: "..." };
</script>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/speakap.js"></script>
</head>
<body>
<p>Hello Speakap user!</p>
</body>
</html>
It’s easy to see where the App ID needs to be filled in. The two JavaScript files are part of our SDK and can be downloaded from Github.
The next hurdle we need to clear is the second property of the Speakap initialization object.
As explained earlier on; a signed request lets you verify that a request actually originated from where you expect it to be originated from. The Speakap Frontend opens an app by sending a POST request to the relevant URL from its manifest. This request is signed using the App Secret which, if kept confidential, is only known to the Speakap API and the Speakap Application.
It’s the app’s responsibility to asses the validity of the request by comparing the signature from the request to one generated on the fly in an identical way. Our SDK provides implementations in various languages to take care of this.
In the next example we will use the PHP SDK to check the signature:
<?php
// Assume auto-load is in place for the Speakap\SDK namespace
use Speakap\SDK as SpeakapSDK;
$signedRequest = new SpeakapSDK\SignedRequest('/* App ID */', '/* Secret */');
if (!$validator->validateSignature($_POST)) {
die('Invalid signature');
}
$encSignedReq = $signedRequest->getSignedRequest($_POST);
echo <<<HTML
<html>
<head>
<title>Hello World</title>
<script type="text/javascript">
var Speakap = { appId: "/* App ID */", signedRequest: "$encSignedReq" };
</script>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/speakap.js"></script>
</head>
<body>
<p>Hello Speakap user!</p>
</body>
</html>
HTML;
With both the correct App ID and Secret in place we were able to bootstrap the JavaScript API with a validated signed request. Subsequently this will trigger a handshake with the Speakap Frontend. Completion of the handshake will lead to the fulfillment of a Promise. This promise acts as the entry point of our code.
We can now personalize our greeting with the full name of the logged in user:
<!-- Rest of page is ommited to save space -->
<body>
<script type="text/javascript">
/* Assume sanitize() is a custom function stripping malicious content */
Speakap.doHandshake.then(function() {
Speakap.getLoggedInUser().then(function(user) {
document.write('<p>Hello ' + sanitize(user.fullName) + '!</p>');
});
});
</script>
</body>
Using the locale
parameter from the signed request you can imagine how the above example can be adapted to support
multiple languages.
To demonstrate doing XHR API requests we could also grab the full name from the user resource after retrieving it from the server. The JavaScript part would then read:
/* Assume sanitize() is a custom function stripping malicious content */
Speakap.doHandshake.then(function() {
Speakap.getLoggedInUser().then(function(loggedInUser) {
Speakap.ajax('/users/' + loggedInUser.EID + '/').done(function(user) {
document.write('<p>Hello ' + sanitize(user.fullName) + '!</p>');
});
});
});
If front-end technologies aren’t your strongest point, the same result can be achieved from the server. As you saw earlier the validation of the signed request is done server-side, so we have access to the EID of the logged-in user there as well.
Using the access token of our Hello World App we will perform a cURL request:
<?php
/*
* Assume signed request has been properly validated and malicious content
* will be stripped from the output using a custom sanitize() function
*/
$signedParams = $signedRequest->getSignedParameters($_POST);
$baseUrl = 'https://api.speakap.io/networks/' . $signedParams['networkEID'];
$accessToken = /* App ID */ '_' /* Secret */;
$ch = curl_init("$baseUrl/users/{$signedParams['userEID']}/");
curl_setopt_array($ch, array(
CURLOPT_HEADER => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => array(
'Accept: application/vnd.speakap.api-v1.4+json',
'Authorization: Bearer ' . $accessToken
)
));
$response = curl_exec($ch);
curl_close($ch);
$user = json_decode($response);
echo "<p>Hello " . htmlspecialchars($user->fullName) . "!</p>";
Or if you are more comfortable using a tool like Guzzle:
<?php
$signedParams = $signedRequest->getSignedParameters($_POST);
$client = new GuzzleHttp\Client(array(
'base_uri' => 'https://api.speakap.io/networks/' . $signedParams['networkEID']
));
$accessToken = /* App ID */ '_' /* Secret */;
$response = $client->get("/users/{$signedParams['userEID']}/", array(
'headers' => [
'Accept' => 'application/vnd.speakap.api-v1.4+json',
'Authorization' => 'Bearer '. $accessToken
]
));
$user = json_decode($response->getBody());
echo "<p>Hello " . htmlspecialchars($user->fullName) . "!</p>";
There you have it! A server-to-server request resulting in a 403-response. Wait, what?!
One important aspect we already touched upon, but did not yet cover: permissions. All our endpoints and resources are protected against unauthorized and unprivileged usage, so you need to include the required permissions in your manifest. For publicly available apps these permissions will be screened by us during an audit we’ll do before publication.
The final manifest will look like this:
{
"name": {
"en-US": "Hello World"
},
"icon": "http://developer.speakap.io/world-icon.png",
"permissions": [
"get_profiles"
],
"entries": [
{
"position": "main",
"devices": "all",
"url": "https://yourdomain.com/app/folder/helloworld.php",
"icon": "\uf0ac",
"label": {
"en-US": "Hello World"
}
},
{
"position": "network-timeline-widget",
"url": "https://yourdomain.com/app/folder/helloworld.php",
"devices": "all",
"label": {
"en-US": "Hello World"
}
}
]
}
One last flow this tutorial doesn’t cover uses the OAuth 2.0 Authorization Code Grant. In this redirection-based flow your app asks the end user explicit permission to do certain requests and retrieve specific data. It is then able to obtain a special access token from the Authenticator scoped to what was allowed earlier by the user.