JavaScript SDK

The SDK is a JavaScript/ECMAScript library built to facilitate front-end interactions with the Rubiq API. It uses the standard JavaScript authentication which means that the requesting domain must be registered in dialogportal™. Contact a Fluid Account Manager for assistance with this.

The SDK is comprised of a number of scripts. core.js is always required but the others are optional - include the ones you need. Here is the complete list of SDK scripts:

https://api.dialogportal.com/v1/sdk/v1/core.js

https://api.dialogportal.com/v1/sdk/v1/entity.js

https://api.dialogportal.com/v1/sdk/v1/preference.js

https://api.dialogportal.com/v1/sdk/v1/terms.js

The SDK uses AJAX to interact with the API. It uses native JavaScript/ECMAScript functionality (XMLHttpRequest), but when jQuery is present on the page then jQuery will be used instead.

The SDK is ECMAScript5 (ES5) compatible, which means it supports most browsers. If you need to support legacy browsers, you may need to include compatibility shims such as es5-shim and json3, which together support all SDK requirements.

SDK authentication

Every page using the Rubiq SDK must begin with a call to rs.sdk.core.init(). The call accepts the AppKey as a parameter, and an optional callback function used to perform subsequent SDK operations once initialization and authentication is complete.

Under development
<script src="https://testapi.dialogportal.com/v1/sdk/v1/core.js"></script>
<script type="text/javascript">
   var APP_KEY = 12345;
   rs.sdk.baseUrl = 'https://testapi.dialogportal.com/v1';
   rs.sdk.core.init(APP_KEY, function() {
      console.debug('SDK initialized');
   }); 
</script>


In production
<script src="https://api.dialogportal.com/v1/sdk/v1/core.js"></script>
<script type="text/javascript">
   var APP_KEY = 12345;
   rs.sdk.core.init(APP_KEY, function() {
      console.debug('SDK initialized');
   });
</script>
Behind the scenes

The SDK is initialized, and authenticated with the Rubiq API. An API "token" is generated and saved in the browser sessionStorage. Subsequent page loads must still call rs.sdk.core.init() to prepare the SDK, but the function will not need to re-authenticate - the stored token will be re-used. 

The API token is only valid for 1 hour from the last use. However, any SDK request that fails with an expired token will automatically re-authenticate, store the new token, and resend the failed request with the new token.

When developing against the test API, the rs.sdk.baseUrl must be set to https://testapi.dialogportal.com/v1 as in the "Under development" example above.


Entity Authentication

All entity-level operations through the SDK require entity authentication. This is done via the rs.sdk.core.login() function.

<script src="https://api.dialogportal.com/v1/sdk/v1/core.js"></script>
<script src="https://api.dialogportal.com/v1/sdk/v1/entity.js"></script>
<script type="text/javascript">
   var APP_KEY = 12345;
   rs.sdk.core.init(APP_KEY, function() {
      // Check whether an entity is already logged in
      if (rs.sdk.core.getEntityID() !== -1) {
         console.debug('entityID from localStorage:', rs.sdk.core.getEntityID());
         rs.sdk.entity.get(function(e) {
            console.debug('Entity fetched:', e.firstName, e.lastName, '[' + e.email + ']');
         });
      }
      else
         // Assumes variables loginID and password have already been populated
         rs.sdk.core.login(loginID, password, loginSuccess, loginError);
   });
   function loginSuccess(data) {
      console.debug('Entity authenticated:', rs.sdk.core.getEntityID());
      console.debug('Name:', data.firstName, data.lastName);
   }
   function loginError(err) {
      console.error('Login failed:', err.responseText);
   }
</script>

There's a lot going on in this example. First, the SDK is authenticated as usual. In the callback, a check is made to see whether an entity is already logged in. If they are, the entity details are fetched with rs.sdk.entity.get(), using the existing authentication details.

If the entity is not already logged in, then rs.sdk.core.login() is called, using variables loginID and password, which have presumably been populated from a login form. In the login callback function (loginSuccess()), the entity details are logged to the debug console.

If a login error occurred (e.g. wrong loginID or password), the login error callback function (loginError()) is called, which logs the error to the error console - in a real scenario this error message would be displayed to the user somehow.

Behind the scenes

rs.sdk.core.login() calls API endpoint 2001: Authenticate to authenticate the entity. The SDK must be used with Data Isolation enabled, and on successful completion, the login function stores the ApiSessionKey and EntityID in the browser localStorage. This means that the entity will not need to be authenticated for each session - next time the user visits the site, the ApiSessionKey and EntityID will be fetched from localStorage and used in subsequent SDK requests.

