Journey Hub API

The Journey Hub API allows OEM organizations to automate the management of Organizations, Users and Projects. 

Hub API Authentication Process

  1. Generate a secret key (you must be a Journey Hub owner) by going to the admin section, clicking users and selecting yourself from the left panel. Then you will see a button to "generate key".
  2. On the same page, copy your user id.
  3. Create the hash (see instructions below)
  4. Create a 'POST' request to the /token route (see 'Request Object' format below)
  5. The response returns a token and an expiration time. You can now include the token in the headers in order to access the user, org, and project routes.

Hub API End Points 

  • /token

  • /org
  • /project
  • /user

Full PDF documentation gives the detail for all of the end points. 

Creating Hash for Provisioning APIs

In order to receive an authorization token to access the provisioning APIs, a user much submit an encrypted value based on their secret key, user id and a user defined salt/nonce. The user then passes the id, nonce/salt, and hash as an object in the request body to the 'POST: /token' route to receive a token. All other provisioning APIs are not accessible without a token.

Note: values defined inside <> are meant to be filled in by the user with their credentials. For example, <user-id> should be replaced with the user's actual id.

Request Object
{
  "userId": <user-id>,
  "nonce": <user-defined-string>,
  "hash": <hashed-value>
}

How to create the hash by language

Cryptographic Hash: SHA-256

Return Value: Hexadecimal representation of binary hash


NOTE: DO NOT REUSE THE SAME NONCE/SALT. CHOOSE DIFFERENT VALUES EACH TIME YOU CALL THE '/TOKEN' ROUTE

NodeJS

var crypto = require('crypto');
var hashSecret = function(secret, nonce) {
	var hash = crypto.createHash('sha256');
	hash.update(secret + nonce);
	return hash.digest('hex');
}

Ruby

require 'digest'
def hashSecret(secret, nonce)
  Digest::SHA256.hexdigest(secret + nonce)
end

Python

import hashlib
def hashSecret(secret, nonce):
    return hashlib.sha256(secret + nonce).hexdigest()

PHP

<?php
function hashSecret($secret, $nonce) {
  return hash('sha256', $secret . $nonce);
}
?>

Javascript Code Sample


/*
 * This code sample creates an new organization, user and project. 
 * First, you need to get an authorization token using your 
 * secret key from the UI (only admins can generate secret keys).
 * You must include the token in the headers to
 * access the user, org, and project routes if you have an authorization token.
 * Information on creating the hash for the /token route can be found at <somewhere-wonderful>
 */


// library for making http calls
var request = require('request');
// library to generate unique time based nonce for hashing secret
var UUID = require('uuid-js');

// header object for requests
var headers = {
  // authorization will be set after an authorization token is generated
  'authorization': null,
  'content-type': 'application/json'
}

// url for creating authorization token - replace <url> with your end point 
var tokenPostURL = '<url>' + '/api/v1/token';
// url to post users
var userPostURL = '<url>' + '/api/v1/user/org/';
// url to post a new organization
var orgPostURL = '<url>' + '/api/v1/org';
// url to post a project 
var projectPostURL = '<url>' + '/api/v1/project/org/';
// url to put template connections in a project
var projectPutURL = '<url>' + '/api/v1/project/';

// credentials that need to be passed in order to get an authorization token
// for more information on creating the hash see <other-wonderful-stuff>
var credentials = {
  // user id must be passed in as a string
  id: '1',
  // time based uuid id as nonce
  nonce: UUID.create(1).toString(),
  hash: '<insert-hashed-value>'
}

// new organization information (to be used in the request body)
// We are not passing in a parentId and will instead use the default
var newOrganization = {
  name: 'Brand Spanking New Org'
}

// user array to add to request body
var users = [
  {
    name: 'Steve Owner',
    email: 'steve@owner.com',
    role: 'Owner'
  },
  {
    name: 'Sally Member',
    email: 'sally@member.com',
    role: 'Member'
  },
  {
    name: 'Jack Admin',
    email: 'jack@admin.com',
    role: 'Member'
  }
]

// new project information to be added to request body
var newProject = {
  name: 'Best Project Ever',
  description: 'This is the best project ever made :)',
  // you can retrieve template ids from the GET '/org/:org_id/templates' route
  templateId: '<insert-template-id>'
}

