If you want to integration Fasttrack notifications to your site without using our js library you can do that with custom integration. That requires more development time from your side, but it also gives you the absolute most possibilities to customize.

Prerequisites: To start with you will need your brand id and brand name. Brand id will always be an integer and your brand name will always be a lower case string. You can get these values from your Fasttrack account manager.

You also have to make sure with your account manager that inbox and/or push notifications are enabled for your brand.

If you have read the other parts in the Fasttrack integration documentation you might be familiar with the sid variable. It is basically an authentication token that can be exchanged in your operator API for a user id. You can read more about it here: .

This guide is written in javascript with jQuery but you could use any language/framework you want. The on-site notifications and inbox solution is based on API endpoints returning JSON data and a web socket connection provided by Pusher. When you have followed all steps and completed this guide, you should be able to have a fully working implementation of on-site notifications and rich inbox. Let's get started! 🚀

1. Getting needed config values

To get started you need a couple of endpoints to different parts of Fasttrack integration. You also need a pusher key. All this will be returned from this endpoint:

    
METHOD: GET
URL: https://am-events-[STAGING_OR_PRODUCTION].fasttrack-solutions.com/api/v1/config/[BRAND_NAME]

Response example:

    
{
"crmUrl": "https://sub.example.com/integration-api",
"fusionUrl": "https://sub.example.com/integration-api",
"prismaUrl": "https://sub.example.com/integration-api",
"pusherKey": "123bc",
"pusherRegion": "eu"
}

2. Log in to Fast Track integration

When you have a config object containing endpoints, a sid, a brand id and a brand name we can continue. Now you want to login to Fasttrack using the sid. That will be done against endpoint

    
METHOD: POST
URL: [FUSION_URL]/Platform/LoginAuthToken

3. Connect to Pusher

On success, the LoginAuthToken endpoint will return a user object which contains values for setting up pusher. Pusher will authenticate with an endpoint in Fasttracks backend. When you are authenticated to pusher you can bind upon which events you want to listen to. Currently FT CRM supports three push notification "event types":

  • message

  • shoutout

  • inbox

When you have bound the events to your functions populating the front end on messages you are done with the push notifications web socket part.

When using pusher on the client side you can either load pusher with a html script tag or via npm. . Pusher also has other libraries if you want to use pusher for your mobile app.

4. Getting existing messages

But there is more! What if the push notification was sent to the user when the user wasn't logged in? There is an endpoint for listing all existing messages a user has received:

    
METHOD: GET
URL: [FUSION_URL]/Notifications/v2/user-notifications?unread-only=false&inbox-only=false

Use the query parameters unread-only and inbox-only to filter your results.

Response example:

    
{
"Data": [
{
"MessageId": 1234,
"UserId": -9999,
"Event": "shoutout", // Can be shoutout, message or inbox
"Title": "Use Fasttrack Integration inbox!",
"Message": "This is the message body. Can contain HTML!",
"PreviewText": "Message preview text",
"FooterText": "Message footer text.",
"Data": {
"OverrideCommunicationStatus": ""
},
"CTAButtonLink": "https://www.google.com",
"CTAButtonText": "Primary button",
"CTAButton2Link": "https://www.google.com",
"CTAButton2Text": "Secondary button",
"ImageUrl": "http://example.com/img/header-image.jpg",
"IsRead": false,
"DisplayType": "push", // DisplayType can be "push" or "silent"
"Date": "2019-09-12 12:37:56",
"Expires": "2019-09-19 11:16:25"
},
...
],
"Success": true,
"Errors": []
}

The DisplayType can be used to send silent inbox notifications. There is a checkbox in the CRM for silent notifications.

By calling this URL on page load you can populate the front end with push notifications that were sent to the user while being logged out.

5. Marking messages

If you want to distingush messages recieved / read by the user you can mark a notification as read using the following endpoint. When recievied the notifications from the endpoints above next time, the notification will be marked as read and you can take care of that in your JS / front end.

    
METHOD: POST
URL: [FUSION_URL]/Notifications/MarkNotificationAsRead
BODY: {MessageId: 123}

You can also mark a notification as deleted. That means that it will never be returned in any call anymore:

    
METHOD: DELETE
URL: [FUSION_URL]/Notifications/v2/user-notification/[MESSAGE_ID]

The full flow

    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>FT CRM NOTIFICATIONS - Demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
