REST API
  • 21 Jul 2021
  • 7 Minutes to read
  • Contributors
  • Dark
    Light
  • PDF

REST API

  • Dark
    Light
  • PDF

Article Summary

Authentication

To obtain an api-key you will initially need to authenticate using a username/password combination.

POST /api/v1/oauth/authorize
Content-Type: application/x-www-form-urlencoded
Accept: application/json

username=demo&password=1234 

On successful authentication, the following json will be returned containing a JWT access token which should b stored for future REST calls.

Response 200 OK
{
    "access_token" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTE4Njc5MzksImV4cCI6Mdvas...",
    "refresh_token" : "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJmODBjYmYzZS1kMWM5LTQwZWItOGZjYS1hY2I4MDU5ZmYyOTcifQ.eyJleH..."
    "refresh_expires_in": 36000
    "expires_in" :  3600
}

The JWT will contain important information, for example, the allowed roles for your user:-

...
"realm_access": {
    "roles": [
      "OrganisationAdmin",
      "AdminRecorder",
      "VoiceChannel"
    ]
  }
...

Head over to jwt.io to take a peak at the full token details. Also there are plenty of libraries to decode the jwt, here is a few:

LanguageLibrary / CMD
Pythonpip install pyjwt
Node.jsnpm install jsonwebtoken
Javamaven: io.jsonwebtoken / jjwt-root / 0.11.1
PHPcomposer require firebase/php-jwt

Refresh Token

The refresh_token expiry is longer than the access_roken expiry. Use will need to use the refresh_token to renew your access_token when it expires.

POST /api/v1/oauth/authorize
Content-Type: application/x-www-form-urlencoded
Accept: application/json

token=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIi...

A successful response will return a new json object as above .

Organisation

Get Organisation Details

GET /api/v1/userAccounts/me 
Authorization: Bearer {access_token}
Accept: application/json
Response 200 OK
{
    "id" : "3h74872eb0731b38efa4d556",
    "name" : "Demo Organisation"
}

Account

List Accounts

GET /api/v1/account 
Authorization: Bearer {access_token}
Accept: application/json 
Response 200 OK
[
    {
        "id" : "5554872eb0731b38efa4d444",
        "name" : "Darren's Pizzas"
    },
    {
        "id" : "5564872eb0731b38efa4d555",
        "name" : "Dean's Taxis"
    }
]

Get Account Details

Get Darren's Pizzas account details

GET /api/v1/account/5554872eb0731b38efa4d444
Authorization: Bearer {access_token}
Accept: application/json 
Response 200 OK
{
    "id" : "5554872eb0731b38efa4d444",
    "name" : "Darren's Pizzas"
    "mbn" : "441234567890",
    "domain" : "darrenspizzas"
}

Get Account Address

Darren's Pizzas Address

GET /api/v1/account/5554872eb0731b38efa4d444/address
Authorization: Bearer {access_token}
Accept: application/json
Response 200 OK
{
    "line1" : "Unit 5 The Old Printworks",
    "line2" : "20 Wharf Rd",
    "level1" : "East Sussex",
    "level2" : "Eastbourne",
    "postalCode" : "BN213AW",
    "country" : "United Kingdom"
}

Update Account Address

Update Darren's Pizzas Address

PUT /api/v1/account/5554872eb0731b38efa4d444/address
Authorization: Bearer {access_token}
Accept: application/json

{
    "line1" : "Unit 5 The Old Printworks",
    "line2" : "20 Wharf Rd",
    "level1" : "East Sussex",
    "level2" : "Eastbourne",
    "postalCode" : "BN213AW",
    "country" : "United Kingdom"
}
Response 204 No Content

Inbound Numbers

Inbound numbers or DDIs connect to voice flows allowing for inbound routing of voice. To allocate a new DDI please see Porting & Allocations

List DDIs

Get Darren's Pizza's inbound ddis

GET /api/v1/account/5554872eb0731b38efa4d444/ddi
Authorization: Bearer {access_token}
Accept: application/json
Response 200 OK
[
    {
        "id" : "7774872eb9991b38efa4d888",
        "name" : "441234567890"
    },
    {
        "id" : "8884872eb9991b38efa4d999",
        "name" : "441234567891"
    }
]

SIP Trunking

Add authorised IP addresses to whitelist the connection of onsite PBX equipment.

List Trunks

Get Darren's Pizza's sip trunks

GET /api/v1/account/5554872eb0731b38efa4d444/trunk
Authorization: Bearer {access_token}
Accept: application/json
Response 200 OK
[
    {
         "id": "66aa8915-834a-3004-8363-9c73690d8fe1",
        "ip": "1.1.1.1,
        "port": 5060,
        "vendor": "generic",
        "callerFormat": "national",
        "calledFormat": "national",
        "description": "Primary IP Address",
        "zone": "eu-west-1",
        "countryCode": "GB"
    }
]

Get Trunk