// construct the options passed as first parameter in all requests
var createOptions = function(url, body, id) { 
  return {
    url: id ? url + id : url,
    headers: headers,
    body: JSON.stringify(body)
  }
}

/*
 * AUTHORIZATION STEP: 
 * Generate a token to access user, organization and project routes
 */
request.post(createOptions(tokenPostURL, credentials), function handleGenerateToken(err, res, body) {
  if(err || (res && res.statusCode !== 200)) {
    console.log(err || 'ERROR: ' + JSON.parse(body).metadata.message);
    return;
  }

  // convert the response to json
  var formattedTokenBody = JSON.parse(body).token;
  // set the token in the headers object 
  headers.authorization = formattedTokenBody[0].token;
  
  /*
   * CREATE ORGANIZATION: 
   * Post a new organization to host the project and users
   */
  request.post(createOptions(orgPostURL, newOrganization), function handleCreatedOrg(err, res, body) {
    if(err || (res && res.statusCode !== 200)) {
      console.log(err || 'ERROR: ' + JSON.parse(body).metadata.message);
      return;
    }
    // extract the organization id from the response
    var formattedOrgBody = JSON.parse(body).organizations;
    var orgId = formattedOrgBody[0].id;
    console.log('Congrats! You just created an organization!');

    /* 
     * CREATE PROJECT:
     * create a project and add it to the newly created organization
     */
    request.post(createOptions(projectPostURL, newProject, orgId), function handleCreatedProject(err, res, body) {
      if(err || (res && res.statusCode !== 200)) {
        console.log(err || 'ERROR: ' + JSON.parse(body).metadata.message);
        return;
      }
      console.log('Congrats! You just created a project!');
      
      var formattedProjectBody = JSON.parse(body).projects;
      // extract the new project id
      var projectId = formattedProjectBody[0].id;

      // check if response contains template connections
      if(formattedProjectBody[0].templateConnections.length !== 0) {
        // extract the template connections from the response body 
        // and format each connection into correct format for adding it to the project via a PUT
        var templateConnections = formattedProjectBody[0].templateConnections.map(function(connection) {
          return {
            id: connection.id,
            details: {
              type: connection.type
            }
          }
        });

        /* 
         * ADD TEMPLATE CONNECTIONS: 
         * using the response from 'POST', you can now add template connections to the project
         */
        request.put(createOptions(projectPutURL, { connections: templateConnections }, projectId), function handleTempConnections(err, res, body) {
          if(err || (res && res.statusCode !== 200)) {
            console.log(err || 'ERROR: ' + JSON.parse(body).metadata.message);
            return;
          }

          console.log('Congrats! You just added template connections to your project!');
        })
      }
    });
    
    /* 
     * ADD TEMPLATE CONNECTIONS: 
     * add users to the newly created organization
     */
    request.post(createOptions(userPostURL, users, orgId), function handleAddedUsers(err, res, body) {
      if(err || (res && res.statusCode !== 200)) {
        console.log(err || 'ERROR: ' + JSON.parse(body).metadata.message);
        return;
      }

      var formattedUserBody = JSON.parse(body).users;
      console.log('Congrats! You just added users to your organization!');
    });
  });
}); 

Python Code Sample

List the organisations: 

''' Sample Python Code for Xponent Journey Hub API '''
# Python Sample Code to create orgs etc

import hashlib
import uuid
import json
import requests

# Your API secret here - from Admin -> users 
mysecret = 'mylongsecret'
# Your user Id - as a string
myId='1234567'
nonce = str(uuid.uuid1())

def hashSecret(secret, nonce):
    return hashlib.sha256(secret + nonce).hexdigest()

# header object for requests
headers = {
    # authorization will be set after an authorization token is generated
    'authorization': None,
    'content-type': 'application/json'
    }

credentials = {
  # user id must be passed in as a string
  'userId'   : myId,
  # time based uuid id as nonce
  'nonce': nonce,
  'hash' : hashSecret(mysecret,nonce)
}

# url for creating authorization token - replace <url> with your end point
url='http://localhost:3000/api/v1/'

# Request the token using the calculate credentials 
r = requests.post(url+'token',data=credentials)
if r.status_code <> 200 : 
   raise Exception(str(r.text))

# Now we should have a token 
token = dict(r.json())['tokens'][0]['token']

# Get the organizations
r = requests.get(url+'org',headers={'Authorization' : token })
if r.status_code <> 200 : 
   raise Exception(str(r.text))