API authentication is per-session and must be performed on each visit - the token is stored in sessionStorage. Entity authentication persists outside the session - the entityID and ApiSessionKey are stored in localStorage.

Errors

All error callback functions listed below should expect an XMLHttpRequest object parameter. If jQuery is used, this will be the jQuery jqXHR wrapper.

rs.sdk.entity.create(data, cbSuccess, cbError);
function cbError(xhr) {
   var httpStatus = xhr.status;
   var apiStatusSubCode = xhr.getResponseHeader('ApiStatusSubCode') || '-1';
   if (httpStatus === 400)
      // There was a problem with the data, e.g. the email address was not unique
      alert(xhr.responseText);
   else
      console.error('Something went wrong.', httpStatus, apiStatusSubCode);
}

Optional parameters

Optional parameters (displayed in the function list below with a question mark: optional_parameter?) can be excluded from SDK function calls. Any callback function parameters can be sent instead, as they are always last.

For example, to request the active, default terms version text for terms with API ID abcde these 2 calls are equivalent:

rs.sdk.terms.getVersionText('abcde', 'active', 'default', onSuccess);
rs.sdk.terms.getVersionText('abcde', onSuccess);

SDK functions

rs.sdk.core.init(appKey, cb?)
rs.sdk.core.getEntityID()

Return the entityID from localStorage. Returns -1 when no entity has been authenticated.

rs.sdk.core.login(loginID, password, cbSuccess?, cbError?)

Authenticate an entity, saving the entityID and ApiSessionKey in localStorage

rs.sdk.core.logout()

Remove the entityID and ApiSessionKey from localStorage


rs.sdk.entity.create(userData, cbSuccess?, cbError?)

userData: The details of the new entity, see 1001: Create account

cbSuccess: Sends a single parameter containing the details of the new entity.

Create a new entity. The successfully created new entity is automatically authenticated, as if rs.sdk.core.login() had been used.

rs.sdk.entity.get(cbSuccess?, cbError?)

cbSuccess: Sends a single parameter containing the details of the entity, see 1002: Get account data

rs.sdk.entity.update(userData, cbSuccess?, cbError?)

userData: The entity details that are to be updated, see 1003: Update account data

cbSuccess: A callback function for a successful update. Passes a single parameter containing the details of the updated entity.


rs.sdk.preference.get(preferenceID?, cbSuccess?, cbError?)

cbSuccess: Sends a preference details object when preferenceID is given, otherwise an array of all active preferences, see 2300: Get preferences

rs.sdk.preference.getGroup(groupID?, cbSuccess?, cbError?)

cbSuccess: Sends a preference group object when groupID is given, otherwise an array of all active preference groups, see 2305: Get preference groups

rs.sdk.preference.getEntity(cacheHours?, cbSuccess?, cbError?)

cacheHours: Defaults to 1. Number of hours that this result should be cached in localStorage.

cbSuccess: Sends an array of objects, containing the preferenceID and opt-in status for each active preference. See 2310: Get preference opt-in status

rs.sdk.preference.getEntityGroup(groupID, cacheHours?, cbSuccess?, cbError?)

cacheHours: Defaults to 1. Number of hours that this result should be cached in localStorage.

cbSuccess: Sends an array of objects, containing the preferenceID and opt-in status for each member of the group. See 2312: Get preference group opt-in status.

rs.sdk.preference.hasOptedIn(preferenceID, cacheHours?, cbSuccess?, cbError?)

cacheHours: Defaults to 1. Number of hours that this result should be cached in localStorage.

cbSuccess: Sends true or false depending on whether the authenticated entity has opted-in to this preference.

Fetch opt-in status of this entity preference. If there is an unexpired result cached in localStorage then that is returned instead of sending a new request. When cacheHours is 0 then nothing is read from localStorage and the result is not cached.

rs.sdk.preference.optIn(preferenceID, cbSuccess?, cbError?)

See 2315: Opt-in to preference. If preferenceID is currently cached in localStorage, it is updated.

rs.sdk.preference.optOut(preferenceID, reason, cbSuccess?, cbError?)

See 2316: Opt-out of preference. If preferenceID is currently cached in localStorage, it is updated.

rs.sdk.preference.updateEntityGroup(groupID, optOutReason, preferences?, cbSuccess?, cbError?)

preferences: An array of preferenceIDs. Defaults to all members of this group.

See 2317: Update entity preferences for group. If any preferences are currently cached in localStorage they are removed.

rs.sdk.preference.renderGroup(htmlContainerID, groupID, lang?, cbSuccess?, cbError?, cbUpdateSuccess?, cbUpdateError?)

htmlContainerID: An id of an HTML element, e.g. 'entity-preferences' for <div id="entity-preferences"></div>