Get Darren's Pizza's sip trunk

GET /api/v1/account/5554872eb0731b38efa4d444/trunk/66aa8915-834a-3004-8363-9c73690d8fe1
Authorization: Bearer {access_token}
Accept: application/json
Response 200 OK
{
     "id": "66aa8915-834a-3004-8363-9c73690d8fe1",
    "ip": "1.1.1.1,
    "port": 5060,
    "vendor": "generic",
    "callerFormat": "national",
    "calledFormat": "national",
    "description": "Primary IP Address",
    "zone": "eu-west-1",
    "countryCode": "GB"
}

Create a Trunk

Create a Darren's Pizza's sip trunk

POST /api/v1/account/5554872eb0731b38efa4d444/trunk
Authorization: Bearer {access_token}
Accept: application/json
Content-Type: application/json

 {
    "ip": "1.1.1.1,
    "port": 5060,
    "vendor": "generic",
    "callerFormat": "national",
    "calledFormat": "national",
    "description": "Primary IP Address",
    "zone": "eu-west-1",
    "countryCode": "GB"
  }
Response 201 Created

Update a Trunk

Update Darren's Pizza's sip trunk

PUT /api/v1/account/5554872eb0731b38efa4d444/trunk/66aa8915-834a-3004-8363-9c73690d8fe1
Authorization: Bearer {access_token}
Content-Type: application/json

 {
    "id": "66aa8915-834a-3004-8363-9c73690d8fe1",
    "ip": "1.1.1.1,
    "port": 5060,
    "vendor": "generic",
    "callerFormat": "national",
    "calledFormat": "national",
    "description": "Primary IP Address",
    "zone": "eu-west-1",
    "countryCode": "GB"
 }
Response 204 No Content

Hooks

Use flow-hooks to allow 3rd parties to control the flow. event-hooks allow you to receive communication events.

List Hooks

Get Darren's Pizza's hooks

GET /api/v1/account/5554872eb0731b38efa4d444/hook
Authorization: Bearer {access_token}
Accept: application/json
Response 200 OK
[
    {
        "id": "2ad34a16-dc17-42da-b67a-4d68d0046832",
        "app": "flow.generic",
        "url": "http://test.com/myplugin",
        "authType": "DISABLED",
        "method": "POST",
        "priority": 10
    },
    {
        "id": "3ab34a16-dc17-42da-b67a-4d68d0046822",
        "app": "event.generic",
        "url": "http://test.com/myevent",
        "authType": "DISABLED",
        "method": "POST",
        "priority": 10
    }
]

Get Hook

Get Darren's Pizza's hook

GET /api/v1/account/5554872eb0731b38efa4d444/hook/3ab34a16-dc17-42da-b67a-4d68d0046822
Authorization: Bearer {access_token}
Accept: application/json
Response 200 OK
{
    "id": "3ab34a16-dc17-42da-b67a-4d68d0046822",
    "app": "event.generic",
    "url": "http://test.com/myevent",
    "authType": "DISABLED",
    "method": "POST",
    "priority": 10
}

Create a Hook

Create a Darren's Pizza's hook

POST /api/v1/account/5554872eb0731b38efa4d444/hook
Authorization: Bearer {access_token}
Accept: application/json
Content-Type: application/json

 {
    "app": "event.generic",
    "url": "http://test.com/myevent",
    "authType": "DISABLED",
    "method": "POST",
    "priority": 10
}
Response 201 Created

Update a Hook

Update Darren's Pizza's sip trunk

PUT /api/v1/account/5554872eb0731b38efa4d444/hook/3ab34a16-dc17-42da-b67a-4d68d0046822
Authorization: Bearer {access_token}
Content-Type: application/json

 {
    "id": "3ab34a16-dc17-42da-b67a-4d68d0046822",
    "app": "event.generic",
    "url": "http://test.com/myevent",
    "authType": "DISABLED",
    "method": "POST",
    "priority": 10
}
Response 204 No Content

Flow Devices

Devices are the main components of voice flows. Join devices together to create simple to advanced call flows.

List Devices

Get Darren's Pizza's flow devices

In the example below, we can see 2x devices, SIP_GATEWAY & ROUTE_START. This is the basis for a very simple SIP Trunking call flow.

The ROUTE_START device is the entry point for the DDIs to map to the flow and the SIP_GATEWAY device maps the trunks. Pay attention to the connectTo field which maps to the id of a device. This connectTo field may also be populated with an enum, usually HANGUP.

Device Types are defined in more details in the Flow Device Overview