<style type="text/css">
* {
box-sizing: border-box;
}
body {
background-color: #d5d5d5;
}
</style>
<!-- USING jQUERY FOR THIS EXAMPLE: -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<!-- PUSHER.JS SDK: -->
<script src="https://js.pusher.com/5.0/pusher.min.js"></script>
<script>
// DECLARING CONSTANTS:
// URL for getting constans. You will get the brand name from your account manager.
// Remove '-staging' when in production
const CONFIG_URL = "https://am-events-staging.fasttrack-solutions.com/api/v1/config/[BRAND_NAME]";
// SID is used for authenticate the user. The SID should last the entire session.
// There is a hardcoded test sid that will allow you to authenticate and connect to pusher locally.
// Replace this with a real value when going to staging / prod
const SID = "99999999-9999-9999-9999-999999999999-9999";
// The brand id is given to you from your account manager
const BRAND_ID = [BRAND_ID]; // AS INTEGER
// The brand name is also given to you from your account manager
const BRAND_NAME = "[BRAND_NAME]"; // AS STRING
// DECLARING FUNCTIONS
// You can write this the way you want. Here is some methods prepared for a bare minimum.
// Get the base url for the endpoints:
function getBaseEndpoints(callback) {
$.ajax({
type: "GET",
url: CONFIG_URL,
data: {},
success: callback,
error: function (error) {
console.error(error);
}
});
}
// Do the login to Fasttrack integration:
function login(fusionUrl, callback) {
$.ajax({
type: "POST",
url: `${fusionUrl}/Platform/LoginAuthToken`,
headers: { "authtoken": SID },
data: {},
success: callback,
error: function (error) {
console.error(error);
}
});
}
// Initiate pusher:
function initiatePusher(fusionUrl, pusherKey, channelName) {
// Setup pusher object:
const PUSHER = new Pusher(pusherKey, {
authEndpoint: `${fusionUrl}/external/pusher/${BRAND_NAME}?authToken=${SID}`,
cluster: 'eu',
encrypted: true,
});
PUSHER.connection.bind("connected", function (data) {
console.log("Connected to pusher:", data);
});
PUSHER.connection.bind('disconnected', function (data) {
console.error("Disconnected from pusher: ", data);
});
// Bind to channel:
const PUSHER_CHANNEL = PUSHER.subscribe(channelName);
PUSHER_CHANNEL.bind("pusher:subscription_error", function (data) {
console.error("Pusher channel error: ", data);
});
PUSHER_CHANNEL.bind("pusher:subscription_succeeded", function (data) {
console.log("Successfully connected to pusher channel: ", data);
});
// Bind to specific message types:
PUSHER_CHANNEL.bind("message", function (data) {
console.log("Got pusher message: ", data);
});
PUSHER_CHANNEL.bind("shoutout", function (data) {
console.log("Got pusher shoutout: ", data);
});
PUSHER_CHANNEL.bind("inbox", function (data) {
console.log("Got pusher inbox message: ", data);
});
}
// Set up channel name. This is not something you can change. The channel must have this syntax.
function getPusherChannelName(brandId, userID) {
return `private-prisma-${brandId}-${userID}`;
}
// Do API call to get existing messages for user:
function fetchExistingMessages(fusionUrl, authToken, callback) {
$.ajax({
type: "GET",
url: `${fusionUrl}/Notifications/v2/user-notifications?unread-only=false&inbox-only=false`,
headers: { "authtoken": authToken },
data: {},
success: callback,
error: function (error) {
console.error(error);
}
});
}
// Mark a specific notification as read:
function markNotificationAsRead(MessageId, fusionUrl, authToken, callback) {
$.ajax({
type: "POST",
url: `${fusionUrl}/Notifications/MarkNotificationAsRead`,
headers: { "authtoken": authToken },
data: JSON.stringify({
MessageId: MessageId
}),
success: callback,
error: function (error) {
console.error(error);
}
});
}
// Delete a notification:
function deleteNotification(MessageId, fusionUrl, authToken, callback) {
$.ajax({
type: "DELETE",
url: `${fusionUrl}//Notifications/v2/user-notification/${MessageId}`,
headers: { "authtoken": authToken },
data: {},
success: callback,
error: function (error) {
console.error(error);
}
});
}
// EXECUTION OF FUNCTIONS:
// Wait until DOM is ready:
$(document).ready(function () {
// Get config:
getBaseEndpoints(function (confResp) {
// Check if the response contains needed values:
if (confResp.fusionUrl && confResp.pusherKey) {
// Do the login against Fasttrack integration:
login(confResp.fusionUrl, function (loginResp) {
// When you get the response, check if it is successful and got needed values:
if (loginResp.Success && loginResp.Data && loginResp.Data.User.UserId) {
// Fetch existing messages for user to be able to eventuallt display in front end, or in some kind of inbox:
fetchExistingMessages(confResp.fusionUrl, loginResp.Data.Authentication.AuthToken, function (response) {
// Check that everything went well:
if (response.Success && response.Data.length > 0) {
// Do what's needed with the messages inside response.Data
console.log("Notifications: ", response.Data);
}
});
// Then initiate pusher:
const pusherChannelName = getPusherChannelName(BRAND_ID, loginResp.Data.User.UserId);
initiatePusher(confResp.fusionUrl, confResp.pusherKey, pusherChannelName);
// To show how it works when a message is marked as read:
var messageIdToMarkAsRead = 1234;
markNotificationAsRead(messageIdToMarkAsRead, confResp.fusionUrl, loginResp.Data.Authentication.AuthToken, function (response) {
if (response.Success) {
console.log(`Successfully marked message id ${messageIdToMarkAsRead} as read!`);
} else if (!response.Success && response.Errors.length > 0) {
// You might wanna do some error handling here...
console.warn("Could not mark notification as read. Errors: ", response.Errors);
} else {
// You might wanna do some error handling here...
console.warn("Could not mark notification as read.");
}
});
// To show how it works when a message is deleted:
var messageIdToBeDeleted = 1234;
deleteNotification(messageIdToBeDeleted, confResp.fusionUrl, loginResp.Data.Authentication.AuthToken, function (response) {
if (response.Success) {
console.log(`Successfully delete message id ${messageIdToBeDeleted} as read!`);
} else if (!Response.Success && Response.Errors.length > 0) {
// You might wanna do some error handling here...
console.log("Could not delete notification. Errors: ", Response.Errors.length);
} else {
// You might wanna do some error handling here...
console.log("Could not delete notification.");
}
});
} else if (!loginResp.Success && loginResp.Errors.length > 0) {
// You might wanna do some error handling here...
console.error("Failed to login. Error: ", loginResp.Errors);
} else {
// You might wanna do some error handling here...
console.error("Failed to login.");
}
});
} else {
// You might wanna do some error handling here...
console.error("No fusionUrl or pusherKey in config response");
}
});
});
</script>
</head>
<body>
<h1>look in the console...</h1>
</body>
</html>

Let us know if you have any further questions