lang: The preferred label language for the group, preferences and controls. Falls back to the browser language.

cbSuccess: Parameterless callback, called after the preference group HTML has been output and existing entity preferences selected.

cbError: Called on error fetching the group, or the existing entity preferences for the group.

cbUpdateSuccess: Called on successful preference update, after rendered "OK" button is clicked.

cbUpdateError: Called on error during preference update, after rendered "OK" button is clicked.

Fetch an entity preference group and render it as HTML, pre-selecting existing entity preferences.


rs.sdk.terms.acceptConsent(consentID, sourceID, cbSuccess?, cbError?)

See 2105: Accept permission. If consentID is currently cached in localStorage, it is updated.

rs.sdk.terms.acceptTerms(termsID, sourceID, version?, consents?, cbSuccess?, cbError?)

version: A version string, formatted as major.minor, i.e. '1.0'. Defaults to the active version.

consents: An array of consentIDs. Defaults to all consents for this version of the terms.

See 2102: Accept terms. If any consents are currently cached in localStorage they are removed.

rs.sdk.terms.hasAccepted(termsID, latest?, cbSuccess?, cbError?)

latest: Defaults to false. When true, only pass true to cbSuccess when the entity has accepted the latest version of the terms.

cbSuccess: Sends true or false depending on whether the authenticated entity has accepted these terms.

rs.sdk.terms.hasConsented(consentID, cacheHours?, cbSuccess?, cbError?)

cacheHours: Defaults to 1. Number of hours that this result should be cached in localStorage.

cbSuccess: Sends true or false depending on whether the authenticated entity has accepted this consent.

Fetch acceptance status of this consent. If there is an unexpired result cached in localStorage then that is returned instead of sending a new request. When cacheHours is 0 then nothing is read from localStorage and the result is not cached.

rs.sdk.terms.get(termsID?, cbSuccess?, cbError?)

cbSuccess: Sends a terms details object when termsID is given, otherwise an array of all active terms, see 2100: Get terms

rs.sdk.terms.getVersion(termsID, version?, cbSuccess?, cbError?)

version: A version string, formatted as major.minor, i.e. '1.0'. Defaults to the active version.

cbSuccess: Sends a terms version details object, see 2101: Get terms version

rs.sdk.terms.getVersionText(termsID, version?, textKey?, cbSuccess?, cbError?)

version: A version string, formatted as major.minor, i.e. '1.0'. Defaults to the active version.

textKey: The key of the text to fetch. Defaults to the default text for this version.

cbSuccess: Sends a terms version text object, with authenticated entity details merged into the text, see 2111: Get terms version text

Fetch terms version text, as described in 2111: Get terms version text. Note that the SDK automatically base64-decodes the resulting text, so it can be used directly.

rs.sdk.terms.withdrawConsent(consentID, sourceID, reason, cbSuccess?, cbError?)

See 2107: Withdraw permission. If consentID is currently cached in localStorage, it is updated.

rs.sdk.terms.withdrawTerms(termsID, sourceID, reason, cbSuccess?, cbError?)

See 2104: Withdraw terms acceptance. If any consents are currently cached in localStorage they are removed.


rs.sdk.terms.renderVersionText(htmlContainerID, sourceID, termsID, version?, textKey?, cbSuccess?, cbError?, cbAcceptSuccess?, cbAcceptError?, cbValidationError?)

htmlContainerID: An id of an HTML element, e.g. 'terms-acceptance' for <div id="terms-acceptance"></div>

version: A version string, formatted as major.minor, i.e. '1.0'. Defaults to the active version.

textKey: The key of the text to fetch. Defaults to the default text for this version.

cbSuccess: Parameterless callback, called after the terms version and version text have been fetched and rendered.

cbError: Called on error fetching terms version or version text.

cbAcceptSuccess: Called on successful terms acceptance, after rendered "Accept" button is clicked.

cbAcceptError: Called on error during terms acceptance, after rendered "Accept" button is clicked.

cbValidationError: Called when rendered "Accept" button is clicked but required consent radio options have not been selected. The callback argument is an array of elementIDs of <li> elements containing invalid radio options.

Fetch terms version text with merged authenticated entity details, and render it as HTML.

Placeholders in the text can be used to:

  • Display all consents as an unordered list (ul) of checkboxes:
Placeholder: <!--rs.sdk:consents-->
<ul style="list-style: none">
  <li>
    <input id="C-9a8b7-12345-edfba" type="checkbox">
    <label for="C-9a8b7-12345-edfba">Track me</label>
  </li>
  <li>
    <input id="C-abcdef-12345-abcdef" type="checkbox">
    <label for="C-abcdef-12345-abcdef">Contact me</label>
  </li>