GET /api/v1/account/5554872eb0731b38efa4d444/device
Authorization: Bearer {access_token}
Accept: application/json
Response 200 OK
[
    {
        "id": "7aa48c2a-aa01-488b-abfb-4eabce3ce9f8",
        "type": "SIP_GATEWAY",
        "name": "Primary GW",
        "extension": "601",
        "sipGateway": {
            "ringTime": 180,
            "maxCallTime": 14400,
            "record": false,
            "trunks": ["66aa8915-834a-3004-8363-9c73690d8fe1"],
            "present": "pass-through",
            "countryCode": "GB",
            "onComplete": "HANGUP",
            "onFail": "HANGUP",
            "onNoAnswer": "HANGUP",
            "onBusy": "HANGUP"
        }
    }, 
    {
        "id": "4db61df1-f214-4037-9a89-1276bc83a83a",
        "type": "ROUTE_START",
        "name": "Start of Flow",
        "extension": "600",
        "startRoute": {
            "ddis": ["7774872eb9991b38efa4d888"],
            "connectTo": "7aa48c2a-aa01-488b-abfb-4eabce3ce9f8"
        }
    }
]

Get Device

Get Darren's Pizza's device

GET /api/v1/account/5554872eb0731b38efa4d444/device/4db61df1-f214-4037-9a89-1276bc83a83a
Authorization: Bearer {access_token}
Accept: application/json
Response 200 OK
{
    "id": "4db61df1-f214-4037-9a89-1276bc83a83a",
    "type": "ROUTE_START",
    "name": "Start of Flow",
    "extension": "600",
    "startRoute": {
        "ddis": ["7774872eb9991b38efa4d888"],
        "connectTo": "7aa48c2a-aa01-488b-abfb-4eabce3ce9f8"
    }
 }

Create a Device

Create a Darren's Pizza's flow device

Please checkout Flow Device Overview for more details on the Device model

POST /api/v1/account/5554872eb0731b38efa4d444/device
Authorization: Bearer {access_token}
Accept: application/json
Content-Type: application/json

 {
    "type": "ROUTE_START",
    "name": "Start of Flow",
    "extension": "600",
    "startRoute": {
        "ddis": ["7774872eb9991b38efa4d888"],
        "connectTo": "7aa48c2a-aa01-488b-abfb-4eabce3ce9f8"
    }
 }
Response 201 Created

Update a Device

Update Darren's Pizza's flow device

PUT /api/v1/account/5554872eb0731b38efa4d444/device/66aa8915-834a-3004-8363-9c73690d8fe1
Authorization: Bearer {access_token}
Content-Type: application/json

 {
    "id": "4db61df1-f214-4037-9a89-1276bc83a83a",
    "type": "ROUTE_START",
    "name": "Start of Flow",
    "extension": "600",
    "startRoute": {
        "ddis": ["7774872eb9991b38efa4d888"],
        "connectTo": "HANGUP"
    }
}
Response 204 No Content

Channels

Callable currently supports the voice channel allowing you to create, update and remove live voice calls, we will soon be supporting SMS & Email channels. Stay tuned!

Voice Channel

Create a Voice call

We can generate a new call by adhering the following JSON schema:

{
   "callerId" : "",
   "tag" : { ... },
   "target" : { ... }
   "verbs" : [ ... ]
}
FieldDescriptionRequired
callerIdThe number to present to the initially dialled target, if this is left blank then the main billing number of the account will be usedfalse
tagContains a field "data" consisting of key / value pairs, these tags span the lifecycle of the call allowing contextual information to be appliedfalse
targetA Dial verb, this can be of type Device , SipURI, PhoneNumber or Extensiontrue
verbsOn answer of the original Dial, the call will then invoke these verbs. Verbs can be of type Dial, Say, Play, Gather, Reject, Hangup, Redirecttrue

Examples

Create a new outbound call for Darren's Pizzas and tell the customer their pizza is outside

POST /api/v1/account/5554872eb0731b38efa4d444/channels/voice
Authorization: Bearer {access_token}
Accept: application/json
Content-Type: application/json

{
   "callerId" : "+441234567890",
   "tag" : {
        "data" : { "myKey" : "myValue" }
    },
    "target" : {
        "phoneNumber" : { "number" : "+441234567893"  }
    },
    "verbs" : [
        { 
            "say" : { 
                "text" : [ "Your pizza is outside!" ]
            } 
        },
        { 
            "hangup" : { "reason" : "call-complete" } 
        }
    ]
}
Response 201 Created

Create a new outbound call to a registered sip trunk on a particular extension, on connect announce you are connecting them and then dial a phone number

POST /api/v1/account/5554872eb0731b38efa4d444/channels/voice
Authorization: Bearer {access_token}
Accept: application/json
Content-Type: application/json

{
 "callerId" : "+441234567890",
 "target" : {
    "extension" : {
       "extension" : "604", "overrideTo" : "201"
    }
  },
  "verbs" : [
    { 
        "say" : { 
            "text" : [ "Connection you now!" ]
        } 
    },
    {
      "dial" :  {
        "callerId" : "+441234567890",
        "timeout" : 10,
        "timeLimit" : 14400,
        "targets" : [
            {  "phoneNumber" : { "number" : "+441234567891"  }   }
        ]
      }
    }
  ]
 }
Response 201 Created

What's Next