Client Side Flow

All the endpoints consumed in this page can be found here »

1. Getting needed config values

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

2. Log in to Fast Track integration

When you have the config object from previous request and also the current users sid and lastly, a brand name you can continue. Now you want to login to Fast Track using the sid. That will be done against authentication endpoint.

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 Fast Tracks backend. When you are authenticated to pusher you can bind upon which events you want to listen to. Currently Fast Track 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. Read more here about Pusher js. Pusher also has other libraries if you want to use pusher for your mobile app. Pusher docs

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. Look in the API Endpoint Section at "Get All Notifications".

5. Marking messages

If you want to distinguish messages received / read by the user you can mark a notification as read using the following endpoint. When received 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.

Have a look at "Mark Notification As Read" endpoint.

The full flow

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>Fast Track 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', // don't hardcode this one. Use dynamic from config api
        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>

Please let us know if you have any further questions!

Happy coding! 🚀

Last updated

Was this helpful?