XC5 JSON System Provisioning usage and examples

The XC5 JSON System API provides network operators the ability to automate provisioning of the XC5 system through JSON over HTTPS.

A note on testing the API
For API testing designcom recommends and uses Postman

API Usage

Access & Authentication

  • The API uses Basic Authentication for access control, which in most cases will be deployed over HTTPS, and optionally HTTP for select in-house provisioning.
  • The API also supports authentication through Cookie/Secure;HttpOnly JSON Web Tokens however this has been omitted from this document for brevity.
  • The Username/password for Authentication is validated against existing XC5 accounts. To enable to System API for an xc5 account, the username/account must be enabled and have accountresource:api_access=system.
  • Partitioned API access can be granted to a specific account and all descendants using accountresource:api_access=user.
  • This document's examples exclude Authorization details

Most clients will allow basic auth to be specified on the Request Line

(json)
GET https://user:pass@example.com/api-sys/

sends the following to exmple.com

(json)
GET /api-sys/
Authorisation: Basic dXNlcjpwYXNz

Paths

Paths allow you to drill down through the relational data

  • GET /api-sys/account : View all accounts <replies lean account data>
  • GET /api-sys/account/26DF146A-02E3-4A25-AE3F-08FE87DE6674 : View a single account by guid. <replies verbose account data>
  • GET /api-sys/account/alice@example.net : View a single account by accountname
  • GET /api-sys/account/26DF146A-02E3-4A25-AE3F-08FE87DE6674/number : View all numbers of a single account
  • GET /api-sys/account/26DF146A-02E3-4A25-AE3F-08FE87DE6674/number/E6134D37-104E-4320-AEE8-030300F3BF1A : View a specific number

(json)
GET https://user:pass@example.com/api-sys/account/26DF146A-02E3-4A25-AE3F-08FE87DE6674/number
HTTP/1.1 200
content-type: application/hal+json
transfer-encoding: chunked
[{
  "guid": "E6134D37-104E-4320-AEE8-030300F3BF1A",
  "number": "6499740205",
  "assigned": "dave@dcom",
  "is-pilot": true,
  "alert-info": "dr4",
  "account-code": "",
  "_links": {
    "self": {
      "href": "/api-sys/account/26DF146A-02E3-4A25-AE3F-08FE87DE6674/number/E6134D37-104E-4320-AEE8-030300F3BF1A"
    },
    "parent": {
      "href": "/api-sys/account/26DF146A-02E3-4A25-AE3F-08FE87DE6674"
    }
  }
}]

JSON+HAL links

  • Data is returned with relational links
  • The _links data is read-only
  • The content referred to by the link may accept updates.