</ul>
  • Display a predefined group of consents as radio-buttons:
Placeholder: <!--rs.sdk:consentGroup:tracking-->
<div id="consentGroup-tracking" class="rs-cg">
   <div class="rs-cg-text">
      Here are a group of consents, in radio-button form
   </div>

   <div class="rs-cg-select-all">
      <span class="rs-cg-accept-all">
         <input id="acceptAll-tracking" type="checkbox" onclick="if (this.checked) { rs.sdk.terms.internal.onAcceptAllConsents('tracking', true); }">
         <label for="acceptAll-tracking">
            Accept all
         </label>
      </span>
      <span class="rs-cg-decline-all">
         <input id="declineAll-tracking" type="checkbox" onclick="if (this.checked) { rs.sdk.terms.internal.onDeclineAllConsents('tracking', true); }">
         <label for="declineAll-tracking">
            Decline all
         </label>
      </span>
   </div>

   <ul style="list-style: none" class="rs-cg-radio">
      <li class="rs-cg-consent-radio">
         <span class="rs-cg-consent-radio-text">
            Track my purchases
         </span>
         <div class="rs-cg-consent-radio-accept">
            <input id="C-abcdef-12345-abcdef.tracking" name="C-abcdef-12345-abcdef" type="radio" onclick="rs.sdk.terms.internal.onToggleConsent('tracking')">
            <label for="C-abcdef-12345-abcdef.tracking">'
               Yes
            </label>
         </div>
         <div class="rs-cg-consent-radio-decline">
            <input id="C-decline-abcdef-12345-abcdef.tracking" name="C-abcdef-12345-abcdef" type="radio" checked onclick="rs.sdk.terms.internal.onToggleConsent('tracking')">
            <label for="C-decline-abcdef-12345-abcdef.tracking">'
               No
            </label>
         </div>
      </li>
      <li class="rs-cg-consent-radio">
         <span class="rs-cg-consent-radio-text">
            Track my locations
         </span>
         <div class="rs-cg-consent-radio-accept">
            <input id="C-abcdef-12345-98765.tracking" name="C-abcdef-12345-98765" type="radio" onclick="rs.sdk.terms.internal.onToggleConsent('tracking')">
            <label for="C-abcdef-12345-98765.tracking">'
               Yes
            </label>
         </div>
         <div class="rs-cg-consent-radio-decline">
            <input id="C-decline-abcdef-12345-98765.tracking" name="C-abcdef-12345-98765" type="radio" checked onclick="rs.sdk.terms.internal.onToggleConsent('tracking')">
            <label for="C-decline-abcdef-12345-98765.tracking">'
               No
            </label>
         </div>
      </li>
   </ul>
</div>
  • Display a predefined group of consents as checkboxes:
Placeholder: <!--rs.sdk:consentGroup:contact-->
<div id="consentGroup-contact" class="rs-cg">
   <div class="rs-cg-text">
      Here is a group of consents, in checkbox form
   </div>

   <div class="rs-cg-select-all">
      <span class="rs-cg-accept-all">
         <input id="acceptAll-contact" type="checkbox" onclick="if (this.checked) { rs.sdk.terms.internal.onAcceptAllConsents('contact', false); }">
         <label for="acceptAll-contact">
            Accept all
         </label>
      </span>
      <span class="rs-cg-decline-all">
         <input id="declineAll-contact" type="checkbox" onclick="if (this.checked) { rs.sdk.terms.internal.onDeclineAllConsents('contact', false); }">
         <label for="declineAll-contact">
            Decline all
         </label>
      </span>
   </div>

   <ul style="list-style: none" class="rs-cg-check">
      <li class="rs-cg-consent-check">
         <input id="C-9a8b7-12345-edfba.contact" type="checkbox" onclick="rs.sdk.terms.internal.onToggleConsent('contact')">
         <label for="C-9a8b7-12345-edfba.contact">
            Contact me about products
         </label>
      </li>
      <li class="rs-cg-consent-check">
         <input id="C-9a8b7-12345-98765.contact" type="checkbox" onclick="rs.sdk.terms.internal.onToggleConsent('contact')">
         <label for="C-9a8b7-12345-98765.contact">
            Contact me about services
         </label>
      </li>
   </ul>
</div>
  • Display an "Accept" button, which performs terms acceptance for the selected consents:
Placeholder: <!--rs.sdk:accept:Do you accept these terms?-->
<button onclick="this.disabled = true; rs.sdk.terms.internal.onAcceptTerms()">
  Do you accept these terms?
</button>