orgs=dict(r.json())['organizations']
# Print out the Orgs
print "\nList of Organizations:\n"
print "%20s\t%20s\t%20s" % ("Organization Name","Id","ParentId")
for o in sorted(orgs, key=lambda k: k['id']) : 
    print "%(name)20s\t%(id)20s\t%(parentId)20s" % o

# Create a new Org 
r = requests.post(url+'org',headers={'Authorization':token},
                  data={ "name" : "neworg-"+str(uuid.uuid1())[:5], "parentId" : 1})
if r.status_code <> 200 : 
   raise Exception(str(r.text))

newOrg = dict(r.json())['organizations'][0]
print "\nSuccessfully created new Org %(name)s (%(id)s)" % newOrg
# Change the name of the org 
r = requests.put(url+'org/'+newOrg['id'],headers={'Authorization':token},
                 data={ "name" : "changed-"+str(uuid.uuid1())[:5]})
if r.status_code <> 200 : 
   raise Exception(str(r.text))
changeOrg = dict(r.json())['organizations'][0]
print "\nSuccessfully changed org name %s to %s (%s) \n" % (newOrg['name'], changeOrg['name'], changeOrg['id'])
# Add it to the list of orgs
orgs.append(changeOrg)

# Clean down - delete the org we created  
r = requests.delete(url+'org/'+changeOrg['id'],headers={'Authorization':token})
if r.status_code <> 200 : 
    raise Exception(str(r.text))
print "Successfully deleted Org %(name)s (%(id)s)" % changeOrg

Create and delete an organization: 

''' Sample Python Code for Xponent Journey Hub API - Create and delete organization '''
# Python Sample Code to create orgs etc
from os import environ
import hashlib
import uuid
import json
import requests

# Check that we have the correct environment variables first before we do anything else
if environ.get('KW_HUB') is None or environ.get('KW_USERID') is None or environ.get('KW_SECRET') is None:
    print('The KW_HUB, KW_USERID and KW_SECRET environment variables need to be set for this script')
    exit(1)

# Hub Fully qualified hostname
myHub = environ.get('KW_HUB')
# Your user Id - as a string
myId = environ.get('KW_USERID')
# Your API secret here - from Account Settings page for this user
mySecret = environ.get('KW_SECRET')
# A nonce used to hash the secret
nonce = str(uuid.uuid1())


def hashSecret(secret, nonce):
    return hashlib.sha256((secret+nonce).encode('utf-8')).hexdigest()


# header object for requests
headers = {
    # authorization will be set after an authorization token is generated
    'authorization': None,
    'content-type': 'application/json'
}

credentials = {
    # user id must be passed in as a string
    'userId': myId,
    # time based uuid id as nonce
    'nonce': nonce,
    'hash': hashSecret(mySecret, nonce)
}

# url for creating authorization token - replace <url> with your end point
url = 'https://{}/api/v1/'.format(myHub)

# Request the token using the calcculate credentials
r = requests.post(
    url+'token', headers={'Content-Type': 'application/json'}, json=credentials)
if r.status_code != 200:
    raise Exception(str(r.text))

# Now we should have a token
token = dict(r.json())['tokens'][0]['token']
#print '\nSuccessfully got token: '+token+'\n'

# Create a new Org
r = requests.post(url+'org', headers={'Authorization': token},
                  json={"name": "neworg-"+str(uuid.uuid1())[:5], "parentId": '1'})
if r.status_code != 200:
    raise Exception(str(r.text))

newOrg = dict(r.json())['organizations'][0]
print(f'Successfully created new Org {newOrg["name"]} {newOrg["id"]}')
# Change the name of the org
r = requests.put(url+'org/'+newOrg['id'], headers={'Authorization': token},
                 json={"name": "changed-"+str(uuid.uuid1())[:5]})
if r.status_code != 200:
    raise Exception(str(r.text))
changeOrg = dict(r.json())['organizations'][0]
print(f'Successfully changed org name {newOrg["name"]} to {changeOrg["name"]} ({changeOrg["id"]})')

# Clean down - delete the org we created
r = requests.delete(
    url+'org/'+changeOrg['id'], headers={'Authorization': token})
if r.status_code != 200:
    raise Exception(str(r.text))
print(f'Successfully deleted Org {changeOrg["name"]} ({changeOrg["id"]})')





Privacy Policy
© 2022 CSG International, Inc.