Requests

  • CRUD supported through: GET,PUT,PATCH,DELETE (https://en.wikipedia.org/wiki/Create,_read,_update_and_delete)
  • PUT & PATCH both update existing data. PUT creates if required.
  • Can use PUT with the url parameter ?patch=true for clients that don't support PATCH
  • Put/Patch JSON content as an object only. Arrays not accepted
  • Partial PUT/PATCH is supported. Update only the required data
  • Partial PUT/PATCH return the full data-set
  • OPTIONS supported to return path specific documentation
(json)
PUT /api-sys/account/26DF146A-02E3-4A25-AE3F-08FE87DE6674/number/E6134D37-104E-4320-AEE8-030300F3BF1A?patch=true
content-type: application/json
content-length: 44
{ "alert-info":null }
HTTP/1.1 200
content-type: application/hal+json
transfer-encoding: chunked
[{
  "guid": "E6134D37-104E-4320-AEE8-030300F3BF1A",
  "number": "6499740205",
  "assigned": "dave@dcom",
  "is-pilot": true,
  "alert-info": "",
  "account-code": "",
  "_links": {
    "self": {
      "href": "/api-sys/account/26DF146A-02E3-4A25-AE3F-08FE87DE6674/number/E6134D37-104E-4320-AEE8-030300F3BF1A"
    },
    "parent": {
      "href": "/api-sys/account/26DF146A-02E3-4A25-AE3F-08FE87DE6674"
    }
  }
}]

Responses

  • An HTTP/1.1 status code is returned
  • Content-Type: application/hal+json
  • Single or multiple records may be returned. The API frames records within a JSON array in both cases
  • Errors reply: 4xx http response. The content provides more detail
(json)
GET /api-sys/x
HTTP/1.1 404
status: 404
content-type: application/hal+json
transfer-encoding: chunked
[{
  "error": "invalid path"
}]
NOTE: The response is always an array. use response[0].error

The API index

  • Query the root to find available API's.
(json)
GET /api-sys/

Path specific Documentation

  • Issue OPTIONS against a path
  • OPTIONS does not require a context, so use * as a context placeholder

(json)
OPTIONS /api-sys/account/*/number
HTTP/1.1 200
content-type: application/hal+json
[
    {
        "description": "Manage account phonenumbers",
        "methods": [
            "GET",
            "PUT",
            "PATCH",
            "DELETE",
            "OPTIONS"
        ],
        "fields": {
            "guid": {
                "type": "string",
                "description": "Unique identifier for each entry"
            },
            "number": {
                "type": "string",
                "description": "The e.164 phone number. Numbers must be unique, or prefixed with a: if outgoing rewrite is allowed"
            },
            "is-pilot": {
                "type": "boolean",
                "description": "Indicates to use this number a a default for invalid presented caller number"
            },
            "cfa": {
                "type": "string",
                "description": "An e.164 destination. Creates a call-forward-all for calls to this number"
            },
            "alert-info": {
                "type": "string",
                "description": "Assigns a value to the sip Alert-Info header for distinctive ring"
            },
            "account-code": {
                "type": "string",
                "description": "Free for use associated data"
            }
        }
    }
]


A business vPBX example

This example shows the basic requirements for setting up a virtual PBX environment with a front door auto-attendant and conference room for Test Company acmebrick.x.co.nz.

Optional settings are applied at each extension as an example.
Our example is hosted for company x.co.nz. "The acmebrick company" can access their virtual environment through a wildcard domain "acmebrick.x.co.nz"
We will setup the organization "acmebricks" with two users, the Receptionist on DDI 6491231234 extension 600, and Sales on DDI 6499290089 extension 608.

  • Both users will have voicemail
  • All calls to the receptionist will be recorded.
  • Users will be added to a blast and hunt group
  • Both users will be added to the Front Door IVR queue

Creating the virtual environment

First we need to create a space to add the company accounts to.
We do this by calling a basic JSON command in the Postman application.

(json) exec API 'PUT /api-sys/account/', '{"username":"acmebrick.x.co.nz"}'

Create the receptionist account

Use a PUT to add the new data.
We do it through the parent , or specify the parent in the data.
A password will be generated for you.

(json) exec API 'PUT /api-sys/account/acmebrick.x.co.nz/child', '{"username":"reception@acmebrick.x.co.nz"}' 

View the newly created account by calling a JSON GET with the account name.

(json) exec API 'GET /api-sys/account/reception@acmebrick.x.co.nz' 

Assign a DDI to the receptionist

Pick an unused DDI from your pool

(json) exec API 'PUT /api-sys/account/reception@acmebrick.x.co.nz/number', '{ "number":"6491231234"}' 

Advanced
If using XC5 to manage DDI's, The _unassigned.pool account holds free numbers. We can view a filtered selection.
(json) exec API 'GET /api-sys/account/reception@acmebrick.x.co.nz/numberallocate?filter=%88' 
"Allocate" a DDI using a PUT to link the number to the account we've just created
(json) exec API 'PUT /api-sys/account/reception@acmebrick.x.co.nz/number/D5A51C5C-F762-4E82-8B3E-7CB15662D40C' 

View your changes

(json) exec API 'GET /api-sys/account/reception@acmebrick.x.co.nz/number' 

Register the receptionist phone

We can now register the receptionist phone using the username and password for the phone's authorization credentials, and we use the assigned number as the caller in their configuration.

Let's look at their registration

(json) exec API 'GET /api-sys/account/reception@acmebrick.x.co.nz/reg' 

Create a Call Divert to Voicemail for the receptionist

Add a new Account Route

The order of the Account Route is important. Please read the API documentation here for a detailed description of how to use Account Routes.

(json) exec API 'PUT /api-sys/account/reception@acmebrick.x.co.nz/route','{ "order":200, "destination":"email:reception@acmebrick.x.co.nz" }' 

Modify the default behaviour of the account

Let's reduce the call forward time by reducing the time we attempt to ring the reception phone.
We could have included this in step 1, however this may have been an after thought or extra requirement not original specified.

(json) exec API 'PATCH /api-sys/account/reception@acmebrick.x.co.nz','{ "cfna_duration":10 }' 

We also want to record all calls made TO reception. This requires an account route.

The route will have no diversion, it just adds additional and optionally conditional data to the call.
The recording destination needs to be added before call is attempted at Route 0, so we add the route at -12 purely for consistency with the Callrule

(json) exec API 'PUT /api-sys/account/reception@acmebrick.x.co.nz/callrule','{ "order":-12, "record_email":"reception@acmebrick.x.co.nz" }' 

Create a Sales line

(json) exec API 'PUT /api-sys/account/acmebrick.x.co.nz/child', '{"username":"sales@acmebrick.x.co.nz"}' 
(json) exec API 'PUT /api-sys/account/sales@acmebrick.x.co.nz/number', '{ "number":"6499290089"}' 

View the newly created account by calling a JSON GET with the account name.

(json) exec API 'GET /api-sys/account/sales@acmebrick.x.co.nz' 

Allow extension dialing

Now we want Reception and Sales to have internal extension numbers to ease intra-office calling.

The extension plan is created using call rules - like Speeddials. We create the rules on the parent acmebrick.x.co.nz, such that both Sales and Reception can inherit the same plan.
We will standardize our extension call rules at -2. Multiple conditional call rules can exist at the same order.
The prefix condition of callrules is based on the e164 translated dialed number.

Extension numbers are not meaningful PSTN numbers as we base these callrules on the prefix_raw field. This is the untranslated dialed number.
We also rewrite the destination as the extension using the : prefix. This indicates the number is not a PSTN e164 number"

(json) exec API 'PUT /api-sys/account/acmebrick.x.co.nz/callrule','{ "order":-2, "prefix_raw":"600", "username":"reception@acmebrick.x.co.nz", "destination":":600"} ' 
(json) exec API 'PUT /api-sys/account/acmebrick.x.co.nz/callrule','{ "order":-2, "prefix_raw":"608", "username":"sales@acmebrick.x.co.nz", "destination":":608"}' 

Add phones to a Pickup Group

Lets allow Sales to pickup a ringing reception phone and vice versa by adding a pickup group to each.

We could assign pickup_group to each phone, but we can also assign just the virtual environment enabling both sales and reception to inherit the same group.

(json) exec API 'PUT /api-sys/account/acmebrick.x.co.nz','{ "pickup_group":"Alpha" }' 

Completed Stage One.
You should now be able to makes calls to and from these phones. They will be able to cal each other using their 3-digit extension and both will be able to pick up each their ringing phone.

Add a simple inbound Queue

Add phones to a Hunt Group

Hunt groups can be used to sequentially distribute calls to members of the group.

Create a huntgroup for acmebrick.x.co.nz:

(json) exec API 'PUT /api-sys/account/acmebrick.x.co.nz/child','{ "username":"main_entry@acmebrick.x.co.nz" }' 

Bind a public DDI to the hunt group so we can call it:

(json) exec API 'PUT /api-sys/account/main_entry@acmebrick.x.co.nz/number', '{ "number":"6499290087"}' 

Add Reception and Sales to the hunt group (account route)

We set the hunt_user field to true.
We will add the members at order 100 and 101. This sets up the sequential hunt.
The username will be called if not busy. The routes for the called username will also not apply.

(json) exec API 'PUT /api-sys/account/main_entry@acmebrick.x.co.nz/route', '{ "order":"100","username":"reception@acmebrick.x.co.nz","hunt_user":true, "ring_seconds":10 }' 
(json) exec API 'PUT /api-sys/account/main_entry@acmebrick.x.co.nz/route', '{ "order":"101","username":"sales@acmebrick.x.co.nz","hunt_user":true, "ring_seconds":10 }' 

Finally, forward the hunt to voicemail --> email (account route)

(json) exec API 'PUT /api-sys/account/main_entry@acmebrick.x.co.nz/route','{ "order":200, "destination":"reception@acmebrick.x.co.nz" }' 

Completed Stage Two.
Calls to the public DDI 6499290087 will sequentially hunt across Reception and Sales. If neither answer, the call will be directed to voicemail. Reception and Sales can pick up each others call.

Prompt uploading

When we setup the reception voice to email divert, we didn't specify a prompt so the default system prompt was played.
Lets improve this by specifying a prompt for the hunt groups divert.

Note: in postman use Body type form-data, set key to prompt_Data and type to file. Attach a wav or .mp3 file.It returns the created prompt with a self link or guid. We need to remember this guid to add a description and to link it to the IVR route. We can also supply the initial guid (Use /api-sys/guid to generate a new guid for this purpose)
(json) exec API 'GET /api-sys/guid' Returned: 4319C6B9-EAEF-4583-97B3-1CC13514EED4 

(json) exec API 'PUT /api-sys/account/main_entry@acmebrick.x.co.nz/prompt/4319C6B9-EAEF-4583-97B3-1CC13514EED4','..form data of file...' 

The returned data also includes the uploaded prompt_length

Assign a description

(json) exec API 'PATCH /api-sys/account/main_entry@acmebrick.x.co.nz/prompt/4319C6B9-EAEF-4583-97B3-1CC13514EED4','{ "description":"MyMessageGreeting"}' 

Create a final call forward to record/email, and include the prompt

(json) exec API 'PUT /api-sys/account/main_entry@acmebrick.x.co.nz/route','{ "order":200, "destination":"email:reception@acmebrick.x.co.nz","promptguid":"4319C6B9-EAEF-4583-97B3-1CC13514EED4"}' 

Call destination blocking

We may need to stop reception from calling international destinations.

Find a pre-defined location to use:
(json) exec API 'GET /api-sys/location?filter=<CallR%' 

Lets use <CallRule-International>. You may use set any text to appear in the 404 message. In this case we will use "destination blocked"

Lets standardize our destination blocking callrules at order -14

(json) exec API 'PUT /api-sys/account/reception@acmebrick.x.co.nz/callrule','{"order":-14,"location":"<CallRule-International>", "destination":"drop:404:destination blocked"}' 

Also, we should block mobile too

(json) exec API 'PUT /api-sys/account/reception@acmebrick.x.co.nz/callrule','{"order":-14,"location":"<CallRule-Mobile>","destination":"drop:404:destination blocked"}' 

Completed Stage Three.
Prompts should be uploaded and calls made to international destinations will be blocked

Create the Front Door IVR with prompts and key presses

We need to create an after hours attendant that can route to mail or a blast group.

Blast Group (aka Ring Group)

Lets create the blast group first, using forking.

(json) exec API 'PUT /api-sys/account/acmebrick.x.co.nz/child', '{"username":"blast@acmebrick.x.co.nz"}' 

We add the DDI's to the blast group (we are working on allowing usernames instead as well)

(json) exec API 'PUT /api-sys/account/blast@acmebrick.x.co.nz/fork', '{"destination":"6499290088"}'
exec API 'PUT /api-sys/account/blast@acmebrick.x.co.nz/fork', '{"destination":"6499290089"}'

Time of Day After Hours prompt

Let's create our after hours prompt. We want to record this prompt through the reception phone, rather than upload the wav file

(json) exec API 'PUT /api-sys/account/main_entry@acmebrick.x.co.nz/prompt/','{"description":"After Hours Menu"}' 

The guid (ECB3B334-5F1D-4CD7-8446-675FC7476E31), and a group_access code *2200101 is returned.
We can ring *2200101 from any phone within the acmebrick organization to record this prompt.

Some phones have dial-planners that will not pass *22. We create an "early_rule" in acmebrick.x.co.nz to allow a pre-smartphone translation from 14 to *.

Now we can dial 142200101 to record our prompt

(json) exec API 'PUT /api-sys/account/acmebrick.x.co.nz/callrule','{ "order":-2, "prefix_raw":"14", "destination":"*%", "early_rule":true }'

Hunt Group

Now we insert the autoattendant at the start of our huntgroup. We have members at 100, so we will standardize our menus at order -8. This will allow the menu to precede the members and calling any registered contact

We signify this as Menu 1. All IVR/autoattent menus start at 1. However, this one will only be chosen when the specified TimeOfDay matches

The menu has a digit_map. This waits for input and maps the pressed DTMF to a new action. We will make the action jump to menu #2 or menu #3 based on the pressed digit.

We will let those sub-menus implement the action

Menu #1
(json) exec API 'PUT /api-sys/account/main_entry@acmebrick.x.co.nz/route', '{"order":-8,"menu_level":1, "time_definition":"nz_holidays,!Mon-Thur 08:30-17:00","digit_map":"1=#3,5=#2,T=#3","promptguid":"ECB3B334-5F1D-4CD7-8446-675FC7476E31"}' 

Menu #2 will route direct to the blast group
(json) exec API 'PUT /api-sys/account/main_entry@acmebrick.x.co.nz/route', '{"order":-8,"menu_level":2, "username":"blast@acmebrick.x.co.nz"}' 

Menu #3 will play the greeting and forward to email
(json) exec API 'PUT /api-sys/account/main_entry@acmebrick.x.co.nz/route', '{"order":-8,"menu_level":3, "destination":"email:dave@dcom.co.nz","promptguid":"4319C6B9-EAEF-4583-97B3-1CC13514EED4"}' 

Conference Service line

Lets create a conference room with a public DDI

(json) exec API 'PUT /api-sys/account/acmebrick.x.co.nz/child', '{"username":"conference@acmebrick.x.co.nz"}' 
(json) exec API 'PUT /api-sys/account/conference@acmebrick.x.co.nz/number', '{"number":"6499290085"}' 

Conference PIN

We can place a pin on the conference room using a menu

Here we use a prompt "Plese enter your PIN" already loaded into the _prompt.shared infrastructure space.

Note the digit_map maps the correct PIN directly to a conference room conference:6499290085. This is a system wide room and must be unique

(json) exec API 'PUT /api-sys/account/conference@acmebrick.x.co.nz/route', '{"order":-8,"menu_level":1, "digit_map":"5666=conference:6499290085","promptguid":"F4FE3E59-0439-4849-9444-85BEFE8694B3"}' 


Account setup with basic options (beta)

A basic account with default settings may be all that is required. This example will provision a _tel account with POTS features only. Any additional features could be added using the examples above, or making reference to the API.

We have included a "note" key to help describe each feature. It is not required.

Create the account 6499878037 with basic features

(json)
PUT /api-sys/HydraAccount/6499878037
content-type: application/json
{
"password":"5gjgosk2@#",
"cfna_dest":"6499650085",
"cfna_active":true,
"note":"Sets a callforward no-answer (including busy) to the voicemail destination",
"ums_pin":"5676",
"note":"Creates mailbox or resets pin. Use ums_pin:null to remove mailbox",
"concurrent_limit":2,
"note":"point c: concurrent_limit=2 allows call hold, concurrent_limit=1 disables. use for single lines only",
"private":1,
"note":"point e: private controls caller presentation",
"callerid":true,
"note":"point d: callerid allows/disables displaying the caller on the compass phone. "
}

GET the account 6499878037
(json)
GET /api-sys/hydraaccount/6499878037

DELETE the account 6499878037
(json)
DELETE /api-sys/hydraaccount/6499878037

More detail on the hydraaccount API
(json)
OPTIONS /api-sys/hydraaccount