In order to scale an enterprise deployment, developers typically automate the creation of accounts (users) and groups. nVoq's organizational hierarchy allows
for the creation of organization structures that reduce administrative overhead by allowing the application of certain operations to groups of accounts.
For example, if a hospital was located on Squeezepenny Lane, the custom vocabulary word "Squeezepenny" could be added once and applied to all the
accounts within the hospital's organization hierarchy. It then becomes part of those accounts' vocabularies through one administrative operation. This prevents
errors from duplicated data spread across an organization and simplifies troubleshooting.
The nVoq API allows for organization creation (company, division, and group) within each tenant. Accounts can be assigned to groups for performing dictation
and matching operations. Administrative access can be granted at each level in the organization hierarchy as appropriate. Subscription and billing options
can be managed via the API as well.
This How-To covers the creation and management of organizations within your tenant's organizational hierarchy.
Before You Begin
Background Info
If you are not already familiar with nVoq's organization hierarchy functionality, please check out the Organizations page on our support site
that walks you through how organizations are structured, administered, and used to organize accounts and control administrative
privileges. The hierarchy has a fixed structure and is illustrated in the diagram below.
API User Account
If your organization has not already been in contact with our Sales team, please complete this short form on the Developer Registration Page
and we will reach out to you regarding a user account and development with our APIs.
Once you have an account, you must change your password before the account can be used for API calls.
External Dependecies
Most platforms do not include a JSON implementation. So, you will need to download the appropriate third
party implementation from one of these locations:
C#:
Newtonsoft Json,
Use Visual Studio Package Manager to install these from NuGet
Start your IDE
The nVoq API is a RESTful Web Services and WebSocket API and therefore does not constrain you to any specific platform or
programming language. We provide sample code below for shell scripting (bash), C#, Java, and JavaScript.
Follow along and run this code in your environment. But, if you prefer C++, Go, or some other language,
that's great! Just adapt the code below to your language's web services functionality and you should be good to go.
Let's Go!
Choose your programming language...
Step 1: Retrieve Full Hierarchy
The first thing to do when working with your organizational hierarchy is to retrieve the
hierarchy as it exists. A simple web services call returns the organization hierarchy as
a JSON document. The member variables and helper methods are available in the full sample
source code at the bottom of this document.
#!/bin/bash
#TBD
import java.io.*;
import org.json.simple.*;
import org.json.simple.parser.*;
import java.net.*;
import java.util.*;
public class Program {
// Your username
private String username = "yourUsername";
// Your password
private String password = "yourPassword";
// Server URL
private String baseUrl = "https://test.nvoq.com";
// Topmost Organization in the hierarchy accessible to API user
private Organization myTopLevelOrg = null;
// Enterprise Pricing Plan Reference
private Plan myEnterprisePlan = null;
// the Location Header returned from the last Organization Operation
private String lastLocation = null;
/*
* Retrieve the organizations visible to this user.
*/
private void getOrganizations() {
String url = baseUrl + "/SCVmcServices/rest/organizations";
try {
StringBuffer sb = httpHelper("GET", url, null);
myTopLevelOrg = new Organization(sb.toString());
} catch (Exception e) {
System.out.println(e.toString());
}
return;
}
/*
* Helper Method to make a HTTP request and return a StringBuffer with
* the HTTP response body. The contents of the Location HTTP header field
* are also stored in the lastLocation variable for future reference.
*/
private StringBuffer httpHelper(String operation, String url, String content) {
StringBuffer sbIn = null;
lastLocation = null;
try {
URL myurl = new URL(url);
HttpURLConnection con = (HttpURLConnection) myurl.openConnection();
con.setDoOutput(true);
String credentials = username + ":" + password;
String basicAuth = "Basic " + new String(Base64.getEncoder().encode(credentials.getBytes()));
con.setRequestProperty("Authorization", basicAuth);
con.setRequestMethod(operation);
if (operation.equalsIgnoreCase("POST")) {
con.setRequestProperty("Content-Type", "application/json");
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.write(content.getBytes());
wr.flush();
}
lastLocation = con.getHeaderField("Location");
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
sbIn = new StringBuffer();
String inputLine;
while ((inputLine = in.readLine()) != null)
sbIn.append(inputLine);
in.close();
return sbIn;
} catch (Exception e) {
System.out.println(e.toString());
if (sbIn != null) {
System.out.println(sbIn.toString());
}
}
return null;
}
/*
* Inner class to represent an organization in the hierarchy.
*/
class Organization {
String myName;
String myLevel;
String myId;
//many more properties actually available...
//child organizations (it's a hierarchy)
ArrayList<Organization> myChildren = new ArrayList<Organization>();
public Organization(String aName, String aLevel, String aId) {
myName = aName;
myLevel = aLevel;
myId = aId;
}
/*
* Creates an organization object from a JSON string
*/
public Organization(String aJsonString) {
try {
JSONParser jsonParser = new JSONParser();
Object obj = jsonParser.parse(aJsonString.toString());
JSONObject jso = (JSONObject) obj;
myName = jso.get("name").toString();
myLevel = jso.get("level").toString();
myId = jso.get("identifier").toString();
JSONArray childArray = (JSONArray) jso.get("children");
childArray.forEach((child) -> this.addChild(child.toString()));
} catch (Exception e) {
System.out.println("Something went wrong: " + e.toString());
}
}
/*
* Add a child org to this organization
*/
public void addChild(String aChildString) {
JSONParser jsonParser = new JSONParser();
try {
Object obj = jsonParser.parse(aChildString);
JSONObject jso = (JSONObject) obj;
Organization newChildOrg = new Organization(jso.toString());
myChildren.add(newChildOrg);
} catch (Exception e) {
System.out.println("something went wrong: " + e.toString());
}
}
/*
* Print out our full hierarchy including orgs, accounts, and plans.
*/
public void print(int level) {
StringBuffer leadIn = new StringBuffer();
for (int x = 0; x < level; x++) {
leadIn.append("--");
}
StringBuffer sb = new StringBuffer();
sb.append(leadIn);
sb.append("+organization: ");
sb.append(myName);
sb.append(" [" + myLevel + "]");
System.out.println(sb);
myChildren.forEach(c -> c.print(level + 1));
}
}
<script>
//TBD
</script>
using Newtonsoft.Json;
using System;
using System.IO;
using System.Net;
using System.Text;
namespace nVoqHttpApiCSharp
{
class Program
{
/**** Begin configuration settings ****/
// Your username
const string Username = "yourUsername";
// Your password
const string Password = "yourPassword";
// Server URL
const string BaseUrl = "https://test.nvoq.com";
//last Location header returned from the server
static string lastLocation = null;
//reference to the top level org in the hierarchy
static Organization topLevelOrg = null;
public static NullValueHandling NullValueHandling { get; set; }
/**** End configuration settings ****/
/*
* Get the top level organization in the hierarchy
*/
private static Organization getOrgs()
{
string url = BaseUrl + "/SCVmcServices/rest/organizations";
string orgHierarchy = httpHelper("GET", url, null);
topLevelOrg = JsonConvert.DeserializeObject<Organization>(orgHierarchy);
return topLevelOrg;
}
/*
* Internal class to represent organizations
*/
public class Organization
{
public string name;
public string level;
public bool enabled;
public string identifier;
public Organization[] children = new Organization[0];
//don't serialize children if there aren't any
public bool ShouldSerializechildren()
{
if (children.Length == 0){
return false;
}
return true;
}
public Organization()
{
}
public void print(int indent)
{
String leadIn = "";
for (int x = 0; x < indent; x++)
{
leadIn = leadIn + "--";
}
String sb = "";
sb = sb + leadIn;
sb = sb + "+organization: ";
sb = sb + name;
sb = sb + " [" + level + "]";
Console.WriteLine(sb);
foreach(Organization org in children)
{
org.print(indent + 1);
}
}
}
/*
* The following methods are helpers for dealing with the
* HTTP API.
*/
private static string httpHelper(string operation, string url, string content)
{
HttpWebRequest request = BuildRequest(operation, url);
if (operation.Equals("POST"))
{
request.ContentType = "application/json";
byte[] bytes = Encoding.ASCII.GetBytes(content);
using (Stream requestStream = request.GetRequestStream())
requestStream.Write(bytes, 0, bytes.Length);
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string responseString = ReadStreamAsUtf8String(response.GetResponseStream());
//Console.WriteLine(responseString);
lastLocation = response.GetResponseHeader("Location");
return responseString;
}
private static HttpWebRequest BuildRequest(string method, string url)
{
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);
httpRequest.Method = method;
httpRequest.Headers.Add("Authorization", "Basic "
+ Convert.ToBase64String(Encoding.ASCII.GetBytes(Username + ":" + Password)));
return httpRequest;
}
private static byte[] ReadStreamAsBytes(Stream s)
{
using (MemoryStream ms = new MemoryStream())
{
byte[] buf = new byte[8192];
int len;
while ((len = s.Read(buf, 0, buf.Length)) != 0)
ms.Write(buf, 0, len);
return ms.ToArray();
}
}
private static string ReadStreamAsUtf8String(Stream s)
{
return Encoding.UTF8.GetString(ReadStreamAsBytes(s));
}
//...
Step 2: Create an Organization
Once you have a starting point, you can add organizations as children of other organizations.
As a developer you will typically have access to the entire hierarchy, beginning with the
tenant organization at the top. As a reminder, the hierarchy is four levels deep.
#TBD
/*
* Creates an org under the specified parent organization, with the appropriate
* level.
*/
private Organization createOrganization(String organizationName, String parentId) {
String url = baseUrl + "/SCVmcServices/rest/organizations/" + parentId + "/children";
//JSON representation of new organization
StringBuffer sb = new StringBuffer();
sb.append("{\"name\": \"" + organizationName + "\",\n");
sb.append("\"enabled\":true }");
String newOrgDefinition = sb.toString();
//post to create the new organization
try {
StringBuffer sbOrg = httpHelper("POST", url, newOrgDefinition);
//returns JSON representation of new org, including unique ID
Organization org = new Organization(sbOrg.toString());
return org;
} catch (Exception e) {
System.out.println(e.toString());
}
return null;
}
And, of course, the API allows for organization deletion. In order to delete an organization,
the child organizations must be deleted and all the accounts in the organization must be
deactivated. Proceed with caution when deleting an organization. Make sure you really want to
remove it.
#TBD
/*
* Delete an organization
*/
private void deleteOrganization(Organization org) {
// First disable the organization (cannot delete until this is done)
String url = baseUrl + "/SCVmcServices/rest/organizations/" + org.myId;
StringBuffer sb = new StringBuffer();
// An organization is disabled by setting the enabled flag to false
sb.append("{\"enabled\":false }");
String disabledOrg = sb.toString();
StringBuffer sbOrg = httpHelper("POST", url, disabledOrg);
// then delete the organization with HTTP DELETE operation
sbOrg = httpHelper("DELETE", url, null);
}
<script>
//TBD
</script>
/*
* Delete an organization. USE WITH CAUTION
*/
private static void deleteOrg(Organization aOrg)
{
String url = BaseUrl + "/SCVmcServices/rest/organizations/" + aOrg.identifier;
//first disable the org
aOrg.enabled = false;
httpHelper("POST", url, JsonConvert.SerializeObject(aOrg));
//then delete the org
httpHelper("DELETE", url, JsonConvert.SerializeObject(aOrg));
}
Full Sample Code
Below is the full sample code. Copy and paste the entire contents of the code below into your favorite editor and
save locally on your machine. Modify the URL's and username/password according to your credentials and
system access. Then, run the program and enjoy all the excitement of securely converting audio to text via
the nVoq.API platform.
If you have any questions, please reach out to support@nvoq.com.