- Print
- DarkLight
- PDF
The Journey Hub API allows OEM organizations to automate the management of Organizations, Users, and Projects.
Hub API Authentication Process
- 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".
- On the same page, copy your user id.
- Create the hash (see instructions below)
- Create a 'POST' request to the /token route (see 'Request Object' format below)
- 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 details for all of the endpoints.
Creating Hash for Provisioning APIs
In order to receive an authorization token to access the provisioning APIs, a user must 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.
Values defined inside <> are meant to be filled in by the user with their credentials. For example, <user-id> should replace the user's actual id.
{
"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
var crypto = require('crypto');
var hashSecret = function(secret, nonce) {
var hash = crypto.createHash('sha256');
hash.update(secret + nonce);
return hash.digest('hex');
}
require 'digest'
def hashSecret(secret, nonce)
Digest::SHA256.hexdigest(secret + nonce)
end
import hashlib
def hashSecret(secret, nonce):
return hashlib.sha256(secret + nonce).hexdigest()
<?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 organizations:
''' 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"]})')