Introduction
Lumian gives you the tools to develop high-quality unified telecom applications. The REST API interface provides a simple way for external application to talk to Lumian by making HTTP requests.
API Basics
Give it a REST
Crossbar is the REST API server, from which developers can build applications that configure Lumian's myriad services and functionalities.
Almost most of the time requests and responses for Crossbar endpoint are in JSON format, unless other format are expected for specific endpoint which you can find in the documentation.
Crossbar REST API is based on open standards like JSON-Schema (for data validation), you can use any web developer language to work with the API. Although for quick access to API tools like cURL (to work with HTTP protocol from terminal) and Postman (A GUI application to work with HTTP APIs) are come in handy.
A non-exhaustive list of all the things you can do with REST API:
- Access to your account and sub-accounts settings, add/remove and update any parameter.
- Retrieve a list of your account’s devices, users and etc.
- Buy numbers, port number from other providers.
- Create callflows, assign numbers to users.
- Manage your office, defining Open Hour, After Hour, Menus, Voicemail boxes.
Getting Started
After on-boarding is completed an account with default setting is setup and ready to use for you.
Prerequisites
Before you begin you need to know the main URL path to the API which is usually provided to you by e-mail during on-boarding process. If you don’t have this URL you can ask a your reseller salesperson to give you the URL.
Crossbar API requires the request to be authenticated, so you have to first get an authentication token before making any HTTP request to the API. The are various way to get this authentication token, you can learn more about them in Authenticate your REST requests.
Accessing to REST API resources
Let's assume we want to get our own account settings. For doing this we can simply use this cURL command:
$ curl -x GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
'http://crossbar_server.com:8000/v2/accounts/{ACCOUNT_ID}'
Here the explanation of the command:
- -x GET is telling cURL to perform a HTTP GET request.
- -H "X-Auth-Token: {AUTH_TOKEN}" is adding a HTTP header to the request. Here we add X-Auth-Token header required by Crossbar for authentication. {AUTH_TOKEN} is your authentication token.
- http://... part is telling cURL to which URL make the request.
- crossbar_server.com/8000 is the main Crossbar API URL.
- v2 is the API version.
- accounts is the name of the resource we want to have access.
- {ACCOUNT_ID} is a specific instance of this resource we want. Since we want to get our account information (we are using accounts resource here) we give our own account ID.
API resources are available at below location:
/{VERSION}/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID}
Here the explanation:
{VERSION}- The version of the API you are calling.v1- Most APIs respond on thev1v2- A select number of APIs have newer behaviour. If you used the itsv1version, it will work as before.
{ACCOUNT_ID}- Most requests operate against a specific account and thus require theaccount_idto route the request properly{RESOURCE_ID}- When accessing a specific resource, like a device, user, or callflow, this is the{RESOURCE_ID}points to the specific instance you're accessing.
Resources
There are two parts to how a request is routed in Crossbar: the REST endpoint and the resource ID. Let's break down a common URI and see how Crossbar figures out what is an endpoint and what is a resource ID.
Given a URI of /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}:
- First, strip the version off the URI:
- Version:
v2 - URI Remaining:
/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}
- Version:
- See if the next token is a REST endpoint module. It is, so track the module for later routing:
- Version:
v2 - Modules:
{accounts: []} - URI Remaining:
/{ACCOUNT_ID}/devices/{DEVICE_ID}
- Version:
- See if the next token is a REST endpoint module. It is not, so add the token to the last module's data:
- Version:
v2 - Modules:
{accounts: [{ACCOUNT_ID}]} - URI Remaining:
/devices/{DEVICE_ID}
- Version:
- Repeat parsing. devices is a REST endpoint:
- Version:
v2 - Modules:
{accounts: [{ACCOUNT_ID}], devices: []} - Remaining URI:
/{DEVICE_ID}
- Version:
- Repeat parsing. {DEVICE_ID} is an argument:
- Version:
v2 - Modules:
{accounts: [{ACCOUNT_ID}], devices: [{DEVICE_ID}]}
- Version:
So we have a request to account {ACCOUNT_ID} to do something with a device {DEVICE_ID}.
HTTP Verbs
The HTTP verb will determine the class of actions to take against the resource. Generically speaking, the verbs map thusly:
/v2/accounts/{ACCOUNT_ID}/resourcesGET: Fetches a summary of configured resourcesPUT: Creates a new instance of the resource.
/v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID}GET: Fetches the full representation of the resourcePOST: Updates the full representation of the resourceDELETE: Deletes the resource
PATCH
Some resources are supporting the PATCH verb, allowing partial updates instead of requiring the request to include the full version of the document. /users/{USER_ID}, for instance, supports PATCH:
Sample Request:
curl -v -X PATCH \
-H "Content-Type: application/json" \
-H "X-Auth-Token: {AUTH_TOKEN}" \
'http://api.lumian.net:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}' \
-d '{"data":{"vm_to_email_enabled":true}}'
import axios from 'axios';
const response = await axios.patch(
'http://api.lumian.net:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}',
{
'data': {
'vm_to_email_enabled': true
}
},
{
headers: {
'Content-Type': 'application/json',
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
This cURL request will patch the user's document and set vm_to_email_enabled to true. All normal validation will occur after patching the document; this also means clients can PATCH documents with their own data only.
If a resource does not support PATCH yet, clients can expect to receive a 405 Method Not Allowed error.
Tunneling the HTTP Verb
Some clients do not support the full range of HTTP verbs, and are typically limited to GET and POST. To access the functionalities of PUT and DELETE, you can tunnel the verb in a POST in a couple of ways:
- As part of the request envelope:
{"data":{...}, "verb":"PUT"} - As a query string parameter:
/v2/accounts/{ACCOUNT_ID}/resources?verb=PUT
Tunneling the Accept Header
Some clients do not support the ability to set the Accept header in the request, meaning they will not necessarily receive the response in the format they wish. Clients can append accept=text/html to the request body or query string to indicate they'd like the response processed as if the Accept header was text/html.
!!! note
accept=csv is retained for backwards-compatibility but it is encouraged to use a proper media type going forward.
Request Envelope
When issuing a PUT, POST or PUT, a request body is needed. When submitting a JSON (the most common body), Crossbar expects a request envelope with a few bits of metadata:
data: this top-level key will contain the object you wish to create/updateauth_token: optionally put your auth token in the envelopeverb: optionally tunnel aPUTorDELETEin aPOSTrequest
Sample Request Envelope:
Sample Response:
{
"data": {
"foo": "bar"
},
"auth_token": "{AUTH_TOKEN}",
"verb": "delete"
}
Request Data
When using PATCH to edit entities, if you want to remove a field from the entity, set it to null:
Sample Response:
{
"data": {
"update":"this",
"exists": null
}
}
This request would set update to this and would remove exists from the entity.
Response Envelope
When receiving JSON responses, clients will receive the response in an envelope. The response includes some duplicated data from the HTTP Response headers, since some clients do not have access to those headers.
data: contains the results of the request, if anyauth_token: contains theauth_tokenused on the requeststatus: One ofsuccess,error, orfatalmessage: Optional message that should clarify what happened on the requesterror: Error code, if anyrequest_id: ID of the request; usable for debugging the server-side processing of the request
Sample Response Envelope:
Sample Response:
{
"data": {
"the": "response",
"data": "is here"
},
"auth_token": "{AUTH_TOKEN}",
"status": "success",
"request_id": "{REQUEST_ID}"
}
Pagination
All listing APIs in v2 will be paginated by default (v1 will operate as before without pagination).
Let's take a look at the CDRs API to see how to interpret pagination.
CDR Pagination
We start with the typical CDR request for a listing of CDRs:
Sample Request:
curl -v \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
http://{SERVER_URL}:8000/v2/accounts/{ACCOUNT_ID}/cdrs
import axios from 'axios';
const response = await axios.get('http://{SERVER_URL}:8000/v2/accounts/{ACCOUNT_ID}/cdrs', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{CDR_OBJECT},
{CDR_OBJECT},
...
],
"next_start_key": "g2wAAAACbgUAvn1W1A5tAAAACDk4MDE2ODAwag",
"page_size": 25,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"start_key": "g2wAAAACbgUAb0ZX1A5oAWpq",
"status": "success"
}
The pagination response keys are next_start_key, page_size, and start_key.
next_start_key: used to get the next page of results from this API. Will not exist if this is the last page.start_key: used to get back to this page of results (or start pagination from this point)page_size: the number of results returned in this page
Assuming no changes are made to the underlying documents, start_key will get you this page of results, and next_start_key will give you a pointer to the next page (imagine a linked-list).
Encoded Start Keys (Lumian 4.2+ Only)
As you can see from the response above, both the start_key and next_start_key are encoded as URL-safe Base64 strings of their Erlang term representation. A couple character substitutions (_ for / and _ for +) and one character removal (=) ensures a string that plays nice in URLs.
In practice, the client should treat these keys as opaque and supply them as-is in future requests.
Requesting next page
Using the next_start_key value, let's request the next page of CDRs:
Sample Request:
curl -v \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
http://{SERVER_URL}:8000/v2/accounts/{ACCOUNT_ID}/cdrs?start_key=g2wAAAACbgUAb0ZX1A5oAWpq
import axios from 'axios';
const response = await axios.get('http://{SERVER_URL}:8000/v2/accounts/{ACCOUNT_ID}/cdrs', {
params: {
'start_key': 'g2wAAAACbgUAb0ZX1A5oAWpq'
},
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{CDR_OBJECT},
{CDR_OBJECT},
...
],
"next_start_key": "g2wAAAACbgUAbyYO1A5tAAAACDYwMTIzYjdiag",
"page_size": 25,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"start_key": "g2wAAAACbgUAb0ZX1A5oAWpq",
"status": "success"
}
Observe now that start_key is the requested start_key and next_start_key points to the start of the next page of results.
!!! note
If next_start_key is missing from the response envelope, the response represents the last page of results.
You can also choose to receive pages in bigger or smaller increments by specifying page_size on the request. Do take care, as the next_start_key will probably vary if you use the same start_key but differing page_size values.
Setting Page Size
By default, API requests have a page size of 50 results. This value is customizable by system administrator in the crossbar.maximum_range system config setting.
For individual API request, you can also include a page_size query string parameter. For example: http://{SERVER}:8000/v2/{API_URL}?page_size=25.
Setting sorting order
By default, Crossbar returns the results in descending order. To get results in ascending order either set ascending=true (Lumian 4.2+ only) or descending=false in the request query string.
!!! note The field used to sort the individual API results depends on the internal implementation of the API endpoint and is not controllable by the client.
Disabling Pagination
If you want to disable pagination for a request, simply include paginate=false on the query string.
Protecting from (un)intentional abuse
Since pagination can be turned off by a client-supplied query string parameter, it is important that Lumian still protect itself from overly large datasets being loaded. Examples seen include large CDR listings, call recording listings, and ledger listings.
Therefore, during a non-paginated request, Lumian monitors memory consumption of the handling server process and will abort the request if the processing is exceeding a high watermark setting (configured by the system operator). The client can expect to receive an HTTP "416 Range Not Satisfiable" error as a result of exceeding the limit.
Chunked Response
Starting with Lumian 4.2, most of the summary API endpoints can send chunked responses. Some known APIs, which tend to have larger datasets, are chunked by default (e.g. /cdrs/interaction and /ledgers/{LEDGER}).
The query string parameter is_chunked (boolean value) can be used to enable or disable chunking per-request.
To set the default chunk size, you can use chunk_size in the query string. Default value is 50.
Pretty Printing
If needed, the JSON response to be pretty printed, the server can can do so.
Include pretty printing inside the header.
Sample Request:
curl -v \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-H "X-Pretty-Print:true" \
http://{SERVER_URL}:8000/v2/accounts/{ACCOUNT_ID}/
import axios from 'axios';
const response = await axios.get('http://{SERVER_URL}:8000/v2/accounts/{ACCOUNT_ID}/', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json',
'X-Pretty-Print': 'true'
}
});
If the client cannot use headers the options can be included inside the URI.
Sample Request:
curl -v \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
http://{SERVER_URL}:8000/v2/accounts/{ACCOUNT_ID}?pretty_print=true
import axios from 'axios';
const response = await axios.get('http://{SERVER_URL}:8000/v2/accounts/{ACCOUNT_ID}', {
params: {
'pretty_print': 'true'
},
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
});
Requesting a range of binary data
It is useful to be able to get just a section of a file when streaming or resuming a download. This can be accomplished with the range header, e.g.:
Sample Request:
curl -v \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-H "Accept: audio/mpeg" \
-H "Range: bytes={START_BYTE}-{END_BYTE}" \
http://{SERVER_URL}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VMBOX_ID}/messages/{MESSAGE_ID}/raw
import axios from 'axios';
const response = await axios.get('http://{SERVER_URL}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VMBOX_ID}/messages/{MESSAGE_ID}/raw', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json',
'Accept': 'audio/mpeg',
'Range': 'bytes={START_BYTE}-{END_BYTE}'
}
});
Requesting data in CSV format
In some cases (e.g. CDR) its possible to request data in CSV format You must define the Content-type in the header you can define the file name in the request header or URL (Optional)
Sample Request:
curl -v -X GET \
-H "Accept: text/csv" \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "X-File-Name: {FILE_NAME}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs', {
headers: {
'Accept': 'text/csv',
'X-Auth-Token': '{AUTH_TOKEN}',
'X-File-Name': '{FILE_NAME}'
}
});
or
Sample Request:
curl -v -X GET \
-H "Accept: text/csv" \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs?file_name={FILE_NAME}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs?file_name={FILE_NAME}', {
headers: {
'Accept': 'text/csv',
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
About
About About
Schema
Fetch
GET /v2/accounts/{ACCOUNT_ID}/about
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/about
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/about', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"erlang_version": "19",
"ports": 21,
"processes": 1816,
"used_memory": 89615664,
"version": "4.0.0"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Accounts
About Accounts
Accounts are the container for most things in Lumian. They typically represent an office, business, family, etc. Lumian arranges accounts into a tree structure, where parent accounts can access their sub accounts but not their ancestor accounts.
About the Account Tree
Since accounts can be the child of 0 or more parent accounts, it is necessary to track each account's lineage. This is tracked in the account document (_id = ID of the account) in the pvt_tree array. The order of the list is from most-ancestral to parent.
So given "pvt_tree":["1", "2", "3"], it can be determined that "3" is the parent account, "2" the grand-parent, and "1" is the great-grandparent. "pvt_tree":[] indicates the master (or Highlander) account; there should only be one!
Schema
Accounts represent tenants or customers on the system. Each account represents an individual dataset or sandbox that only one tenant can access. The data set is architecturally independent from other tenants.
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
blacklists.[] |
string() |
false |
||
blacklists |
A list blacklist ids that apply to the account | array(string()) |
false |
|
call_recording.account |
endpoint recording settings | #/definitions/call_recording | false |
|
call_recording.endpoint |
endpoint recording settings | #/definitions/call_recording | false |
|
call_recording |
call recording configuration | object() |
false |
|
call_restriction |
Account level call restrictions for each available number classification | object() |
{} |
false |
call_waiting |
Parameters for server-side call waiting | #/definitions/call_waiting | false |
|
caller_id |
The account default caller ID parameters | #/definitions/caller_id | false |
|
caller_id_options.outbound_privacy |
Determines what appears as caller id for offnet outbound calls. Values: full - hides name and number; name - hides only name; number - hides only number; none - hides nothing | `string('full' | 'name' | 'number' |
caller_id_options.show_rate |
Whether to show the rate | boolean() |
false |
|
caller_id_options |
custom properties for configuring caller_id | object() |
false |
|
dial_plan |
A list of default rules used to modify dialed numbers | #/definitions/dialplans | false |
|
do_not_disturb.enabled |
The default value for do-not-disturb | boolean() |
false |
|
do_not_disturb |
object() |
false |
||
enabled |
Determines if the account is currently enabled | boolean() |
true |
false |
flags.[] |
string() |
false |
||
flags |
Flags set by external applications | array(string()) |
false |
|
formatters |
Schema for request formatters | #/definitions/formatters | false |
|
language |
The language for this account | string() |
false |
|
metaflows |
Actions applied to a call outside of the normal callflow, initiated by the caller(s) | #/definitions/metaflows | false |
|
music_on_hold.media_id |
The ID of a media object that should be used as the default music on hold | string(0..2048) |
false |
|
music_on_hold |
The default music on hold parameters | object() |
{} |
false |
name |
A friendly name for the account | string(1..128) |
true |
|
notifications.first_occurrence.sent_initial_call |
has the account made their first call | boolean() |
false |
false |
notifications.first_occurrence.sent_initial_registration |
has the account registered their first device | boolean() |
false |
false |
notifications.first_occurrence |
send emails on these account-firsts | object() |
false |
|
notifications.low_balance.enabled |
should the account be checked for this alert | boolean() |
false |
|
notifications.low_balance.last_notification |
Timestamp, in Gregorian seconds, of when the last low_balance alert was sent | integer() |
false |
|
notifications.low_balance.sent_low_balance |
has the alert been sent (avoids duplication/spamming) | boolean() |
false |
|
notifications.low_balance.threshold |
account balance to send alert on | number() |
false |
|
notifications.low_balance |
Low balance settings | object() |
false |
|
notifications |
account notification settings | object() |
false |
|
org |
Full legal name of the organization | string() |
false |
|
preflow.always |
The ID of a callflow to always execute prior to processing the callflow with numbers/patterns matching the request | string() |
false |
|
preflow |
Each property provides functionality that can be applied to calls using the callflow application | object() |
{} |
false |
realm |
The realm of the account, ie: 'account1.lumian.net' | string(4..253) |
false |
|
ringtones.external |
The alert info SIP header added when the call is from internal sources | string(0..256) |
false |
|
ringtones.internal |
The alert info SIP header added when the call is from external sources | string(0..256) |
false |
|
ringtones |
Ringtone Parameters | object() |
{} |
false |
timezone |
The default timezone | string(5..32) |
false |
|
topup.threshold |
The account balance when topup occurs | number() |
false |
|
topup |
Topup settings for the account | object() |
false |
|
voicemail.notify.callback |
Schema for a callback options | #/definitions/notify.callback | false |
|
voicemail.notify |
object() |
false |
||
voicemail |
object() |
false |
||
zones |
A priority ordered mapping of zones for the account | object() |
false |
call_recording
endpoint recording settings
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
any |
settings for any calls to/from the endpoint | #/definitions/call_recording.source | false |
|
inbound |
settings for inbound calls to the endpoint | #/definitions/call_recording.source | false |
|
outbound |
settings for outbound calls from the endpoint | #/definitions/call_recording.source | false |
call_recording.parameters
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
enabled |
is recording enabled | boolean() |
false |
|
format |
What format to store the recording on disk | `string('mp3' | 'wav')` | |
record_min_sec |
The minimum length, in seconds, the recording must be to be considered successful. Otherwise it is deleted | integer() |
false |
|
record_on_answer |
Recording should start on answer | boolean() |
false |
|
record_on_bridge |
Recording should start on bridge | boolean() |
false |
|
record_sample_rate |
What sampling rate to use on the recording | integer() |
false |
|
time_limit |
Time limit, in seconds, for the recording | integer() |
false |
|
url |
The URL to use when sending the recording for storage | string() |
false |
call_recording.source
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
any |
settings for calls from any network | #/definitions/call_recording.parameters | false |
|
offnet |
settings for calls from offnet networks | #/definitions/call_recording.parameters | false |
|
onnet |
settings for calls from onnet networks | #/definitions/call_recording.parameters | false |
call_waiting
Parameters for server-side call waiting
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
enabled |
Determines if server side call waiting is enabled/disabled | boolean() |
false |
caller_id
Defines caller ID settings based on the type of call being made
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
asserted.name |
The asserted identity name for the object type | string(0..35) |
false |
|
asserted.number |
The asserted identity number for the object type | string(0..35) |
false |
|
asserted.realm |
The asserted identity realm for the object type | string() |
false |
|
asserted |
Used to convey the proven identity of the originator of a request within a trusted network. | object() |
false |
|
emergency.name |
The caller id name for the object type | string(0..35) |
false |
|
emergency.number |
The caller id number for the object type | string(0..35) |
false |
|
emergency |
The caller ID used when a resource is flagged as 'emergency' | object() |
false |
|
external.name |
The caller id name for the object type | string(0..35) |
false |
|
external.number |
The caller id number for the object type | string(0..35) |
false |
|
external |
The default caller ID used when dialing external numbers | object() |
false |
|
internal.name |
The caller id name for the object type | string(0..35) |
false |
|
internal.number |
The caller id number for the object type | string(0..35) |
false |
|
internal |
The default caller ID used when dialing internal extensions | object() |
false |
dialplans
Permit local dialing by converting the dialed number to a routable form
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
system.[] |
string() |
false |
||
system |
List of system dial plans | array(string()) |
false |
formatters
Schema for request formatters
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
^[[:alnum:]_]+$ |
Key to match in the route request JSON | `array(#/definitions/formatters.format_options) | #/definitions/formatters.format_options` |
formatters.format_options
Schema for formatter options
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
direction |
Only apply the formatter on the relevant request direction | `string('inbound' | 'outbound' | 'both')` |
match_invite_format |
Applicable on fields with SIP URIs. Will format the username portion to match the invite format of the outbound request. | boolean() |
false |
|
prefix |
Prepends value against the result of a successful regex match | string() |
false |
|
regex |
Matches against the value, with optional capture group | string() |
false |
|
strip |
If set to true, the field will be stripped from the payload | boolean() |
false |
|
suffix |
Appends value against the result of a successful regex match | string() |
false |
|
value |
Replaces the current value with the static value defined | string() |
false |
metaflow
A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
children./.+/ |
A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to | #/definitions/metaflow | false |
|
children |
Children metaflows | object() |
false |
|
data |
The data/arguments of the metaflow module | object() |
{} |
false |
module |
The name of the metaflow module to execute at this node | string(1..64) |
true |
metaflows
Actions applied to a call outside of the normal callflow, initiated by the caller(s)
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
binding_digit |
What DTMF will trigger the collection and analysis of the subsequent DTMF sequence | `string('1' | '2' | '3' |
digit_timeout |
How long to wait between DTMF presses before processing the collected sequence (milliseconds) | integer() |
false |
|
listen_on |
Which leg(s) of the call to listen for DTMF | `string('both' | 'self' | 'peer')` |
numbers./^[0-9]+$/ |
A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to | #/definitions/metaflow | false |
|
numbers |
A list of static numbers with their flows | object() |
false |
|
patterns./.+/ |
A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to | #/definitions/metaflow | false |
|
patterns |
A list of patterns with their flows | object() |
false |
notify.callback
Schema for a callback options
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
attempts |
How many attempts without answer will system do | integer() |
false |
|
disabled |
Determines if the system will call to callback number | boolean() |
false |
|
interval_s |
How long will system wait between call back notification attempts | integer() |
false |
|
number |
Number for callback notifications about new messages | string() |
false |
|
schedule |
Schedules interval between callbacks | array(integer()) |
false |
|
timeout_s |
How long will system wait for answer to callback | integer() |
false |
Create New Account
PUT /v2/accounts
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"name":"child account"}}' \
http://api.lumian.net:8000/v2/accounts
import axios from 'axios';
const response = await axios.put(
'http://api.lumian.net:8000/v2/accounts',
{
'data': {
'name': 'child account'
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"billing_mode": "manual",
"call_restriction": {},
"caller_id": {},
"created": 63621662701,
"dial_plan": {},
"enabled": true,
"id": "{ACCOUNT_ID}",
"is_reseller": false,
"language": "en-us",
"music_on_hold": {},
"name": "child account",
"preflow": {},
"realm": "aeac33.sip.lumian.net",
"reseller_id": "undefined",
"ringtones": {},
"superduper_admin": false,
"timezone": "America/New_York",
"wnm_allow_additions": false
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Remove an account
DELETE /v2/accounts/{ACCOUNT_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: \{AUTH_TOKEN\}" \
http://\{SERVER\}:8000/v2/accounts/\{ACCOUNT_ID\}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}', {
headers: {
'X-Auth-Token': '\\{AUTH_TOKEN\\}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"billing_mode": "manual",
"call_restriction": {},
"caller_id": {},
"created": 63621662701,
"dial_plan": {},
"enabled": true,
"id": "{ACCOUNT_ID}",
"is_reseller": false,
"language": "en-us",
"music_on_hold": {},
"name": "child account",
"preflow": {},
"realm": "aeac33.sip.lumian.net",
"reseller_id": "undefined",
"ringtones": {},
"superduper_admin": false,
"timezone": "America/New_York",
"wnm_allow_additions": false
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Fetch the account doc
GET /v2/accounts/{ACCOUNT_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"billing_mode": "manual",
"call_restriction": {},
"caller_id": {},
"created": 63621662701,
"dial_plan": {},
"enabled": true,
"id": "{ACCOUNT_ID}",
"is_reseller": false,
"language": "en-us",
"music_on_hold": {},
"name": "child account",
"preflow": {},
"realm": "aeac33.sip.lumian.net",
"reseller_id": "undefined",
"ringtones": {},
"superduper_admin": false,
"timezone": "America/New_York",
"wnm_allow_additions": false
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Patch the account doc
PATCH /v2/accounts/{ACCOUNT_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"some_key":"some_value"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}',
'{"data":{"some_key":"some_value"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"billing_mode": "manual",
"call_restriction": {},
"caller_id": {},
"created": 63621662701,
"dial_plan": {},
"enabled": true,
"id": "{ACCOUNT_ID}",
"is_reseller": false,
"language": "en-us",
"music_on_hold": {},
"name": "child account",
"preflow": {},
"realm": "aeac33.sip.lumian.net",
"reseller_id": "undefined",
"ringtones": {},
"some_key":"some_value",
"superduper_admin": false,
"timezone": "America/New_York",
"wnm_allow_additions": false
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Change the account doc
POST /v2/accounts/{ACCOUNT_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data": {"billing_mode": "manual","call_restriction": {},"caller_id": {},"created": 63621662701,"dial_plan": {},"enabled": true,"is_reseller": false,"language": "en-us","music_on_hold": {},"name": "child account","preflow": {},"realm": "aeac33.sip.lumian.net","reseller_id": "undefined","ringtones": {},"some_key":"some_value","superduper_admin": false,"timezone": "America/New_York","wnm_allow_additions": false}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}',
// '{"data": {"billing_mode": "manual","call_restriction": {},"caller_id": {},"created": 63621662701,"dial_plan": {},"enabled": true,"is_reseller": false,"language": "en-us","music_on_hold": {},"name": "child account","preflow": {},"realm": "aeac33.sip.lumian.net","reseller_id": "undefined","ringtones": {},"some_key":"some_value","superduper_admin": false,"timezone": "America/New_York","wnm_allow_additions": false}}',
{
'data': {
'billing_mode': 'manual',
'call_restriction': {},
'caller_id': {},
'created': 63621662701,
'dial_plan': {},
'enabled': true,
'is_reseller': false,
'language': 'en-us',
'music_on_hold': {},
'name': 'child account',
'preflow': {},
'realm': 'aeac33.sip.lumian.net',
'reseller_id': 'undefined',
'ringtones': {},
'some_key': 'some_value',
'superduper_admin': false,
'timezone': 'America/New_York',
'wnm_allow_additions': false
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"billing_mode": "manual",
"call_restriction": {},
"caller_id": {},
"created": 63621662701,
"dial_plan": {},
"enabled": true,
"id": "{ACCOUNT_ID}",
"is_reseller": false,
"language": "en-us",
"music_on_hold": {},
"name": "child account",
"preflow": {},
"realm": "aeac33.sip.lumian.net",
"reseller_id": "undefined",
"ringtones": {},
"some_key":"some_value",
"superduper_admin": false,
"timezone": "America/New_York",
"wnm_allow_additions": false
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Create a new child account
Puts the created account under {ACCOUNT_ID}
PUT /v2/accounts/{ACCOUNT_ID}
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"name":"child account"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}',
{
'data': {
'name': 'child account'
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"billing_mode": "manual",
"call_restriction": {},
"caller_id": {},
"created": 63621662701,
"dial_plan": {},
"enabled": true,
"id": "{CHILD_ACCOUNT_ID}",
"is_reseller": false,
"language": "en-us",
"music_on_hold": {},
"name": "child account",
"preflow": {},
"realm": "aeac33.sip.lumian.net",
"reseller_id": "undefined",
"ringtones": {},
"superduper_admin": false,
"timezone": "America/New_York",
"wnm_allow_additions": false
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Fetch the parent account IDs
GET /v2/accounts/{ACCOUNT_ID}/parents
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/parents
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/parents', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"id": "{PARENT_ACCOUNT_ID}",
"name": "{PARENT_ACCOUNT_NAME}"
}
],
"page_size": 1,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Fetch an account's ancestor tree
GET /v2/accounts/{ACCOUNT_ID}/tree
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tree
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tree', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"id": "{PARENT_ACCOUNT_ID}",
"name": "{PARENT_ACCOUNT_NAME}"
}
],
"page_size": 1,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Fetch the account's API key
The API key is used by the api_auth API to obtain an auth_token. This is intended for use by applications talking to Lumian and provides a mechanism for authentication that does not require storing a username and password in the application. The API key can be obtained via the accounts API's endpoint api_key.
GET /v2/accounts/{ACCOUNT_ID}/api_key
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/api_key
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/api_key', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"api_key": "{API_KEY}"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Re-create the account's API key
If you think that your account's API key might be exposed you can create a new one with api_key endpoint. Issuing a PUT request to this endpoint will generates a new API key for the account and will returned it in response.
PUT /v2/accounts/{ACCOUNT_ID}/api_key
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/api_key
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/api_key',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"api_key": "{API_KEY}"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Fetch sibling accounts
By default a user account under an admin/reseller account can view all the other accounts under that reseller. If you would like current account only will be able to query its child accounts' sibling and not other accounts then set allow_sibling_listing in system_config/crossbar.accounts to false. Admin account can unrestrictedly list siblings.
GET /v2/accounts/{ACCOUNT_ID}/siblings
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/siblings
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/siblings', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"descendants_count": 1,
"id": "{ACCOUNT_ID}",
"name": "{ACCOUNT_NAME}",
"realm": "{ACCOUNT_REALM}"
}
],
"page_size": 1,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"start_key": "",
"status": "success"
}
Fetch all descendants of an account
This will include children, grandchildren, etc
GET /v2/accounts/{ACCOUNT_ID}/descendants
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/descendants
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/descendants', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"id": "{CHILD_ACCOUNT}",
"name": "{CHILD_NAME}",
"realm": "{CHILD_REALM}",
"tree": [
"{ACCOUNT_ID}"
]
}
],
"page_size": 1,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"start_key": "",
"status": "success"
}
Fetch immediate children of an account
GET /v2/accounts/{ACCOUNT_ID}/children
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/children
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/children', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"id": "{CHILD_ACCOUNT}",
"name": "{CHILD_NAME}",
"realm": "{CHILD_REALM}",
"tree": [
"{ACCOUNT_ID}"
]
}
],
"page_size": 1,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"start_key": "",
"status": "success"
}
Demote a reseller
Requires superduper admin auth token
DELETE /v2/accounts/{ACCOUNT_ID}/reseller
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/reseller
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/reseller', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Promote a reseller
Requires superduper admin auth token
PUT /v2/accounts/{ACCOUNT_ID}/reseller
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/reseller
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/reseller',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Move an account
An account can only be moved by a "superduper_admin" or if enabled by anyone above the desired account.
You can enable that feature by editing the document crossbar.accounts in your system_config database and set the value to tree.
| Key | Value | Description |
|---|---|---|
allow_move |
enum("tree", "superduper_admin") | Who can move a sub-account |
POST /v2/accounts/{ACCOUNT_ID}/move
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"to": "{ACCOUNT_ID_DESTINATION}"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/move
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/move',
'{"data": {"to": "{ACCOUNT_ID_DESTINATION}"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"billing_mode": "manual",
"call_restriction": {},
"caller_id": {},
"created": 63621662701,
"dial_plan": {},
"enabled": true,
"id": "{ACCOUNT_ID}",
"is_reseller": false,
"language": "en-us",
"music_on_hold": {},
"name": "child account",
"preflow": {},
"realm": "aeac33.sip.lumian.net",
"reseller_id": "undefined",
"ringtones": {},
"superduper_admin": false,
"timezone": "America/New_York",
"wnm_allow_additions": false
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Access Lists
SBC level per-account and per-device access lists allow setting individual IP-based access filtering rules which significantly increases security for users working on-premise.
Rules can be applied at account level or at individual device level
About Access Lists
access_lists API works at the level of both accounts and devices documents.
Sections:
access_lists: root elementorder- order of rules: can be"allow,deny"or"deny,allow", just like in Apache configuration filecidrs- array containing IPv4 subnet addresses in CIDR notation that should be allowed or denied (CIDR array looks much like one in ecallmgr configuration document)user_agent- regex foruser_agentfield specified in SIP packet. Useful for protecting hardware phone accounts from various brute-force attacks
Schema
Access Control List entries for device or account
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
cidrs.[] |
string() |
true |
|||
cidrs |
Classless Inter-Domain Routing IP notation for use on the access lists | array(string()) |
true |
||
order |
Allow-Deny or Deny-Allow? | `string('allow,deny' | 'deny,allow')` | true |
|
user_agent |
Regexp to match valid user agent strings | string() |
false |
Fetch account-level access lists
GET /v2/accounts/{ACCOUNT_ID}/access_lists
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/access_lists
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/access_lists', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Update account-level access lists
POST /v2/accounts/{ACCOUNT_ID}/access_lists
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"order": "allow,deny","cidrs": ["127.0.0.3/32"]}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/access_lists
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/access_lists',
'{"data": {"order": "allow,deny","cidrs": ["127.0.0.3/32"]}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"cidrs": [
"127.0.0.3/32"
],
"order": "allow,deny"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Remove account-level access lists
DELETE /v2/accounts/{ACCOUNT_ID}/access_lists
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/access_lists
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/access_lists', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch device-level access lists
GET /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/access_lists
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/access_lists
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/access_lists', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"cidrs": [
"127.0.0.3/32"
],
"order": "allow,deny"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Update device-level access lists
POST /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/access_lists
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"order": "deny,allow","cidrs": ["127.0.0.3/32"]}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/access_lists
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/access_lists',
'{"data": {"order": "deny,allow","cidrs": ["127.0.0.3/32"]}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"cidrs": [
"127.0.0.3/32"
],
"order": "deny,allow"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Remove device-level access lists
DELETE /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/access_lists
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/access_lists
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/access_lists', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Acdc Call Stats
About Acdc Call Stats
Schema
Fetch
GET /v2/accounts/{ACCOUNT_ID}/acdc_call_stats
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/acdc_call_stats
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/acdc_call_stats', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Get a time range of ACDC Call Stats (using Gregorian seconds for timestamps):
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/acdc_call_stats?created_from={FROM_TIMESTAMP}&created_to={TO_TIMESTAMP}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/acdc_call_stats?created_from={FROM_TIMESTAMP}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Get ACDC Call Stats as CSV:
Sample Request:
curl -v -X GET \
-H "Accept: text/csv" \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/acdc_call_stats
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/acdc_call_stats', {
headers: {
'Accept': 'text/csv',
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Acls
About Acls
Schema
Access Control List entries
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
cidr |
Classless Inter-Domain Routing IP notation for use on the ACL | string() |
true |
||
description |
Will be added as a comment for quick identification later | string(0..30) |
false |
||
network-list-name |
The trusted list should represent anything that can issue calls without authorization. The authoritative list should indicate inter-network routing equipment (SBC, etc). | `string('authoritative' | 'trusted')` | true |
|
type |
Allow or deny this CIDR | `string('allow' | 'deny')` | allow |
true |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/acls
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/acls
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/acls', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
API for managing agent status
This API provides convenient way for agent status management without need to dial feature codes. It's useful for various call center agent/supervisor interfaces.
Log In/Log Out agent to/from some queue
/agents/AID/queue_status (GET, POST):
Sample Response:
{
"data":{
"action":{{action}},
"queue_id":{{queue_id}}
}
}
where
{{action}} - "login" | "logout" and {{queue_id}} is an ID of the queue
Set agent status:
/agents/AID/status (GET, POST):
Sample Response:
{
"data":{
"status":{{status}},
"timeout":{{timeout}},
"presence_id":{{id}},
"presence_state":{{state}}
}
}
where
{{status}} - "login" | "logout" | "pause" | "resume"
{{timeout}} - timeout for "pause" status
presence_id и presence_state - optional fields for presence information
If the agent is on call in time of request, then "pause", "resume" and "logout" commands will be executed right after the agent is back from the call.
Alerts
About Alerts
Schema
Fetch
GET /v2/accounts/{ACCOUNT_ID}/alerts
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/alerts
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/alerts', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create
PUT /v2/accounts/{ACCOUNT_ID}/alerts
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/alerts
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/alerts',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Fetch
GET /v2/accounts/{ACCOUNT_ID}/alerts/{ALERT_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/alerts/{ALERT_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/alerts/{ALERT_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Remove
DELETE /v2/accounts/{ACCOUNT_ID}/alerts/{ALERT_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/alerts/{ALERT_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/alerts/{ALERT_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Allotments
Allotments Explanation
Each object have name (outbound_national) which build from direction (inbound or outbound) and classification from number manager configuration.
Properties
amount: time in seconds. which can be consumedcycle: when we reset consumed allotments counter, must be one ofminutely,hourly,daily,weekly,monthly.increment: step (in seconds) of incrementing counter, minimum 1 secondminimum: minimum amount added to counterno_consume_time: if call less or equal of this time (in seconds), then no allotment consumed.group_consume: other allotments which will be summed, when calculating rest of allotments time on authorization. See examples below.
Examples
increment", "minimum" and "no_consume_time"
Sample Response:
{
"outbound_local": {
"increment": 10,
"minimum": 60,
"no_consume_time": 5
}
}
Call consumed time rounded before store it to DB. Call with duration 40 seconds will be count as 60 seconds.
69 seconds -> 70
75 seconds -> 80
5 seconds -> 0
6 seconds -> 60
"group_consume"
Sample Response:
{
"Class1": {
"amount": 600,
"group_consume": [
"Class2"
]
},
"Class2": {
"amount": 600,
"group_consume": [
"Class1"
]
}
}
Here we have 2 classifiers which share same counter.
If Class1 already consumed 400 seconds and Class2 consumed 150 seconds, next call with classifier Class2 (or Class1) will have 50 free seconds.
Little more complex example:
Sample Response:
{
"Class1": {
"amount": 600,
"group_consume": [
"Class2",
"Class3"
]
},
"Class2": {
"amount": 120,
"group_consume": [
"Class1"
]
},
"Class3": {
"amount": 300,
"group_consume": [
"Class2"
]
}
}
So if we already have consumed calls:
Class1 - 300
Class2 - 60
Class3 - 180
As result next call will have this free seconds:
Class1 - 60 (300 Class1 + 60 Class2 + 180 Class3 = 540, 600-540 = 60)
Class2 - 0 (60 Class2 + 300 Class1 = 360, 360 > 120)
Class3 - 60 (180 Class3 + 60 Class2 = 240, 300-240 = 60)
Schema
Create buckets of minutes per time-period
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
^\w+$.amount |
integer() |
false |
|||
^\w+$.cycle |
`string('minutely' | 'hourly' | 'daily' | 'weekly' | |
^\w+$.group_consume.[] |
string() |
false |
|||
^\w+$.group_consume |
array(string()) |
false |
|||
^\w+$.increment |
integer() |
false |
|||
^\w+$.minimum |
integer() |
false |
|||
^\w+$.no_consume_time |
integer() |
false |
|||
^\w+$ |
object() |
false |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/allotments
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/allotments
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/allotments', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": {
"outbound_national": {
"amount": 600,
"cycle": "hourly",
"increment": 60,
"minimum": 60,
"no_consume_time": 2,
"group_consume": [
"outbound_local"
]
},
"outbound_local": {
"amount": 600,
"cycle": "hourly",
"increment": 60,
"minimum": 60,
"no_consume_time": 2,
"group_consume": [
"outbound_national"
]
}
},
"status": "success"
}
Update allotments configuration for a given account
POST /v2/accounts/{ACCOUNT_ID}/allotments
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/allotments
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/allotments',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Sample Response:
{
"data": {
"outbound_national": {
"amount": 3600,
"cycle": "monthly",
"increment": 60,
"minimum": 60,
"no_consume_time": 2,
"group_consume": [
"outbound_local"
]
},
"outbound_local": {
"amount": 3600,
"cycle": "monthly",
"increment": 60,
"minimum": 60,
"no_consume_time": 2,
"group_consume": [
"outbound_national"
]
}
}
}
Get consumed allotments for a given account
GET /v2/accounts/{ACCOUNT_ID}/allotments/consumed
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/allotments/consumed
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/allotments/consumed', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": {
"outbound_local": {
"consumed": 120,
"consumed_to": 63608284800,
"consumed_from": 63605606400,
"cycle": "monthly"
},
"outbound_national": {
"consumed": 120,
"consumed_to": 63606384000,
"consumed_from": 63605779200,
"cycle": "weekly"
}
},
"status": "success",
}
Get consumed allotments for a certain period of time
{TIMESTAMP} - Gregorian epoch seconds.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/allotments/consumed?created_from={TIMESTAMP}&created_to={TIMESTAMP}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/allotments/consumed?created_from={TIMESTAMP}&created_to={TIMESTAMP}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": {
"outbound_local": {
"consumed": 180,
"consumed_to": 63607728001,
"consumed_from": 63605046001,
"cycle": "manual"
},
"outbound_national": {
"consumed": 120,
"consumed_to": 63607728001,
"consumed_from": 63605046001,
"cycle": "manual"
}
},
"status": "success",
}
Get consumed allotments at certain time
{TIMESTAMP} - Gregorian epoch seconds.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/allotments/consumed?created_from={TIMESTAMP}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/allotments/consumed?created_from={TIMESTAMP}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
or
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/allotments/consumed?created_to={TIMESTAMP}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/allotments/consumed?created_to={TIMESTAMP}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Response:
{
"data": {
"outbound_local": {
"consumed": 180,
"consumed_to": 63692087455, // month2_end_timestamp
"consumed_from": 63691988379, // month2_start_timestamp
"cycle": "monthly"
},
"outbound_national": {
"consumed": 60,
"consumed_to": 63692088370, // week4_end_timestamp
"consumed_from": 63692078446, // week4_start_timestamp
"cycle": "weekly"
}
},
"status": "success",
}
Example Time Diagram
{TIMESTAMP}
||
----+--------------------+-----------||-------+--------------------+--------
| week3 | week4 || | week5 | week6
----+------------+-------+-----------||-------+--------------------+--------
month1 | month2 ||
-----------------+-------------------||-------------------------------------
API Authentication
About API Authentication
Schema
Provides an auth-token via an Account API key
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
api_key |
The Accounts API key | string(64) |
true |
Create
HTTP Request
PUT /v2/api_auth
Sample Request:
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/api_auth
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/api_auth',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Account API Authentication
Use your account's API token to instruct Crossbar to create an authentication token to be used on subsequent requests requiring authentication.
Getting your API key from the API:
Use Account API to get API key for your account:
!!! note Must already authenticated as a user.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/api_key
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/api_key', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token":"{AUTH_TOKEN}",
"data":{
"api_key":"{API_KEY}"
},
"revision":"{REQUEST_ID}",
"request_id":"{REQUEST_ID}",
"status":"success"
}
Schema
Provides an auth-token via an Account API key
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
api_key |
The Accounts API key | string(64) |
true |
Create
PUT /v2/api_auth
Note:
{AUTH_TOKEN}: this is your authentication token to include in future requests{ACCOUNT_ID}: your account's ID, useful for constructing URIs{OWNER_ID}: the user's ID of the owner of the credentials used to generate this token{RESELLER_ID}: this account's reseller account ID, if any.{REQUEST_ID}: useful for debugging requests on your installation
Sample Request:
curl -v -X PUT \
-d '{"data": {"api_key":"{API_KEY}"} }' \
http://{SERVER}:8000/v2/api_auth
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/api_auth',
'{"data": {"api_key":"{API_KEY}"} }',
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"account_id": "{ACCOUNT_ID}",
"apps": [...],
"is_reseller": true,
"language": "en-US",
"owner_id": "{OWNER_ID}",
"reseller_id": "{RESELLER_ID}",
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Apps Link
About Apps Link
Schema
Fetch
GET /v2/accounts/{ACCOUNT_ID}/apps_link/authorize
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_link/authorize
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_link/authorize', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"account": {
"account_id": "{ACCOUNT_ID}",
"account_name": "{ACCOUNT_NAME}",
"is_master": false,
"is_reseller": false,
"language": "en-us",
"reseller_id": "6b71cb72c876b5b1396a335f8f8a2594"
},
"auth_token": {
"account_id": "{ACCOUNT_ID}",
"account_name": "{ACCOUNT_NAME}",
"apps": [
{
"api_url": "http://localhost:8000/v2",
"id": "44c076738144b5f4f80542ce49035a27",
"label": "Accounts Manager",
"name": "accounts"
},
{
"api_url": "http://localhost:8000/v2",
"id": "06815c7173aafa575bcf3c68ee124a77",
"label": "Callflows",
"name": "callflows"
},
{
"api_url": "http://localhost:8000/v2",
"id": "41f5eba03d33fc10740df7f541745f1d",
"label": "Number Manager",
"name": "numbers"
},
{
"api_url": "http://localhost:8000/v2",
"id": "3eb4f9230f95a7a60ac825021ad0affe",
"label": "Smart PBX",
"name": "voip"
},
{
"api_url": "http://localhost:8000/v2",
"id": "bbd90ad61193b2a9a3529b4f78038b5e",
"label": "Webhooks",
"name": "webhooks"
}
],
"is_master": false,
"is_reseller": false,
"language": "en-us",
"method": "cb_user_auth",
"owner_id": "8e248327b85591955749e53ea45b6baa",
"reseller_id": "6b71cb72c876b5b1396a335f8f8a2594"
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Apps Store
Apps Store list apps allowed by your service plan.
Apps Structure
Cannot be modified, only accessible by GET requests.
Ex:
Sample Response:
{
"name": "numbers",
"i18n": {
"en-US": {
"label": "Number Manager",
"description": "Number Manager app allows you to easily buy, port and manage all numbers in your account.",
"extended_description": "When you're managing a PBX or running a business there are more numbers in your hands than you can manage. Number Manager allows you to easily purchase and delete numbers, port numbers away from other carriers, and assign them to your own clients.",
"features": ["Purchase new numbers", "Delete numbers", "Port numbers from other carriers", "Set a Caller ID for each number", "Set a Failover Number", "Associate e911 address to each number"]
}
},
"tags": ["reseller", "developer"],
"icon": "NumberManager_app.png",
"api_url": "http://{{SERVER}}:8000/v2/",
"source_url": "http://{{SERVER}}/monster-apps/numbers",
"author": "Lumian",
"version": "1.0",
"license": "-",
"price": 0,
"screenshots": ["numbermanager1.png", "numbermanager2.png", "numbermanager3.png"],
"urls": {
"documentation": "{documentation_url}",
"howto": "{howto_video_url}"
},
"id": "d5c75363d3d188f08dfcf5f5b80f645f"
}
Install Master applications
Assuming you've installed your Monster applications to /path/to/monster-ui/apps, you can run the following SUP command on the {{SERVER}}:
sup crossbar_maintenance init_apps '/path/to/monster-ui/apps' 'http://your.api.{{SERVER}}:8000/v2'
This will load the apps (and let you know which apps it couldn't automatically load) into the master account (including icons, if present). For any apps that failed to be loaded automatically, you can follow the manual instructions below.
If you want to install a single Monster application:
sup crossbar_maintenance init_app '/path/to/monster-ui/apps/{{APP}}' 'http://{{SERVER}}:8000/v2'
App Permission
This is located on the account document.
Sample Response:
{
"apps": {
"{{application_id}}": {
"allowed_users": "specific",
"users": []
},
"{{application_id}}": {
"allowed_users": "specific",
"users": [{
"id": {{user_id}}
}]
},
"{{application_id}}": {
"allowed_users": "admins"
},
"{{application_id}}": {
"allowed_users": "all"
}
}
}
| Allowed Users | To | key |
|---|---|---|
| Specific with no user | No one | specific |
| Specific with user(s) | Only listed users | specific |
| All | Everyone in the account | all |
| Admins | Only Admins | admins |
Fetch App(s):
GET /v2/accounts/{ACCOUNT_ID}/apps_store
GET /v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": [
{APP}
],
"status": "success"
}
Install App:
PUT /v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID}
Install app on your account.
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"allowed_users": "specific", "users": []}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID}
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID}',
'{"data": {"allowed_users": "specific", "users": []}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"data": {
"name": "{APP_ID}",
"allowed_users": "specific",
"users": []
}
}
Update an App permission:
POST /v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID}
Update app permission on your account.
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"allowed_users": "all"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID}',
'{"data": {"allowed_users": "all"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"data": {
"allowed_users": "all"
},
"status": "success"
}
Uninstall an App:
DELETE /v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID}
Uninstall app on your account (remove permission for all users).
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": {},
"status": "success"
}
Fetch App icon
GET /v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID}/icon
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID}/icon
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID}/icon', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Streams application icon back.
Fetch App screen shots
GET /v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID}/screenshot/{APP_SCREENSHOT_INDEX}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID}/screenshot/{APP_SCREENSHOT_INDEX}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID}/screenshot/{APP_SCREENSHOT_INDEX}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Streams application screenshot number {APP_SCREENSHOT_INDEX} back.
Get Blacklist
GET /v2/accounts/{ACCOUNT_ID}/apps_store/blacklist
Need to be reseller.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store/blacklist
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store/blacklist', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": {
"blacklist": [
"{APP_1}",
"{APP_2}"
]
},
"status": "success"
}
Update Blacklist
POST /v2/accounts/{ACCOUNT_ID}/apps_store/blacklist
Need to be reseller.
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"blacklist": [{APP_3}]}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store/blacklist
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store/blacklist',
'{"data": {"blacklist": [{APP_3}]}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"data": {
"blacklist": [
"{APP_1}",
"{APP_2}",
"{APP_3}"
]
},
"status": "success"
}
Attachment Handlers Errors
Retrieve attachment handlers errors
List all the stored errors
GET /v2/accounts/{ACCOUNT_ID}/att_handlers_errors
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/att_handlers_errors
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/att_handlers_errors', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"page_size" : 5,
"start_key" : "g24FANAHFtQO",
"data" : [
{
"id" : "201803-586ce197ae32cfa5f16e94736f47fbd3",
"attachment_name" : "99a81a3436ce569631a4f8e82f0afae0_test_credentials_file.txt",
"resp_code" : 403,
"reason" : "The AWS Access Key Id you provided does not exist in our records."
},
{
"id" : "201803-586ce197ae32cfa5f16e94736f47ec5f",
"attachment_name" : "18cdfa814a6451bff0604b86f0dc76f9_test_credentials_file.txt",
"resp_code" : 403,
"reason" : "The AWS Access Key Id you provided does not exist in our records."
},
{
"id" : "201803-c371e3fdd10f5cdb88b1756e6ce0d877",
"attachment_name" : "579a7ceb533bd63391ce5c035e626781_test_credentials_file.txt",
"resp_code" : 403,
"reason" : "The AWS Access Key Id you provided does not exist in our records."
},
{
"id" : "201803-6d670f21a8184140cb31770959e09dbd",
"attachment_name" : "01c5f64e1c8f14d1123cacf6921e43b4_test_credentials_file.txt",
"resp_code" : 403,
"reason" : "The AWS Access Key Id you provided does not exist in our records."
},
{
"id" : "201803-461d4a97783105a46deb559e45d12266",
"attachment_name" : "c669cd4df0cb57625a8634562dd994e6_test_credentials_file.txt",
"resp_code" : 403,
"reason" : "The AWS Access Key Id you provided does not exist in our records."
}
],
"revision" : "ef20ee5deff0a85f34e5c5555faa4903",
"timestamp" : "2018-03-08T19:15:28",
"version" : "4.3.1",
"node" : "p1vlV1a_qodo9eHpALZAKw",
"request_id" : "b70dbb60666e83a6316df8e0681fa417",
"status" : "success",
"auth_token" : "..."
}
Get all the information for a given stored error
GET /v2/accounts/{ACCOUNT_ID}/att_handlers_errors/{ERROR_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/att_handlers_errors/{ERROR_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/att_handlers_errors/{ERROR_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data" : {
"attachment_name" : "c669cd4df0cb57625a8634562dd994e6_test_credentials_file.txt",
"db_name" : "account%2F67%2Fc6%2Fd3eb4b5f3486ac51dea16e8064a9-201803",
"document_id" : "aeda8252cb95a4943d91c11d0fd1ac04",
"handler_props" : {
"bucket" : "my_S3_BUCKET",
"key" : "my_AWS_ACCESS_KEY",
"secret" : "my_AWS_SECRET_KEY"
},
"options" : {
"rev" : "1-b9b24bdddc20aa1a8702a78b5f111406",
"doc_type" : "storage_settings_probe",
"error_verbosity" : "verbose"
},
"req_url" : "account%2F67%2Fc6%2Fd3eb4b5f3486ac51dea16e8064a9-201803/aeda8252cb95a4943d91c11d0fd1ac04_c669cd4df0cb57625a8634562dd994e6_test_credentials_file.txt",
"resp_body" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Error><Code>InvalidAccessKeyId</Code><Message>The AWS Access Key Id you provided does not exist in our records.</Message><AWSAccessKeyId>my_AWS_ACCESS_KEY</AWSAccessKeyId><RequestId>F9ABFC34EDBD7CF4</RequestId><HostId>v9p8GqEAolAyMc39sByE5hsDw9BQMbRxV0D6fajkCASWs5zTx0poP42AdlHTcRdojEkaOwLHjFM=</HostId></Error>",
"resp_code" : 403,
"handler_id" : "custom-handler-id",
"reason" : "The AWS Access Key Id you provided does not exist in our records.",
"id" : "201803-461d4a97783105a46deb559e45d12266"
},
"revision" : "1-1d947805e5c21477d094cbb678fdcaea",
"timestamp" : "2018-03-08T19:18:37",
"version" : "4.3.1",
"node" : "p1vlV1a_qodo9eHpALZAKw",
"request_id" : "c9e00eeeeb28508114697e0d1e7200b0",
"status" : "success",
"auth_token" : "..."
}
Get all the stored errors generated by the given handler-id
GET /v2/accounts/{ACCOUNT_ID}/att_handlers_errors/handler/{HANDLER_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/att_handlers_errors/handler/{HANDLER_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/att_handlers_errors/handler/{HANDLER_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"page_size" : 3,
"start_key" : "g2wAAAACbQAAABFjdXN0b20taGFuZGxlci1pZG4FABgGFtQOag",
"data" : [
{
"id" : "201803-c371e3fdd10f5cdb88b1756e6ce0d877",
"attachment_name" : "579a7ceb533bd63391ce5c035e626781_test_credentials_file.txt",
"resp_code" : 403,
"reason" : "The AWS Access Key Id you provided does not exist in our records."
},
{
"id" : "201803-6d670f21a8184140cb31770959e09dbd",
"attachment_name" : "01c5f64e1c8f14d1123cacf6921e43b4_test_credentials_file.txt",
"resp_code" : 403,
"reason" : "The AWS Access Key Id you provided does not exist in our records."
},
{
"id" : "201803-461d4a97783105a46deb559e45d12266",
"attachment_name" : "c669cd4df0cb57625a8634562dd994e6_test_credentials_file.txt",
"resp_code" : 403,
"reason" : "The AWS Access Key Id you provided does not exist in our records."
}
],
"revision" : "7eebf3cd4c24826feeb59f9d59ab2493",
"timestamp" : "2018-03-08T19:08:08",
"version" : "4.3.1",
"node" : "p1vlV1a_qodo9eHpALZAKw",
"request_id" : "573f2d76601744af316f1e2fc24c9304",
"status" : "success",
"auth_token" : "..."
}
Authentication Token Operations
Crossbar module for operations on JWT Token, SSO/OAuth tokens.
About Authentication
Schema for auth.callback
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
client_id |
client id, usually application id for OAuth providers | string |
true |
|
code |
access code emitted by provider | string |
true |
true |
provider |
provider | string |
true |
true |
redirect_uri |
redirect URI | string |
true |
|
state |
state | string |
false |
Schema for auth.provider
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
id |
id | string |
true |
Schema for auth.app
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
client_id |
client id, usually application id for OAuth providers | string |
true |
|
email |
email for application | string |
true |
false |
provider |
provider | string |
true |
true |
secret |
secret for application | string |
true |
Resetting System (Lumian) Signature Secret
System signature secret and the subject signature is being used to sign the signature in the JWT token that Lumian is issuing.
If you feel that this system secret is compromised, use this API to reset it.
!!! danger Resetting system signature secret will invalidate all issued token! In other words all login users will be logout from the system and can't make any further request until login again. Use this API if you feel the system secret is compromised only.
!!! note Only super duper admin can reset system secret!
PUT /v2/auth
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{ "action": "reset_signature_secret", "data": {} }' \
http://{SERVER}:8000/v2/auth
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/auth',
'{ "action": "reset_signature_secret", "data": {} }',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Responses
Returns an empty success response.
Sample Response:
{
"timestamp": "{TIMESTAMP}",
"version": "4.0.0",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Resetting an Account or a User Signature Secret
System signature secret and the subject signature is being used to sign the signature in the JWT token that Lumian is issuing.
If you feel that an account or a user secret is compromised, use this API to reset it.
!!! danger Resetting signature secret will invalidate user's issued token! In other words if the user is already login, it will be logout from the system and can't make any further request until login again.
!!! note Only the user or an account admin can reset the user's secret.
To Reset an Account Signature Secret
PUT /v2/accounts/{ACCOUNT_ID}/auth
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{ "action": "reset_signature_secret", "data": {} }' \
http://{SERVER}:8000/v2/accounts/290ac723eb6e73dd4a0adcd77785e04e/auth
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/290ac723eb6e73dd4a0adcd77785e04e/auth',
'{ "action": "reset_signature_secret", "data": {} }',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
To Reset a User Signature Secret
PUT /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/auth
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{ "action": "reset_signature_secret", "data": {} }' \
http://{SERVER}:8000/v2/accounts/290ac723eb6e73dd4a0adcd77785e04e/users/3bedb94b3adfc4873a548b41d28778b5/auth
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/290ac723eb6e73dd4a0adcd77785e04e/users/3bedb94b3adfc4873a548b41d28778b5/auth',
'{ "action": "reset_signature_secret", "data": {} }',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Response
Returns an empty success response.
Sample Response:
{
"timestamp": "{TIMESTAMP}",
"version": "4.0.0",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Request a new token while current token is still valid
!!! note This will fail if your password or User Signature Secret was reset.
PUT /v2/auth
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{ "action": "refresh_token", "data": {} }' \
http://{SERVER}:8000/v2/auth
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/auth',
'{ "action": "refresh_token", "data": {} }',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Get a List of Registered SSO App
This list all registered Single Sign On applications for the account's reseller. Account ID is determined in order by first from the query string account_id, or from request path (/accounts/{ACCOUNT_ID}) or from authenticated user's account id.
GET /v2/auth/apps
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/auth/apps
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/auth/apps', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"page_size": 1,
"data": [
{
"id": "iamatestclientid.apps.googleusercontent.com",
"provider": "google"
}
],
"timestamp": "{TIMESTAMP}",
"version": "4.0.0",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
List SSO Provider
Get a list of all Single Sign On provider.
GET /v2/auth/providers
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/auth/providers
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/auth/providers', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"page_size": 3,
"start_key": [
"oauth"
],
"data": [
{
"id": "salesforce",
"provider_type": "oauth"
},
{
"id": "office365",
"provider_type": "oauth"
},
{
"id": "google",
"provider_type": "oauth"
},
{
"id": "duo",
"enabled": false,
"name": "System Default Provider",
"provider_name": "duo",
"provider_type": "multi_factor"
}
],
"timestamp": "{TIMESTAMP}",
"version": "4.0.0",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
List User's Linked SSO Applications
Get a list of the linked Single Sign On applications for the authenticated user.
GET /v2/auth/links
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/auth/links
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/auth/links', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"page_size": 1,
"data": [
{
"id": "{LINKED_USER_ID}",
"app": "{LINKED_OAUTH_APP_ID}",
"provider": "{LINKED_OAUTH_PROVIDER}",
"scopes": [
"https://www.googleapis.com/auth/plus.me",
"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email"
],
"email": "{USER_EMAIL}"
}
],
"timestamp": "{TIMESTAMP}",
"version": "4.0.0",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
List Public Key Cryptography
Lists a list of keys which is being used to sign and validate JWT tokens.
GET /v2/auth/keys
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/auth/keys
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/auth/keys', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"page_size": 1,
"data": [
"96247ed90b4bec8294c09ae6ece923a2"
],
"timestamp": "{TIMESTAMP}",
"version": "4.0.0",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Authenticate a User with a SSO (Create a Token from SSO Response)
After a user authenticate with Single Sign On provider, use this API to send the provider response to Crossbar to login and create a token.
PUT /v2/auth/callback
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{ "data": { "redirect_uri": "{MONSTER_UI_IP}", "client_id": "{OAUTH_CLIENT_ID}", "provider": "{OAUTH_PROVIDER_NAME}", "code": "{OAUTH_RESP_CODE}" } }' \
http://{SERVER}:8000/v2/auth/callback
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/auth/callback',
'{ "data": { "redirect_uri": "{MONSTER_UI_IP}", "client_id": "{OAUTH_CLIENT_ID}", "provider": "{OAUTH_PROVIDER_NAME}", "code": "{OAUTH_RESP_CODE}" } }',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Response when no User is Linked yet
If this is the first time that the user is authenticating using this SSO provider, Lumian returns and empty response indicating that user should first login using it's own Lumian credentials first to link the SSO application with its user. After login the user is linked with the application and it no need to manual login again.
Sample Response:
{
"page_size": 1,
"data": {},
"timestamp": "{TIMESTAMP}",
"version": "4.0.0",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Response when the User is Linked
Sample Response:
{
"page_size": 1,
"data": {
"owner_id": "{OWNER_ID}",
"account_id": "{ACCOUNT_ID}",
"reseller_id": "{RESELLER_ID}",
"account_name": "{ACCOUNT_NAME}",
"language": "{LANG}",
"apps": []
},
"timestamp": "{TIMESTAMP}",
"version": "4.0.0",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Validate and Authorize a Foreign SSO Token/App
PUT /v2/auth/authorize
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/auth/authorize
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/auth/authorize',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Get Token Information (Query String version)
Returns the information encoded in the specified authentication token (from query string token parameter).
GET /v2/auth/tokeninfo
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/auth/tokeninfo?token={AN_AUTH_TOKEN}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/auth/tokeninfo?token={AN_AUTH_TOKEN}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"page_size": 1,
"data": {
"owner_id": "{OWNER_ID}",
"account_id": "{ACCOUNT_ID}",
"reseller_id": "{RESELLER_ID}",
"account_name": "{ACCOUNT_NAME}",
"language": "{LANG}",
"apps": []
},
"timestamp": "{TIMESTAMP}",
"version": "4.0.0",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Get Token Information (Request Body version)
Returns the information encoded in the specified authentication token (from request body token parameter).
POST /v2/auth/tokeninfo
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{ "data": { "token": "{AN_AUTH_TOKEN}" } }' \
http://{SERVER}:8000/v2/auth/tokeninfo
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/auth/tokeninfo',
'{ "data": { "token": "{AN_AUTH_TOKEN}" } }',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Responses
Sample Response:
{
"page_size": 1,
"data": {
"owner_id": "{OWNER_ID}",
"account_id": "{ACCOUNT_ID}",
"reseller_id": "{RESELLER_ID}",
"account_name": "{ACCOUNT_NAME}",
"language": "{LANG}",
"apps": []
},
"timestamp": "{TIMESTAMP}",
"version": "4.0.0",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Get a SSO Application
Get a Single Sign On application by it's ID.
GET /v2/auth/apps/{APP_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/auth/apps/{APP_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/auth/apps/{APP_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"page_size": 1,
"data": {
"id": "{APP_ID}"
},
"timestamp": "{TIMESTAMP}",
"version": "4.0.0",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Change a SSO Application
POST /v2/auth/apps/{APP_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/auth/apps/{APP_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/auth/apps/{APP_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove a SSO Application
DELETE /v2/auth/apps/{APP_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/auth/apps/{APP_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/auth/apps/{APP_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Get a Public Key
Get a public key used for signing the JWT tokens issued by system.
!!! note
To get the public key in form of a PEM file set Accept header as application/x-pem-file.
GET /v2/auth/keys/{KEY_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/auth/keys/96247ed90b4bec8294c09ae6ece923a2
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/auth/keys/96247ed90b4bec8294c09ae6ece923a2', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"page_size": 1,
"data": {
"public_key_pem": "-----BEGIN RSA PUBLIC KEY-----\n{A_PUBLIC_KEY}\n-----END RSA PUBLIC KEY-----\n\n"
},
"timestamp": "{TIMESTAMP}",
"version": "4.0.0",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Reset a Private Key
Reset the private key of the system used to signing and verifying issued JWT tokens. If you feel that the private key is compromised, use this API to generate a new private and public key.
!!! danger Resetting system private will invalidate all issued token! In other words all login users will be logout from the system and can't make any further request until login again. Use this API if you feel the system private key is compromised only.
!!! note Only super duper admin can reset system private key!
PUT /v2/auth/keys/{KEY_ID}
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{ "action": "reset_private_key", "data": {} }' \
http://{SERVER}:8000/v2/auth/keys/96247ed90b4bec8294c09ae6ece923a2
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/auth/keys/96247ed90b4bec8294c09ae6ece923a2',
'{ "action": "reset_private_key", "data": {} }',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Responses
Sample Response:
{
"timestamp": "{TIMESTAMP}",
"version": "4.0.0",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Fetch a SSO Provider Information
GET /v2/auth/providers/{PROVIDER_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/auth/providers/google
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/auth/providers/google', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"data": {
"access_code_url": "https://accounts.google.com/o/oauth2/token",
"auth_module": "oauth",
"auth_url": "https://accounts.google.com/o/oauth2/token",
"discovery": "https://accounts.google.com/.well-known/openid-configuration",
"issuer_domains": [
"accounts.google.com"
],
// rest of the provider information...
"id": "google"
},
"timestamp": "{TIMESTAMP}",
"version": "4.0.0",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Make changes to SSO Provider
!!! note Only super duper admin can make changes to SSO provider!
POST /v2/auth/providers/{PROVIDER_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/auth/providers/{PROVIDER_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/auth/providers/{PROVIDER_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove a SSO Provider
!!! note Only super duper admin can delete a SSO provider!
DELETE /v2/auth/providers/{PROVIDER_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/auth/providers/{PROVIDER_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/auth/providers/{PROVIDER_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Get an User's Linked SSO Applications Information
GET /v2/auth/links/{LINK_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/auth/links/d6faaff6b054393f28356ab7b38ad1bf-116254222860442180295
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/auth/links/d6faaff6b054393f28356ab7b38ad1bf-116254222860442180295', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"data": {
"email": "{USER_EMAIL}",
"verified_email": true,
"scope": "{PROVIDER_SCOPE}",
"scopes": ["{SCOPES}"],
"profile": { //user's profile },
"display_name": "{Test Person}",
"id": "d6faaff6b054393f28356ab7b38ad1bf-116254222860442180295"
},
"timestamp": "{TIMESTAMP}",
"version": "4.0.0",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Link an User to a SSO Application
When the user is signing on with A Single Sign On provider for the first time, it should login with its own Lumian credentials one more time, and then make a request to this API to link its Lumian's user to the SSO. After that the user can sign in with SSO regularly and no need to use Lumian credentials again.
PUT /v2/auth/links/{LINK_ID}
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/auth/links/d6faaff6b054393f28356ab7b38ad1bf-116254222860442180295
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/auth/links/d6faaff6b054393f28356ab7b38ad1bf-116254222860442180295',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Responses
Sample Response:
{
"data": {
"email": "{USER_EMAIL}",
"verified_email": true,
"scope": "{PROVIDER_SCOPE}",
"scopes": ["{SCOPES}"],
"profile": { //user's profile },
"display_name": "{Test Person}",
"id": "d6faaff6b054393f28356ab7b38ad1bf-116254222860442180295"
},
"timestamp": "{TIMESTAMP}",
"version": "4.0.0",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Unlink a user from SSO Application
DELETE /v2/auth/links/{LINK_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/auth/links/d6faaff6b054393f28356ab7b38ad1bf-116254222860442180295
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/auth/links/d6faaff6b054393f28356ab7b38ad1bf-116254222860442180295', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"data": {
"email": "{USER_EMAIL}",
"verified_email": true,
"scope": "{PROVIDER_SCOPE}",
"scopes": ["{SCOPES}"],
"profile": { //user's profile },
"display_name": "{Test Person}",
"id": "d6faaff6b054393f28356ab7b38ad1bf-116254222860442180295"
},
"timestamp": "{TIMESTAMP}",
"version": "4.0.0",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Basic Auth
As an alternative for generated Tokens, you can make request with HTTP Basic Auth using your account ID and user name and password.
Basic Auth Username
Should be set to account_id of the authorizing account.
Basic Password Password
Should be set to MD5 hash of your username:password
Sample Request:
PASSWORD=`echo -n username:password | md5sum | awk '{print $1}'`
import axios from 'axios';
const response = await axios.get('http://PASSWORD=ca664ea481da78792223bf19f17824ae');
Sample cURL Requests
Sample Request:
curl -v \
--basic --user {AUTH_ACCOUNT_ID}:$PASSWORD \
http://server.com:8000/v2/accounts/{ACCOUNT_ID}/devices
import axios from 'axios';
const response = await axios.get('http://server.com:8000/v2/accounts/{ACCOUNT_ID}/devices', {
auth: {
username: '{AUTH_ACCOUNT_ID}'
}
});
This is useful for reseller to execute requests against a their sub-account quickly.
Blacklists
About Blacklists
A blacklist is a map of caller id numbers that can be then apply to the account to block these callers to call the system.
Schema
Schema for a blacklists
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
flags.[] |
string() |
false |
supported |
||
flags |
Flags set by external applications | array(string()) |
false |
supported |
|
name |
A friendly name for the temporal rule set | string(1..128) |
true |
supported |
|
numbers |
Map of caller id number to block | object() |
{} |
false |
supported |
should_block_anonymous |
Should block Anonymous call | boolean() |
false |
supported |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/blacklists
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/blacklists
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/blacklists', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create
PUT /v2/accounts/{ACCOUNT_ID}/blacklists
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/blacklists
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/blacklists',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Fetch
GET /v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Change
POST /v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Patch
PATCH /v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove
DELETE /v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Braintree
About Braintree
DISCLAIMER: Please read the docs available at braintree to know how braintree works and how its APIs are intended to work.
Braintree provides good docs to make you knowledgeable about what are important fields and what fields can be left from the API requests.
This doc just provides examples as what is possible with the API but you should consult braintree and their API documentation before using Lumian's braintree modules.
Test out braintree using sandbox account before deploying it in production as the module is considered NOT PRODUCTION READY.
Schema
Fetch
GET /v2/accounts/{ACCOUNT_ID}/braintree/client_token
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/client_token
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/client_token', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"client_token": "{BRAINTREE_CLIENT_TOKEN}"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Show this account's credits
GET /v2/accounts/{ACCOUNT_ID}/braintree/credits
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/credits
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/credits', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"amount": 500.0,
"billing_account_id": "31a05ddba6a9df166c7d50fc4b683606"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Add credit to this account
PUT /v2/accounts/{ACCOUNT_ID}/braintree/credits
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"amount":200.00}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/credits
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/credits',
// '{"data":{"amount":200.00}}',
{
'data': {
'amount': 200
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"bookkeeper_info": {
"add_ons": [],
"amount": "20.00",
"avs_postal_response": "M",
"avs_street_response": "I",
"card": {
"bin": "411111",
"card_type": "Visa",
"customer_location": "US",
"default": false,
"expiration_month": "11",
"expiration_year": "2020",
"expired": false,
"id": "7gz3qw",
"last_four": "1111"
},
"ccv_response_code": "I",
"created_at": "2016-09-29T14:22:54Z",
"currency_code": "USD",
"customer": {
"company": "ACME Corp",
"first_name": "John",
"id": "31a05ddba6a9df166c7d50fc4b657854",
"last_name": "Doe",
"phone": "9122475533"
},
"discounts": [],
"id": "0gmy6jrw",
"is_api": true,
"is_automatic": false,
"is_recurring": false,
"merchant_account_id": "romanat",
"order_id": "a6268d1a31a76d53857fae0d",
"processor_authorization_code": "XJ3YL9",
"processor_response_code": "1000",
"processor_response_text": "Approved",
"purchase_order": "3001",
"status": "submitted_for_settlement",
"tax_exempt": false,
"type": "sale",
"update_at": "2016-09-29T14:22:54Z"
},
"description": "credit addition from credit card",
"id": "80591de5690374ebba7adc4ffaaf51c1",
"order_id": "a6268d1a31a76d53857fae0d310552ab",
"sub_account_id": "22f1b082e505064cc930e944bf9a0728",
"sub_account_name": "romana"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
List this account's transactions
GET /v2/accounts/{ACCOUNT_ID}/braintree/transactions
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/transactions
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/transactions', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [{
"id": "{TRANSACTION_ID}",
"status": "{STATUS_OF_TRANSACTION}",
"type": "sale",
"currency_code": "{CURRENCY_CODE}",
"amount": "20.00",
"merchant_account_id": "{BRAINTREE_MERCHANT_ID}",
"order_id": "{ORDER_ID}",
"purchase_order": "3001",
"created_at": "2016-09-29T14:22:54Z",
"update_at": "2016-09-29T14:22:54Z",
"avs_postal_response": "M",
"avs_street_response": "I",
"ccv_response_code": "I",
"processor_authorization_code": "XJ3LR9",
"processor_response_code": "1000",
"processor_response_text": "Approved",
"tax_exempt": false,
"billing_address": {
{BRAINTREE_CUSTOMER_ADDRESS}
},
"shipping_address": {
{BRAINTREE_CUSTOMER_SHIPPING_ADDRESS}
},
"customer": {
{BRAINTREE_CUSTOMER_INFO}
},
"card": {
{BRAINTREE_CREDIT_CARD_DETAILS}
},
"add_ons": [
{ADDONS_IN_ORDER}
],
"discounts": [
{DISCOUNTS_APPLIED_TO_ORDER}
],
"is_api": true,
"is_automatic": {AUTOMATIC_BILLING},
"is_recurring": {RECURRING_SUBSCRIPTION}
}],
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
List addresses
GET /v2/accounts/{ACCOUNT_ID}/braintree/addresses
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/addresses
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/addresses', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"company": "{CUSTOMER_COMPANY}",
"country_code": "{BRAINTREE_COUNTRY_CODE}",
"country_code_three": "{BRAINTREE_COUNTRY_CODE_THREE}",
"country_code_two": "{BRAINTREE_COUNTRY_CODE_TWO}",
"country_name": "{BRAINTREE_COUNTRY_NAME}",
"created_at": "2016-09-23T00:20:51Z",
"customer_id": "{ACCOUNT_ID}",
"extended_address": "{EXTENDED_CUSTOMER_ADDRESS}",
"first_name": "{CUSTOMER_FIRST_NAME}",
"id": "7x",
"last_name": "{CUSTOMER_LAST_NAME}",
"locality": "{CUSTOMER_LOCALITY}",
"postal_code": "{CUSTOMER_POSTAL_CODE}",
"region": "{BRAINTREE_REGION}",
"street_address": "{CUSTOMER_ADDRESS}",
"updated_at": "2016-09-23T00:20:51Z"
}
],
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Add an address
PUT /v2/accounts/{ACCOUNT_ID}/braintree/addresses
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"{ADDRESS_INFORMATION}"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/addresses
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/addresses',
'{"data":{"{ADDRESS_INFORMATION}"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"company": "{CUSTOMER_COMPANY}",
"country_code": "{BRAINTREE_COUNTRY_CODE}",
"country_code_three": "{BRAINTREE_COUNTRY_CODE_THREE}",
"country_code_two": "{BRAINTREE_COUNTRY_CODE_TWO}",
"country_name": "{BRAINTREE_COUNTRY_NAME}",
"created_at": "2016-09-23T00:20:51Z",
"customer_id": "{ACCOUNT_ID}",
"extended_address": "{EXTENDED_CUSTOMER_ADDRESS}",
"first_name": "{CUSTOMER_FIRST_NAME}",
"id": "7x",
"last_name": "{CUSTOMER_LAST_NAME}",
"locality": "{CUSTOMER_LOCALITY}",
"postal_code": "{CUSTOMER_POSTAL_CODE}",
"region": "{BRAINTREE_REGION}",
"street_address": "{CUSTOMER_ADDRESS}",
"updated_at": "2016-09-23T00:20:51Z"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
List credit cards
GET /v2/accounts/{ACCOUNT_ID}/braintree/cards
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/cards
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/cards', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [{
"id": "{CARD_ID}",
"bin": "{CARD_FIRST_SIX_DIGITS}",
"card_type": "Visa",
"created_at": "2016-09-23T00:20:51Z",
"updated_at": "2016-09-29T14:22:54Z",
"default": true,
"expiration_month": "11",
"expiration_year": "2020",
"expired": false,
"customer_location": "US",
"last_four": "1111",
"customer_id": "{ACCOUNT_ID}",
"created_at": "2016-09-23T00:20:51Z",
"updated_at": "2016-09-29T14:22:54Z",
"billing_address": {
{BRAINTREE_ADDRESS}
},
"billing_address_id": "{BRAINTREE_ADDRESS_ID}"
}],
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Add a credit card
PUT /v2/accounts/{ACCOUNT_ID}/braintree/cards
To add a credit card, the information about a credit card can be sent in the request or payment_token_nonce.
with payment method nonce
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"payment_method_nonce":"valid-nonce"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/cards
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/cards',
{
'data': {
'payment_method_nonce': 'valid-nonce'
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"id": "{CARD_ID}",
"bin": "{CARD_FIRST_SIX_DIGITS}",
"card_type": "Visa",
"created_at": "2016-09-23T00:20:51Z",
"updated_at": "2016-09-29T14:22:54Z",
"default": true,
"expiration_month": "11",
"expiration_year": "2020",
"expired": false,
"customer_location": "US",
"last_four": "1111",
"customer_id": "{ACCOUNT_ID}",
"created_at": "2016-09-23T00:20:51Z",
"updated_at": "2016-09-29T14:22:54Z",
"billing_address": {
{BRAINTREE_ADDRESS}
},
"billing_address_id": "{BRAINTREE_ADDRESS_ID}"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
with credit card info
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"{CREDIT_CARD_INFO}"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/cards
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/cards',
'{"data":{"{CREDIT_CARD_INFO}"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"id": "{CARD_ID}",
"bin": "{CARD_FIRST_SIX_DIGITS}",
"card_type": "Visa",
"created_at": "2016-09-23T00:20:51Z",
"updated_at": "2016-09-29T14:22:54Z",
"default": true,
"expiration_month": "11",
"expiration_year": "2020",
"expired": false,
"customer_location": "US",
"last_four": "1111",
"customer_id": "{ACCOUNT_ID}",
"created_at": "2016-09-23T00:20:51Z",
"updated_at": "2016-09-29T14:22:54Z",
"billing_address": {
{BRAINTREE_ADDRESS}
},
"billing_address_id": "{BRAINTREE_ADDRESS_ID}"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Get this account's details
GET /v2/accounts/{ACCOUNT_ID}/braintree/customer
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/customer
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/customer', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"id": "{ACCOUNT_ID}",
"first_name": "John",
"last_name": "Doe",
"company": "Presentation",
"phone": "9122475533",
"created_at": "2016-09-17T21:08:01Z",
"updated_at": "2016-09-23T00:20:53Z",
"credit_cards": [{
{BRAINTREE_CREDIT_CARD}
}],
"addresses": [{
{BRAINTREE_CUSTOMER_ADDRESS}
}]
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Add a customer
POST /v2/accounts/{ACCOUNT_ID}/braintree/customer
To add a customer we can send the customer's info as with just customer's name, company and phone or can add a payment_method_nonce with it,
or add a credit card with the customer info with card's info or with payment_method_nonce token.
the user can be added without any credit card
Sample Response:
{
"data": {
"first_name": "John",
"last_name": "Doe",
"company": "ACME CORP",
"phone": "6000000000"
}
}
without any credit card and contains payment method nonce in their json request
Sample Response:
{
"data": {
"first_name": "John",
"last_name": "Doe",
"company": "ACME CORP",
"phone": "6000000000",
"payment_method_nonce": "valid-nonce"
}
}
payment method nonce is added to the credit card section
Sample Response:
{
"data": {
"first_name": "John",
"last_name": "Doe",
"company": "ACME CORP",
"phone": "6000000000",
"credit_card":{
"payment_method_nonce": "valid-nonce"
}
}
}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"{CUSTOMER_INFO}"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/customer
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/customer', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
},
data: '{"data":{"{CUSTOMER_INFO}"}}'
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"id": "{ACCOUNT_ID}",
"first_name": "John",
"last_name": "Doe",
"company": "Presentation",
"phone": "9122475533",
"created_at": "2016-09-17T21:08:01Z",
"updated_at": "2016-09-23T00:20:53Z",
"credit_cards": [{
{BRAINTREE_CREDIT_CARD}
}],
"addresses": [{
{BRAINTREE_CUSTOMER_ADDRESS}
}]
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Fetch details on a transaction
GET /v2/accounts/{ACCOUNT_ID}/braintree/transactions/{TRANSACTION_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/transactions/{TRANSACTION_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/transactions/{TRANSACTION_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"id": "{TRANSACTION_ID}",
"status": "{STATUS_OF_TRANSACTION}",
"type": "sale",
"currency_code": "{CURRENCY_CODE}",
"amount": "20.00",
"merchant_account_id": "{BRAINTREE_MERCHANT_ID}",
"order_id": "{ORDER_ID}",
"purchase_order": "3001",
"created_at": "2016-09-29T14:22:54Z",
"update_at": "2016-09-29T14:22:54Z",
"avs_postal_response": "M",
"avs_street_response": "I",
"ccv_response_code": "I",
"processor_authorization_code": "XJ3LR9",
"processor_response_code": "1000",
"processor_response_text": "Approved",
"tax_exempt": false,
"billing_address": {
{BRAINTREE_CUSTOMER_ADDRESS}
},
"shipping_address": {
{BRAINTREE_CUSTOMER_SHIPPING_ADDRESS}
},
"customer": {
{BRAINTREE_CUSTOMER_INFO}
},
"card": {
{BRAINTREE_CREDIT_CARD_DETAILS}
},
"add_ons": [
{ADDONS_IN_ORDER}
],
"discounts": [
{DISCOUNTS_APPLIED_TO_ORDER}
],
"is_api": true,
"is_automatic": {AUTOMATIC_BILLING},
"is_recurring": {RECURRING_SUBSCRIPTION}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Remove an address
DELETE /v2/accounts/{ACCOUNT_ID}/braintree/addresses/{ADDRESS_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/addresses/{ADDRESS_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/addresses/{ADDRESS_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Fetch an address' details
GET /v2/accounts/{ACCOUNT_ID}/braintree/addresses/{ADDRESS_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/addresses/{ADDRESS_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/addresses/{ADDRESS_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"id": "7x",
"customer_id": "{ACCOUNT_ID}",
"first_name": "{CUSTOMER_FIRST_NAME}",
"last_name": "{CUSTOMER_LAST_NAME}",
"company": "{CUSTOMER_COMPANY}",
"street_address": "{CUSTOMER_ADDRESS}",
"extended_address": "{EXTENDED_CUSTOMER_ADDRESS}",
"locality": "{CUSTOMER_LOCALITY}",
"region": "{BRAINTREE_REGION}",
"postal_code": "{CUSTOMER_POSTAL_CODE}",
"country_code": "{BRAINTREE_COUNTRY_CODE}",
"country_code_two": "{BRAINTREE_COUNTRY_CODE_TWO}",
"country_code_three": "{BRAINTREE_COUNTRY_CODE_THREE}",
"country_name": "{BRAINTREE_COUNTRY_NAME}",
"created_at": "2016-09-23T00:20:51Z",
"updated_at": "2016-09-23T00:20:51Z"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Update an address
POST /v2/accounts/{ACCOUNT_ID}/braintree/addresses/{ADDRESS_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"{ADDRESS_INFORMATION}"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/addresses/{ADDRESS_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/addresses/{ADDRESS_ID}',
'{"data":{"{ADDRESS_INFORMATION}"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"id": "7x",
"customer_id": "{ACCOUNT_ID}",
"first_name": "{CUSTOMER_FIRST_NAME}",
"last_name": "{CUSTOMER_LAST_NAME}",
"company": "{CUSTOMER_COMPANY}",
"street_address": "{CUSTOMER_ADDRESS}",
"extended_address": "{EXTENDED_CUSTOMER_ADDRESS}",
"locality": "{CUSTOMER_LOCALITY}",
"region": "{BRAINTREE_REGION}",
"postal_code": "{CUSTOMER_POSTAL_CODE}",
"country_code": "{BRAINTREE_COUNTRY_CODE}",
"country_code_two": "{BRAINTREE_COUNTRY_CODE_TWO}",
"country_code_three": "{BRAINTREE_COUNTRY_CODE_THREE}",
"country_name": "{BRAINTREE_COUNTRY_NAME}",
"created_at": "2016-09-23T00:20:51Z",
"updated_at": "2016-09-23T00:20:51Z"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Remove a credit card
DELETE /v2/accounts/{ACCOUNT_ID}/braintree/cards/{CARD_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/cards/{CARD_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/cards/{CARD_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": { },
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Fetch a credit card's details
GET /v2/accounts/{ACCOUNT_ID}/braintree/cards/{CARD_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/cards/{CARD_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/cards/{CARD_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"id": "{CARD_ID}",
"bin": "{CARD_FIRST_SIX_DIGITS}",
"card_type": "Visa",
"created_at": "2016-09-23T00:20:51Z",
"updated_at": "2016-09-29T14:22:54Z",
"default": true,
"expiration_month": "11",
"expiration_year": "2020",
"expired": false,
"customer_location": "US",
"last_four": "1111",
"customer_id": "{ACCOUNT_ID}",
"created_at": "2016-09-23T00:20:51Z",
"updated_at": "2016-09-29T14:22:54Z",
"billing_address": {
{BRAINTREE_ADDRESS}
},
"billing_address_id": "{BRAINTREE_ADDRESS_ID}"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Update a credit card
POST /v2/accounts/{ACCOUNT_ID}/braintree/cards/{CARD_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"{CREDIT_CARD_INFO_OR_PAYMENT_NONCE}"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/cards/{CARD_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/cards/{CARD_ID}',
'{"data":{"{CREDIT_CARD_INFO_OR_PAYMENT_NONCE}"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"id": "{CARD_ID}",
"bin": "{CARD_FIRST_SIX_DIGITS}",
"card_type": "Visa",
"created_at": "2016-09-23T00:20:51Z",
"updated_at": "2016-09-29T14:22:54Z",
"default": true,
"expiration_month": "11",
"expiration_year": "2020",
"expired": false,
"customer_location": "US",
"last_four": "1111",
"customer_id": "{ACCOUNT_ID}",
"created_at": "2016-09-23T00:20:51Z",
"updated_at": "2016-09-29T14:22:54Z",
"billing_address": {
{BRAINTREE_ADDRESS}
},
"billing_address_id": "{BRAINTREE_ADDRESS_ID}"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Bulk
About Bulk
Schema
Fetch
GET /v2/accounts/{ACCOUNT_ID}/bulk
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"ids": ["{ID1}", "{ID2}", "{ID3}"]}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/bulk
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/bulk', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
},
data: '{"data": {"ids": ["{ID1}", "{ID2}", "{ID3}"]}}'
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
...
],
"page_size": 0,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Call Inspector
About Call Inspector
The Call Inspector Crossbar resource allows the client to query and inspect data related to the Call Inspector application.
The Call Inspector endpoint is not loaded on start in a default Lumian installation.
- To enable at runtime:
sup crossbar_maintenance start_module cb_call_inspector
- To autostart on Crossbar boot:
- Navigate to
http://localhost:15984/_utils/document.html?system_config/crossbar - Edit the
autoload_moduleslist to include 'cb_call_inspector' - Click the green check box to the right of the input box
- Click 'Save Document' in top left of the screen
- Navigate to
Note: adding cb_call_inspector to the crossbar system_config doc will not start the endpoint; only on restarting Crossbar will cb_call_inspector be loaded. Use the sup command above to start the endpoint at runtime.
Schema
Fetch
GET /v2/accounts/{ACCOUNT_ID}/call_inspector
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/call_inspector
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/call_inspector', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{CALL_ID1},
{CALL_ID2}
]
"status": "success"
}
Read a call's SIP dialogue
GET /v2/accounts/{ACCOUNT_ID}/call_inspector/{CALL_ID}
{CALL_ID}is the unique string identifying a call. Call has to be under the authority of{ACCOUNT_ID}.{ACCOUNT_ID}has to be a reseller's account id.
Note: {CHUNKS} is an array of JSON-formatted chunks.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/call_inspector/{CALL_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/call_inspector/{CALL_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"analysis": [],
"messages": {CHUNKS}
}
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Callflows
About Callflows
Callflows are the instructions Lumian uses to process a call. A callflow includes a list of numbers or regex patterns used by Lumian to determine what callflow is used when a call comes in for an account. The flow parameter defines the tree of actions, allowing branching (such as in the menu action) and chaining actions together. You can also branch to other callflows and execute its flow (useful to avoid recreating the same sub-flow structure).
Schema
Call flows describe steps to take in order to process a phone call. They are trees of information related to a phone call such as "answer, play file, record file" etc. that are logically grouped together and ordered.
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
featurecode.name |
string(1..128) |
false |
|||
featurecode.number |
string(1..30) |
false |
|||
featurecode |
When the callflow is used as a featurecode this object tracks the intended match of the pattern and name of the feature | object() |
false |
||
flags.[] |
string() |
false |
supported |
||
flags |
Flags set by external applications | array(string()) |
false |
supported |
|
flow |
A callflow node defines a module to execute, data to provide to that module, and zero or more children to branch to | #/definitions/callflows.action | false |
||
metaflow |
Actions applied to a call outside of the normal callflow, initiated by the caller(s) | #/definitions/metaflows | false |
||
numbers.[] |
string(1..36) |
false |
|||
numbers |
A list of static numbers that the callflow should execute for | array(string(1..36)) |
[] |
false |
|
patterns.[] |
string(1..) |
false |
|||
patterns |
A list of regular expressions that the callflow should execute for, with optional capture groups | array(string(1..)) |
[] |
false |
callflows.action
Call flows describe steps to take in order to process a phone call. They are trees of information related to a phone call such as "answer, play file, record file" etc. that are logically grouped together and ordered.
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
children./.+/ |
Call flows describe steps to take in order to process a phone call. They are trees of information related to a phone call such as "answer, play file, record file" etc. that are logically grouped together and ordered. | #/definitions/callflows.action | false |
||
children |
Children callflows | object() |
false |
||
data |
The data/arguments of the callflow module | object() |
{} |
true |
|
module |
The name of the callflow module to execute at this node | string(1..64) |
true |
metaflow
A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
children./.+/ |
A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to | #/definitions/metaflow | false |
||
children |
Children metaflows | object() |
false |
||
data |
The data/arguments of the metaflow module | object() |
{} |
false |
|
module |
The name of the metaflow module to execute at this node | string(1..64) |
true |
metaflows
Actions applied to a call outside of the normal callflow, initiated by the caller(s)
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
binding_digit |
What DTMF will trigger the collection and analysis of the subsequent DTMF sequence | `string('1' | '2' | '3' | '4' |
digit_timeout |
How long to wait between DTMF presses before processing the collected sequence (milliseconds) | integer() |
false |
||
listen_on |
Which leg(s) of the call to listen for DTMF | `string('both' | 'self' | 'peer')` | |
numbers./^[0-9]+$/ |
A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to | #/definitions/metaflow | false |
||
numbers |
A list of static numbers with their flows | object() |
false |
||
patterns./.+/ |
A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to | #/definitions/metaflow | false |
||
patterns |
A list of patterns with their flows | object() |
false |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/callflows
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create a new callflow
PUT /v2/accounts/{ACCOUNT_ID}/callflows
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove a callflow
DELETE /v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch a callflow's details
GET /v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Patch a callflow object
PATCH /v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Change a callflow object
POST /v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Cccps
About Cccps
Schema
Calling cards callback platform user's info
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
active |
Show's whether CID/PIN active | boolean() |
false |
false |
|
cid |
CID to authorize | string() |
false |
||
comment |
Some notes regarding what this pin/cid for | string() |
false |
||
max_concurent_calls_per_user |
Calls per user limit. Counts all user's legs and compares to max_concurrent_calls_per_user multiplied by 2 | integer() |
false |
||
pin |
PIN to authorize | string() |
false |
||
retain_cid |
Pass initial caller number to the callee | boolean() |
false |
||
user_id |
The ID of the user object that 'owns' cid/pin | string(32) |
false |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/cccps
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cccps
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cccps', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Call Detail Records
CDRs (Call Detail Records) provide a summary view of a call leg.
Schema
Call Detail Records
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
app_name |
The Lumian application that issued the CDR | string() |
false |
||
app_version |
The internal Lumian version number of the application that issued the CDR | string() |
false |
||
billing_seconds |
The number of seconds the call leg can be billed for (typically from when the call leg is answered | integer() |
false |
||
call_direction |
Direction of the call, relative to the media switch | `string('inbound' | 'outbound')` | false |
|
call_id |
Unique identifier of the call leg | string() |
true |
||
callee_id_name |
The indicated name of the callee | string() |
false |
||
callee_id_number |
The indicated number of the callee | string() |
false |
||
caller_id_name |
The indicated name of the caller | string() |
false |
||
caller_id_number |
The indicated number of the caller | string() |
false |
||
channel_call_state |
Media Server channel call state | string() |
false |
||
channel_created_time |
Media Server channel creation time | integer() |
false |
||
channel_name |
Media Server channel name | string() |
false |
||
channel_state |
Media Server channel state | string() |
false |
||
custom_application_vars |
Any custom-set values | object() |
false |
||
custom_channel_vars |
Lumian-specific key/value pairs set on the channel | object() |
false |
||
custom_sip_headers.in |
Custom SIP Headers to be applied to calls inbound to Lumian from the endpoint | #/definitions/custom_sip_headers | false |
||
custom_sip_headers.out |
Custom SIP Headers to be applied to calls outbound from Lumian to the endpoint | #/definitions/custom_sip_headers | false |
||
custom_sip_headers.^[a-zA-z0-9_\-]+$ |
The SIP header to add | string() |
false |
||
custom_sip_headers |
A property list of SIP headers | object() |
false |
||
digits_dialed |
All the DTMF tones detected on this leg of the call | string() |
false |
||
disposition |
Who sent the SIP BYE message | string() |
false |
||
duration_seconds |
The duration of the call leg, in seconds | integer() |
false |
||
event_category |
Lumian specific key (Event-Category) included on each payload it publishes | string() |
false |
||
event_name |
Lumian specific key (Event-Name) included on each payload it publishes | string() |
false |
||
fax_bad_rows |
Number of rows that failed to transfer | string() |
false |
||
fax_ecm_used |
Was ECM (error correction mode) used on the fax | string() |
false |
||
fax_result_code |
Media Server's result code of the transmission | string() |
false |
||
fax_result_text |
Error String, if any, or 'OK' if successful | string() |
false |
||
fax_success |
Whether the fax was considered a success or not | string() |
false |
||
fax_total_pages |
Number of pages in the fax | string() |
false |
||
fax_transfer_rate |
Baud of the fax transfer | string() |
false |
||
fax_transferred_pages |
Number of pages transferred | string() |
false |
||
from |
Built by Lumian, depending on direction, to represent the From user | string() |
false |
||
from_tag |
SIP From TAG | string() |
false |
||
from_uri |
The From SIP URI | string() |
false |
||
hangup_cause |
The reason for the call leg's termination | string() |
false |
||
hangup_code |
The SIP hangup code, if available | string() |
false |
||
interaction_id |
correlating ID among related call legs | string() |
false |
||
interaction_key |
Unique portion of the interaction ID | string() |
false |
||
interaction_time |
Timestamp of the creation of the interaction ID | integer() |
false |
||
local_sdp |
The SDP negotiated by the local agent | string() |
false |
||
media_server |
The hostname of the media server that processed the call | string() |
false |
||
msg_id |
Lumian specific key (Msg-Id) assigned to each payload it publishes | string() |
false |
||
node |
The ecallmgr which issued the CDR | string() |
false |
||
other_leg_call_id |
If this leg was bridged, the call-id of the opposite leg | string() |
false |
||
other_leg_caller_id_name |
Caller ID name of the bridged leg | string() |
false |
||
other_leg_caller_id_number |
Caller ID number of the bridged leg | string() |
false |
||
other_leg_destination_number |
Dialed number of the other leg | string() |
false |
||
other_leg_direction |
direction of the other leg, relative to the media server | string() |
false |
||
presence_id |
ID used in NOTIFY SIP messages | string() |
false |
||
remote_sdp |
The SDP negotiated by the remote agent | string() |
false |
||
request |
Built by Lumian this is the processed request URI | string() |
false |
||
ringing_seconds |
How many seconds the leg was ringing (pre-answer) | integer() |
false |
||
switch_hostname |
Media Server hostname (as reported by the switch) | string() |
false |
||
switch_nodename |
Media Server node name (as known in ecallmgr) | string() |
false |
||
switch_uri |
Media Server URI | string() |
false |
||
switch_url |
Media Server URL | string() |
false |
||
timestamp |
UTC timestamp, in Gregorian seconds, of when the CDR was generated | integer() |
false |
||
to |
Built by Lumian, depending on direction, to represent the To user | string() |
false |
||
to_tag |
SIP TO Tag | string() |
false |
||
to_uri |
The To SIP URI | string() |
false |
||
user_agent |
User agent header from SIP packet | string() |
false |
custom_sip_headers
Custom SIP headers applied to an INVITE
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
^[a-zA-z0-9_\-]+$ |
The SIP header to add | string() |
false |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/cdrs
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Get a time range of CDRs (using Gregorian seconds for timestamps):
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs?created_from={FROM_TIMESTAMP}&created_to={TO_TIMESTAMP}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs?created_from={FROM_TIMESTAMP}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Get CDRs and update datetime field to local time zone (using seconds for timeoffset from UTC time):
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs?created_from={FROM_TIMESTAMP}&created_to={TO_TIMESTAMP}&utc_offset={SECONDS_OFFSET}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs?created_from={FROM_TIMESTAMP}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Get CDRs as CSV:
Sample Request:
curl -v -X GET \
-H "Accept: text/csv" \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs', {
headers: {
'Accept': 'text/csv',
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Get CDRs as CSV and define filename:
Sample Request:
curl -v -X GET \
-H "Accept: text/csv" \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "X-File-Name: {FILE_NAME}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs', {
headers: {
'Accept': 'text/csv',
'X-Auth-Token': '{AUTH_TOKEN}',
'X-File-Name': '{FILE_NAME}'
}
});
or
Sample Request:
curl -v -X GET \
-H "Accept: text/csv" \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs?file_name={FILE_NAME}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs?file_name={FILE_NAME}', {
headers: {
'Accept': 'text/csv',
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch a CDR's details
GET /v2/accounts/{ACCOUNT_ID}/cdrs/{CDR_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs/{CDR_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs/{CDR_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch interaction summary
GET /v2/accounts/{ACCOUNT_ID}/cdrs/interaction
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs/interaction
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs/interaction', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch all legs related to an interaction
Crossbar cdrs was extended to provide simplified interaction call detail records. It groups all CDRs that interacted with each other to form a list of calls.
GET /v2/accounts/{ACCOUNT_ID}/cdrs/legs/{INTERACTION_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs/legs/{INTERACTION_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs/legs/{INTERACTION_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Variations
You can select CDRs/interactions for a specific user by adding them to the URI:
GET /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/cdrs
Notes on fields
Some fields need a little more explanation to help you understand what they are telling you about the call leg.
call_direction- direction of the leg, relative to the media switchinbound- leg came into the media switch (typically the A-leg)outbound- leg started on the media switch (typically the B-leg)
hangup_cause- The reason why the call leg ended. See the FreeSWITCH Hangup Causes page for descriptions.billing_seconds- How many seconds of the call are billable (post answer, normally)to- Depends on the direction of the leg- outbound - Uses the presence-id or else it uses the SIP Request address
- inbound - the SIP To header
Lumian-specific properties
These are properties set by Lumian for internal purposes. These are the properties found under the custom_channel_vars property at the top-level of the CDR JSON object. The non-exhaustive list of properties:
account_id- Account ID this leg belongs toauthorizing_id- Document ID used to authorize this call legauthorizing_type- Type of document used to authorize calldevice- the call leg is to/from a known Lumian devicemobile- the call leg is to/from a known Lumian mobile deviceresource- the call leg is from a known offnet carrieroutbound_fax
bridge_id- Typically the A-leg's call-id; helps with tracking transfersecallmgr_node- Which ecallmgr node is processing the call legfetch_id- The dialplan XML fetch ID from FreeSWITCHrealm- the SIP realm of the accountresource_id- Resource ID used for the leg; typically a carrier, local or global, that the call was routed tousername- the SIP username of the endpoint that started the leg
Billing-related Properties
These properties relate to how the leg was rated and billed. Some of these properties are not accessible via Crossbar, but may exist on the CDR
reseller_billing- tag describing what billing was used for the resellerreseller_id- Account ID of the reseller for the account of this legaccount_billing- tag describing what billing was used for the accountrate- Rate of the callbase_cost- How much the call costs to start (if per-minute)rate_name- Name of the rate doc usedsurcharge- Surcharge added to the legrate_minimum- Minimum number of seconds to bill forrate_increment- Increment of seconds to bill for
Fax-specific Properties
These properties may exist on a CDR for a fax request (inbound or outbound):
fax_transfer_rate- Baud of the fax transferfax_bad_rows- Number of rows that failed to transferfax_total_pages- Number of pages in the fax (seefax_transferred_pagesfor how many made it)fax_transferred_pages- Number of pages transferredfax_ecm_used- Was ECM (error correction mode) used on the faxfax_result_text- Error String, if any, or 'OK' if successfulfax_result_code- Result code of the transmissionfax_success- boolean for whether the fax was considered a successfax_t38- boolean for whether the fax T.38 was used
Resource Properties
All resource properties are set by the Stepswitch application.
resource_type- This property attempts to explain the reason the resource was used. The possible values are:- offnet-origination - Inbound call from a resource/carrier to a Lumian account
- offnet-termination - Outbound call from a Lumian account to a resource/carrier
- onnet-origination - Inbound call from a Lumian account to another Lumian account
- onnet-termination - Outbound call from a Lumian account to another Lumian account
global_resource- This boolean is TRUE when the channel has been created by processing a resource from the offnet database, and FALSE if the resource is from an account database (local).resource_id- This is resource document id used to create the channel
Call Channels
About Call Channels
The Channels API allows queries to find active channels for an account, a user, or a device. Given a call-id for a channel, a limited set of commands are allowed to be executed against that channel (such as hangup, transfer, or play media).
NOTE: Konami is an outdated and unsupported Lumian module. If you need support on this module, please ensure you are signed up for Konami Pro.
Fetch active channels system wide.
!!! note
For super duper admin only. Be sure to set system_config->crossbar.channels->system_wide_channels_list flag to true
GET /v2/channels
Sample Request:
curl -v -X GET \
-H "Content-Type: application/json" \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/channels
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/channels', {
headers: {
'Content-Type': 'application/json',
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch active channels for an account
GET /v2/accounts/{ACCOUNT_ID}/channels
Sample Request:
curl -v -X GET \
-H "Content-Type: application/json" \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/channels
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/channels', {
headers: {
'Content-Type': 'application/json',
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"answered": true,
"authorizing_id": "63fbb9ac78e11f3ccb387928a423798a",
"authorizing_type": "device",
"destination": "user_zu0bf7",
"direction": "outbound",
"other_leg": "d220c187-e18edc42-bab2459d@10.26.0.91",
"owner_id": "72855158432d790dfb22d03ff64c033e",
"presence_id": "user_zu0bf7@account.realm.com",
"timestamp": 63573977746,
"username": "user_zu0bf7",
"uuid": "dab25c76-7479-4ed2-ba92-6b725d68e351"
}
],
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Fetch channels for a user or device
GET /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/channels
For user with {USER_ID}:
Sample Request:
curl -v -X GET \
-H "Content-Type: application/json" \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/channels
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/channels', {
headers: {
'Content-Type': 'application/json',
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
For device with {DEVICE_ID}:
GET /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/channels
Sample Request:
curl -v -X GET \
-H "Content-Type: application/json" \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/channels
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/channels', {
headers: {
'Content-Type': 'application/json',
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch a channel's details
GET /v2/accounts/{ACCOUNT_ID}/channels/{UUID}
Sample Request:
curl -v -X GET \
-H "Content-Type: application/json" \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/channels/{UUID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/channels/{UUID}', {
headers: {
'Content-Type': 'application/json',
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Execute an application against a Channel
!!! note This API requires Konami Pro to be running and metaflows to be enabled on the call
POST /v2/accounts/{ACCOUNT_ID}/channels/{UUID}
Sample Request:
curl -v -X POST \
-H "Content-Type: application/json" \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"action": "transfer", "target": "Lumian", "takeback_dtmf": "*1", "moh": "media_id" }}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/channels/{UUID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/channels/{UUID}',
// '{"data": {"action": "transfer", "target": "Lumian", "takeback_dtmf": "*1", "moh": "media_id" }}',
{
'data': {
'action': 'transfer',
'target': 'Lumian',
'takeback_dtmf': '*1',
'moh': 'media_id'
}
},
{
headers: {
'Content-Type': 'application/json',
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Available action values are transfer, hangup, break, callflow, move and intercept.
Move
Sample Request:
curl -v -x POST \
-H "Content-Type: application/json" \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"action": "move", "owner_id": "2e04e3205b36b6291f854995e80985b0", "device_id": "c27b0a86c5e7b0f2a5999967fd8bbf09", "auto_answer": true, "can_call_self": true, "dial_strategy": "simultaneous"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/channels/{UUID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/channels/{UUID}',
// '{"data": {"action": "move", "owner_id": "2e04e3205b36b6291f854995e80985b0", "device_id": "c27b0a86c5e7b0f2a5999967fd8bbf09", "auto_answer": true, "can_call_self": true, "dial_strategy": "simultaneous"}}',
{
'data': {
'action': 'move',
'owner_id': '2e04e3205b36b6291f854995e80985b0',
'device_id': 'c27b0a86c5e7b0f2a5999967fd8bbf09',
'auto_answer': true,
'can_call_self': true,
'dial_strategy': 'simultaneous'
}
},
{
headers: {
'Content-Type': 'application/json',
'X-Auth-Token': '{AUTH_TOKEN}'
},
proxy: {
protocol: 'http',
host: 'POST',
port: 1080
}
}
);
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
auto_answer |
Whether to auto-answer the new leg | boolean() |
false |
false |
can_call_self |
Can intercept devices of the same targeted user | boolean() |
true |
false |
device_id |
Move the call to a specific device | string() |
false |
|
dial_strategy |
How to ring the endpoints, if multiple | string() |
simultaneous |
false |
owner_id |
User ID to use for finding endpoints | string() |
false |
Transfer
Sample Request:
curl -v -X POST \
-H "Content-Type: application/json" \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"module":"transfer","data":{"target":"Lumian","Transfer-Type":"blind","leg":"bleg"}},"action":"metaflow"}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/channels/{UUID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/channels/{UUID}',
{
'data': {
'module': 'transfer',
'data': {
'target': 'Lumian',
'Transfer-Type': 'blind',
'leg': 'bleg'
}
},
'action': 'metaflow'
},
{
headers: {
'Content-Type': 'application/json',
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
| Key | Description | Type | Default |
|---|---|---|---|
leg |
Defines which leg of the call to take action against | `string('self' | 'bleg')` |
target |
Extension/DID to transfer the {UUID} |
string() |
|
transfer-type |
What type of transfer to perform | `string('attended' | 'blind')` |
moh |
Music on hold to play while transferring | string() |
Put a feature (metaflow) on a channel
!!! note This API requires Konami Pro to be running and metaflows to be enabled on the call
PUT /v2/accounts/{ACCOUNT_ID}/channels/{UUID}
Sample Request:
curl -v -X PUT \
-H "Content-Type: application/json" \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"action":"metaflow", "data": {"data": { "module": "hangup" }}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/channels/{UUID}
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/channels/{UUID}',
// '{"action":"metaflow", "data": {"data": { "module": "hangup" }}}',
{
'action': 'metaflow',
'data': {
'data': {
'module': 'hangup'
}
}
},
{
headers: {
'Content-Type': 'application/json',
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
The Metaflow feature is a metaflow object which validates with its corresponding JSON schema.
Reasoning
The POST action requires that every Metaflow action would have to be coded into the module.
Benefits
The Metaflow feature allows adding new types of Metaflows without changing the code.
It also allows full Metaflows and not only single actions, i.e., the children node is also processed.
Click To Call
Schema
Click-to-call allows you to create URLs that can be POSTed to with a phone number or SIP URI and create a phone call from the provided contact information to a destination you have pre-determined.
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
auth_required |
Determines if this click to call requires valid auth-tokens when invoked | boolean() |
true |
false |
|
bypass_media |
Default bypass media mode (The string type is deprecated, please use this as a boolean) | `boolean() | string('true' | 'false' | 'auto')` |
caller_id_number |
Explicitly set caller id number | string() |
false |
||
custom_application_vars./[a-zA-Z0-9\-_]+/ |
string() |
false |
|||
custom_application_vars |
Key-value pairs to set as custom_application_vars on the channel | object() |
{} |
false |
|
custom_sip_headers.in |
Custom SIP Headers to be applied to calls inbound to Lumian from the endpoint | #/definitions/custom_sip_headers | false |
||
custom_sip_headers.out |
Custom SIP Headers to be applied to calls outbound from Lumian to the endpoint | #/definitions/custom_sip_headers | false |
||
custom_sip_headers.^[a-zA-z0-9_\-]+$ |
The SIP header to add | string() |
false |
||
custom_sip_headers |
A property list of SIP headers | object() |
false |
||
dial_first |
Determines what will be dialed first: extension or contact | `string('extension' | 'contact')` | false |
|
extension |
The extension to connect to when the click to call is invoked | string() |
true |
||
media.ignore_early_media |
The option to determine if early media from the endpoint should always be ignored | boolean() |
false |
||
media |
object() |
false |
|||
music_on_hold.media_id |
The ID of a media object that should be used as the music on hold | string(0..2048) |
false |
||
music_on_hold |
The music on hold parameters used if not a property of the device owner | object() |
false |
||
name |
A friendly name for the click to call | string(1..128) |
true |
||
outbound_callee_id_name |
Callee ID Name of the device calling out to the contact number | string() |
false |
||
outbound_callee_id_number |
Callee ID Number of the device calling out to the contact number | string() |
false |
||
presence_id |
Static presence ID (used instead of SIP username) | string() |
false |
supported |
|
ringback |
Ringback to use | string() |
false |
||
throttle |
The rate that this click to call can be invoked | integer() |
false |
||
timeout |
How long, in seconds, to wait for the call to progress | integer() |
false |
||
whitelist.[] |
string(1..) |
false |
|||
whitelist |
A list of regular expressions that the click to call can dial to | array(string(1..)) |
false |
custom_sip_headers
Custom SIP headers applied to an INVITE
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
^[a-zA-z0-9_\-]+$ |
The SIP header to add | string() |
false |
List all clicktocall endpoints
GET /v2/accounts/{ACCOUNT_ID}/clicktocall
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token":"{AUTH_TOKEN}",
"data": [
{
"extension": "{EXTENSION}",
"id": "{C2C_ID}",
"name": "{NAME}"
}
],
"node": "{NODE_HASH}",
"page_size": 1,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success",
"timestamp": "{TIMESTAMP}",
"version": "4.3.1"
}
Create a clicktocall endpoint
PUT /v2/accounts/{ACCOUNT_ID}/clicktocall
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"name":"{NAME}, "auth_required":false, "extension":"{EXTENSION}"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall',
'{"data":{"name":"{NAME}, "auth_required":false, "extension":"{EXTENSION}"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token":"{AUTH_TOKEN}",
"data": {
"auth_required": false,
"custom_application_vars": {},
"extension": "{EXTENSION}",
"id": "{C2C_ID}",
"name": "{NAME}"
},
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success",
"timestamp": "{TIMESTAMP}",
"version": "4.3.1"
}
Fetch
GET /v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token":"{AUTH_TOKEN}",
"data": {
"auth_required": false,
"custom_application_vars": {},
"extension": "{EXTENSION}",
"id": "{C2C_ID}",
"name": "{NAME}"
},
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success",
"timestamp": "{TIMESTAMP}",
"version": "4.3.1"
}
Change
POST /v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Patch
PATCH /v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove
DELETE /v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch
GET /v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}/history
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}/history
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}/history', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Execute the clicktocall with a supplied number
GET/POST /v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}/connect
Non-blocking version
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}/connect?contact={CONTACT}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}/connect?contact={CONTACT}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Will return immediately with a 202
Sample Response:
"data": {
"application_data": {
"route": "{CONTACT}"
},
"application_name": "transfer",
"continue_on_fail": true,
"custom_application_vars": {
"contact": "{CONTACT}"
},
"custom_channel_vars": {
"account_id": "{ACCOUNT_ID}",
"authorizing_id": "{C2C_ID}",
"authorizing_type": "clicktocall",
"auto_answer_loopback": true,
"from_uri": "{EXTENSION}@{ACCOUNT_REALM}",
"inherit_codec": false,
"loopback_request_uri": "{CONTACT}@{ACCOUNT_REALM}",
"request_uri": "{CONTACT}@{ACCOUNT_REALM}",
"retain_cid": true
},
"dial_endpoint_method": "single",
"endpoints": [
{
"invite_format": "loopback",
"route": "{EXTENSION}",
"to_did": "{EXTENSION}",
"to_realm": "{ACCOUNT_REALM}"
}
],
"export_custom_channel_vars": [
"Account-ID",
"Authorizing-ID",
"Authorizing-Type",
"Loopback-Request-URI",
"From-URI",
"Request-URI"
],
"ignore_early_media": true,
"loopback_bowout": "false",
"outbound_call_id": "c2c-{C2C_ID}-{RANDOM}",
"outbound_callee_id_name": "{EXTENSION}",
"outbound_callee_id_number": "{EXTENSION}",
"outbound_caller_id_name": "{C2C NAME}",
"outbound_caller_id_number": "{CONTACT}",
"simplify_loopback": "false",
"start_control_process": "false",
"timeout": 30
},
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success",
"timestamp": "{TIMESTAMP}",
"version": "4.3.1"
}
Change
POST /v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}/connect
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}/connect
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID}/connect',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Comments
About Comments
Allows you to add comments to "any" documents in Lumian.
Fetch
DELETE /v2/accounts/{ACCOUNT_ID}/comments
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/comments
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/comments', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": [
],
"status": "success"
}
Fetch a Comment
GET /v2/accounts/{ACCOUNT_ID}/comments
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/comments
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/comments', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": "{COMMENT}",
"status": "success"
}
Add a Comment
PUT /v2/accounts/{ACCOUNT_ID}/comments
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"comments": [{COMMENT_3}]}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/comments
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/comments',
'{"data": {"comments": [{COMMENT_3}]}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"data": {
"comments": [
"{COMMENT_1}",
"{COMMENT_2}",
"{COMMENT_3}"
]
},
"status": "success"
}
Delete a Comment
DELETE /v2/accounts/{ACCOUNT_ID}/comments/{COMMENT_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/comments/{COMMENT_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/comments/{COMMENT_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": {
"comments": [
"{COMMENT_1}",
"{COMMENT_2}"
]
},
"status": "success"
}
Fetch a Comment
GET /v2/accounts/{ACCOUNT_ID}/comments/{COMMENT_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/comments/{COMMENT_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/comments/{COMMENT_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": {
"comments": [
"{COMMENT_1}",
"{COMMENT_2}"
]
},
"status": "success"
}
Update a Comment
POST /v2/accounts/{ACCOUNT_ID}/comments/{COMMENT_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": "{COMMENT}"}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/comments/{COMMENT_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/comments/{COMMENT_ID}',
'{"data": "{COMMENT}"}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"data": "{COMMENT}",
"status": "success"
}
Configuring Conferences
About Conferences
Conference documents are enriched with real-time information along side their configuration, namely showing the number of members, number of moderators, duration of the conference, conference locked status.
The real-time information (if available) is added to conference document under _read_only key (to avoid accident document update).
Schema
Schema for conferences
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
bridge_password |
the password used for a conference bridge | string() |
false |
||
bridge_username |
the username used for a conference bridge | string() |
false |
||
caller_controls |
caller controls (config settings) | string() |
false |
||
conference_numbers.[] |
string() |
false |
|||
conference_numbers |
Defines conference numbers that can be used by members or moderators | array(string()) |
[] |
false |
|
controls |
controls | object() |
false |
||
domain |
domain | string() |
false |
||
flags.[] |
string() |
false |
supported |
||
flags |
Flags set by external applications | array(string()) |
false |
supported |
|
focus |
This is a read-only property indicating the media server hosting the conference | string() |
false |
||
language |
Prompt language to play in the conference | string() |
false |
||
max_members_media |
Media to play when the conference is full | string() |
false |
||
max_participants |
The maximum number of participants that can join | integer() |
false |
||
member.join_deaf |
Determines if a member will join deaf | boolean() |
false |
false |
supported |
member.join_muted |
Determines if a member will join muted | boolean() |
true |
false |
supported |
member.numbers.[] |
string() |
false |
|||
member.numbers |
Defines the conference (call in) number(s) for members | array(string()) |
[] |
false |
|
member.pins.[] |
string() |
false |
|||
member.pins |
Defines the pin number(s) for members | array(string()) |
[] |
false |
|
member.play_entry_prompt |
Whether to play the entry prompt on member join | boolean() |
false |
||
member |
Defines the discovery (call in) properties for a member | object() |
{} |
false |
|
moderator.join_deaf |
Determines if a moderator will join deaf | boolean() |
false |
false |
|
moderator.join_muted |
Determines if a moderator will join muted | boolean() |
false |
false |
|
moderator.numbers.[] |
string() |
false |
|||
moderator.numbers |
Defines the conference (call in) number(s) for moderators | array(string()) |
[] |
false |
|
moderator.pins.[] |
string() |
false |
|||
moderator.pins |
Defines the pin number(s) for moderators | array(string()) |
[] |
false |
|
moderator |
Defines the discovery (call in) properties for a moderator | object() |
{} |
false |
|
moderator_controls |
profile on the switch for controlling the conference as a moderator | string() |
false |
||
name |
A friendly name for the conference | string(1..128) |
false |
supported |
|
owner_id |
The user ID who manages this conference | string(32) |
false |
supported |
|
play_entry_tone |
Whether to play an entry tone, or the entry tone to play | `boolean() | string()` | false |
|
play_exit_tone |
Whether to play an exit tone, or the exit tone to play | `boolean() | string()` | false |
|
play_name |
Do we need to announce new conference members? | boolean() |
false |
false |
|
play_welcome |
Whether to play the welcome prompt | boolean() |
false |
||
profile |
Profile configuration | object() |
false |
||
profile_name |
conference profile name | string() |
false |
||
require_moderator |
does the conference require a moderator | boolean() |
false |
||
wait_for_moderator |
should members wait for a moderator before joining the conference | boolean() |
false |
conferences.profile
Schema for conference profiles
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
alone-sound |
Audio that plays while you are alone in the conference | string() |
false |
||
announce-count |
Play member count to conference when above this threshold | integer() |
false |
||
caller-controls |
Name of the caller control group | string() |
false |
||
comfort-noise |
The volume level of background white noise | integer() |
false |
||
energy-level |
Energy level required for audio to be sent to other users | integer() |
false |
||
enter-sound |
Audio to play when entering a conference | string() |
false |
||
exit-sound |
Audio to play when exiting a conference | string() |
false |
||
interval |
Milliseconds per frame | integer() |
false |
||
locked-sound |
Audio to play when the conference is locked | string() |
false |
||
max-members |
Set the maximum number of members in the conference | integer() |
false |
||
max-members-sound |
If max-members has been reached, audio to play to caller instead of joining the conference | string() |
false |
||
moderator-controls |
Name of the moderator control group to use | string() |
false |
||
moh-sound |
Audio to play, on a loop, while participant count is 1 | string() |
false |
||
muted-sound |
Audio to play when muted | string() |
false |
||
rate |
Audio sample rate | integer() |
false |
||
unmuted-sound |
Audio to play when unmuted | string() |
false |
Keys under development
require_moderatorwait_for_moderator
Perform an action on a conference
PUT /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}
Sample Request:
curl -v -X PUT \
-d '{"action": "{CONFERENCE_ACTION}", "data": {"ACTION":"DATA"}}' \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}',
'{"action": "{CONFERENCE_ACTION}", "data": {"ACTION":"DATA"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
| Action | Description |
|---|---|
lock |
Lock the conference; no new participants may join |
unlock |
Unlock the conference; new participants may join |
dial |
Dial an endpoint (user/device/DID) |
play |
Play media to the conference (all participants) |
Dialing an endpoint
Sometimes you want to dial out from a conference to an endpoint (versus waiting for the caller to dial into the conference). Similar to how the group callflow works, you can include device and user IDs; unlike groups, you can include DIDs as well (similar to quickcall/click2call).
Schema
Schema for conferences
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
bridge_password |
the password used for a conference bridge | string() |
false |
||
bridge_username |
the username used for a conference bridge | string() |
false |
||
caller_controls |
caller controls (config settings) | string() |
false |
||
conference_numbers.[] |
string() |
false |
|||
conference_numbers |
Defines conference numbers that can be used by members or moderators | array(string()) |
[] |
false |
|
controls |
controls | object() |
false |
||
domain |
domain | string() |
false |
||
flags.[] |
string() |
false |
supported |
||
flags |
Flags set by external applications | array(string()) |
false |
supported |
|
focus |
This is a read-only property indicating the media server hosting the conference | string() |
false |
||
language |
Prompt language to play in the conference | string() |
false |
||
max_members_media |
Media to play when the conference is full | string() |
false |
||
max_participants |
The maximum number of participants that can join | integer() |
false |
||
member.join_deaf |
Determines if a member will join deaf | boolean() |
false |
false |
supported |
member.join_muted |
Determines if a member will join muted | boolean() |
true |
false |
supported |
member.numbers.[] |
string() |
false |
|||
member.numbers |
Defines the conference (call in) number(s) for members | array(string()) |
[] |
false |
|
member.pins.[] |
string() |
false |
|||
member.pins |
Defines the pin number(s) for members | array(string()) |
[] |
false |
|
member.play_entry_prompt |
Whether to play the entry prompt on member join | boolean() |
false |
||
member |
Defines the discovery (call in) properties for a member | object() |
{} |
false |
|
moderator.join_deaf |
Determines if a moderator will join deaf | boolean() |
false |
false |
|
moderator.join_muted |
Determines if a moderator will join muted | boolean() |
false |
false |
|
moderator.numbers.[] |
string() |
false |
|||
moderator.numbers |
Defines the conference (call in) number(s) for moderators | array(string()) |
[] |
false |
|
moderator.pins.[] |
string() |
false |
|||
moderator.pins |
Defines the pin number(s) for moderators | array(string()) |
[] |
false |
|
moderator |
Defines the discovery (call in) properties for a moderator | object() |
{} |
false |
|
moderator_controls |
profile on the switch for controlling the conference as a moderator | string() |
false |
||
name |
A friendly name for the conference | string(1..128) |
false |
supported |
|
owner_id |
The user ID who manages this conference | string(32) |
false |
supported |
|
play_entry_tone |
Whether to play an entry tone, or the entry tone to play | `boolean() | string()` | false |
|
play_exit_tone |
Whether to play an exit tone, or the exit tone to play | `boolean() | string()` | false |
|
play_name |
Do we need to announce new conference members? | boolean() |
false |
false |
|
play_welcome |
Whether to play the welcome prompt | boolean() |
false |
||
profile |
Profile configuration | object() |
false |
||
profile_name |
conference profile name | string() |
false |
||
require_moderator |
does the conference require a moderator | boolean() |
false |
||
wait_for_moderator |
should members wait for a moderator before joining the conference | boolean() |
false |
conferences.profile
Schema for conference profiles
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
alone-sound |
Audio that plays while you are alone in the conference | string() |
false |
||
announce-count |
Play member count to conference when above this threshold | integer() |
false |
||
caller-controls |
Name of the caller control group | string() |
false |
||
comfort-noise |
The volume level of background white noise | integer() |
false |
||
energy-level |
Energy level required for audio to be sent to other users | integer() |
false |
||
enter-sound |
Audio to play when entering a conference | string() |
false |
||
exit-sound |
Audio to play when exiting a conference | string() |
false |
||
interval |
Milliseconds per frame | integer() |
false |
||
locked-sound |
Audio to play when the conference is locked | string() |
false |
||
max-members |
Set the maximum number of members in the conference | integer() |
false |
||
max-members-sound |
If max-members has been reached, audio to play to caller instead of joining the conference | string() |
false |
||
moderator-controls |
Name of the moderator control group to use | string() |
false |
||
moh-sound |
Audio to play, on a loop, while participant count is 1 | string() |
false |
||
muted-sound |
Audio to play when muted | string() |
false |
||
rate |
Audio sample rate | integer() |
false |
||
unmuted-sound |
Audio to play when unmuted | string() |
false |
Endpoints
Dial-able endpoints are
- Devices (by device id or device JSON)
- Users (by user id)
- Phone Numbers
- SIP URIs (
sip:user@realm)
Note: Phone numbers will involve some internal legs being generated (loopback legs) to process the number as if it was a call coming in for the desired number. This means billing and limits will be applied just the same as if a user dialed the number from their device.
Dial schema
Schema for conference dial API command
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
caller_id_name |
Caller ID Name to use when dialing out to endpoints | string() |
false |
||
caller_id_number |
Caller ID Number to use when dialing out to endpoints | string() |
false |
||
endpoints.[] |
`string() | #/definitions/devices` | |||
endpoints |
Endpoints to dial out to and join to the conference | array() |
true |
||
participant_flags.[] |
`string('mute' | 'deaf' | 'distribute_dtmf' | 'is_moderator' | |
participant_flags |
Participant flags applied to each endpoint when it joins the conference | `array(string('mute' | 'deaf' | 'distribute_dtmf' | 'is_moderator' |
profile_name |
The profile name to use for configuration | string() |
false |
||
target_call_id |
Existing UUID to use as a hint for where to start the conference | string() |
false |
||
timeout |
How long to try to reach the endpoint(s) | integer() |
false |
Example payloads
Sample Response:
{
"action":"dial"
,"data":{
"data":{
"endpoints":["{DEVICE_ID}","{USER_ID}","{NUMBER}","sip:{URI}"],
"caller_id_name":"Conference XYZ",
"caller_id_number":"5551212"
}
}
}
As when making QuickCalls, you can include custom_application_vars:
Sample Response:
{
"action":"dial"
,"data":{
"custom_application_vars":{
"foo":"bar"
}
,"data":{
"endpoints":["{DEVICE_ID}","{USER_ID}","{NUMBER}","sip:{URI}"],
"caller_id_name":"Conference XYZ",
"caller_id_number":"5551212"
}
}
}
You can also include the outbound call id you'd like the leg to use:
Sample Response:
{
"action":"dial"
,"data":{
"custom_application_vars":{
"foo":"bar"
}
,"data":{
"endpoints":["{DEVICE_ID}","{USER_ID}","{NUMBER}","sip:{URI}"],
"caller_id_name":"Conference XYZ",
"caller_id_number":"5551212",
"outbound_call_id":"xyz-abc"
}
}
}
Participant Flags
You can specify how a participant will enter a conference with a list of attributes:
| Value | Description |
|---|---|
deaf |
Participant joins unable to hear conference audio |
disable_moh |
Disable music on hold when the participant is the only one in the conference |
distribute_dtmf |
Send DTMF from participant's leg to all other participants |
ghost |
Uncounted in conference membership total |
is_moderator |
Participant will join as a moderator |
join_existing |
Participant may only join a running conference (won't start a conference) |
mute |
Participant joins muted |
video_mute |
Participant joins with video stream muted |
Sample Response:
{
"action":"dial"
,"data":{
"data":{
"endpoints":["{DEVICE_ID}","{USER_ID}","{NUMBER}","sip:{URI}"],
"caller_id_name":"Conference XYZ",
"caller_id_number":"5551212",
"participant_flags":["deaf", "mute"]
}
}
}
Dialing out to a dynamic conference
Sometimes you want to create ad-hoc conferences and put a participant in there. You can PUT a conference and the endpoints to dial out to create a temporary conference. The {CONFERENCE_ID} you supply will be used to name the conference and any conference schema parameters in the request will be used when creating the conference. For example:
Sample Response:
{
"action":"dial"
,"data":{
"data":{
"endpoints":["{DEVICE_ID}","{USER_ID}","{NUMBER}","sip:{URI}"],
"caller_id_name":"Conference XYZ",
"caller_id_number":"5551212",
"play_entry_tone": true,
"play_exit_tone": true,
"play_name": false
}
}
}
These properties will be merged into a "default" conference document and then executed the same as if the conference was preconfigured.
The API response
Sample Response:
{
"data": {
"endpoint_responses": [
{
"call_id": "522bb682-da03-11e7-8ce9-5364ba916f96",
"endpoint_id": "{ENDPOINT_FROM_REQUEST}",
"job_id": "137b1e9e-d9fb-11e7-8cad-5364ba916f96",
"message": "dial resulted in call id 522bb682-da03-11e7-8ce9-5364ba916f96",
"status": "success"
}
]
}
,...
}
Playing media to a conference
Playing a media file to everyone in a conference:
Sample Response:
{
"action":"play",
"data": {
"data":{"media_id":"{MEDIA_ID}"}
}
}
{MEDIA_ID} can be a pre-uploaded media ID or a URL to fetch media from.
Perform an action on participants
PUT /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants
Sample Request:
curl -v -X PUT \
-d '{"data": {"action": {PARTICIPANTS_ACTION}}}' \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants',
'{"data": {"action": {PARTICIPANTS_ACTION}}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
| Action | Description |
|---|---|
mute |
Mute all the participants that are currently unmuted |
unmute |
Unmute all the participants that are currently muted |
deaf |
Stop sending conference audio to all participants |
undeaf |
Start sending conference audio to all participants |
kick |
Kick all the participants from the conference |
relate |
Relate two participants |
Relate participants
The relate action takes a data object:
{
"data":{
"action":"relate"
,"data":{
"participant_id":{ID}
,"other_participant":{ID}
,"relationship":"{RELATIONSHIP}"
}
}
}
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
other_participant |
The other participant ID to relate | `string() | integer()` | |
participant_id |
The participant ID to relate | `string() | integer()` | |
relationship |
The relationship to establish between the two participants | `string('deaf' | 'clear' | 'mute')` |
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: $AUTH_TOKEN" \
"http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants" \
-d'{"data":{"action":"relate","data":{"participant_id":23, "other_participant":24}}}'
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants',
'{"data":{"action":"relate","data":{"participant_id":23, "other_participant":24}}}',
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": "relating participants",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"revision": "1-100475067fa624422c9a21bd976c7b84",
"status": "success",
"timestamp": "{TIMESTAMP}",
"version": "4.2.2"
}
Perform an action on participant
PUT /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants/{PARTICIPANT_ID}
Sample Request:
curl -v -X PUT \
-d '{"data": {"action": {PARTICIPANT_ACTION}}}' \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants/{PARTICIPANT_ID}
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants/{PARTICIPANT_ID}',
'{"data": {"action": {PARTICIPANT_ACTION}}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sometimes you may get a HTTP/1.1 304 Not Modified response from crossbar for similar API calls. If you do, add a random string filter to the end of the call to ensure the request is viewed as 'unique'. For example:
Sample Request:
curl -v -X PUT \
-d '{"data": {"action": {PARTICIPANT_ACTION}}}' \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants/{PARTICIPANT_ID}?random={RANDOM_BIT}
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants/{PARTICIPANT_ID}?random={RANDOM_BIT}',
'{"data": {"action": {PARTICIPANT_ACTION}}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
| Action | Description |
|---|---|
mute |
Mute the participant |
unmute |
Unmute the participant |
deaf |
Stop sending conference audio to the participant |
undeaf |
Start sending conference audio to the participant |
kick |
Kick the participant from the conference |
play |
Play media to a single participant |
Playing media to a conference
Playing a media file to everyone in a conference:
Sample Response:
{"data":{
"action":"play",
"data":{"media_id":"{MEDIA_ID}"}
}
}
{MEDIA_ID} can be a pare-uploaded media ID or a URL to fetch media from.
List of conferences example
Sample Response:
[
{
"id": "",
"name": "",
"owner_id": "",
"member": {
"join_muted": false,
"join_deaf": false,
"numbers": [],
"pins": []
},
"moderator": {
"join_deaf": false,
"join_muted": false,
"numbers": [],
"pins": []
},
"members": 0,
"admins": 0,
"duration": 0,
"is_locked": false
},
...
]
Conference document
Sample Response:
{
"name": "Conf",
"id": "",
"owner_id": "",
"play_entry_tone": true,
"play_exit_tone": true,
"play_name": false,
"conference_numbers": [],
"member": {
"join_muted": false,
"join_deaf": false,
"numbers": [],
"pins": []
},
"ui_metadata": {
"ui": "lumian-ui"
},
"moderator": {
"join_deaf": false,
"join_muted": false,
"numbers": [],
"pins": []
},
"_read_only": {
"members": 0,
"admins": 0,
"duration": 0,
"is_locked": false,
"participants": [
{
"call_id": "",
"conference_name": "",
"conference_uuid": "",
"switch_hostname": "",
"floor": false,
"hear": true,
"speak": true,
"talking": false,
"mute_detect": false,
"participant_id": 1,
"energy_level": 20,
"current_energy": 0,
"video": false,
"is_moderator": false,
"join_time": 63635217275,
"duration": 10
},
...
]
}
}
join_time is participant's join time as epoch, duration is number of seconds participant participate in conference.
Here we can see values set up for a Member, then for a Moderator.
The last field, play_entry_tone, is at the root of the document: meaning this field applies to everyone in the conference.
Available fields
- play_entry_tone and play_exit_tone: can be either a boolean or a non-empty string.
truemeans play the default tone when someone joins (or leaves) the conferencefalsedisables the tone from being played- A string like a tone string or a URI to a media file can be inputted.
Actions
Actions are JSON objects in format:
Sample Response:
{
"action": "{ACTION}"
}
Conference actions
lock: lock conference (prevent participants to join) unlock: unlock conference (allow everybody to join)
Participants actions
mute/unmute: mute/unmute all participants except moderators deaf/undeaf: deaf/undeaf all participants except moderators kick: kick every participant out
Participant actions
mute/unmute: mute/unmute participant deaf/undeaf: deaf/undeaf participant kick: kick participant
Web-socket events
A client may subscribe to conference event using websocket connection. Participant events are published as
amqp conference.event.{conference_id}.{call_id}, where call_id is participant"s call.
The list of published events is determined by publish_participant_event parameter of ecallmgr configuration,
if parameter is unset, then all events are published.
Participant events
add-member del-member stop-talking start-talking mute-member unmute-member deaf-member undeaf-member
Example event
Sample Response:
{
"custom_channel_vars": {
"account_id": "9d351ad7ffd6f846313af9eed3bb7b85",
"authorizing_id": "6507f40b09a61fbb8b025dbad9316eb5",
"authorizing_type": "device",
"owner_id": "32d8788da9506b4b1991d5bb86d27b0a",
"presence_id": "1000@kamailio.lumian",
"fetch_id": "56507071-a216-4e0a-a28f-ff3bd9c86ac3",
"bridge_id": "934800819",
"precedence": 5,
"realm": "kamailio.lumian",
"username": "sip1",
"call_interaction_id": "63635497023-3e247b2e"
},
"channel_presence_id": "1000@kamailio.lumian",
"caller_id_number": "sip1",
"caller_id_name": "sip1",
"mute_detect": false,
"video": false,
"energy_level": 20,
"current_energy": 0,
"talking": false,
"speak": true,
"hear": true,
"floor": false,
"participant_id": 20,
"instance_id": "d5765180-53d5-4104-860e-b352f3f8e6b1",
"conference_id": "5edbfdd3b825314a71b0a05957392edb",
"focus": "freeswitch@freeswitch.lumian",
"call_id": "934800819",
"event": "add-member",
"node": "lumian@jh460",
"msg_id": "a6fbbf034b5cd3af",
"event_name": "participant_event",
"event_category": "conference",
"app_version": "4.0.0",
"app_name": "ecallmgr",
"routing_key": "participant_event"
}
Conferences
About Conferences
Schema
Schema for conferences
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
bridge_password |
the password used for a conference bridge | string() |
false |
||
bridge_username |
the username used for a conference bridge | string() |
false |
||
caller_controls |
caller controls (config settings) | string() |
false |
||
conference_numbers.[] |
string() |
false |
|||
conference_numbers |
Defines conference numbers that can be used by members or moderators | array(string()) |
[] |
false |
|
controls |
controls | object() |
false |
||
domain |
domain | string() |
false |
||
flags.[] |
string() |
false |
supported |
||
flags |
Flags set by external applications | array(string()) |
false |
supported |
|
focus |
This is a read-only property indicating the media server hosting the conference | string() |
false |
||
language |
Prompt language to play in the conference | string() |
false |
||
max_members_media |
Media to play when the conference is full | string() |
false |
||
max_participants |
The maximum number of participants that can join | integer() |
false |
||
member.join_deaf |
Determines if a member will join deaf | boolean() |
false |
false |
supported |
member.join_muted |
Determines if a member will join muted | boolean() |
true |
false |
supported |
member.numbers.[] |
string() |
false |
|||
member.numbers |
Defines the conference (call in) number(s) for members | array(string()) |
[] |
false |
|
member.pins.[] |
string() |
false |
|||
member.pins |
Defines the pin number(s) for members | array(string()) |
[] |
false |
|
member.play_entry_prompt |
Whether to play the entry prompt on member join | boolean() |
false |
||
member |
Defines the discovery (call in) properties for a member | object() |
{} |
false |
|
moderator.join_deaf |
Determines if a moderator will join deaf | boolean() |
false |
false |
|
moderator.join_muted |
Determines if a moderator will join muted | boolean() |
false |
false |
|
moderator.numbers.[] |
string() |
false |
|||
moderator.numbers |
Defines the conference (call in) number(s) for moderators | array(string()) |
[] |
false |
|
moderator.pins.[] |
string() |
false |
|||
moderator.pins |
Defines the pin number(s) for moderators | array(string()) |
[] |
false |
|
moderator |
Defines the discovery (call in) properties for a moderator | object() |
{} |
false |
|
moderator_controls |
profile on the switch for controlling the conference as a moderator | string() |
false |
||
name |
A friendly name for the conference | string(1..128) |
false |
supported |
|
owner_id |
The user ID who manages this conference | string(32) |
false |
supported |
|
play_entry_tone |
Whether to play an entry tone, or the entry tone to play | `boolean() | string()` | false |
|
play_exit_tone |
Whether to play an exit tone, or the exit tone to play | `boolean() | string()` | false |
|
play_name |
Do we need to announce new conference members? | boolean() |
false |
false |
|
play_welcome |
Whether to play the welcome prompt | boolean() |
false |
||
profile |
Profile configuration | object() |
false |
||
profile_name |
conference profile name | string() |
false |
||
require_moderator |
does the conference require a moderator | boolean() |
false |
||
wait_for_moderator |
should members wait for a moderator before joining the conference | boolean() |
false |
conferences.profile
Schema for conference profiles
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
alone-sound |
Audio that plays while you are alone in the conference | string() |
false |
||
announce-count |
Play member count to conference when above this threshold | integer() |
false |
||
caller-controls |
Name of the caller control group | string() |
false |
||
comfort-noise |
The volume level of background white noise | integer() |
false |
||
energy-level |
Energy level required for audio to be sent to other users | integer() |
false |
||
enter-sound |
Audio to play when entering a conference | string() |
false |
||
exit-sound |
Audio to play when exiting a conference | string() |
false |
||
interval |
Milliseconds per frame | integer() |
false |
||
locked-sound |
Audio to play when the conference is locked | string() |
false |
||
max-members |
Set the maximum number of members in the conference | integer() |
false |
||
max-members-sound |
If max-members has been reached, audio to play to caller instead of joining the conference | string() |
false |
||
moderator-controls |
Name of the moderator control group to use | string() |
false |
||
moh-sound |
Audio to play, on a loop, while participant count is 1 | string() |
false |
||
muted-sound |
Audio to play when muted | string() |
false |
||
rate |
Audio sample rate | integer() |
false |
||
unmuted-sound |
Audio to play when unmuted | string() |
false |
Fetch
HTTP Request
GET /v2/accounts/{ACCOUNT_ID}/conferences
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create
HTTP Request
PUT /v2/accounts/{ACCOUNT_ID}/conferences
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Fetch
HTTP Request
GET /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create
HTTP Request
PUT /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Change
HTTP Request
POST /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Patch
HTTP Request
PATCH /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove
HTTP Request
DELETE /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch
HTTP Request
GET /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create
HTTP Request
PUT /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Fetch
HTTP Request
GET /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants/{PARTICIPANT_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants/{PARTICIPANT_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants/{PARTICIPANT_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create
HTTP Request
PUT /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants/{PARTICIPANT_ID}
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants/{PARTICIPANT_ID}
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants/{PARTICIPANT_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Configs
Certain settings are available per account. What settings are understood by Lumian is determined by account_config.{CONFIG_ID}.json schemas. Please note not all possible configuration options are available on per-account basis, some (most) of them are system-wide.
About Configs
All requests returns merged configuration. Following documents are merged (if they are exists): account-specific configuration, account's reseller account-specific configuration, then default section of system config of the same name, and then default values deduced from system config schema.
On PUT/POST/PATCH operations a difference of parent configuration is calculated and written as account-specific config document. Therefore if a provided value is equal to default it will not be stored in account-specific config document.
If the difference with default is empty, then account-specific configuration document will be deleted.
Schema
Fetch
GET /v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": {
"entry_tone": "tone_stream://v=-7;>=2;+=.1;%(300,0,523,659);v=-7;>=3;+=.1;%(800,0,659,783)",
"exit_tone": "tone_stream://v=-7;>=2;+=.1;%(300,0,523,440);v=-7;>=3;+=.1;%(800,0,349,440)",
"moderator_entry_tone": "tone_stream://v=-7;>=2;+=.1;%(300,0,523,659);v=-7;>=3;+=.1;%(800,0,659,783)",
"moderator_exit_tone": "tone_stream://v=-7;>=2;+=.1;%(300,0,523,440);v=-7;>=3;+=.1;%(800,0,349,440)",
"number_timeout": 5000,
"pin_timeout": 5000,
"support_name_announcement": true,
"id": "configs_conferences"
},
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_ID}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Create
PUT /v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID}
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID}
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
PUT is completely equal to POST
Change
POST /v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d @data.json \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID}',
'@data.json',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Request's data.json:
Sample Response:
{
"data": {
"entry_tone": "tone_stream://%(1000,0,2600)",
"exit_tone": "tone_stream://v=-7;>=2;+=.1;%(300,0,523,440);v=-7;>=3;+=.1;%(800,0,349,440)",
"moderator_entry_tone": "tone_stream://v=-7;>=2;+=.1;%(300,0,523,659);v=-7;>=3;+=.1;%(800,0,659,783)",
"moderator_exit_tone": "tone_stream://v=-7;>=2;+=.1;%(300,0,523,440);v=-7;>=3;+=.1;%(800,0,349,440)",
"number_timeout": 5000,
"pin_timeout": 5000,
"support_name_announcement": true,
"id": "configs_conferences"
}
}
Response:
Sample Response:
{
"data": {
"entry_tone": "tone_stream://%(1000,0,2600)",
"exit_tone": "tone_stream://v=-7;>=2;+=.1;%(300,0,523,440);v=-7;>=3;+=.1;%(800,0,349,440)",
"moderator_entry_tone": "tone_stream://v=-7;>=2;+=.1;%(300,0,523,659);v=-7;>=3;+=.1;%(800,0,659,783)",
"moderator_exit_tone": "tone_stream://v=-7;>=2;+=.1;%(300,0,523,440);v=-7;>=3;+=.1;%(800,0,349,440)",
"number_timeout": 5000,
"pin_timeout": 5000,
"support_name_announcement": true,
"id": "configs_conferences"
},
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_ID}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Patch
PATCH /v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"pin_timeout":3000}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID}',
'{"data":{"pin_timeout":3000}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"data": {
"entry_tone": "tone_stream://v=-7;>=2;+=.1;%(300,0,523,659);v=-7;>=3;+=.1;%(800,0,659,783)",
"exit_tone": "tone_stream://v=-7;>=2;+=.1;%(300,0,523,440);v=-7;>=3;+=.1;%(800,0,349,440)",
"moderator_entry_tone": "tone_stream://v=-7;>=2;+=.1;%(300,0,523,659);v=-7;>=3;+=.1;%(800,0,659,783)",
"moderator_exit_tone": "tone_stream://v=-7;>=2;+=.1;%(300,0,523,440);v=-7;>=3;+=.1;%(800,0,349,440)",
"number_timeout": 5000,
"pin_timeout": 3000,
"support_name_announcement": true,
"id": "configs_conferences"
},
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_ID}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Remove
DELETE /v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Configuration is effectively reset to default:
Sample Response:
{
"data": {
"entry_tone": "tone_stream://v=-7;>=2;+=.1;%(300,0,523,659);v=-7;>=3;+=.1;%(800,0,659,783)",
"exit_tone": "tone_stream://v=-7;>=2;+=.1;%(300,0,523,440);v=-7;>=3;+=.1;%(800,0,349,440)",
"moderator_entry_tone": "tone_stream://v=-7;>=2;+=.1;%(300,0,523,659);v=-7;>=3;+=.1;%(800,0,659,783)",
"moderator_exit_tone": "tone_stream://v=-7;>=2;+=.1;%(300,0,523,440);v=-7;>=3;+=.1;%(800,0,349,440)",
"number_timeout": 5000,
"pin_timeout": 5000,
"support_name_announcement": true,
"id": "configs_conferences"
},
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_ID}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Crossbar Configuration
System Configs
The following table outlines the configs that can be found in the system_config database, crossbar document:
| Key | Type | Default | Description |
|---|---|---|---|
api_auth_tokens |
integer() |
35 | Default token cost of creating an auth token via API key |
autoload_modules |
list(string()) |
The list of Crossbar modules initially started | |
cache_ttl |
integer() |
300 | Cache TTL, in seconds |
cleanup_timer |
integer() |
86400 | Time, in seconds, to run the cleanup routines |
compress_response_body |
boolean() |
true |
Whether to compress the response body before sending |
default_allow_anonymous_quickcalls |
boolean() |
true |
Whether to allow unauthenticated quickcall API requests |
default_language |
string() |
en-US |
The default language, if none are defined on the account |
magic_path_patterns |
list(string()) |
Magic path templates | |
max_upload_size |
integer() |
8000000 bytes (8Mb) | Max upload size for request bodies |
maximum_range |
integer() |
2682000 | Maximum range, in seconds, for time-based view queries |
pagination_page_size |
integer() |
50 | Default page size when paginating |
port |
integer() |
8000 | Port to listen for unencrypted traffic |
pretty_metrics |
boolean() |
true |
Pretty-print metrics in logs |
request_timeout_ms |
integer() |
10000 | Time, in milliseconds, for requests to timeout |
reset_id_size |
integer() |
250 | Password-reset ID length |
schema_strict_validation |
boolean() |
false |
Toggles whether to perform type conversions on client data when validating |
soft_delete_pause_ms |
integer() |
10000 | Time, in milliseconds, to pause between deletions |
ssl_ca_cert |
string() |
undefined |
Path to CA cert file |
ssl_cert |
string() |
/path/to/crossbar/priv/ssl/crossbar.crt |
Path to cert file |
ssl_key |
string() |
/path/to/crossbar/priv/ssl/crossbar.key |
Path to key file |
ssl_password |
string() |
"" |
Cert password |
ssl_port |
integer() |
8443 | Port to listen for SSL traffic |
ssl_workers |
integer() |
100 | Number of SSL listeners to start |
token_costs |
integer() |
1 | Default token cost of an API request |
trace_path |
string() |
/tmp |
Path to put trace files when profiling API requests |
use_plaintext |
boolean() |
true |
Whether to start unencrypted listener (port 8000 traffic, typically) |
use_ssl |
boolean() |
false |
Whether to start an SSL listener |
user_auth_tokens |
integer() |
35 | Default token cost of creating an auth token via username |
workers |
integer() |
100 | Number of TCP listeners to start |
Additional Configs
Some modules use the crossbar namespace to create a specific system_config document for settings as well.
crossbar.accounts
crossbar.auth
crossbar.braintree
crossbar.callflows
crossbar.cdrs
crossbar.devices
crossbar.fax
crossbar.freeswitch
crossbar.local_resources
crossbar.media
crossbar.notifications
crossbar.onboard
crossbar.port_requests
crossbar.presence
crossbar.provisioner_templates
crossbar.queues
crossbar.resource_selectors
crossbar.resource_templates
crossbar.resources
crossbar.services
crossbar.sms
crossbar.token_restrictions
Connectivity
About Connectivity
Schema
Trunkstore configuration document - this is old stuff; do not recommend building off this if possible
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
account.caller_id.cid_name |
string(0..35) |
false |
|||
account.caller_id.cid_number |
string(0..35) |
false |
|||
account.caller_id |
object() |
false |
|||
account.emergency_caller_id.cid_name |
string(0..35) |
false |
|||
account.emergency_caller_id.cid_number |
string(0..35) |
false |
|||
account.emergency_caller_id |
object() |
false |
|||
account.trunks |
The number of two-way trunks this account has purchased | integer() |
false |
||
account |
Information that applies to the account as a whole | object() |
false |
||
name |
Human-friendly name of the trunkstore account | string() |
false |
||
servers.[].DIDs./^\+?\d*$/.caller_id.cid_name |
string(1..35) |
false |
|||
servers.[].DIDs./^\+?\d*$/.caller_id.cid_number |
string(1..35) |
false |
|||
servers.[].DIDs./^\+?\d*$/.caller_id |
object() |
false |
|||
servers.[].DIDs./^\+?\d*$/.failover.e164 |
An E.164 formatted DID to dial for failover | string() |
false |
||
servers.[].DIDs./^\+?\d*$/.failover.sip |
A SIP URI (sip:user@host) to call for failover | string() |
false |
||
servers.[].DIDs./^\+?\d*$/.failover |
Route inbound call to another destination if this server fails to handle the call | object() |
false |
||
servers.[].DIDs./^\+?\d*$/.force_outbound |
boolean() |
false |
false |
||
servers.[].DIDs./^\+?\d*$/.options.[] |
string() |
false |
|||
servers.[].DIDs./^\+?\d*$/.options |
array(string()) |
false |
|||
servers.[].DIDs./^\+?\d*$/ |
object() |
false |
|||
servers.[].DIDs |
object() |
false |
|||
servers.[].auth.auth_method |
What type of auth mechanism to use | `string('password' | 'Password' | 'IP' | 'ip')` |
servers.[].auth.auth_password |
Password of the user@auth_realm | string(1..) |
false |
||
servers.[].auth.auth_user |
Username for authentication | string(1..) |
false |
||
servers.[].auth.ip |
IP (sip) address for this device | string() |
false |
||
servers.[].auth.port |
Port to send SIP traffic for the remote device | integer() |
false |
||
servers.[].auth |
object() |
true |
|||
servers.[].name |
Human-friendly name of the server | string(1..) |
false |
||
servers.[].options.caller_id.cid_name |
string(1..35) |
false |
|||
servers.[].options.caller_id.cid_number |
string(1..35) |
false |
|||
servers.[].options.caller_id |
object() |
false |
|||
servers.[].options.delay |
The time, in seconds, to wait before attempting to call the server | integer() |
0 |
false |
|
servers.[].options.dynamic_flags.[] |
string() |
false |
|||
servers.[].options.dynamic_flags |
List of function names (or 'zone') that are called on the Call record to populate the 'flags' array sent to the resource(s) for matching | array(string()) |
false |
||
servers.[].options.emergency_caller_id.cid_name |
string(0..35) |
false |
|||
servers.[].options.emergency_caller_id.cid_number |
string(0..35) |
false |
|||
servers.[].options.emergency_caller_id |
object() |
false |
|||
servers.[].options.enabled |
Is the server ready for sending and receiving calls | boolean() |
true |
false |
|
servers.[].options.failover.e164 |
An E.164 formatted DID to dial for failover | string() |
false |
||
servers.[].options.failover.sip |
A SIP URI (sip:user@host) to call for failover | string() |
false |
||
servers.[].options.failover |
Route inbound call to another destination if this server fails to handle the call | object() |
false |
||
servers.[].options.flags.[] |
string() |
false |
|||
servers.[].options.flags |
List of flags to use when matching resources to route the call | array(string()) |
false |
||
servers.[].options.force_outbound |
If true, will send the call over configured carriers instead of to the server (as opposed to the 'enabled' flag, which will reject the calls) | boolean() |
false |
false |
|
servers.[].options.hunt_account_id |
When using local resources, use this account instead of the account making the call (useful for resellers) | string() |
false |
||
servers.[].options.hunt_non_reconcilable |
Whether to allow routing to continue on a non-reconcilable TO number | boolean() |
false |
false |
|
servers.[].options.ignore_early_media |
boolean() |
false |
|||
servers.[].options.inbound_format |
Determines how the INVITE is sent to the server | `string('e164' | 'npan' | '1npan' | 'username')` |
servers.[].options.ip |
IP (sip) address for this device | string() |
false |
||
servers.[].options.media_handling |
Determine whether the switch should be in the media path or not | `string('process' | 'bypass')` | bypass |
false |
servers.[].options.port |
Port to send SIP traffic for the remote device | integer() |
false |
||
servers.[].options.progress_timeout |
The time, in seconds, to wait for the server to progress in the call, before trying an optionally defined failover route or terminating the call | integer() |
false |
||
servers.[].options.sip_headers |
List of arbitrary SIP headers to add to the INVITE | array(object()) |
false |
||
servers.[].options.timeout |
The time, in seconds, to wait for an answer from the server | integer() |
false |
||
servers.[].options |
object() |
false |
|||
servers |
What servers will be allowed to make/receive calls via this account | array(object()) |
[] |
false |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/connectivity
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/connectivity
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/connectivity', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create
PUT /v2/accounts/{ACCOUNT_ID}/connectivity
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/connectivity
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/connectivity',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Fetch
GET /v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Change
POST /v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Patch
PATCH /v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove
DELETE /v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Contact List
About Contact List
Schema
Fetch
GET /v2/accounts/{ACCOUNT_ID}/contact_list
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/contact_list
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/contact_list', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"external_number": "+14157775555",
"internal_number": "1000",
"name": "John Quux"
}
],
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Devices
About Devices
Devices are the endpoints assigned to an account that serve that account's needs. Devices like fax machines, SIP phones, soft phone clients, and cell phones (via call forwarding), among others, can be represented by Lumian devices.
Schema
A device be it a SIP phone or landline number
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
call_forward.direct_calls_only |
Determines if the calls that are not directly sent to the device should be forwarded | boolean() |
false |
false |
supported |
call_forward.enabled |
Determines if the call forwarding should be used | boolean() |
false |
false |
supported |
call_forward.failover |
Enable the call-forwarding parameters if the device is offline | boolean() |
false |
false |
supported |
call_forward.ignore_early_media |
The option to determine if early media from the call forwarded number should ignored | boolean() |
true |
false |
|
call_forward.keep_caller_id |
Determines if the caller id is kept when the call is forwarded, if not the devices caller id is used | boolean() |
true |
false |
supported |
call_forward.number |
The number to forward calls to | string(0..15) |
false |
supported |
|
call_forward.require_keypress |
Determines if the callee is prompted to press 1 to accept the call | boolean() |
true |
false |
supported |
call_forward.substitute |
Determines if the call forwarding replaces the device | boolean() |
true |
false |
supported |
call_forward |
The device call forward parameters | object() |
false |
||
call_recording |
endpoint recording settings | #/definitions/call_recording | false |
||
call_restriction |
Device level call restrictions for each available number classification | object() |
{} |
false |
|
call_waiting |
Parameters for server-side call waiting | #/definitions/call_waiting | false |
||
caller_id |
The device caller ID parameters | #/definitions/caller_id | false |
||
caller_id_options.outbound_privacy |
Determines what appears as caller id for offnet outbound calls. Values: full - hides name and number; name - hides only name; number - hides only number; none - hides nothing | `string('full' | 'name' | 'number' | 'none')` |
caller_id_options |
custom properties for configuring caller_id | object() |
false |
||
contact_list.exclude |
If set to true the device is excluded from the contact list | boolean() |
false |
supported |
|
contact_list |
Contact List Parameters | object() |
{} |
false |
|
device_type |
Arbitrary device type used by the UI and billing system | string() |
false |
||
dial_plan |
A list of rules used to modify dialed numbers | #/definitions/dialplans | false |
||
do_not_disturb.enabled |
Is do-not-disturb enabled for this device? | boolean() |
false |
||
do_not_disturb |
DND Parameters | object() |
false |
||
enabled |
Determines if the device is currently enabled | boolean() |
true |
false |
supported |
exclude_from_queues |
Do not ring this device when calling user/agent in queue | boolean() |
false |
false |
|
flags.[] |
string() |
false |
supported |
||
flags |
Flags set by external applications | array(string()) |
false |
supported |
|
formatters |
Schema for request formatters | #/definitions/formatters | false |
||
hotdesk.users./^[a-zA-Z0-9]{32}$/ |
user-specific hotdesk settings | object() |
false |
||
hotdesk.users |
The user(s) currently hotdesked into the device | object() |
false |
||
hotdesk |
The hotdesk status of this device | object() |
false |
||
language |
The language for the device | string() |
false |
supported |
|
mac_address |
The MAC Address of the device (if applicable) | string() |
false |
supported |
|
media |
Configure audio/video/etc media options for this device | #/definitions/endpoint.media | false |
||
metaflows |
The device metaflow parameters | #/definitions/metaflows | false |
||
music_on_hold.media_id |
The ID of a media object that should be used as the music on hold | string(0..2048) |
false |
||
music_on_hold |
The music on hold parameters used if not a property of the device owner | object() |
{} |
false |
|
mwi_unsolicited_updates |
When true enables unsolicited mwi notifications | boolean() |
true |
false |
|
name |
A friendly name for the device | string(1..128) |
true |
supported |
|
outbound_flags |
List of flags (features) this device requires when making outbound calls | `array(string()) | object()` | false |
|
owner_id |
The ID of the user object that 'owns' the device | string(32) |
false |
||
presence_id |
Static presence ID (used instead of SIP username) | string() |
false |
supported |
|
provision.check_sync_event |
Value to use in Event header for device reload/reboot | string() |
false |
||
provision.check_sync_reboot |
Value to append to 'check-sync' event if phone should reboot after reloading settings | string() |
false |
||
provision.check_sync_reload |
Value to append to 'check-sync' event if phone should not reboot after reloading settings | string() |
false |
||
provision.combo_keys./^[0-9]+$/ |
Device provisioner Combo/Feature Key | #/definitions/devices.combo_key | false |
||
provision.combo_keys |
object() |
false |
|||
provision.endpoint_brand |
Brand of the phone | string() |
false |
||
provision.endpoint_family |
Family name of the phone | string() |
false |
||
provision.endpoint_model |
Model name of the phone | `string() | integer()` | false |
|
provision.feature_keys./^[0-9]+$/ |
Device provisioner Combo/Feature Key | #/definitions/devices.combo_key | false |
||
provision.feature_keys |
object() |
false |
|||
provision |
Provision data | object() |
false |
||
register_overwrite_notify |
When true enables overwrite notifications | boolean() |
false |
false |
|
ringtones.external |
The alert info SIP header added when the call is from internal sources | string(0..256) |
false |
||
ringtones.internal |
The alert info SIP header added when the call is from external sources | string(0..256) |
false |
||
ringtones |
Ringtone Parameters | object() |
{} |
false |
|
sip.custom_sip_headers.in |
Custom SIP Headers to be applied to calls inbound to Lumian from the endpoint | #/definitions/custom_sip_headers | false |
||
sip.custom_sip_headers.out |
Custom SIP Headers to be applied to calls outbound from Lumian to the endpoint | #/definitions/custom_sip_headers | false |
||
sip.custom_sip_headers.^[a-zA-z0-9_\-]+$ |
The SIP header to add | string() |
false |
||
sip.custom_sip_headers |
A property list of SIP headers | object() |
false |
||
sip.expire_seconds |
The time, in seconds, sent to the provisioner for the registration period that the device should be configured with. | integer() |
300 |
false |
supported |
sip.ignore_completed_elsewhere |
When set to false the phone should not consider ring group calls answered elsewhere as missed | boolean() |
false |
||
sip.invite_format |
The SIP request URI invite format | `string('username' | 'npan' | '1npan' | 'e164' |
sip.ip |
IP address for this device | string() |
false |
supported |
|
sip.method |
Method of authentication | `string('password' | 'ip')` | password |
false |
sip.number |
The number used if the invite format is 1npan, npan, or e164 (if not set the dialed number is used) | string() |
false |
||
sip.password |
SIP authentication password | string(5..32) |
false |
supported |
|
sip.realm |
The realm this device should use, overriding the account realm. Should rarely be necessary. | string(4..253) |
false |
||
sip.route |
The SIP URL used if the invite format is 'route' | string() |
false |
supported |
|
sip.static_route |
Sends all inbound calls to this string (instead of dialed number or username) | string() |
false |
||
sip.username |
SIP authentication username | string(2..32) |
false |
supported |
|
sip |
SIP Parameters | object() |
{} |
false |
|
suppress_unregister_notifications |
When true disables deregister notifications | boolean() |
false |
false |
|
timezone |
Device's timezone | string() |
false |
supported |
call_recording
endpoint recording settings
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
any |
settings for any calls to/from the endpoint | #/definitions/call_recording.source | false |
||
inbound |
settings for inbound calls to the endpoint | #/definitions/call_recording.source | false |
||
outbound |
settings for outbound calls from the endpoint | #/definitions/call_recording.source | false |
call_recording.parameters
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
enabled |
is recording enabled | boolean() |
false |
||
format |
What format to store the recording on disk | `string('mp3' | 'wav')` | false |
|
record_min_sec |
The minimum length, in seconds, the recording must be to be considered successful. Otherwise it is deleted | integer() |
false |
||
record_on_answer |
Recording should start on answer | boolean() |
false |
||
record_on_bridge |
Recording should start on bridge | boolean() |
false |
||
record_sample_rate |
What sampling rate to use on the recording | integer() |
false |
||
time_limit |
Time limit, in seconds, for the recording | integer() |
false |
||
url |
The URL to use when sending the recording for storage | string() |
false |
call_recording.source
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
any |
settings for calls from any network | #/definitions/call_recording.parameters | false |
||
offnet |
settings for calls from offnet networks | #/definitions/call_recording.parameters | false |
||
onnet |
settings for calls from onnet networks | #/definitions/call_recording.parameters | false |
call_waiting
Parameters for server-side call waiting
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
enabled |
Determines if server side call waiting is enabled/disabled | boolean() |
false |
caller_id
Defines caller ID settings based on the type of call being made
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
asserted.name |
The asserted identity name for the object type | string(0..35) |
false |
||
asserted.number |
The asserted identity number for the object type | string(0..35) |
false |
||
asserted.realm |
The asserted identity realm for the object type | string() |
false |
||
asserted |
Used to convey the proven identity of the originator of a request within a trusted network. | object() |
false |
||
emergency.name |
The caller id name for the object type | string(0..35) |
false |
||
emergency.number |
The caller id number for the object type | string(0..35) |
false |
||
emergency |
The caller ID used when a resource is flagged as 'emergency' | object() |
false |
||
external.name |
The caller id name for the object type | string(0..35) |
false |
||
external.number |
The caller id number for the object type | string(0..35) |
false |
||
external |
The default caller ID used when dialing external numbers | object() |
false |
||
internal.name |
The caller id name for the object type | string(0..35) |
false |
||
internal.number |
The caller id number for the object type | string(0..35) |
false |
||
internal |
The default caller ID used when dialing internal extensions | object() |
false |
custom_sip_headers
Custom SIP headers applied to an INVITE
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
^[a-zA-z0-9_\-]+$ |
The SIP header to add | string() |
false |
devices.combo_key
Device provisioner Combo/Feature Key
| Key | Description | Type | Default | Required | Support Level |
|---|
dialplans
Permit local dialing by converting the dialed number to a routable form
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
system.[] |
string() |
false |
|||
system |
List of system dial plans | array(string()) |
false |
endpoint.media
Schema for endpoint media options
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
audio.codecs.[] |
`string('OPUS' | 'CELT@32000h' | 'G7221@32000h' | 'G7221@16000h' | |
audio.codecs |
A list of audio codecs the endpoint supports | `array(string('OPUS' | 'CELT@32000h' | 'G7221@32000h' | 'G7221@16000h' |
audio |
The audio media parameters | object() |
{} |
false |
|
bypass_media |
Default bypass media mode (The string type is deprecated, please use this as a boolean) | `boolean() | string('true' | 'false' | 'auto')` |
encryption.enforce_security |
Is Encryption Enabled? | boolean() |
false |
false |
|
encryption.methods.[] |
`string('zrtp' | 'srtp')` | false |
||
encryption.methods |
Supported Encryption Types | `array(string('zrtp' | 'srtp'))` | [] |
false |
encryption |
Encryption Parameters | object() |
{} |
false |
|
fax_option |
Is T.38 Supported? | boolean() |
false |
||
ignore_early_media |
The option to determine if early media from the endpoint should always be ignored | boolean() |
false |
||
progress_timeout |
The progress timeout to apply to the endpoint (seconds) | integer() |
false |
||
video.codecs.[] |
`string('H261' | 'H263' | 'H264' | 'VP8')` | |
video.codecs |
A list of video codecs the endpoint supports | `array(string('H261' | 'H263' | 'H264' | 'VP8'))` |
video |
The video media parameters | object() |
{} |
false |
formatters
Schema for request formatters
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
^[[:alnum:]_]+$ |
Key to match in the route request JSON | `array(#/definitions/formatters.format_options) | #/definitions/formatters.format_options` | false |
formatters.format_options
Schema for formatter options
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
direction |
Only apply the formatter on the relevant request direction | `string('inbound' | 'outbound' | 'both')` | |
match_invite_format |
Applicable on fields with SIP URIs. Will format the username portion to match the invite format of the outbound request. | boolean() |
false |
||
prefix |
Prepends value against the result of a successful regex match | string() |
false |
||
regex |
Matches against the value, with optional capture group | string() |
false |
||
strip |
If set to true, the field will be stripped from the payload | boolean() |
false |
||
suffix |
Appends value against the result of a successful regex match | string() |
false |
||
value |
Replaces the current value with the static value defined | string() |
false |
metaflow
A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
children./.+/ |
A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to | #/definitions/metaflow | false |
||
children |
Children metaflows | object() |
false |
||
data |
The data/arguments of the metaflow module | object() |
{} |
false |
|
module |
The name of the metaflow module to execute at this node | string(1..64) |
true |
metaflows
Actions applied to a call outside of the normal callflow, initiated by the caller(s)
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
binding_digit |
What DTMF will trigger the collection and analysis of the subsequent DTMF sequence | `string('1' | '2' | '3' | '4' |
digit_timeout |
How long to wait between DTMF presses before processing the collected sequence (milliseconds) | integer() |
false |
||
listen_on |
Which leg(s) of the call to listen for DTMF | `string('both' | 'self' | 'peer')` | |
numbers./^[0-9]+$/ |
A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to | #/definitions/metaflow | false |
||
numbers |
A list of static numbers with their flows | object() |
false |
||
patterns./.+/ |
A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to | #/definitions/metaflow | false |
||
patterns |
A list of patterns with their flows | object() |
false |
Call forwarding
Currently the call_forward object allows you to define call forwarding or failover but not both. If call_forward.enabled is true it will take precedence and settings will be used only for call forwarding. If call_forward.enabled is false and call_forward.failover is true, failover settings will be used.
Fetch
GET /v2/accounts/{ACCOUNT_ID}/devices
Sample Request:
curl -v -X GET \
-X "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices
import axios from 'axios';
const response = await axios('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices', {
method: 'x-auth-token: {auth_token}'
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"device_type": "sip_device",
"enabled": false,
"id": "{DEVICE_ID}",
"mac_address": "00:04:f2:ab:7e:fd",
"name": "MyPolycom"
}
],
"page_size": 1,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Create a new device
See the schema for available fields to include in the data portion
PUT /v2/accounts/{ACCOUNT_ID}/devices
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"name":"New Device"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices',
{
'data': {
'name': 'New Device'
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"call_restriction": {},
"caller_id": {},
"contact_list": {},
"dial_plan": {},
"enabled": true,
"exclude_from_queues": false,
"id": "{DEVICE_ID}",
"media": {
"audio": {
"codecs": [
"PCMU"
]
},
"encryption": {
"enforce_security": false,
"methods": []
},
"video": {
"codecs": []
}
},
"music_on_hold": {},
"mwi_unsolicited_updates": true,
"name": "New Device",
"register_overwrite_notify": false,
"ringtones": {},
"sip": {
"invite_format": "username",
"method": "password",
"registration_expiration": 300
},
"suppress_unregister_notifications": false
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Remove a device
DELETE /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"call_restriction": {},
"caller_id": {},
"contact_list": {},
"dial_plan": {},
"enabled": true,
"exclude_from_queues": false,
"id": "{DEVICE_ID}",
"media": {
"audio": {
"codecs": [
"PCMU"
]
},
"encryption": {
"enforce_security": false,
"methods": []
},
"video": {
"codecs": []
}
},
"music_on_hold": {},
"mwi_unsolicited_updates": true,
"name": "New Device",
"register_overwrite_notify": false,
"ringtones": {},
"sip": {
"invite_format": "username",
"method": "password",
"registration_expiration": 300
},
"suppress_unregister_notifications": false
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Fetch a device
GET /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"call_restriction": {},
"caller_id": {},
"contact_list": {},
"dial_plan": {},
"enabled": true,
"exclude_from_queues": false,
"id": "{DEVICE_ID}",
"media": {
"audio": {
"codecs": [
"PCMU"
]
},
"encryption": {
"enforce_security": false,
"methods": []
},
"video": {
"codecs": []
}
},
"music_on_hold": {},
"mwi_unsolicited_updates": true,
"name": "New Device",
"register_overwrite_notify": false,
"ringtones": {},
"sip": {
"invite_format": "username",
"method": "password",
"registration_expiration": 300
},
"suppress_unregister_notifications": false
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Change a device doc
Including "sync":true in the "data" will attempt to reboot the phone. See the sync section below.
POST /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{
"name": "new device",
"call_restriction": {},
"caller_id": {},
"contact_list": {},
"dial_plan": {},
"enabled": true,
"exclude_from_queues": false,
"media": {
"audio": {"codecs": ["PCMU"]},
"encryption": {"enforce_security": false, "methods": []},
"video": {"codecs": []}
},
"music_on_hold": {},
"mwi_unsolicited_updates": true,
"register_overwrite_notify": false,
"ringtones": {},
"sip": {
"invite_format": "username",
"method": "password",
"registration_expiration": 300
},
"suppress_unregister_notifications": false,
"id": "4f3330e78e664bb57f8fb23fbaac2429"
}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}',
// '{"data":{\n "name": "new device",\n "call_restriction": {},\n "caller_id": {},\n "contact_list": {},\n "dial_plan": {},\n "enabled": true,\n "exclude_from_queues": false,\n "media": {\n "audio": {"codecs": ["PCMU"]},\n "encryption": {"enforce_security": false, "methods": []},\n "video": {"codecs": []}\n },\n "music_on_hold": {},\n "mwi_unsolicited_updates": true,\n "register_overwrite_notify": false,\n "ringtones": {},\n "sip": {\n "invite_format": "username",\n "method": "password",\n "registration_expiration": 300\n },\n "suppress_unregister_notifications": false,\n "id": "4f3330e78e664bb57f8fb23fbaac2429"\n }}',
{
'data': {
'name': 'new device',
'call_restriction': {},
'caller_id': {},
'contact_list': {},
'dial_plan': {},
'enabled': true,
'exclude_from_queues': false,
'media': {
'audio': {
'codecs': [
'PCMU'
]
},
'encryption': {
'enforce_security': false,
'methods': []
},
'video': {
'codecs': []
}
},
'music_on_hold': {},
'mwi_unsolicited_updates': true,
'register_overwrite_notify': false,
'ringtones': {},
'sip': {
'invite_format': 'username',
'method': 'password',
'registration_expiration': 300
},
'suppress_unregister_notifications': false,
'id': '4f3330e78e664bb57f8fb23fbaac2429'
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"call_restriction": {},
"caller_id": {},
"contact_list": {},
"dial_plan": {},
"enabled": true,
"exclude_from_queues": false,
"id": "{DEVICE_ID}",
"media": {
"audio": {
"codecs": [
"PCMU"
]
},
"encryption": {
"enforce_security": false,
"methods": []
},
"video": {
"codecs": []
}
},
"music_on_hold": {},
"mwi_unsolicited_updates": true,
"name": "new device",
"register_overwrite_notify": false,
"ringtones": {},
"sip": {
"invite_format": "username",
"method": "password",
"registration_expiration": 300
},
"suppress_unregister_notifications": false
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Patch a device
PATCH /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"presence_id":"dis_my_device"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}',
'{"data":{"presence_id":"dis_my_device"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"call_restriction": {},
"caller_id": {},
"contact_list": {},
"dial_plan": {},
"enabled": true,
"exclude_from_queues": false,
"id": "{DEVICE_ID}",
"media": {
"audio": {
"codecs": [
"PCMU"
]
},
"encryption": {
"enforce_security": false,
"methods": []
},
"video": {
"codecs": []
}
},
"music_on_hold": {},
"mwi_unsolicited_updates": true,
"name": "new device",
"presence_id":"dis_my_device",
"register_overwrite_notify": false,
"ringtones": {},
"sip": {
"invite_format": "username",
"method": "password",
"registration_expiration": 300
},
"suppress_unregister_notifications": false
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Send a SIP NOTIFY to a device
Lumian will generate the NOTIFY packet if the device is registered.
PUT body options:
| Key | Type | Description |
|---|---|---|
action |
'notify' |
Perform the 'notify' action |
data.event |
string() |
The value of the Event header in the NOTIFY packet |
data |
object() |
Parameters for the action |
PUT /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"action": "notify",
"data": {
"event": "event"
}
}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/notify
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/notify',
// '{"action": "notify",\n "data": {\n "event": "event"\n }\n }',
{
'action': 'notify',
'data': {
'event': 'event'
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Fetch registration statuses of all devices
This will fetch the current registrations of any devices. If no devices are registered, an empty list will be returned.
GET /v2/accounts/{ACCOUNT_ID}/devices/status
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/status
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/status', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"device_id": "{DEVICE_ID}",
"registered": true
}
],
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Reboot a device
Some devices support receiving SIP NOTIFY packets with event = check-sync. This is typically used to reboot the phone if the configuration has changed. Lumian will generate the NOTIFY packet if the device is registered.
POST /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": "sync request sent",
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Reboot or not after syncing
If your device can support it, you can toggle whether to reboot the phone after it resyncs its configuration.
On the device document, set provision.check_sync_reboot to the suffix to add to the check-sync event when syncing the phone and rebooting.
On the device document, set provision.check_sync_reload to the suffix to add to the check-sync event when syncing the phone when not rebooting.
And of course you can override the check-sync prefix with provision.check_sync_event.
Rebooting example
The device settings:
Sample Response:
{"provision":{
"check_sync_reboot":"reboot=true"
}
}
API to force the reboot: POST /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync?reboot=true
Will generate Event: check-sync;reboot=true in the SIP NOTIFY.
Reloading example
The device settings:
Sample Response:
{"provision":{
"check_sync_reload":"reboot=false"
}
}
API to force the reboot: POST /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync?reboot=false
Will generate Event: check-sync;reboot=false in the SIP NOTIFY.
Check Sync Event
Should the device respond to a different value for the purposes of syncing, it can be overridden in the provision.check_sync_event.
There is also a system_config in crossbar.devices, check_sync_event, that can be set for defaults.
Quickcalls
See the quickcall docs for how to perform this action.
Adding Ringtones
You can setup internal and external ringtones by adding this:
Sample Response:
{
"name": "Device with custom ringtones",
"ringtones": {
"internal": "alert info SIP header",
"external": "alert info SIP header"
}
}
See, for instance, the Polycom example
Load a user's devices
Often you'll want to see what devices belong to a user, or devices that a user has hot-desked into.
Notice that the first device, {DEVICE_ID_1} is owned by {USER_ID} but the second device, {DEVICE_ID_2}, is owned by {OWNER_ID} and is currently hotdesked to {USER_ID} (see the "hotdesked":true attribute).
GET /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/devices
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/devices
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/devices', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"device_type": "sip_device",
"enabled": true,
"hotdesked": false,
"id": "{DEVICE_ID_1}",
"mac_address": "",
"name": "USER_ID_DEVICE",
"owner_id": "{USER_ID}"
},
{
"device_type": "sip_device",
"enabled": true,
"hotdesked": true,
"id": "{DEVICE_ID_2}",
"mac_address": "",
"name": "OWNER_ID_DEVICE",
"owner_id": "{OWNER_ID}"
}
],
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Create an Authn-By-IP Device
Here is a minimal API request that creates a device that will authenticate by IP address instead of username/password
PUT /v2/accounts/{ACCOUNT_ID}/devices
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"enabled":true,"name":"authn_by_ip","sip":{"invite_format":"e164", "ip":"{IP_ADDRESS}","method":"ip"}}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices',
// '{"data":{"enabled":true,"name":"authn_by_ip","sip":{"invite_format":"e164", "ip":"{IP_ADDRESS}","method":"ip"}}}',
{
'data': {
'enabled': true,
'name': 'authn_by_ip',
'sip': {
'invite_format': 'e164',
'ip': '{IP_ADDRESS}',
'method': 'ip'
}
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"call_restriction": {},
"caller_id": {},
"contact_list": {},
"dial_plan": {},
"enabled": true,
"exclude_from_queues": false,
"id": "{DEVICE_ID}",
"media": {
"audio": {
"codecs": [
"PCMU"
]
},
"encryption": {
"enforce_security": false,
"methods": []
},
"video": {
"codecs": []
}
},
"music_on_hold": {},
"mwi_unsolicited_updates": true,
"name": "authn_by_ip",
"register_overwrite_notify": false,
"ringtones": {},
"sip": {
"invite_format": "e164",
"ip": "{IP_ADDRESS}",
"method": "ip",
"registration_expiration": 300
},
"suppress_unregister_notifications": false
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Dialplans
About Dialplans
Schema
Permit local dialing by converting the dialed number to a routable form
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
system.[] |
string() |
false |
|||
system |
List of system dial plans | array(string()) |
false |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/dialplans
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/dialplans
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/dialplans', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Directories
About Directories
Directories provide the ability to route a caller to a user by having the caller enter DTMF corresponding to the directory users' first or last names (versus having to know the user's extension).
Schema
Allow a caller to search for a user/device by name instead of extension/DID
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
confirm_match |
When one match is found, require caller to confirm the match before connecting | boolean() |
true |
false |
supported |
flags.[] |
string() |
false |
supported |
||
flags |
Flags set by external applications | array(string()) |
false |
supported |
|
max_dtmf |
Cap the number of DTMF characters collected from a caller, 0 for unlimited | integer() |
0 |
false |
supported |
min_dtmf |
How many DTMF characters to collect from a caller before processing the directory | integer() |
3 |
false |
supported |
name |
The name of the directory | string(1..) |
true |
supported |
|
sort_by |
What field to sort on in matching documents when a caller enters characters | `string('first_name' | 'last_name')` | last_name |
false |
users.[] |
string() |
false |
supported |
||
users |
The list of users associated with this directory | array(string()) |
[] |
false |
supported |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/directories
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/directories
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/directories', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"id": "77dfb38ff2353624e35bf4df91acda94",
"name": "SmartPBX Directory"
}
],
"page_size": 1,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Remove a directory
DELETE /v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch a directory listing
GET /v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/directories/77dfb38ff2353624e35bf4df91acda94
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/directories/77dfb38ff2353624e35bf4df91acda94', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"confirm_match": false,
"id": "77dfb38ff2353624e35bf4df91acda94",
"max_dtmf": 0,
"min_dtmf": 3,
"name": "SmartPBX Directory",
"sort_by": "last_name",
"ui_metadata": {
"origin": "voip",
"ui": "monster-ui",
"version": "3.23"
},
"users": []
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
It is possible to fetch the directory as a PDF for download (such as a company directory, a sales department directory, etc).
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Accept: application/pdf" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Accept': 'application/pdf'
}
});
Streams back a PDF document.
If your client does not support setting the Accept header, you can append ?accept=pdf to the URI and Lumian will pretend you sent the proper Accept header.
Faxboxes
About Faxboxes
Fax boxes are used to receive, send and store incoming or outgoing faxes, allowing for configuration of individual fax virtual machines.
Schema
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
attempts |
The number of attempts made, this will be set by the system and reset automatically on put/post | integer() |
0 |
false |
|
caller_id |
The Caller-ID-Number | string() |
false |
supported |
|
caller_name |
The Caller-ID-Name | string() |
Lumian Fax Printer |
false |
supported |
custom_smtp_email_address |
custom smtp address | string() |
false |
supported |
|
fax_header |
The name printed at the top of the fax | string() |
Lumian Fax Printer |
false |
supported |
fax_identity |
The number printed at the top of the fax | string() |
false |
supported |
|
fax_timezone |
The timezone announced | string() |
false |
supported |
|
media.fax_option |
Is T.38 Supported? | boolean() |
false |
beta |
|
media |
The faxbox media parameters | object() |
{} |
false |
beta |
name |
A friendly name for the faxbox | string(1..128) |
true |
supported |
|
notifications.inbound.callback.method |
The http method to use when sending the results | `string('post' | 'put')` | false |
|
notifications.inbound.callback.type |
The content-type to use when sending the results | `string('json' | 'www-url-form-encoded')` | false |
|
notifications.inbound.callback.url |
The URL to call back with the results | string() |
false |
||
notifications.inbound.callback |
A URL to send results to | object() |
false |
beta |
|
notifications.inbound.email.send_to.[] |
string() |
false |
|||
notifications.inbound.email.send_to |
A list or string of email recipient(s) | `string() | array(string())` | false |
|
notifications.inbound.email |
Inbound Email Notifications | object() |
false |
supported |
|
notifications.inbound.sms.send_to.[] |
string() |
false |
|||
notifications.inbound.sms.send_to |
A list or string of sms recipient(s) | `string() | array(string())` | false |
|
notifications.inbound.sms |
SMS notifications | object() |
false |
beta |
|
notifications.inbound |
Inbound Status notifications | object() |
false |
supported |
|
notifications.outbound.callback.method |
The http method to use when sending the results | `string('post' | 'put')` | false |
|
notifications.outbound.callback.type |
The content-type to use when sending the results | `string('json' | 'www-url-form-encoded')` | false |
|
notifications.outbound.callback.url |
The URL to call back with the results | string() |
false |
||
notifications.outbound.callback |
A URL to send results to | object() |
false |
beta |
|
notifications.outbound.email.send_to.[] |
string() |
false |
|||
notifications.outbound.email.send_to |
A list or string of email recipient(s) | `string() | array(string())` | false |
|
notifications.outbound.email |
Email notifications | object() |
false |
supported |
|
notifications.outbound.sms.send_to.[] |
string() |
false |
|||
notifications.outbound.sms.send_to |
A list or string of sms recipient(s) | `string() | array(string())` | false |
|
notifications.outbound.sms |
SMS notifications | object() |
false |
beta |
|
notifications.outbound |
Outbound Status notifications | object() |
false |
supported |
|
notifications |
Status notifications | object() |
false |
supported |
|
retries |
The number of times to retry | integer() |
1 |
false |
supported |
smtp_permission_list.[] |
string() |
false |
supported |
||
smtp_permission_list |
smtp permission list. accepts regular expressions | array(string()) |
[] |
false |
supported |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/faxboxes
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxboxes
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxboxes', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create
PUT /v2/accounts/{ACCOUNT_ID}/faxboxes
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxboxes
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxboxes',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Fetch
GET /v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Change
POST /v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Patch
PATCH /v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove
DELETE /v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Faxes
Fax Subsystem Overview
The Faxes API exposes lots of ways to send, receive, track and manage faxes.
As a general concept, faxes are either considered inbound or outbound faxes. In addition:
- API calls with the term "incoming" are used for tracking faxes currently in the process of being received
- API calls with the term "inbox" are used for managing faxes which have already been received
- API calls with the term "outgoing" are used for tracking faxes currently in the process of being sent
- API calls with the term "outbox" are used for managing faxes which have already been sent
Schema
Faxes API allows you to update and access fax jobs for both sending and receiving
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
attempts |
The number of attempts made, this will be set by the system and reset automatically on put/post | integer() |
0 |
false |
|
document.content |
The content provided in the body when fetching for transmission as a post | string(0..256) |
false |
||
document.content_type |
The content type header to be used when fetching for transmission as a post | string() |
false |
||
document.host |
The host header to be used when fetching for transmission | string() |
false |
||
document.method |
The method that should be used to retrieve the document | `string('get' | 'post')` | get |
false |
document.referer |
The referer header to be used when fetching for transmission | string() |
false |
||
document.url |
The url of the fax document | string() |
true |
||
document |
Parameters related to the storage of a fax document | object() |
false |
||
from_name |
The sender name for the fax | string() |
false |
||
from_number |
The sender number for the fax | string() |
true |
||
notifications.email.send_to.[] |
string() |
false |
|||
notifications.email.send_to |
A list or string of email recipient(s) | `string() | array(string())` | false |
|
notifications.email |
Email notifications | object() |
false |
||
notifications.sms.send_to.[] |
string() |
false |
|||
notifications.sms.send_to |
A list or string of sms recipient(s) | `string() | array(string())` | false |
|
notifications.sms |
SMS notifications | object() |
false |
||
notifications |
Status notifications | object() |
false |
||
retries |
The number of times to retry | integer() |
1 |
false |
|
subject |
The subject header in an email to fax message | string() |
false |
||
to_name |
The recipient name for the fax | string() |
false |
||
to_number |
The recipient number for the fax | string() |
true |
||
tx_result.error_message |
A description of any error that occurred | string() |
"" | false |
|
tx_result.fax_bad_rows |
The number of bad rows | integer() |
0 |
false |
|
tx_result.fax_error_correction |
True if fax error correction was used | boolean() |
false |
false |
|
tx_result.fax_receiver_id |
The receiver id reported by the remote fax device | string() |
"" | false |
|
tx_result.fax_speed |
The speed (Baud-Rate) achieved during transmission | integer() |
0 |
false |
|
tx_result.pages_sent |
The number of pages transmitted | integer() |
0 |
false |
|
tx_result.success |
True if the fax transmission was successful | boolean() |
false |
false |
|
tx_result.time_elapsed |
The amount of time from submission to completion | integer() |
0 |
false |
|
tx_result |
The result of a transmission attempt | object() |
false |
Send Outgoing Fax
There are two way to send outgoing fax. You can provide a URL to the document you wish or send or you can provide the the document with the same send request payload.
PUT /v2/accounts/{ACCOUNT_ID}/faxes
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"document":{"url":"http://myserver.com/fax.pdf","method":"get"},"retries":3,"from_name":"Test Fax","from_number":"18884732963","to_name":"To Name","to_number":"18884732963"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes',
'{"data":{"document":{"url":"http://myserver.com/fax.pdf","method":"get"},"retries":3,"from_name":"Test Fax","from_number":"18884732963","to_name":"To Name","to_number":"18884732963"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"data":{
"document":{
"url":"http://myserver.com/fax.pdf",
"method":"get"
},
"retries":3,
"from_name":"Test Fax",
"from_number":"18884732963",
"to_name":"To Name",
"to_number":"18884732963",
"attempts":0,
"tx_result":{
"error_message":"",
"fax_bad_rows":0,
"fax_error_correction":false,
"fax_receiver_id":""
,"fax_speed":0,
"pages_sent":0,
"success":false,
"time_elapsed":0
},
"fax_timezone":"undefined",
"id":"{FAX_JOB_ID}"
},
"revision":"{REVISION}",
"request_id":"{REQUEST_ID}",
"status":"success",
"auth_token":"{AUTH_TOKEN}"
}
In the second method, you can use a single PUT request and send a multi-part content-type to attach both the JSON metadata about the fax transmission and the document itself, in a single request. This avoids needing to have an external storage location for storing fax attachments prior to processing. This is a good solution for portals that upload documents.
Sample Request:
curl -v -X PUT \
-H "Content-Type: multipart/mixed" \
-F "content=@fax.json; type=application/json" \
-F "content=@fax.pdf; type=application/pdf" \
-H 'X-Auth-Token: {AUTH_TOKEN}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes
import axios from 'axios';
import FormData from 'form-data';
import * as fs from 'fs';
const form = new FormData();
form.append('content', fs.readFileSync('fax.json'), 'fax.json');
form.append('content', fs.readFileSync('fax.pdf'), 'fax.pdf');
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes',
form,
{
headers: {
...form.getHeaders(),
'Content-Type': 'multipart/mixed',
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Create an outgoing fax (Alias)
This is identical to the PUT /faxes above.
PUT /v2/accounts/{ACCOUNT_ID}/faxes/outgoing
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outgoing
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outgoing',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Fetch outgoing faxes and their statuses
This API retrieves a listing of all outgoing faxes. Use the "id" to fetch details about a particular job. Results will contain a listing of both API- and SMTP (email) - initiated outbound faxes.
GET /v2/accounts/{ACCOUNT_ID}/faxes/outgoing
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outgoing
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outgoing', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"created": 63626410973,
"from": "18884732963",
"id": "{FAX_JOB_ID}",
"status": "pending",
"to": "18884732963"
}
],
"page_size": 1,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"start_key": [
"{START_KEY}"
],
"status": "success"
}
Fetch details of a queued outgoing fax job
Get all the details about a fax that is in the outgoing queue.
GET /v2/accounts/{ACCOUNT_ID}/faxes/outgoing/{FAX_JOB_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outgoing/{FAX_JOB_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outgoing/{FAX_JOB_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"attempts": 0,
"created": 63626410973,
"delivered": "undefined",
"document": {
"method": "get",
"url": "http://myserver.com/fax.pdf"
},
"fax_timezone": "undefined",
"from_name": "Test Fax",
"from_number": "18884732963",
"id": "{FAX_JOB_ID}",
"retries": 3,
"status": "pending",
"to_name": "To Name",
"to_number": "18884732963",
"tx_result": {
"error_message": "",
"fax_bad_rows": 0,
"fax_error_correction": false,
"fax_receiver_id": "",
"fax_speed": 0,
"pages_sent": 0,
"success": false,
"time_elapsed": 0
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Managing Past Outbound Faxes
Fetch All Previously Sent Faxes In The Outbox Folder
This API retrieves a listing of all outgoing faxes which have already been sent or attempted and are no longer in queue. Results will contain a listing of both API- and SMTP (email) - initiated outbound faxes.
GET /v2/accounts/{ACCOUNT_ID}/faxes/outbox
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch A Fax From The Outbox Folder
GET /v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Resubmit A Fax From The Outbox Folder
PUT /v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"action": "resubmit", "data": {}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}',
'{"action": "resubmit", "data": {}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Fetch The Fax Payload
GET /v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}/attachment
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}/attachment
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}/attachment', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch Logs Related To Outbound Faxes Submitted Via Email
If a fax job was queued or attempted to be queued as the result of an inbound email, the SMTP log for that fax can be retrieved via this API. This is also useful for helping debug problems with inbound faxes, such as when the domain matched an account for an inbound fax, but not a specific faxbox, and thus failed to process.
GET /v2/accounts/{ACCOUNT_ID}/faxes/smtplog
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/smtplog
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/smtplog', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch A Specific Log Related To Email
GET /v2/accounts/{ACCOUNT_ID}/faxes/smtplog/{ATTEMPT_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/smtplog/{ATTEMPT_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/smtplog/{ATTEMPT_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Remove A Fax From The Outbox Folder
This API allows you to delete an old fax message. For privacy reasons, this may be useful if you wish to remove all evidence of a previously sent outbound fax.
DELETE /v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Remove The Fax Payload
In some cases, you may wish to remove the document from a fax (usually for privacy reasons) but keep evidence that the fax transmission occurred. This will remove attachments but not the metadata from a sent fax.
DELETE /v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}/attachment
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}/attachment
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}/attachment', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Managing Past Inbound Faxes
Fetch All Faxes In The Inbox Folder
Retrieve a list of faxes that have previously been received.
GET /v2/accounts/{ACCOUNT_ID}/faxes/inbox
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch A Fax From The Inbox Folder
Retrieve all metadata about a particular fax for which you have the fax ID.
GET /v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch The Fax Payload
Retrieve the fax document / attachments for a particular inbound fax for which you have the fax ID.
GET /v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}/attachment
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}/attachment
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}/attachment', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Remove A Fax From The Inbox Folder
Delete an old fax message. For privacy reasons, this may be useful if you wish to remove all evidence of a previously received inbound fax.
DELETE /v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Remove The Fax Payload
In some cases, you may wish to remove the document from a fax (usually for privacy reasons) but keep evidence that the fax receipt occurred. This will remove attachments but not the metadata from a received fax. Useful after you've done post-processing on a fax externally.
DELETE /v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}/attachment
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}/attachment
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}/attachment', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
APIs under active development
Receiving Inbound Faxes
List Incoming Fax Jobs
Retrieve a list of faxes that are currently being received or attempted to be received. NOTE: THIS FUNCTION DOES NOT WORK YET AS OF THE WRITING OF THIS DOCUMENT. We'll update this doc once this function is complete.
GET /v2/accounts/{ACCOUNT_ID}/faxes/incoming
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/incoming
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/incoming', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch An Incoming Fax Job
GET /v2/accounts/{ACCOUNT_ID}/faxes/incoming/{FAX_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/incoming/{FAX_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/incoming/{FAX_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Query String Filters
Overview
Query string filters allow the API results to be filtered by additional criteria to limit the result set. This is especially useful when querying a collection that could be massive (like CDRs) but you're only interested in results that match certain criteria.
Available Filters
| Filter | Operates On | Description |
|---|---|---|
filter_not_{KEY} |
{VALUE} |
Doc include if {KEY} is not {VALUE} |
filter_{KEY} |
{VALUE} |
Doc included if {KEY} is {VALUE} |
has_key |
{KEY} |
Doc included if {KEY} is present on the doc |
key_missing |
{KEY} |
Doc included if {KEY} is not present on the doc |
has_value |
{KEY} |
Doc included if {KEY} exists and the {VALUE} is non-empty |
missing_value |
{KEY} |
Doc included if {KEY} is not present or the {VALUE} is empty |
created_from |
{VALUE} |
Doc included if the created time is greater than or equal to {VALUE} |
created_to |
{VALUE} |
Doc included if the created time is less than or equal to {VALUE} |
modified_from |
{VALUE} |
Doc included if the last-modified time is greater than or equal to {VALUE} |
modified_to |
{VALUE} |
Doc included if the last-modified time is less than or equal to {VALUE} |
Keys
Filters can be used on validated keys (those appearing in the schema) and on custom keys (those included by the caller).
{KEY} can be a dot-delimited string representing a JSON key path. So filter_foo.bar.baz=1 would match a doc that had {"foo":{"bar":{"baz":1}}} in it.
Multiple Filters
Filters can be chained together on a query string and will be applied as a boolean AND operation. For example, ?filter_foo=1&has_key=bar will look for docs where foo=1 and the key bar exists on the doc.
Freeswitch
About Freeswitch
Schema
Fetch
Global Provisioner Templates
About Global Provisioner Templates
Schema
Fetch
GET /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create
PUT /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Fetch
GET /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Change
POST /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove
DELETE /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch
GET /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Change
POST /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove
DELETE /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Groups
About Groups
Schema
Validator for the group
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
endpoints |
Endpoints included into group | object() |
{} |
true |
supported |
flags.[] |
string() |
false |
supported |
||
flags |
Flags set by external applications | array(string()) |
false |
supported |
|
music_on_hold.media_id |
The ID of a media object that should be used as music on hold | string(0..128) |
false |
||
music_on_hold |
The music on hold parameters | object() |
{} |
false |
beta |
name |
A friendly name for the group | string(1..128) |
true |
supported |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/groups
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/groups
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/groups', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": [
{
"id": "18ccfd6cea456cbdd38133e5aa726ec4",
"name": "Group Name",
"features": [],
"endpoints": 2
}
],
"status": "success"
}
Fetch all groups containing a user
GET /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/groups
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/groups
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/groups', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": [
{
"id": "18ccfd6cea456cbdd38133e5aa726ec4",
"name": "Group Name",
"features": [],
"endpoints": 2
}
],
"status": "success"
}
Create a group for a given account
PUT /v2/accounts/{ACCOUNT_ID}/groups
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{
"data": {
"music_on_hold": {},
"name": "Test group",
"endpoints": {
"df9274b450ea6795cdb381055c3f9b45": {
"type": "user",
"weight": 1
},
"dd03d7442a4bec5c092ea6a0e6d579ef": {
"type": "device",
"weight": 2
}
}
},
"verb": "PUT"
}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/groups
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/groups',
'{\n "data": {\n "music_on_hold": {},\n "name": "Test group",\n "endpoints": {\n "df9274b450ea6795cdb381055c3f9b45": {\n "type": "user",\n "weight": 1\n },\n "dd03d7442a4bec5c092ea6a0e6d579ef": {\n "type": "device",\n "weight": 2\n }\n }\n },\n "verb": "PUT"\n }',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"data": {
"music_on_hold": {},
"name": "Test group",
"endpoints": {
"df9274b450ea6795cdb381055c3f9b45": {
"type": "user",
"weight": 1
},
"dd03d7442a4bec5c092ea6a0e6d579ef": {
"type": "device",
"weight": 2
}
},
"id": "1743724cd775bf6994380dbc79c1af09"
},
"status": "success"
}
Remove a group
DELETE /v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": {
"music_on_hold": {},
"name": "Test group 2",
"id": "1743724cd775bf6994380dbc79c1af09",
"endpoints": {
"df9274b450ea6795cdb381055c3f9b45": {
"type": "user",
"weight": 1
},
"dd03d7442a4bec5c092ea6a0e6d579ef": {
"type": "device",
"weight": 2
}
}
},
"status": "success"
}
Get a group for a given account
GET /v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": {
"music_on_hold": {},
"name": "Test group",
"endpoints": {
"df9274b450ea6795cdb381055c3f9b45": {
"type": "user",
"weight": 1
},
"dd03d7442a4bec5c092ea6a0e6d579ef": {
"type": "device",
"weight": 2
}
},
"ui_metadata": {
"ui": "lumian-ui"
},
"id": "1743724cd775bf6994380dbc79c1af09"
},
"status": "success"
}
Update a group for a given account
POST /v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID}
PATCH /v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{
"data": {
"music_on_hold": {},
"name": "Test group 2",
"id": "1743724cd775bf6994380dbc79c1af09",
"endpoints": {
"df9274b450ea6795cdb381055c3f9b45": {
"type": "user",
"weight": 1
},
"dd03d7442a4bec5c092ea6a0e6d579ef": {
"type": "device",
"weight": 2
}
}
},
"verb": "POST"
}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID}',
'{\n "data": {\n "music_on_hold": {},\n "name": "Test group 2",\n "id": "1743724cd775bf6994380dbc79c1af09",\n "endpoints": {\n "df9274b450ea6795cdb381055c3f9b45": {\n "type": "user",\n "weight": 1\n },\n "dd03d7442a4bec5c092ea6a0e6d579ef": {\n "type": "device",\n "weight": 2\n }\n }\n },\n "verb": "POST"\n }',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"data": {
"music_on_hold": {},
"name": "Test group 2",
"endpoints": {
"df9274b450ea6795cdb381055c3f9b45": {
"type": "user",
"weight": 1
},
"dd03d7442a4bec5c092ea6a0e6d579ef": {
"type": "device",
"weight": 2
}
},
"ui_metadata": {
"ui": "lumian-ui"
},
"id": "1743724cd775bf6994380dbc79c1af09"
},
"status": "success"
}
Hotdesks
About Hotdesks
Schema
Fetch
GET /v2/accounts/{ACCOUNT_ID}/hotdesks
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/hotdesks
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/hotdesks', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Authenticating REST request
Almost every request to Crossbar must be supplying with authentication credentials.
Failing to do so will result in in 401 Unauthorized HTTP response status with response payload like this:
Sample Response:
{
"data": {
"message": "invalid credentials"
},
"error": "401",
"message": "invalid_credentials",
"status": "error",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{API_NODE}",
"request_id": "{REQUEST_ID}",
"auth_token": "{AUTH_TOKEN}"
}
Crossbar provide a number of ways of authenticating request. Most common way is authenticated as user and received a token usable on subsequent requests.
Basic Authentication
This is very simple and quick way of authentication. In this method you have to add Authorization HTTP header to request. The authorization method is Basic and the value is concatenation of your account ID and md5 hash of username and password. Refer to Basic Authentication for more information on how to generate the value for Authorization header.
Basic authentication has the disadvantage you have to provide the username and password in unencrypted text in every request.
Token based Authentication
This is the prefer and more secure way to do authentication with Crossbar API.
In Token based authentication you have to login first to get a token which you can then use in other requests. The token should be set in X-Auth-Token HTTP header in subsequent requests.
The are different ways to do login authentication.
Authenticate as a User
The best way to get authenticated and get the token for UI applications and making manual requests.
In this method, you provide the credentials of your user just for login and crossbar will generate an authentication token in response.
User credentials is MD5 hash of USERNAME:PASSWORD. So for example if your the username is john@example.com (usernames are always in lower case) and the password is m32c6NfqYEt MD5 hash of john@example.com:m32c6NfqYEt (note the colon : which separates the username and password) is 82a2dc91686ec828a67152d45a5c5ef7.
For generating MD5 of a text in terminal you can use md5sum (in Linux) or md5 (in macOS) as follow:
Sample Request:
$ echo -n 'john@example.com:m32c6NfqYEt' | md5sum
82a2dc91686ec828a67152d45a5c5ef7 -
NOTE: You can also use more secure SHA1 as your hash function. For generating SHA1 hash in terminal use
shasumcommand.
If you are using a programming language, refer to its documentation on how to generate MD5 hash.
You also need another field of data to identify the user: account's name or account's realm or phone number assigned to this user.
After the required data is ready, you can use user_auth API to get an authentication token:
Sample Request:
$ curl -v -X PUT \
-H "Content-Type: application/json" \
-d '{"data":{"credentials":"82a2dc91686ec828a67152d45a5c5ef7", "account_name":"{ACCOUNT_NAME"}, "method":[md5|sha]}' \
https://{SERVER}:8000/v2/user_auth
import axios from 'axios';
const response = await axios.put(
'http://
And a successful response:
> **Sample Response:**
```json
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"account_id": "{ACCOUNT_ID}",
"apps": [],
"is_reseller": true,
"language": "en-US",
"owner_id": "{OWNER_ID}",
"reseller_id": "{RESELLER_ID}"
},
"node": "{API_NODE}",
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
}
Here {AUTH_TOKEN}, the authentication token, is a long list of characters which you can use in future requests.
Sample Request:
curl -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
https://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}
import axios from 'axios';
const response = await axios.get('https://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
See User Authentication to learn more about this API resource.
Account API Authentication
Uses your account's API token to generate authentication token. If you're building a server applications, this is the best way to authenticate your application.
This is the same as authenticating as user, except you supplying the API key as data.
Sample Request:
curl -X PUT \
-d '{"data": {"api_key":"{API_KEY}"} }' \
http://{SERVER}:8000/v2/api_auth
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/api_auth',
'{"data": {"api_key":"{API_KEY}"} }',
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
You can find the API key in Authentication application in UI, or you can get it using Accounts API.
Next Steps
There are more way to authenticate your request, learn more about them in Authentication APIs section.
- For adding more security to your system see Multi-Factor Authentication.
- Use Security API for configuring authentication method. , '{"data":{"credentials":"82a2dc91686ec828a67152d45a5c5ef7", "account_name":"{ACCOUNT_NAME"}, "method":[md5|sha]}', { headers: { 'Content-Type': 'application/json' } } ); ```
And a successful response:
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"account_id": "{ACCOUNT_ID}",
"apps": [],
"is_reseller": true,
"language": "en-US",
"owner_id": "{OWNER_ID}",
"reseller_id": "{RESELLER_ID}"
},
"node": "{API_NODE}",
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
}
Here {AUTH_TOKEN}, the authentication token, is a long list of characters which you can use in future requests.
Sample Request:
curl -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
https://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}
See User Authentication to learn more about this API resource.
Account API Authentication
Uses your account's API token to generate authentication token. If you're building a server applications, this is the best way to authenticate your application.
This is the same as authenticating as user, except you supplying the API key as data.
Sample Request:
curl -X PUT \
-d '{"data": {"api_key":"{API_KEY}"} }' \
http://{SERVER}:8000/v2/api_auth
You can find the API key in Authentication application in UI, or you can get it using Accounts API.
Next Steps
There are more way to authenticate your request, learn more about them in Authentication APIs section.
- For adding more security to your system see Multi-Factor Authentication.
- Use Security API for configuring authentication method.
IP Authentication
About IP Authentication
Schema
Create
PUT /v2/ip_auth
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/ip_auth
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/ip_auth',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Ledgers
About Ledgers
The Ledgers API provides an easy way to see usage like per-minutes or flat-rate and manage your account's credit/debit values.
Ledgers Schema
ledgers document
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
account.id |
Account ID | string() |
false |
|
account.name |
Account name | string() |
false |
|
account |
Account info | object() |
false |
|
amount |
Ledger amount, in currency amount | number() |
false |
|
description |
Useful description for ledger | string() |
false |
|
metadata |
Metadata for ledger document | object() |
false |
|
period.end |
Period end | integer() |
false |
|
period.start |
Period start | integer() |
false |
|
period |
Period of ledger | object() |
false |
|
source.id |
Source ID | string() |
true |
|
source.service |
Source service | string() |
true |
|
source |
Origin of ledger | object() |
true |
|
usage.quantity |
Usage quantity | integer() |
true |
|
usage.type |
Usage type | string() |
true |
|
usage.unit |
Usage unit | string() |
true |
|
usage |
Usage for ledger | object() |
true |
Get Available Ledgers
List available ledger sources from the account's reseller.
GET /v2/accounts/{ACCOUNT_ID}/ledgers/available
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/available
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/available', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"name": "per-minute-voip",
"friendly_name": "Per Minute VoIP",
"markup_type": [
"percentage"
]
}
],
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}"
}
Fetch
GET /v2/accounts/{ACCOUNT_ID}/ledgers
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"mobile_data": {
"amount": -10.5,
"usage": {
"quantity": 1000,
"type": "debit",
"unit": "MB"
}
},
"per-minute-voip": {
"amount": -54.7404,
"usage": {
"quantity": 14520,
"type": "voice",
"unit": "sec"
}
}
},
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}"
}
Fetch Ledgers by source
GET /v2/accounts/{ACCOUNT_ID}/ledgers/{SOURCE_SERVICE}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/{SOURCE_SERVICE}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/{SOURCE_SERVICE}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Get Ledger values
List ledger values for an account with paging and filtering support
GET /v2/accounts/{ACCOUNT_ID}/ledgers/{LEDGER_ID}?created_from=11111111&created_to=22222222
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/{LEDGER_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/{LEDGER_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"page_size": 30,
"data": [
{
"source": {
"service": "per-minute-voip",
"id": "{CALL_ID}"
},
"account": {
"id": "{ACCOUNT_ID}",
"name": "{ACCOUNT_NAME}"
},
"usage": {
"type": "voice",
"quantity": 3,
"unit": "sec"
},
"amount": 6,
"description": "US Hollywood",
"period": {
"start": 63630348840
},
"id": "{DOC_ID}"
}
],
"revision": "{REVISION}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Get Ledger document
GET /v2/accounts/{ACCOUNT_ID}/ledgers/{LEDGER_ID}/{LEDGER_ENTRY_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/{LEDGER_ID}/{LEDGER_ENTRY_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/{LEDGER_ID}/{LEDGER_ENTRY_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": {
"source": {
"service": "per-minute-voip",
"id": "{CALL_ID}"
},
"account": {
"id": "{ACCOUNT_ID}",
"name": "{ACCOUNT_NAME}"
},
"usage": {
"type": "voice",
"quantity": 3,
"unit": "sec"
},
"amount": 6,
"description": "US Hollywood",
"period": {
"start": 63630348840
},
"id": "{DOC_ID}"
},
"revision": "{REVISION}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Credit / Debit
Credit or Debit a specific ledger.
the account_id for AUTH_TOKEN must be reseller of target account.
Parameter "impact_reseller" (boolean not required) when true will also create the document in the reseller
PUT /v2/accounts/{ACCOUNT_ID}/ledgers/debit
PUT /v2/accounts/{ACCOUNT_ID}/ledgers/credit
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/debit
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/debit',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Sample Response:
{
"data": {
"amount": 100,
"description": "blablabla",
"source": {
"service": "tower/support/...",
"id": "mac/mdn/..."
},
"usage": {
"type": "data",
"quantity": 5,
"unit": "MB"
},
"period": {
"start": 10938710938,
"end": 214109238023899
}
},
"impact_reseller": true
}
Fetch
GET /v2/accounts/{ACCOUNT_ID}/ledgers/{SOURCE_SERVICE}/{LEDGER_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/{SOURCE_SERVICE}/{LEDGER_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/{SOURCE_SERVICE}/{LEDGER_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch Ledger and Account Summary Breakdown
Fetches the account ledger summary as well as a breakdown of ledgers per account for a given YYYYMM.
GET /v2/accounts/{ACCOUNT_ID}/ledgers/summary/{MODB_SUFFIX}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/summary/{MODB_SUFFIX}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/summary/{MODB_SUFFIX}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Example
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/summary/201905
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/summary/201905', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
"data": {
"summary": {
"per-minute-voip": {
"amount": -880.0,
"usage": {
"type": "voice",
"quantity": 232320,
"unit": "sec"
}
},
"payments": {
"amount": 251970.82,
"usage": {
"type": "debit",
"quantity": 0,
"unit": "dollars"
}
},
"prorations": {
"amount": -1.9258,
"usage": {
"quantity": 0
}
},
"rollovers": {
"amount": 36.102,
"usage": {
"quantity": 0
}
}
},
"breakdown": [
{
"account": {
"id": "de6fd29a54407cfe46e6c9d3828ab0d8",
"name": "Account A"
},
"ledgers": {
"payments": {
"amount": -1250000.0,
"usage": {
"type": "debit",
"quantity": 0,
"unit": "dollars"
}
},
"per-minute-voip": {
"amount": -385.0,
"usage": {
"type": "voice",
"quantity": 101640,
"unit": "sec"
}
}
},
"total": -1250385.0
},
{
"account": {
"id": "cc580f94d7da53816a94b87b2a1d25f8",
"name": "Account 1"
},
"ledgers": {
"payments": {
"amount": 1501970.82,
"usage": {
"type": "credit",
"quantity": 0,
"unit": "dollars"
}
},
"prorations": {
"amount": -1.9258,
"usage": {
"quantity": 0
}
},
"rollovers": {
"amount": 36.102,
"usage": {
"quantity": 0
}
}
},
"total": 1500004.9962
},
{
"account": {
"id": "a71a670531d7dc92d2a4f9fc6774df36",
"name": "Account B"
},
"ledgers": {
"per-minute-voip": {
"amount": -495.0,
"usage": {
"type": "voice",
"quantity": 130680,
"unit": "sec"
}
}
},
"total": -495.0
}
]
}
Limits
Configures limit on call consumed for your account.
About Limits
Schema
Limit an account's ability to place concurrent calls using flat rate trunks
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
allow_prepay |
Determines if the account would like to allow per-minute calls if they have no available credit | boolean() |
true |
false |
supported |
burst_trunks |
The number of two-way, flat-rate trunks used only if no other trunks are available | integer() |
false |
beta |
|
calls |
A hard limit for the total number calls | integer() |
false |
beta |
|
inbound_trunks |
The number of inbound, flat-rate trunks | integer() |
false |
supported |
|
outbound_trunks |
The number of outbound, flat-rate trunks | integer() |
false |
supported |
|
resource_consuming_calls |
A hard limit for the number of resource consuming calls | integer() |
false |
beta |
|
twoway_trunks |
The number of two-way, flat-rate trunks | integer() |
false |
beta |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/limits
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/limits
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/limits', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": {
"twoway_trunks": 0,
"inbound_trunks": 0,
"id": "limits",
"allow_prepay": true,
"outbound_trunks": 5
},
"status": "success"
}
Update limits for a given account
POST /v2/accounts/{ACCOUNT_ID}/limits
First using API v1 (simplest):
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {
"twoway_trunks": 0,
"inbound_trunks": 11,
"id": "limits",
"allow_prepay": true,
"outbound_trunks": 5
}}' \
http://{SERVER}:8000/v1/accounts/{ACCOUNT_ID}/limits
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v1/accounts/{ACCOUNT_ID}/limits',
'{"data": {\n "twoway_trunks": 0,\n "inbound_trunks": 11,\n "id": "limits",\n "allow_prepay": true,\n "outbound_trunks": 5\n }}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"data": {
"twoway_trunks": 0,
"inbound_trunks": 11,
"id": "limits",
"allow_prepay": true,
"outbound_trunks": 5
},
"status": "success",
}
Now with API v2:
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {
"twoway_trunks": 0,
"inbound_trunks": 11,
"id": "limits",
"allow_prepay": true,
"outbound_trunks": 5
}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/limits
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/limits',
'{"data": {\n "twoway_trunks": 0,\n "inbound_trunks": 11,\n "id": "limits",\n "allow_prepay": true,\n "outbound_trunks": 5\n }}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Reply warns that charges have to be accepted (402):
{
"data": {
"limits": {
"inbound_trunks": {
"category": "limits",
"item": "inbound_trunks",
"quantity": 11,
"rate": 6.9900000000000002132,
"single_discount": true,
"single_discount_rate": 0.0,
"cumulative_discount": 0,
"cumulative_discount_rate": 0.0
}
}
},
"error": "402",
"message": "accept charges",
"status": "error",
}
Re-do the same request, setting accept_charges to true.
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {
"twoway_trunks": 0,
"inbound_trunks": 11,
"id": "limits",
"allow_prepay": true,
"outbound_trunks": 5,
"accept_charges": true
}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/limits
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/limits',
'{"data": {\n "twoway_trunks": 0,\n "inbound_trunks": 11,\n "id": "limits",\n "allow_prepay": true,\n "outbound_trunks": 5,\n "accept_charges": true\n }}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"data": {
"twoway_trunks": 0,
"inbound_trunks": 11,
"id": "limits",
"allow_prepay": true,
"outbound_trunks": 5
},
"status": "success",
}
Lists
Lists API provide to create list of numbers ore prefix numbers to match and route calls.
In the new behavior of List API, list is a collection of list entries (number, user, prefix numbers) allows you more flexibility to create and assign multi entries to different match list.
Schema
Schema for a match list
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
description |
A friendly list description | string(1..128) |
false |
||
name |
A friendly match list name | string(1..128) |
true |
||
org |
Full legal name of the organization | string() |
false |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/lists
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Add new list (beware: no entries)
PUT /v2/accounts/{ACCOUNT_ID}/lists
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"name": "list name"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists',
'{"data": {"name": "list name"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Delete list and its entries
DELETE /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Get list properties (doesn't return entries)
GET /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Updating list (without entries)
PATCH /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"description": "desc"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}',
'{"data": {"description": "desc"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Rewrite list
POST /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"name": "New List name"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}',
'{"data": {"name": "New List name"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Delete all entries from list
DELETE /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Get list entries
GET /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Add an entry to a list
PUT /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"number": "0123", "displayname" : "List Entry"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries',
'{"data": {"number": "0123", "displayname" : "List Entry"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Delete entry from the list
DELETE /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
List entry properties
GET /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Update list entry
PATCH /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"firstname" : "First name"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}',
'{"data": {"firstname" : "First name"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Replace list entry
POST /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"number": "0123", "displayname" : "New List Entry"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}',
'{"data": {"number": "0123", "displayname" : "New List Entry"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Add photo to List entry
POST /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}/photo
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}/photo
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}/photo',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
List entry vcard
GET /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}/vcard
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}/vcard
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}/vcard', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
v1 examples.
Get lists and their entries
curl -v -X GET -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v1/accounts/{ACCOUNT_ID}/lists
Create new list
curl -v -X PUT -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v1/accounts/{ACCOUNT_ID}/lists -d '{"data": {"name": "List name"}}'
Get list with LIST_ID
curl -v -X GET -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v1/accounts/{ACCOUNT_ID}/lists/{LIST_ID}
Add new entry to list
curl -v -X PUT -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v1/accounts/{ACCOUNT_ID}/lists/{LIST_ID} -d '{"data": {"pattern": "345"}}'
Delete list
curl -v -X DELETE -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v1/accounts/{ACCOUNT_ID}/lists/{LIST_ID}
Get entry {LIST_ENTRY_ID} from list {LIST_ID}
curl -v -X GET -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v1/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/{LIST_ENTRY_ID}
Rewrite entry {LIST_ENTRY_ID} in list {LIST_ID}
curl -v -X POST -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v1/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/{LIST_ENTRY_ID} -d "{"data": {"132", "321"}}"
Delete entry from list
curl -v -X DELETE -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v1/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/{LIST_ENTRY_ID}
Local Provisioner Templates
About Local Provisioner Templates
Schema
Fetch
GET /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create
PUT /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Fetch
GET /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Change
POST /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove
DELETE /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch
GET /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Change
POST /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove
DELETE /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Crossbar Maintenance Functions
Migrate Ring Group Callflow
The migrate_ring_group_callflow function will migrate callflow create with a ring group by Monster UI before v3.19.
It will extract the ring group and create a new callflow and then reference this new callflow in the old one. This function will not impact any other callflows or ring group callflows create by Lumian UI.
Update UI apps metadata
List all apps
Sample Request:
sup crossbar_maintenance apps
Get one app's metadata
Sample Request:
sup crossbar_maintenance app AppName_Or_AppId
Update an app's en-US fields
Sample Request:
sup crossbar_maintenance set_app_label AppId NewValue
Sample Request:
sup crossbar_maintenance set_app_description AppId NewValue
Sample Request:
sup crossbar_maintenance set_app_extended_description AppId NewValue
Note: features must be @-separated if more than one is supplied.
Sample Request:
sup crossbar_maintenance set_app_features AppId 'my feature'
sup crossbar_maintenance set_app_features AppId feature1@featureB@feat3
Update an app's icon
Sample Request:
sup crossbar_maintenance set_app_icon AppId PathToPNGIcon
Update an app's screenshots
Sample Request:
sup crossbar_maintenance set_app_screenshots AppId PathToScreenshotsFolder
Media
About Media
Uploading media for custom music on hold, IVR prompts, or TTS (if a proper TTS engine is enabled).
Lumian provides some default system media files for common things like voicemail prompts. These are accessible via the media Crossbar endpoint as well, if your user has super duper admin privileges. To manipulate those resources, simply omit the /accounts/{ACCOUNT_ID} from the URI.
For example, to get a listing of all system media files:
Sample Request:
curl -v -X GET -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v2/media
You can then get the id of the media file and manipulate it in a similar fashion as regular account media (including TTS if you have a TTS engine like iSpeech configured).
Media Languages
Part of the schema of media files is a language attribute. It defaults to a system_config/media value for the default_language key (and is "en-us" by default). Properly defined media files can be searched for based on language using the basic filters provided by Crossbar:
Sample Request:
curl -v -X GET -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v2/media?filter_language=en
curl -v -X GET -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v2/media?filter_language=en-US
curl -v -X GET -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v2/media?filter_language=fr-FR
The comparison is case-insensitive, but en and en-US are treated separately. If a media metadata object is missing a language attribute (on an older installation when system media was imported with no language field, say), use key_missing=language in the request.
Once you've assigned languages, you can use the language callflow action to set the language for that call.
Normalize Media Files
Lumian can be configured to normalize uploaded media files. This can fix things like:
- Normalizing volume
- Fix clipping
- Standardize formats
By default, if enabled, normalization will convert all media to MP3 (retaining the original upload as well) using the sox utility to accomplish the conversion.
Enable Normalization Via SUP
- Enable normalization for this particular server:
sup kapps_config set crossbar.media normalize_media true - Enable normalization for all servers:
sup kapps_config set_default crossbar.media normalize_media true
Enable Normalization Via DB
- Open
system_config/crossbar.mediadocument, create or update the keynormalize_mediatotrue. - Flush the
kapps_configcache,sup kapps_config flush crossbar.media, on all servers running Crossbar.
Set Target Format Via SUP
- For the server:
sup kapps_config set crossbar.media normalization_format ogg - For all servers:
sup kapps_config set_default crossbar.media normalization_format ogg
Set Target Format Via DB
In the system_config/crossbar.media document, create or update the key normalization_format to your desired format (mp3, wav, etc). Flush the kapps_config cache on all servers running Crossbar. All new uploads will be normalized (if possible) to the new format.
Normalization parameters
The default sox command is sox -t <input_format> - -r 8000 -t <output_format> - but this is configurable via the system_config/media document (or similar SUP command).
You can fine-tune the source and destination arguments using the normalize_source_args and normalize_destination_args keys respectively. By default, the source args are "" and the destination args are "-r 8000" (as can be seen from the default sox command above.
The normalizer code uses stdin to send the binary data to sox and reads from stdout to get the normalized binary data back (the " - " (there are 2) in command above).
You can also set the specific path for sox in the normalize_executable key, in case you've installed it to a non-standard path.
Be sure to install sox with mp3 support! Conversion will not happen (assuming you're targeting mp3) if sox can't write the mp3. You can check the media meta document for the key normalization_error if sox failed for some reason.
Schema
Schema for media
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
content_length |
Length, in bytes, of the file | integer() |
false |
supported |
|
content_type |
Used to override the automatic upload type | `string('audio/mp3' | 'audio/mpeg' | 'audio/mpeg3' | 'audio/x-wav' |
description |
A brief description of the media update, usually the original file name | string(1..128) |
false |
supported |
|
language |
The language of the media file or text | string() |
en-us |
false |
supported |
media_source |
Defines the source of the media | `string('recording' | 'upload' | 'tts')` | upload |
name |
A friendly name for the media | string(1..128) |
true |
supported |
|
prompt_id |
The prompt this media file represents | string() |
false |
||
source_id |
If the media was generated from a callflow module, this is ID of the properties | string(32) |
false |
beta |
|
source_type |
If the media was generated from a callflow module, this is the module name | string() |
false |
beta |
|
streamable |
Determines if the media can be streamed | boolean() |
true |
false |
supported |
tts.text |
The text to be converted into audio | string(1..) |
false |
supported |
|
tts.voice |
The voice to be used during the conversion | `string('female/en-US' | 'male/en-US' | 'female/en-CA' | 'female/en-AU' |
tts |
Text-to-speech options used to create audio files from text | object() |
{} |
false |
supported |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/media
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"id": "0c347bba3754056caad610bb8a337342",
"is_prompt": false,
"language": "en-us",
"media_source": "tts",
"name": "Main AA BG"
}
],
"page_size": 1,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Create a new media object (required before uploading the actual media data)
PUT /v2/accounts/{ACCOUNT_ID}/media
- For a file:
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{
"streamable":true,
"name": "File",
"description": "My Test Media File",
}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media
- For a prompt:
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{
"streamable": true,
"name": "FR-vm-enter_pass",
"description": "FR - Enter Password prompt",
"prompt_id": "vm-enter_pass",
"language":"fr"
}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media
- For a TTS document: (requires iSpeech to be enabled)
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{
"name": "TestTTS",
"media_source": "tts",
"tts": {"text": "Testing TTS", "voice": "female/en-US"}
}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media
A response:
Sample Response:
{
"data":
{
"streamable": true,
"name": "vm-enter_pass",
"description": "FR - Enter Password prompt",
"prompt_id": "vm-enter_pass",
"language": "fr-fr",
"tts": {
"voice": "female/en-US"
},
"media_source": "upload",
"id": "fr-fr%2Fvm-enter_pass"
},
"revision": "{REVISION}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Remove metadata
Optional Parameter: "hard_delete": true - will perform a hard delete of the document (default is soft delete)
DELETE /v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID}
Get metadata about a media file
GET /v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media/0c347bba3754056caad610bb8a337342
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"description": "tts file",
"id": "0c347bba3754056caad610bb8a337342",
"language": "en-us",
"media_source": "tts",
"name": "Main AA BG",
"streamable": true,
"tts": {
"text": "Thank you for calling My Amazing Company where we do amazing things. You may dial any extension at any time. To schedule an appointment, press 1. For billing questions about your account, press 2. For all other inquiries, press 0. To hear this menu again, please stay on the line.",
"voice": "female/en-US"
},
"ui_metadata": {
"origin": "callflows",
"ui": "monster-ui",
"version": "4.0-7"
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Update metadata
POST /v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID}
List all prompts and the number of translations existing
GET /v2/accounts/{ACCOUNT_ID}/media/prompts
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media/prompts
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"agent-already_logged_in": 1,
"agent-enter_pin": 1,
"agent-invalid_choice": 1,
"agent-logged_in": 1,
"agent-logged_out": 1,
"agent-not_call_center_agent": 1,
"agent-pause": 1,
"agent-resume": 1,
"agent_enter_pin": 1,
"agent_logged_already_in": 1,
"agent_logged_in": 1,
"agent_logged_out": 1,
"cf-disabled": 1,
"cf-disabled_menu": 1,
"cf-enabled_menu": 1,
"cf-enter_number": 1,
"cf-move-no_channel": 1,
"cf-move-no_owner": 1,
"cf-move-too_many_channels": 1,
"cf-not_available": 1,
"cf-now_forwarded_to": 1,
"cf-unauthorized_call": 1,
"conf-alone": 1,
"conf-bad_conf": 1,
"conf-bad_pin": 1
}
],
"next_start_key": "conf-deaf",
"page_size": 25,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
List languages available
GET /v2/accounts/{ACCOUNT_ID}/media/languages
This request will return a list of languages found, as well as the counts of how many media files have that language defined:
Note, the "missing" key indicates how many media files have no associated language.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media/languages
Sample Response:
{
"data": [{ "en": 3
,"missing": 1
}
],
}
Get the raw media file
GET /v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID}/raw
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H 'Accept: audio/mp3' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID}/raw
Streams back an MP3-encoded media.
Add the media binary file to the media meta data
POST /v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID}/raw
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H 'Content-Type: audio/mp3' \
--data-binary @/path/to/file.mp3 \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID}/raw
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H 'Content-Type: audio/x-wav \
--data-binary @/path/to/file.wav \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID}/raw
Only one of the above; any subsequent POSTs will overwrite the existing binary data.
List all translations of a given prompt
GET /v2/accounts/{ACCOUNT_ID}/media/prompts/{PROMPT_ID}
You can use that list to fetch the specific media files associated with that prompt.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media/prompts/{PROMPT_ID}
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
"fr-fr%2Fvm-enter_pass",
"en-us%2Fvm-enter_pass"
],
"page_size": 2,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"start_key": "vm-enter_pass",
"status": "success"
}
List media files with specific language
GET /v2/accounts/{ACCOUNT_ID}/media/languages/{LANGUAGE}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media/languages/{LANGUAGE}
Sample Response:
{
"data":["media_id_1", "media_id_2",...]
}
To get the IDs of the media docs missing a language:
Sample Request:
curl -v -X GET -H "X-Auth-Token: {AUTH_TOKEN}" http://server.com:8000/v2/accounts/{ACCOUNT_ID}/media/languages/missing
...
"data":["media_id_1", "media_id_2",...]
...
Menus
Menus, IVRs, what ever you call them, allow you to create branches in the callflow based on the caller's input.
About Menus
The DTMF entered is matched against the "children" keys and that branch is taken.
Additionally, you can branch based on a timeout (no DTMF entered) by using "timeout" in the "children" keys":
Sample Response:
{
"module":"menu",
"data": {...},
"children": {
"1": {"module":"...",...},
"2": {"module":"...",...},
"timeout": {"module":"...",...}
}
}
If no timeout child is specified, the menu is retried (until retries are exceeded).
Schema
Schema for a menus
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
allow_record_from_offnet |
Determines if the record pin can be used by external calls | boolean() |
false |
false |
supported |
flags.[] |
string() |
false |
supported |
||
flags |
Flags set by external applications | array(string()) |
false |
supported |
|
hunt |
Determines if the callers can dial internal extensions directly | boolean() |
true |
false |
supported |
hunt_allow |
A regular expression that an extension the caller dialed must match to be allowed to continue | string(1..256) |
false |
supported |
|
hunt_deny |
A regular expression that if matched does not allow the caller to dial directly | string(1..256) |
false |
supported |
|
interdigit_timeout |
The amount of time (in milliseconds) to wait for the caller to press the next digit after pressing a digit | integer() |
false |
supported |
|
max_extension_length |
The maximum number of digits that can be collected | integer() |
4 |
false |
supported |
media.exit_media |
When a call is transferred from the menu after all retries exhausted this media can be played (prior to transfer if enabled) | `boolean() | string(3..2048)` | false |
|
media.greeting |
The ID of a media object that should be used as the menu greeting | string(3..2048) |
false |
supported |
|
media.invalid_media |
When the collected digits don't result in a match or hunt this media can be played | `boolean() | string(3..2048)` | false |
|
media.transfer_media |
When a call is transferred from the menu, either after all retries exhausted or a successful hunt, this media can be played | `boolean() | string(3..2048)` | false |
|
media |
The media (prompt) parameters | object() |
{} |
false |
supported |
name |
A friendly name for the menu | string(1..128) |
true |
supported |
|
record_pin |
The pin number used to record the menu prompt | string(3..6) |
false |
supported |
|
retries |
The number of times a menu should be played until a valid entry is collected | integer() |
3 |
false |
supported |
suppress_media |
Determines if the playing of 'Invalid Entry' is suppressed. | boolean() |
false |
false |
supported |
timeout |
The amount of time (in milliseconds) to wait for the caller to begin entering digits | integer() |
false |
supported |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/menus
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/menus
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/menus', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create
PUT /v2/accounts/{ACCOUNT_ID}/menus
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/menus
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/menus',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Fetch
GET /v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Change
POST /v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Patch
PATCH /v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove
DELETE /v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Metaflows
About Metaflows
Metaflows allow functionality to be executed on an in-progress call, triggered by DTMFs from the caller/callee or an API call.
For instance, a callee could setup a metaflow on their user doc such that when they receive a call, they can press *9 to initiate a recording of the call.
Schema
Actions applied to a call outside of the normal callflow, initiated by the caller(s)
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
binding_digit |
What DTMF will trigger the collection and analysis of the subsequent DTMF sequence | `string('1' | '2' | '3' | '4' |
digit_timeout |
How long to wait between DTMF presses before processing the collected sequence (milliseconds) | integer() |
false |
||
listen_on |
Which leg(s) of the call to listen for DTMF | `string('both' | 'self' | 'peer')` | |
numbers./^[0-9]+$/ |
A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to | #/definitions/metaflow | false |
||
numbers |
A list of static numbers with their flows | object() |
false |
||
patterns./.+/ |
A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to | #/definitions/metaflow | false |
||
patterns |
A list of patterns with their flows | object() |
false |
metaflow
A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
children./.+/ |
A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to | #/definitions/metaflow | false |
||
children |
Children metaflows | object() |
false |
||
data |
The data/arguments of the metaflow module | object() |
{} |
false |
|
module |
The name of the metaflow module to execute at this node | string(1..64) |
true |
Fetch account-level metaflows
These are available to all users and devices within the account
GET /v2/accounts/{ACCOUNT_ID}/metaflows
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/metaflows
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/metaflows', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
No metaflows assigned
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {},
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"timestamp": "{TIMESTAMP}",
"version": "4.2.42"
}
Set metaflows on the account
POST /v2/accounts/{ACCOUNT_ID}/metaflows
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: $AUTH_TOKEN" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/metaflows \
-d '{"data":{"binding_digit":"*", "patterns":{"2(\\d+)":{"module":"transfer", "data":{"takeback_dtmf":"*1"}}}}}'
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/metaflows',
'{"data":{"binding_digit":"*", "patterns":{"2(\\\\d+)":{"module":"transfer", "data":{"takeback_dtmf":"*1"}}}}}',
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"binding_digit": "*",
"patterns": {
"2(\\d+)": {
"data": {
"captures": [
"no_match"
],
"takeback_dtmf": "*1",
"transfer_type": "blind"
},
"module": "transfer"
}
}
},
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success",
"timestamp": "{TIMESTAMP}",
"version": "4.2.42"
}
In the above example, the binding_digit is * which, when pressed on the phone's keypad, tells Lumian that a metaflow is starting. 2(\\d+) tells Lumian to look for a 2 and then capture one or more digits.
Thus *21234 would instruct Lumian to blind-transfer the caller to extension 1234.
Remove metaflows from the account
DELETE /v2/accounts/{ACCOUNT_ID}/metaflows
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/metaflows
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/metaflows', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {},
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success",
"timestamp": "{TIMESTAMP}",
"version": "4.2.42"
}
Users and devices
If you want to assign metaflows to a particular user or device, the API commands are the same except you need to include the user or device in the URI:
- Account:
/v2/accounts/{ACCOUNT_ID}/metaflows - User:
/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/metaflows - Device:
/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/metaflows
Metaflow actions
To see what actions can be set in a metaflow, look at the relevant documentation in Konami
Migrations
About Migrations
The migrations API allows you to perform various account based migrations on an account, or an account and its sub-accounts.
List
Lists all available migrations.
GET /v2/accounts/{ACCOUNT_ID}/migrations
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/migrations
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/migrations', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Summary
Provides a summary of a migration, including information on if it was performed and by whom and when.
GET /v2/accounts/{ACCOUNT_ID}/migrations/{MIGRATION_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/migrations/{MIGRATION_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/migrations/{MIGRATION_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Perform Migration
Allows you to perform a migration, with the following potential parameters:
| Name | Values | Description |
|---|---|---|
| perform_migration | now | Performs the migration now (now is the only currently supported option) |
| include_descendants | true / false (default: false) | If true the migration is performed on the account and sub-accounts |
| include_resellers | true / false (default: false) | If true the migration is performed on reseller sub-accounts |
POST /v2/accounts/{ACCOUNT_ID}/migrations/{MIGRATION_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/migrations/{MIGRATION_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/migrations/{MIGRATION_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
MMS
About MMS
Lumian offers API-based message services for inbound and outbound messages. Outbound messages sent through the Lumian API must be sent from a telephone number assigned to your Lumian account with an active messaging feature to be eligible for use.
Schema
MMS Document
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
body |
mime encoded mms message | string(1..) |
false |
|
from |
caller-id-number, taken from user if absent | string() |
false |
|
to |
callee-id-number | string() |
true |
|
media |
media-url | string() |
true |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/mms
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/mms
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/mms', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create
PUT /v2/accounts/{ACCOUNT_ID}/mms
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{ \
"data": { \
"from": "15555555555", \
"to": "14444444444", \
"body": "Hello", \
"media": ["https://www.lumian.net/lmn/media/LM/Theme/images/logo.svg"] \
} \
}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/mms
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/mms',
'{"data": {
"from": "15555555555",
"to": "14444444444",
"body": "Hello",
"media": ["https://www.lumian.net/lmn/media/LM/Theme/images/logo.svg"]
}
}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Sample Response:
{
"success": true,
"reason": "SUCCESS",
"detail": "SUCCESS",
"result": {
"referenceId": "d88231b5-13b3-4fb2-8528-bc7164309389",
"from": "15555555555",
"text": "Hello",
"media": [
"https://www.lumian.net/lmn/media/LM/Theme/images/logo.svg"
],
"messageType": "MMS",
"resultResponses": [
{
"to": "14444444444",
"status": "SUCCESS"
}
]
}
}
Fetch
GET /v2/accounts/{ACCOUNT_ID}/mms/{MMS_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/mms/{MMS_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/mms/{MMS_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Remove
DELETE /v2/accounts/{ACCOUNT_ID}/mms/{MMS_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/mms/{MMS_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/mms/{MMS_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Multi Factor Authentication Configuration
About Multi Factor
API endpoint to configure Crossbar Multi Factor Authentication (MFA) providers.
Enable MFA for a Crossbar auth module
If you want to use multi factor authentication for a module, set the multi_factor.enabled to true for that authentication module. You can control if the multi factor settings can be applied to the account's children by multi_factor.include_subaccounts. See Crossbar Security API documentation.
!!! note
You can specify the id of multi factor provider settings. If you miss this value, system's default MFA provider will be used!
Multi Factor Authentication (MFA) flow summary
The MFA process in Lumian is straight forward. You configured the Lumian integrated MFA service provider, and enabling the multi factor for an authentication endpoint. User will authenticate as usual by its own Lumian credential. If the first factor authentication passed, second-factor provider information (usually a signed token) would be returned to client with HTTP 401 Unauthorized status.
User's client performs the second-factor authentication with the provider and sends provider response to Lumian. If the provider validates user will be authenticated successful and a Lumian token will be generated as usual otherwise if the second-factor provider response is not validated a HTTP 401 Unauthorized will be returned.
Provider Configuration Schema
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
enabled |
whether or not this configuration is enabled or not | boolean |
true |
|
name |
A friendly name for the configuration | string |
true |
|
provider_name |
multi factor provider name | string |
true |
|
settings |
provider configuration | object |
false |
List Account Configuration and Available System Providers
List configured multi factor providers and available system multi factor provider.
GET /v2/accounts/{ACCOUNT_ID}/multi_factor
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/multi_factor
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/multi_factor', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"data": {
"configured": [
{
"id": "c757665dca55edba2395df3ca6423f4f",
"enabled": true,
"name": "a nice day",
"provider_name": "duo",
"provider_type": "multi_factor"
}
],
"multi_factor_providers": [
{
"id": "duo",
"enabled": false,
"name": "System Default Provider",
"provider_name": "duo",
"provider_type": "multi_factor"
}
]
},
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Create a Provider Configuration for an Account
Create configuration for a MFA provider. Provider config should be in "settings". See Lumian Auth Multi-Factor to find out required configuration for each provider.
PUT /v2/accounts/{ACCOUNT_ID}/multi_factor
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
--data '{"data": {"name": "another nice day", "enabled": true, "provider_name": "duo", "settings": {"integration_key": "{DUO_IKEY}", "secret_key": "{DUO_SKEY}", "application_secret_key": "{DUO_AKEY}", "api_hostname": "{DUO_HOST_NAME}", "duo_expire": 300,"app_expire": 3600}}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/multi_factor
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/multi_factor',
'{"data": {"name": "another nice day", "enabled": true, "provider_name": "duo", "settings": {"integration_key": "{DUO_IKEY}", "secret_key": "{DUO_SKEY}", "application_secret_key": "{DUO_AKEY}", "api_hostname": "{DUO_HOST_NAME}", "duo_expire": 300,"app_expire": 3600}}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Responses
Sample Response:
{
"data": {
"settings": {
"secret_key": "{DUO_SKEY}",
"integration_key": "{DUO_IKEY}",
"duo_expire": 300,
"application_secret_key": "{DUO_AKEY}",
"app_expire": 3600,
"api_hostname": "{DUO_HOST_NAME}"
},
"provider_name": "duo",
"name": "another nice day",
"enabled": true,
"id": "c757665dca55edba2395df3ca6423f4f"
},
"revision": "{REVERSION}",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Fetch an Account's Provider Configuration
Get account's configuration of a provider.
GET /v2/accounts/{ACCOUNT_ID}/multi_factor/{CONFIG_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/multi_factor/c757665dca55edba2395df3ca6423f4f
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/multi_factor/c757665dca55edba2395df3ca6423f4f', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"data": {
"settings": {
"secret_key": "{DUO_SKEY}",
"integration_key": "{DUO_IKEY}",
"duo_expire": 300,
"application_secret_key": "{DUO_AKEY}",
"app_expire": 3600,
"api_hostname": "{DUO_HOST_NAME}"
},
"provider_name": "duo",
"name": "another nice day",
"enabled": true,
"id": "c757665dca55edba2395df3ca6423f4f"
},
"revision": "{REVERSION}",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Change an Account's Provider Configuration
POST /v2/accounts/{ACCOUNT_ID}/multi_factor/{CONFIG_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
--data '{"data": {"name": "another nice day with a change", "enabled": true, "provider_name": "duo", "settings": {"integration_key": "{DUO_IKEY}", "secret_key": "{DUO_SKEY}", "application_secret_key": "{DUO_AKEY}", "api_hostname": "{DUO_HOST_NAME}", "duo_expire": 300,"app_expire": 3600}}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/multi_factor/c757665dca55edba2395df3ca6423f4f
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/multi_factor/c757665dca55edba2395df3ca6423f4f',
'{"data": {"name": "another nice day with a change", "enabled": true, "provider_name": "duo", "settings": {"integration_key": "{DUO_IKEY}", "secret_key": "{DUO_SKEY}", "application_secret_key": "{DUO_AKEY}", "api_hostname": "{DUO_HOST_NAME}", "duo_expire": 300,"app_expire": 3600}}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Responses
Sample Response:
{
"data": {
"settings": {
"secret_key": "{DUO_SKEY}",
"integration_key": "{DUO_IKEY}",
"duo_expire": 300,
"application_secret_key": "{DUO_AKEY}",
"app_expire": 3600,
"api_hostname": "{DUO_HOST_NAME}"
},
"provider_name": "duo",
"name": "another nice day with a change",
"enabled": true,
"id": "c757665dca55edba2395df3ca6423f4f"
},
"revision": "{REVERSION}",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Patch Fields in an Account's Provider Configuration
PATCH /v2/accounts/{ACCOUNT_ID}/multi_factor/{CONFIG_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
--data '{"data": {"enabled": false}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/multi_factor/c757665dca55edba2395df3ca6423f4f
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/multi_factor/c757665dca55edba2395df3ca6423f4f',
'{"data": {"enabled": false}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Responses
Sample Response:
{
"data": {
"settings": {
"secret_key": "{DUO_SKEY}",
"integration_key": "{DUO_IKEY}",
"duo_expire": 300,
"application_secret_key": "{DUO_AKEY}",
"app_expire": 3600,
"api_hostname": "{DUO_HOST_NAME}"
},
"provider_name": "duo",
"name": "another nice day with a change",
"enabled": false,
"id": "c757665dca55edba2395df3ca6423f4f"
},
"revision": "{REVERSION}",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Remove an Account's Provider Configuration
DELETE /v2/accounts/{ACCOUNT_ID}/multi_factor/{CONFIG_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/multi_factor/c757665dca55edba2395df3ca6423f4f
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/multi_factor/c757665dca55edba2395df3ca6423f4f', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Get a Summary of Multi Factor Login Attempts
GET /v2/accounts/{ACCOUNT_ID}/multi_factor/attempts
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/multi_factor/attempts
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/multi_factor/attempts', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"data": [
{
"id": "201702-09a979346eff06746e445a8cc1e574c4",
"auth_type": "multi_factor",
"auth_module": "cb_user_auth",
"status": "failed",
"message": "no multi factor authentication provider is configured",
"timestamp": 63655033238,
"client_ip": "10.1.0.2:8000",
}
],
"revision": "{REVERSION}",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Fetch Details of a Multi Factor Login Attempts
GET /v2/accounts/{ACCOUNT_ID}/multi_factor/attempts/{ATTEMPT_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/multi_factor/attempts/201702-09a979346eff06746e445a8cc1e574c4
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/multi_factor/attempts/201702-09a979346eff06746e445a8cc1e574c4', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"data": {
"auth_type": "multi_factor",
"status": "failed",
"auth_module": "cb_user_auth",
"message": "no multi factor authentication provider is configured",
"client_headers": {
"host": "10.1.0.2:8000",
"connection": "keep-alive",
"content-length": "83",
"accept": "application/json, text/javascript, */*; q=0.01",
"x-auth-token": "undefined",
"user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.39 Safari/537.36",
"origin": "http://127.0.0.1:3000",
"content-type": "application/json",
"dnt": "1",
"referer": "http://127.0.0.1:3000/",
"accept-encoding": "gzip, deflate",
"accept-language": "en-US,en;q=0.8"
},
"client_ip": "10.1.0.2:8000",
"crossbar_request_id": "5dd9a7b69f74b3c09ca065316096b83e",
"timestamp": 63655033238,
"metadata": {
"owner_id": "b6205d9a4a62d8e971c2d8f177676130",
"account_id": "a391d64a083b99232f6d2633c47432e3"
},
"id": "201702-09a979346eff06746e445a8cc1e574c4"
},
"revision": "{REVERSION}",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
List System Multi Factor Providers
List system multi factor providers
GET /v2/multi_factor
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/multi_factor
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/multi_factor', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"page_size": 1,
"start_key": [
"multi_factor"
],
"data": [
{
"id": "duo",
"enabled": false,
"name": "System Default Provider",
"provider_name": "duo",
"provider_type": "multi_factor"
}
],
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Create a System Provider Configuration
Provider config should be in "settings". See Lumian Auth Multi-Factor to find out required configuration for each provider.
!!! note Only super duper admin can create system providers configuration!
PUT /v2/multi_factor
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
--data '{"data": {"name": "have a nice day", "enabled": true, "provider_name": "duo", "settings": {"integration_key": "{DUO_IKEY}", "secret_key": "{DUO_SKEY}", "application_secret_key": "{DUO_AKEY}", "api_hostname": "{DUO_HOST_NAME}", "duo_expire": 300,"app_expire": 3600}}}' \
http://{SERVER}:8000/v2/multi_factor
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/multi_factor',
'{"data": {"name": "have a nice day", "enabled": true, "provider_name": "duo", "settings": {"integration_key": "{DUO_IKEY}", "secret_key": "{DUO_SKEY}", "application_secret_key": "{DUO_AKEY}", "api_hostname": "{DUO_HOST_NAME}", "duo_expire": 300,"app_expire": 3600}}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Responses
Sample Response:
{
"data": {
"settings": {
"secret_key": "{DUO_SKEY}",
"integration_key": "{DUO_IKEY}",
"duo_expire": 300,
"application_secret_key": "{DUO_AKEY}",
"app_expire": 3600,
"api_hostname": "{DUO_HOST_NAME}"
},
"provider_name": "duo",
"name": "have a nice day",
"enabled": true,
"id": "5c61dd2098466017f716417792f769cc"
},
"revision": "{REVERSION}",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Fetch a System Provider Configuration
!!! note Only super duper admin can get system providers configuration!
GET /v2/multi_factor/{CONFIG_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/multi_factor/c757665dca55edba2395df3ca6423f4f
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/multi_factor/c757665dca55edba2395df3ca6423f4f', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"data": {
"settings": {},
"provider_name": "duo",
"name": "System Default Provider",
"enabled": false,
"id": "duo"
},
"revision": "{REVERSION}",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Change a System Provider Configuration
!!! note Only super duper admin can change system providers configuration!
POST /v2/multi_factor/{CONFIG_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
--data '{"data": {"name": "System Default Provider", "enabled": true, "provider_name": "duo", "settings": {"integration_key": "{DUO_IKEY}", "secret_key": "{DUO_SKEY}", "application_secret_key": "{DUO_AKEY}", "api_hostname": "{DUO_HOST_NAME}", "duo_expire": 300,"app_expire": 3600}}}' \
http://{SERVER}:8000/v2/multi_factor/duo
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/multi_factor/duo',
'{"data": {"name": "System Default Provider", "enabled": true, "provider_name": "duo", "settings": {"integration_key": "{DUO_IKEY}", "secret_key": "{DUO_SKEY}", "application_secret_key": "{DUO_AKEY}", "api_hostname": "{DUO_HOST_NAME}", "duo_expire": 300,"app_expire": 3600}}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Responses
Sample Response:
{
"data": {
"settings": {
"secret_key": "{DUO_SKEY}",
"integration_key": "{DUO_IKEY}",
"duo_expire": 300,
"application_secret_key": "{DUO_AKEY}",
"app_expire": 3600,
"api_hostname": "{DUO_HOST_NAME}"
},
"provider_name": "duo",
"name": "System Default Provider",
"enabled": true,
"id": "duo"
},
"revision": "{REVERSION}",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Patch fields in a System provider configuration
!!! note Only super duper admin can change system providers configuration!
PATCH /v2/multi_factor/{CONFIG_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
--data '{"data": {"enabled": false}}' \
http://{SERVER}:8000/v2/multi_factor/duo
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/multi_factor/duo',
'{"data": {"enabled": false}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Responses
Sample Response:
{
"data": {
"settings": {
"secret_key": "{DUO_SKEY}",
"integration_key": "{DUO_IKEY}",
"duo_expire": 300,
"application_secret_key": "{DUO_AKEY}",
"app_expire": 3600,
"api_hostname": "{DUO_HOST_NAME}"
},
"provider_name": "duo",
"name": "System Default Provider",
"enabled": false,
"id": "duo"
},
"revision": "{REVERSION}",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Multi-part Request
Some APIs support sending a multi part request, such as outgoing faxes.
Sending Multi-part Outgoing Faxes Request
With multi part you can create an outgoing fax request and upload the document to fax (e.g.: a PDF file) at the same time.
Create a JSON file for the outgoing fax options
Sample Response:
{
"data": {
"retries": 3,
"from_name": "Fax Sender",
"from_number": "{FROM_NUMBER}",
"to_name": "Fax Recipient",
"to_number": "{TO_NUMBER}",
"fax_identity_number": "{ID_NUMBER}",
"fax_identity_name": "Fax Header"
}
}
Execute the cURL request
Sample Request:
curl -v -X PUT -i \
-H 'X-Auth-Token: {AUTH_TOKEN}' \
-H "Content-Type: multipart/mixed" \
-F "content=@{FILE.json}; type=application/json" \
-F "content=@{FILE.pdf}; type=application/pdf" \
http://{SERVER}/v2/accounts/{ACCOUNT_ID}/faxes/outgoing
import axios from 'axios';
import FormData from 'form-data';
import * as fs from 'fs';
const form = new FormData();
form.append('content', fs.readFileSync('{FILE.json}'), '{FILE.json}');
form.append('content', fs.readFileSync('{FILE.pdf}'), '{FILE.pdf}');
const response = await axios.put(
'http://{SERVER}/v2/accounts/{ACCOUNT_ID}/faxes/outgoing',
form,
{
headers: {
...form.getHeaders(),
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'multipart/mixed'
}
}
);
Email Notifications Template
Allow managing templates for notification emails.
About Notifications
Flowing is a basic structure of a notification object (here it is a digest of voicemail_to_email notification).
Sample Response:
{
"enabled": true,
"macros": {
"voicemail.vmbox_id": {
"i18n_label": "voicemail_vmbox_id",
"friendly_name": "Voicemail Box Id",
"description": "Which voicemail box was the message left in"
}
},
"subject": "New voicemail from {{caller_id.name}} ({{caller_id.number}})",
"category": "voicemail",
"friendly_name": "Voicemail To Email",
"to": {
"type": "original"
},
"from": "no_reply@localhost.me",
"cc": {
"type": "specified",
"email_addresses": []
},
"bcc": {
"type": "specified",
"email_addresses": []
},
"id": "voicemail_to_email",
"account_overridden": true,
"templates": {
"text/plain": {
"length": 971
},
"text/html": {
"length": 13350
}
}
}
By looking at above structure, there are some points of interest to say about notification parameters:
- The
account_overriddenparameter would be added if the notification is account-specific; lack of the key indicates it is the system default notification. - The
enabledparameter indicates should system send an E-mail notifying of the causing event. Lacking of this parameter would considered as the notification is enabled. - The
macrosobject is a per-template, system-defined set of macros you can use in your templates. You cannot configure this via the API.
In addition to the JSON data describing configuration of a notification, notification templates can be represented in various formats and can be modified by uploading the representation document (such as using a WYSIWYG tool). Currently supported formats are plain text and HTML documents.
Template Formats
Creating the configuration documents is all well and good, but it is necessary to be able to attach the templates in their various forms as well. Currently supported formats are text/html and text/plain.
Operation considerations
In Lumian versions prior to 3.19, notification templates were managed and processed by the notify application. In the newer Lumian versions this has been replace by a robust and more featureful teletype application.
All accounts will continue to be processed by the notify application until the Crossbar notification APIs are accessed for the first time (for instance, when using the Branding application in Monster). Once a client has accessed the APIs, a flag is set on the account telling the notify application to ignore processing and instructs the teletype application to process it instead. This allows administrators to run both notify and teletype concurrently without sending multiple copies of each notification.
Notifications Schema
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
bcc.email_addresses.[] |
string() |
false |
||
bcc.email_addresses |
BCC Email Addresses | array(string()) |
false |
|
bcc.type |
`string('original' | 'specified' | 'admins')` | |
bcc |
Bcc email field | object() |
false |
|
category |
Category of the template, for grouping purposes | string(1..) |
false |
|
cc |
CC email field | object() |
false |
|
cc.email_addresses.[] |
string() |
false |
||
cc.email_addresses |
CC Email Addresses | array(string()) |
false |
|
cc.type |
string('original' or 'specified' or 'admins') |
false |
||
enabled |
Enable notification | boolean() |
true |
false |
friendly_name |
Friendly name of the template | string(1..) |
false |
|
from |
From: email address | string() |
true |
|
macros |
object() |
{} |
false |
|
reply_to |
Reply-To: email address | string() |
false |
|
subject |
Email subject | string(1..200) |
true |
|
template_charset |
string(1..) |
utf-8 |
false |
|
to |
To email field | object() |
true |
|
to.email_addresses.[] |
string() |
false |
||
to.email_addresses |
array(string()) |
false |
||
to.type |
string('original' or 'specified' or 'admins') |
false |
Summary of Available System Notifications
Request to see what templates exist on the system to override.
GET /v2/notifications
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"id": "voicemail_to_email",
"macros": {
"call_id": {
"description": "Call ID of the caller",
"friendly_name": "Call ID",
"i18n_label": "call_id"
},
"caller_id.name": {
"description": "Caller ID Name",
"friendly_name": "Caller ID Name",
"i18n_label": "caller_id_name"
}
"..."
}
}
"..."
],
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Summary of Account Overridden Notifications
To see what notification templates an account overrides. The key account_overridden will exist on any templates that are account-specific.
GET /v2/accounts/{ACCOUNT_ID}/notifications
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications
Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"id": "voicemail_to_email",
"macros": {
"call_id": {
"description": "Call ID of the caller",
"friendly_name": "Call ID",
"i18n_label": "call_id"
},
"caller_id.name": {
"description": "Caller ID Name",
"friendly_name": "Caller ID Name",
"i18n_label": "caller_id_name"
}
"..."
},
"account_overridden": true
}
"..."
],
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Create a New System Notification
Creates a new system notification template.
!!! note Only a super duper admin can create/modify/delete system notifications!
PUT /v2/notifications
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{ \
"data": { \
"id":"voicemail_to_email", \
"to": { \
"type": "users", \
"email_addresses": ["user@account.com"] \
}, \
"from": "reseller@resellerdomain.com", \
"subject": "Hello {{user.first_name}}, you received a new voicemail!", \
"enabled": true, \
"template_charset": "utf-8" \
}}' \
http://{SERVER}:8000/v2/notifications
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/notifications',
'{ \\\n "data": { \\\n "id":"voicemail_to_email", \\\n "to": { \\\n "type": "users", \\\n "email_addresses": ["user@account.com"] \\\n }, \\\n "from": "reseller@resellerdomain.com", \\\n "subject": "Hello {{user.first_name}}, you received a new voicemail!", \\\n "enabled": true, \\\n "template_charset": "utf-8" \\\n }}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Responses
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"enabled": true,
"id": "voicemail_to_email",
"from": "reseller@resellerdomain.com",
"macros": { "..." },
"subject": "Hello {{user.first_name}}, you received a new voicemail!",
"template_charset": "utf-8",
"to": {
"email_addresses": [
"user@account.com"
],
"type": "users"
}
},
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Create a Notification as Account Override
Now that you've fetched the system default template, modify the template and PUT it back to the account.
!!! note
This request will fail if id does not already exist in the system defaults.
PUT /v2/accounts/{ACCOUNT_ID}/notifications
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{ \
"data": { \
"id":"voicemail_to_email", \
"to": { \
"type": "users", \
"email_addresses": ["user@account.com"] \
}, \
"from": "reseller@resellerdomain.com", \
"subject": "Hello {{user.first_name}}, you received a new voicemail!", \
"enabled": true, \
"template_charset": "utf-8" \
}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications',
'{ \\ \n "data": { \\\n "id":"voicemail_to_email", \\\n "to": { \\\n "type": "users", \\\n "email_addresses": ["user@account.com"] \\\n }, \\\n "from": "reseller@resellerdomain.com", \\\n "subject": "Hello {{user.first_name}}, you received a new voicemail!", \\\n "enabled": true, \\\n "template_charset": "utf-8" \\ \n }}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Responses
Same as PUT for system level, but with the "account_overridden": true flag added.
Details of a System Notification
Using the ID from the system listing above, get the template object. This document allows you to set some "static" properties (things not derived from the event causing the notification, e.g. call data, system alert, etc).
GET /v2/notifications/{NOTIFICATION_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/notifications/{NOTIFICATION_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/notifications/{NOTIFICATION_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"id": "{NOTIFICATION_ID}",
"macros": { "..." },
"templates": {
"text/html": {
"length": 600
}
,"text/plain": {
"length": 408
}
}
}
"..."
],
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Details of an Account Overridden Notification
Performing a GET with an account ID will return the notification object, again with the account_overridden flag added.
GET /v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Same as above with the account_overridden flag added.
Update a Notification
Similar to the PUT, POST will update an existing configuration:
POST /v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}
!!! note
Omit /accounts/{ACCOUNT_ID} to update the system's version. Only a super duper admin can create/modify/delete system notifications!
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{ \
"data": { \
"id":"{NOTIFICATION_ID}", \
"to": { \
"type": "users", \
"email_addresses": ["user@account.com"] \
}, \
"from": "reseller@resellerdomain.com", \
"subject": "Hello {{user.first_name}}, you received a new voicemail!", \
"enabled": true, \
"template_charset": "utf-8", \
"macros": { \
"user.first_name": { \
"i18n_label": "first_name", \
"friendly_name": "First Name", \
"description": "If the voicemail box has an owner id, this is the first name of that user. Not always present" \
}, \
"user.last_name": { \
"i18n_label": "last_name", \
"friendly_name": "Last Name", \
"description": "If the voicemail box has an owner id, this is the last name of that user. Not always present" \
} \
} \
}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}',
'{ \\ \n "data": { \\\n "id":"{NOTIFICATION_ID}", \\\n "to": { \\\n "type": "users", \\\n "email_addresses": ["user@account.com"] \\\n }, \\\n "from": "reseller@resellerdomain.com", \\\n "subject": "Hello {{user.first_name}}, you received a new voicemail!", \\\n "enabled": true, \\\n "template_charset": "utf-8", \\\n "macros": { \\\n "user.first_name": { \\\n "i18n_label": "first_name", \\\n "friendly_name": "First Name", \\\n "description": "If the voicemail box has an owner id, this is the first name of that user. Not always present" \\\n }, \\\n "user.last_name": { \\\n "i18n_label": "last_name", \\\n "friendly_name": "Last Name", \\\n "description": "If the voicemail box has an owner id, this is the last name of that user. Not always present" \\\n } \\\n } \\\n }}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Remove a Notification
DELETE /v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}
Note: Omit the
/accounts/{ACCOUNT_ID}to remove the system default. Only a super duper admin can create/modify/delete system notifications!Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Get Notification Template:
GET /v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}
When you perform a GET request to fetch a notification configuration (using Accept: application/json header or not setting Accept header at all), there is a Content-Type HTTP header in the response headers. Use those content types to fetch a specific template by setting your request Accept header:
Get as text/html
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H 'Accept: text/html' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Accept': 'text/html'
}
});
Get as text/plain
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H 'Accept: text/plain' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Accept': 'text/plain'
}
});
Note that the only difference is the Accept attribute. This will determine which attachment is returned in the payload. If you specify a nonexistent Accept MIME type, expect to receive a 406 Not Acceptable error.
For clients that do not support setting the Accept header, a query string parameter can be included (e.g. /v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}?accept=text/html to get the HTML template).
Update Notification Template:
POST /v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}
Update text/plain
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H 'Content-Type: text/plain' \
-d 'some plain text template code' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}',
'some plain text template code',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'text/plain'
}
}
);
Update text/html
An Example using Curl Upload File:
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H 'Content-Type: text/html' \
-F content=@file.html \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}
import axios from 'axios';
import FormData from 'form-data';
import * as fs from 'fs';
const form = new FormData();
form.append('content', fs.readFileSync('file.html'), 'file.html');
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}',
form,
{
headers: {
...form.getHeaders(),
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'text/html'
}
}
);
!!! note
Omit /accounts/{ACCOUNT_ID} to update the system's version. Only a super duper admin can create/modify/delete system notifications!
Preview a new template
It can be helpful to preview the resulting email when modifying templates, but before actually saving the template.
POST /v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}/preview
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H 'Content-Type: application/json' \
-d '{"data": { \
"to": {"email_addresses": ["me@lumian.net"]}, \
"from": "lumian@lumian.net", \
"subject": "Testing NOTIFICATION", \
"html": "SSUyNTIwJTI1dTI2NjElMjUyMFVuaWNvZGUlMjUyMQ==", \
"plain": "You just received an email! It was sent to {{user.email}}", \
"enabled": true \
}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}/preview
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}/preview',
'{"data": { \\\n "to": {"email_addresses": ["me@lumian.net"]}, \\\n "from": "lumian@lumian.net", \\\n "subject": "Testing NOTIFICATION", \\\n "html": "SSUyNTIwJTI1dTI2NjElMjUyMFVuaWNvZGUlMjUyMQ==", \\\n "plain": "You just received an email! It was sent to {{user.email}}", \\\n "enabled": true \\\n }}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
htmlis the base64 encoded HTML templateplainis the plain-text template
Remove All Account's Notification Customizations
To remove all notification customizations made on the account use a DELETE method with action remove_customizations.
DELETE /v2/accounts/{ACCOUNT_ID}/notifications/
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"action": "remove_customizations", "data": {}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
},
data: '{"action": "remove_customizations", "data": {}}'
});
Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"account_zone_change": "deleted",
"cnam_request": "deleted",
"customer_update": "deleted",
"denied_emergency_bridge": "deleted",
"deregister": "deleted",
"fax_inbound_error_to_email": "deleted",
"fax_inbound_error_to_email_filtered": "deleted",
"fax_inbound_to_email": "deleted",
"fax_outbound_error_to_email": "deleted",
"fax_outbound_smtp_error_to_email": "deleted",
"fax_outbound_to_email": "deleted",
"first_occurrence": "deleted",
"low_balance": "deleted",
"missed_call": "deleted",
"new_account": "deleted",
"new_user": "deleted",
"password_recovery": "deleted",
"port_cancel": "deleted",
"port_comment": "deleted",
"port_pending": "deleted",
"port_rejected": "deleted",
"port_request": "deleted",
"port_request_admin": "deleted",
"port_scheduled": "deleted",
"port_unconfirmed": "deleted",
"ported": "deleted",
"service_added": "deleted",
"skel": "deleted",
"system_alert": "deleted",
"topup": "deleted",
"transaction": "deleted",
"transaction_failed": "deleted",
"voicemail_full": "deleted",
"voicemail_to_email": "deleted",
"webhook_disabled": "deleted"
},
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Force All Account's Notifications to System Default
To remove all notification customizations made on the account and use the notification from system use a PUT method with action force_system.
PUT /v2/accounts/{ACCOUNT_ID}/notifications/
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"action": "force_system", "data": {}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications',
'{"action": "force_system", "data": {}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Responses
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"account_zone_change": "replaced",
"cnam_request": "replaced",
"customer_update": "replaced",
"denied_emergency_bridge": "replaced",
"deregister": "replaced",
"fax_inbound_error_to_email": "replaced",
"fax_inbound_error_to_email_filtered": "replaced",
"fax_inbound_to_email": "replaced",
"fax_outbound_error_to_email": "replaced",
"fax_outbound_smtp_error_to_email": "replaced",
"fax_outbound_to_email": "replaced",
"first_occurrence": "replaced",
"low_balance": "replaced",
"missed_call": "replaced",
"new_account": "replaced",
"new_user": "replaced",
"password_recovery": "replaced",
"port_cancel": "replaced",
"port_comment": "replaced",
"port_pending": "replaced",
"port_rejected": "replaced",
"port_request": "replaced",
"port_request_admin": "replaced",
"port_scheduled": "replaced",
"port_unconfirmed": "replaced",
"ported": "replaced",
"service_added": "replaced",
"skel": "replaced",
"system_alert": "replaced",
"topup": "replaced",
"transaction": "replaced",
"transaction_failed": "replaced",
"voicemail_full": "replaced",
"voicemail_to_email": "replaced",
"webhook_disabled": "replaced"
},
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Get the Notifications SMTP Logs
GET /v2/accounts/{ACCOUNT_ID}/notifications/smtplog
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H 'Content-Type: text/plain' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/smtplog
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/smtplog', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'text/plain'
}
});
Get a notification's SMTP log
GET /v2/accounts/{ACCOUNT_ID}/notifications/smtplog/{SMTP_LOG_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/smtplog/{SMTP_LOG_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/smtplog/{SMTP_LOG_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": {
"rendered_templates": {
"text/plain": "Expired registration in account \"teste\".\nNotifications are enabled for loss of registration on the device 995582142@teste.sip.90e9.com\n\nLast Registration:\nDevice ID: 4e411cf70ad352a222e24fbacf467c18\nAccount ID: 85ea6075c6c1e266f8512e2233541bdb\nUser Agent: Grandstream GXP2130 1.0.7.25\nContact: sip:995582142@192.168.26.13:5060;reg-id=1;+sip.instance="urn:uuid:00000000-0000-1000-8000-000B826C4283"\n\nThis may be due to a network connectivity issue, power outage, or misconfiguration. Please check the device.",
"text/html": "<h2>Expired registration in account \"teste\"</h2><p>Notifications are enabled for loss of registration on the device 995582142@teste.sip.90e9.com</p><h3>Last Registration</h3><table><tbody><tr><td>Device ID</td><td>4e411cf70ad352a222e24fbacf467c18</td></tr><tr><td>Account ID</td><td>85ea6075c6c1e266f8512e2233541bdb</td></tr><tr><td>User Agent</td><td>Grandstream GXP2130 1.0.7.25</td></tr><tr><td>Contact</td><td>sip:995582142@192.168.26.13:5060;reg-id=1;+sip.instance="urn:uuid:00000000-0000-1000-8000-000B826C4283"</td></tr></tbody></table><p>This may be due to a network connectivity issue, power outage, or misconfiguration. Please check the device.</p>"
},
"subject": "Loss of Registration for 995582142@teste.sip.90e9.com",
"emails": {
"from": "no_reply@dev-01.90e9.com",
"to": [
"teste@factorlusitano.com"
]
},
"receipt": "2.0.0 Ok: queued as B60E22044B",
"account_id": "{ACCOUNT_ID}",
"account_db": "{ACCOUNT_DB}",
"template_id": "deregister",
"template_account_id": "5ba01ad7ad1611d436b1860d8c552897",
"id": "{SMTP_LOG_ID}"
},
"revision": "{REVISION}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Customer update
You can use the special Customer Update notification to send a message to all reseller's children users or to a particular account's users.
Send Message to All Reseller's Accounts:
POST /v2/accounts/{ACCOUNT_ID}/notifications/customer_update/message
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H 'Content-Type: text/html' \
-F content=@file.html \
http://{SERVER}:8000/v2/accounts/{RESELLER_ACCOUNT_ID}/notifications/customer_update/message
import axios from 'axios';
import FormData from 'form-data';
import * as fs from 'fs';
const form = new FormData();
form.append('content', fs.readFileSync('file.html'), 'file.html');
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{RESELLER_ACCOUNT_ID}/notifications/customer_update/message',
form,
{
headers: {
...form.getHeaders(),
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'text/html'
}
}
);
Send Message to a Particular Account:
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H 'Content-Type: text/html' \
-d '{"data": {"recipient_id": "33ca3929ed585e0e423eb39e4ffe1452"}}' \
http://{SERVER}:8000/v2/accounts/{PARTICULAR_ACCOUNT_ID}/notifications/customer_update/message
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{PARTICULAR_ACCOUNT_ID}/notifications/customer_update/message',
'{"data": {"recipient_id": "33ca3929ed585e0e423eb39e4ffe1452"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'text/html'
}
}
);
Send Message to Particular Users
You can send a message to all users, administrators only or a particular user within an account. Just add a user_type field to your payload:
- All users:
Sample Response:
{
"data": {"user_type": "all_users"}
}
- Particular user:
Note: Applicable to send message to a particular account only.
Sample Response:
{
"data": {"user_type": "{USER_ID}"}
}
- Admin privileged users only
Note: This is the default behavior, so
user_typecould be omitted.Sample Response:
{
"data": {"user_type": "admins_only"}
}
Specifying the Message
For specifying the actual message (and the email subject) you want to send, provide HTML and plain text templates by uploading document:
Sample Response:
{
"data": {
"recipient_id": "33ca3929ed585e0e423eb39e4ffe1452",
"user_type": "3d9b564d5c95d52d81a2e49ea0c57941",
"id": "customer_update",
"account_overridden": true,
"enabled": true,
"category": "user",
"friendly_name": "Customer update",
"from": "info@localhost.me",
"subject": "Test Reseller customer update",
"bcc": {
"email_addresses": [],
"type": ""
},
"cc": {
"email_addresses": [],
"type": ""
},
"macros": {
"user.email": {
"description": "Email of the user",
"friendly_name": "Email",
"i18n_label": "user_email"
},
"user.first_name": {
"description": "First Name",
"friendly_name": "First Name",
"i18n_label": "first_name"
},
"user.last_name": {
"description": "Last Name",
"friendly_name": "Last Name",
"i18n_label": "last_name"
},
"user.timezone": {
"description": "Timezone of the user",
"friendly_name": "Timezone",
"i18n_label": "user_timezone"
},
"user.username": {
"description": "Username",
"friendly_name": "Username",
"i18n_label": "username"
}
},
"template_charset": "utf-8",
"html": "PHA+RGVhciB7e3VzZXIuZmlyc3RfbmFtZX19IHt7dXNlci5sYXN0X25hbWV9fS48L3A+CjxwPkhlcmUgYXJlIHNvbWUgbmV3cyB0aGF0IHdlIGhhdmUgc2VsZWN0ZWQgZm9yIHlvdTwvcD4KPHA+QmVzdCByZWdhcmRzLDwvcD4KPHA+T25OZXQgSW5ub3ZhdGlvbnMgTGltaXRlZC48L3A+",
"plain": "Dear {{user.first_name}} {{user.last_name}}.\n\nHere are some more news that we have selected for you.\n\nBest regards,\nYour Imagination, Corp",
"templates": {
"text/html": {
"length": 161
},
"text/plain": {
"length": 136
}
},
}
}
Send Message from your Lumian Application
To send an update to a customer from your Lumian Application, you can build payload include your application data (<<"DataBag">> field) and send it over AMQP using predefined particular template (<<"Template-ID">> field) or your own hard coded templates (<<"HTML">> and <<"Text">> fields):
-spec send_account_update(ne_binary()) -> 'ok'.
send_account_update(AccountId) ->
case kz_amqp_worker:call(build_customer_update_payload(AccountId)
,fun kapi_notifications:publish_customer_update/1
,fun kapi_notifications:customer_update_v/1
)
of
{'ok', _Resp} ->
lager:debug("published customer_update notification");
{'error', _E} ->
lager:debug("failed to publish_customer update notification: ~p", [_E])
end.
-spec build_customer_update_payload(ne_binary()) -> kz_proplist().
build_customer_update_payload(AccountId) ->
props:filter_empty(
[{<<"Account-ID">>, kz_services_reseller:get_id(AccountId)}
,{<<"Recipient-ID">>, AccountId}
%% DataBag is useful if you have a customized template and wants to pass some your info from your app
,{<<"DataBag">>, kz_json:from_list([{<<"field1">>,<<"value1">>},{<<"field2">>,{[{<<"subfield1">>,<<"subvalue1">>},{<<"subfield2">>,<<"subvalue2">>}]}}])}
%% set below prop if you have a customized template with this ID in your account's DB
,{<<"Template-ID">>, <<"customer_update_billing_period">>}
%% otherwise set your customized message as below:
,{<<"HTML">>, base64:encode(<<"Dear {{user.first_name}} {{user.last_name}}. <br /> DataBag test: {{databag.field2.subfield1}} <br /> Kind regards,">>)}
,{<<"Text">>, <<"Oh Dear {{user.first_name}} {{user.last_name}}.\n\nDataBag test: {{databag.field2.subfield2}}\n\nBest regards,">>}
| kz_api:default_headers(?APP_NAME, ?APP_VERSION)
]).
Onboard
About Onboard
Schema
Create
Onboarding
Used to create new accounts without being signed in.
NOTICE
This API has been deprecated and is no longer maintained by the Lumian core team. The preferred method would be to code your own middleware to create accounts using an appropriate parent account API key or auth-token. The PHP SDK is an excellent starting point or you can roll your own!
An example request
PUT to /v1/onboard
{
"data": {
"account": {
"available_apps": [
"voip",
"demo_done",
"cluster",
"userportal",
"accounts",
"developer",
"numbers",
"pbxs"
],
"caller_id": {
"default": {
"number": "{COMPANY_PRIMARY_CALLERID}"
},
"emergency": {
"number": "{COMPANY_EMERGENCY_CALLERID}"
}
},
"default_api_url": "http://{SERVER}/v1",
"name": "{COMPANY_NAME}",
"role": "{ACCOUNT_TYPE}"
},
"braintree": {
"company": "{COMPANY_NAME}",
"credit_card": {
"billing_address": {
"country": "{COMPANY_COUNTRY}",
"extended_address": "{COMPANY_EXTENDED_ADDRESS}",
"first_name": "{BILLING_CONTACT_FIRST_NAME}",
"last_name": "{BILLING_CONTACT_LAST_NAME}",
"locality": "{COMPANY_CITY}",
"postal_code": "{COMPANY_ZIP_CODE}",
"region": "{COMPANY_STATE}",
"street_address": "{COMPANY_ADDRESS}"
},
"cardholder_name": "{CREDIT_CARD_HOLDER_NAME}",
"cvv": "{CREDIT_CARD_SECURITY_CODE}",
"expiration_date": "{CREDIT_CARD_EXPIRATION}",
"make_default": true,
"number": "{CREDIT_CARD_NUMBER}"
},
"email": "{ADMIN_EMAIL}",
"first_name": "{ADMIN_FIRST_NAME}",
"last_name": "{ADMIN_LAST_NAME}"
},
"extensions": [
{
"callflow": {
"numbers": [
"{ADMIN_DID}",
"{ADMIN_EXTENSION_NUMBER}"
]
},
"user": {
"apps": {
"accounts": {
"api_url": "http://{SERVER}:8000/v1",
"icon": "account",
"label": "Accounts"
},
"numbers": {
"api_url": "http://{SERVER}:8000/v1",
"icon": "menu",
"label": "Number Manager"
},
"voip": {
"api_url": "http://{SERVER}:8000/v1",
"icon": "phone",
"label": "Hosted PBX"
},
"Demo": {
"api_url": "http://{SERVER}:8000/v1",
"icon": "phone",
"label": "Test App"
}
},
"credentials": "a9e4685a973f0ed2844ee9f36e211736",
"email": "{ADMIN_EMAIL}",
"first_name": "{ADMIN_FIRST_NAME}",
"last_name": "{ADMIN_LAST_NAME}",
"priv_level": "admin"
}
},
{
"callflow": {
"numbers": [
"{USER1_EXTENSION_NUMBER}"
]
},
"user": {
"first_name": "{USER1_FIRST_NAME}",
"last_name": "{USER1_LAST_NAME}",
"priv_level": "user"
}
},
{
"callflow": {
"numbers": [
"{USER2_EXTENSION_NUMBER}"
]
},
"user": {
"first_name": "{USER2_FIRST_NAME}",
"last_name": "{USER2_LAST_NAME}",
"priv_level": "user"
}
},
{
"callflow": {
"numbers": [
"{USER3_EXTENSION_NUMBER}"
]
},
"user": {
"first_name": "{USER3_FIRST_NAME}",
"last_name": "{USER4_LAST_NAME}",
"priv_level": "user"
}
},
{
"callflow": {
"numbers": [
"{USER4_EXTENSION_NUMBER}"
]
},
"user": {
"first_name": "{USER4_FIRST_NAME}",
"last_name": "{USER4_LAST_NAME}",
"priv_level": "user"
}
}
],
"invite_code": "9351b14aa94b9d580dea57b8deefff0c",
"phone_numbers": {
"{ADMIN_EXTENSION_NUMBER}": {
"e911": {
"extended_address": "{ADMIN_EXTENDED_ADDRESS}",
"locality": "{ADMIN_CITY}",
"postal_code": "{ADMIN_ZIP_CODE}",
"region": "{ADMIN_STATE}",
"street_address": "{ADMIN_ADDRESS}"
}
}
}
},
"verb": "PUT"
}
Parked Calls Slots
Fetch
GET /v2/accounts/{ACCOUNT_ID}/parked_calls
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/parked_calls
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/parked_calls', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Phone Numbers API
About Phone Numbers
The Lumian API for managing numbers.
Per-number CRUD operations
{PHONE_NUMBER}has to be URL-encoded- e.g. turn
+14155555555into%2B14155555555 - Note
4123456789is turned into+14123456789 - Note however,
41234567is turned into+41234567, so be careful!
- e.g. turn
- To add/modify numbers, either:
- Account document must be showing
pvt_wnm_allow_additionsastrue - Or auth must be done via master account.
- Account document must be showing
Schema
Schema for a number
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
carrier_name |
string(1..30) |
false |
|||
cnam.display_name |
string(1..15) |
false |
|||
cnam.inbound_lookup |
boolean() |
false |
|||
cnam |
object() |
false |
|||
create_with_state |
The state to create numbers in | `string('aging' | 'available' | 'deleted' | 'discovery' |
e911.activated_time |
The time stamp e911 was provisioned | string() |
false |
||
e911.caller_name |
The name that will show to emergency services | string(3..) |
false |
||
e911.extended_address |
The suit/floor/apt. address where the number is in service | string() |
false |
||
e911.latitude |
The e911 provisioning system calculated service address latitude | string() |
false |
||
e911.legacy_data.house_number |
The name that will show to emergency services | string() |
false |
||
e911.legacy_data.predirectional |
The name that will show to emergency services | string() |
false |
||
e911.legacy_data.streetname |
The name that will show to emergency services | string() |
false |
||
e911.legacy_data.suite |
The name that will show to emergency services | string() |
false |
||
e911.legacy_data |
Legacy E911 information | object() |
false |
||
e911.locality |
The locality (city) where the number is in service | string() |
true |
||
e911.location_id |
The e911 provisioning system internal id for this service address | string() |
false |
||
e911.longitude |
The e911 provisioning system calculated service address longitude | string() |
false |
||
e911.notification_contact_emails.[] |
string() |
false |
|||
e911.notification_contact_emails |
A list of email addresses to receive notification when this number places an emergency call | array(string()) |
[] |
false |
|
e911.plus_four |
The extended zip/postal code where the number is in service | string() |
false |
||
e911.postal_code |
The zip/postal code where the number is in service | string() |
true |
||
e911.region |
The region (state) where the number is in service | string(2) |
true |
||
e911.status |
The e911 provisioning system status for this service address | `string('INVALID' | 'GEOCODED' | 'PROVISIONED' | 'REMOVED' |
e911.street_address |
The street address where the number is in service | string() |
true |
||
e911 |
object() |
false |
|||
porting.billing_account_id |
The account id the losing carrier has on file | string() |
false |
||
porting.billing_extended_address |
The suit/floor/apt. address the losing carrier has on file | string() |
false |
||
porting.billing_locality |
The locality (city) the losing carrier has on file | string() |
false |
||
porting.billing_name |
The name or company name the losing carrier has on file | string() |
false |
||
porting.billing_postal_code |
The zip/postal code the losing carrier has on file | string() |
false |
||
porting.billing_region |
The region (state) the losing carrier has on file | string() |
false |
||
porting.billing_street_address |
The street address the losing carrier has on file | string() |
false |
||
porting.billing_telephone_number |
The BTN of the account the number belongs to | string() |
false |
||
porting.comments.[] |
string() |
false |
|||
porting.comments |
An array of comments | array(string()) |
false |
||
porting.customer_contact |
The phone number that can be used to contact the owner of the number | string() |
false |
||
porting.port_id |
The id of the port request | string() |
false |
||
porting.requested_port_date |
The requested port date | string() |
false |
||
porting.service_provider |
The name of the losing carrier | string() |
false |
||
porting |
Porting (in) information for the phone number | object() |
false |
Search For Available Numbers On System
PREFIX: a 3-digit number prefix or an URL-encoded e164 prefix (e.g.499or%2B1499)QUANTITY: maximum amount of numbers to be returned (e.g.2)OFFSET: page number (e.g.0)
GET /v2/phone_numbers?prefix={PREFIX}&quantity={QUANTITY}&offset={OFFSET}&country={COUNTRY}
Sample Request:
curl -v -X GET \
http://{SERVER}:8000/v2/phone_numbers?prefix=415&quantity=2
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/phone_numbers', {
params: {
'prefix': '415'
}
});
Sample Response:
{
"auth_token": "",
"data": [
{
"e164": "+14152338397",
"formatted_number": "1-415-233-8397",
"npa_nxx": "415233",
"number": "+14152338397",
"number_id": "4AA418FB-3409-4340-8210-E7EAFE2AB118",
"rate_center": {
"lata": "722",
"name": "SAN RAFAEL",
"state": "CA"
},
"status": "Available",
"ten_digit": "4152338397"
},
{
"e164": "+14152338421",
"formatted_number": "1-415-233-8421",
"npa_nxx": "415233",
"number": "+14152338421",
"number_id": "0CD68E85-F149-477F-9C13-1E720ACCC3EE",
"rate_center": {
"lata": "722",
"name": "SAN RAFAEL",
"state": "CA"
},
"status": "Available",
"ten_digit": "4152338421"
}
],
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Search for available numbers you own
PREFIX: a 3-digit number prefix or an URL-encoded e164 prefix (e.g.499or%2B1499)QUANTITY: maximum amount of numbers to be returned (e.g.2)OFFSET: page number (e.g.0)
GET /v2/accounts/{ACCOUNT_ID}/phone_numbers?prefix={PREFIX}&quantity={QUANTITY}&offset={OFFSET}
Sample Request:
curl -v -X GET \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers?prefix=555&quantity=3&offset=6
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers', {
params: {
'prefix': '555'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"number": "+15552225562",
"state": "available"
},
{
"number": "+15554445558",
"state": "discovery"
},
{
"number": "+15552225562",
"state": "available"
}
],
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
See How Many Digits A {PREFIX} Can Take
GET /v2/accounts/{ACCOUNT_ID}/phone_numbers/carriers_info
Depending on your carriers configuration you may be allowed to query numbers by NPA-NXX instead of just NPA.
Sample Request:
curl -v -X GET \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/carriers_info
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/carriers_info');
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"maximal_prefix_length": 3,
"usable_carriers": [
"bandwidth2",
"bandwidth",
"inum",
"local",
"inventory",
"managed",
"mdn",
"other",
"simwood",
"telnyx",
"vitelity",
"voip_innovations"
],
"usable_creation_states": [
"aging",
"available",
"in_service",
"port_in",
"reserved"
]
},
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"timestamp": "2017-05-01T20:31:35",
"version": "4.0.0"
}
List Account's Phone Numbers
This lists the numbers an account owns, along with their properties.
!!! note
one can apply filters such as ?filter_state=in_service or ?created_from=63627345744
GET /v2/accounts/{ACCOUNT_ID}/phone_numbers
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers?page_size=3&start_key=%2B14152338421
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers', {
params: {
'page_size': '3'
},
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
"auth_token": "{AUTH_TOKEN}",
"data": {
"cascade_quantity": 0,
"numbers": {
"+14152338421": {
"assigned_to": "{ACCOUNT_ID}",
"created": 63628550806,
"features": [],
"state": "in_service",
"updated": 63628550806
},
"+14155234712": {
"assigned_to": "{ACCOUNT_ID}",
"created": 63636963275,
"features": [
"local"
],
"state": "in_service",
"updated": 63636963275
},
"+14155558920": {
"assigned_to": "{ACCOUNT_ID}",
"created": 63633211146,
"features": [
"local"
],
"state": "reserved",
"updated": 63633211146
}
}
},
"next_start_key": "+14155558921",
"page_size": 3,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"start_key": "+14152338421",
"status": "success"
}
Remove a number from the account owning it
DELETE /v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Response
Success
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"_read_only": {
"created": 63627848588,
"modified": 63627848588,
"state": "available"
},
"id": "{PHONE_NUMBER}",
"state": "available"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Number not in account
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"message": "bad identifier",
"not_found": "The number could not be found"
},
"error": "404",
"message": "bad_identifier",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Remove A Number From Account (admin Only)
DELETE /v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}?hard=true
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}', {
params: {
'hard': 'true'
},
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"_read_only": {
"created": 63627848588,
"modified": 63627848588,
"state": "deleted"
},
"id": "{PHONE_NUMBER}",
"state": "deleted"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
List An Account's Specific Phone Number
Show the number's properties along with user-defined properties.
GET /v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Success Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"_read_only": {
"created": 63627848989,
"features": [
"local"
],
"modified": 63627848989,
"state": "reserved"
},
"features": [
"local"
],
"id": "{PHONE_NUMBER}",
"state": "reserved",
"my_own_field": {}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Failure Response
Possible reasons for failure:
- Account does not have enough privileges to read number
- Number does not exist
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"message": "bad identifier",
"not_found": "The number could not be found"
},
"error": "404",
"message": "bad_identifier",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Update Public Fields Of A Number
!!! note some public fields are used to configure number features.
POST /v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"my_own_field":"some other value", "cnam":{"display_name":"My caller ID", "inbound_lookup":true}}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}',
'{"data":{"my_own_field":"some other value", "cnam":{"display_name":"My caller ID", "inbound_lookup":true}}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"_read_only": {
"created": 63635220353,
"features": [
"outbound_cnam",
"inbound_cnam"
],
"modified": 63635220353,
"state": "in_service",
"used_by": "callflow"
},
"cnam": {
"display_name": "My caller ID",
"inbound_lookup": true
},
"features": [
"outbound_cnam",
"inbound_cnam"
],
"id": "{PHONE_NUMBER}",
"my_own_field": "some other value",
"state": "in_service",
"used_by": "callflow"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Patch Public Fields Of A Number
PATCH /v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"my_own_field":42}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}',
'{"data":{"my_own_field":42}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"_read_only": {
"created": 63635220353,
"features": [
"outbound_cnam",
"inbound_cnam"
],
"modified": 63635220353,
"state": "in_service",
"used_by": "callflow"
},
"cnam": {
"display_name": "My caller ID",
"inbound_lookup": true
},
"features": [
"outbound_cnam",
"inbound_cnam"
],
"id": "{PHONE_NUMBER}",
"my_own_field": 42,
"state": "in_service",
"used_by": "callflow"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Add a number to the database
Adds a number to the database, returning its properties.
!!! note
Set field "create_with_state" in payload to your desired number state (defaults to "reserved").
!!! note Payload is optional.
PUT /v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"my_own_field": {}}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}',
'{"data": {"my_own_field": {}}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Success Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"_read_only": {
"created": 63627848989,
"modified": 63627848989,
"state": "reserved"
},
"id": "{PHONE_NUMBER}",
"state": "reserved",
"my_own_field": {}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Failure Responses
Number already exists
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"cause": "{PHONE_NUMBER}",
"code": 409,
"error": "number_exists",
"message": "number {PHONE_NUMBER} already exists"
},
"error": "409",
"message": "number_exists",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Number does not conform to E.164 format
A non-conforming {PHONE_NUMBER}: "+141510010+15".
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"cause": "{PHONE_NUMBER}",
"code": 404,
"error": "not_reconcilable",
"message": "number {PHONE_NUMBER} is not reconcilable"
},
"error": "404",
"message": "not_reconcilable",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Account unauthorized
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"message": "unknown failure",
"unauthorized": "Not authorized to perform requested number operation"
},
"error": "500",
"message": "unauthorized",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Check Availability Of Phone Numbers
POST /v2/accounts/{ACCOUNT_ID}/phone_numbers/check
This API checks if the numbers are still available for purchase.
A status of "error" may be due to:
- Number not being handled by carrier
knm_other phonebookbeing unresponsive
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"numbers": [{PHONE_NUMBER1}, {PHONE_NUMBER2}]}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/check
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/check',
'{"data": {"numbers": [{PHONE_NUMBER1}, {PHONE_NUMBER2}]}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"{PHONE_NUMBER1}": "success",
"{PHONE_NUMBER2}": "error"
}
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Get Locality Information For A Collection Of Numbers
POST /v2/accounts/{ACCOUNT_ID}/phone_numbers/locality
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"numbers": ["{PHONE_NUMBER1}", "{PHONE_NUMBER2}"]}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/locality
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/locality',
'{"data":{"numbers": ["{PHONE_NUMBER1}", "{PHONE_NUMBER2}"]}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Success Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"{PHONE_NUMBER1}": {
"carrier": {
"company": "T-Mobile USA Inc",
"dba": "T-Mobile USA Inc",
"id": "6529",
"type": "WIRELESS"
},
"country": "US",
"e164_number": "{PHONE_NUMBER1}",
"geocode": {
"locality": "California"
},
"locality": {
"alt_postal_codes": [
"94965",
"94941"
],
"extended_postal_code": null,
"latitude": "37.8725359094361",
"locality": "Belvedere",
"longitude": "-122.465900466078",
"postal_code": "94920",
"province": "CA",
"switch": "OKLECAZVGT0",
"type": "WIRELESS"
},
"number": "{PHONE_NUMBER1}",
"status": "success"
},
"{PHONE_NUMBER2}": {
"carrier": {
"company": "Bandwidth.com CLEC LLC - CA",
"dba": "Bandwidth.com CLEC LLC",
"id": "981E",
"type": "CLEC"
},
"country": "US",
"e164_number": "{PHONE_NUMBER2}",
"geocode": {
"locality": "California"
},
"locality": {
"alt_postal_codes": [
"94939",
"94976"
],
"extended_postal_code": null,
"latitude": "37.9267845442655",
"locality": "Corte Madera",
"longitude": "-122.527924297914",
"postal_code": "94904",
"province": "CA",
"switch": "SNFCCA21XUY",
"type": "LANDLINE"
},
"number": "{PHONE_NUMBER2}",
"status": "success"
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Backend to PhoneBook not set up
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": "Unable to acquire numbers missing carrier url",
"error": "500",
"message": "init failed",
"request_id": "{REQUEST_ID}",
"status": "error"
}
List Available Numbers Of A Given US City
GET /v2/accounts/{ACCOUNT_ID}/phone_numbers/prefix
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/prefix?city={CITY}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/prefix?city={CITY}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Success Response
Sample Response:
Country or city not found
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"data": {},
"error": 404,
"message": "Not Found",
"status": "error"
},
"error": "500",
"message": "init failed",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Backend to PhoneBook not set up
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": "Unable to acquire numbers missing carrier url",
"error": "500",
"message": "init failed",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Remove a list of numbers from the database
DELETE /v2/accounts/{ACCOUNT_ID}/phone_numbers/collection
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"numbers": ["{PHONE_NUMBER1}", "{PHONE_NUMBER2}", "{PHONE_NUMBER3}"]}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/collection
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/collection', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
},
data: '{"data":{"numbers": ["{PHONE_NUMBER1}", "{PHONE_NUMBER2}", "{PHONE_NUMBER3}"]}}'
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"success": {
"{PHONE_NUMBER1": {
"_read_only": {
"created": 63628473168,
"modified": 63628473168,
"state": "available"
},
"id": "{PHONE_NUMBER1}",
"state": "available"
},
"{PHONE_NUMBER2}": {
"_read_only": {
"created": 63628473168,
"modified": 63628473168,
"state": "available"
},
"id": "{PHONE_NUMBER2}",
"state": "available"
},
"{PHONE_NUMBER3}": {
"_read_only": {
"created": 63628473168,
"modified": 63628473168,
"state": "available"
},
"id": "{PHONE_NUMBER3}",
"state": "available"
}
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Remove a list of numbers from account (admin only)
DELETE /v2/accounts/{ACCOUNT_ID}/phone_numbers/collection
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"numbers": ["{PHONE_NUMBER1}", "{PHONE_NUMBER2}", "{PHONE_NUMBER3}"]}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/collection?hard=true
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/collection', {
params: {
'hard': 'true'
},
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
},
data: '{"data":{"numbers": ["{PHONE_NUMBER1}", "{PHONE_NUMBER2}", "{PHONE_NUMBER3}"]}}'
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"success": {
"{PHONE_NUMBER1": {
"_read_only": {
"created": 63628473168,
"modified": 63628473168,
"state": "deleted"
},
"id": "{PHONE_NUMBER1}",
"state": "deleted"
},
"{PHONE_NUMBER2}": {
"_read_only": {
"created": 63628473168,
"modified": 63628473168,
"state": "deleted"
},
"id": "{PHONE_NUMBER2}",
"state": "deleted"
},
"{PHONE_NUMBER3}": {
"_read_only": {
"created": 63628473168,
"modified": 63628473168,
"state": "deleted"
},
"id": "{PHONE_NUMBER3}",
"state": "deleted"
}
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Update public fields of a list of numbers
POST /v2/accounts/{ACCOUNT_ID}/phone_numbers/collection
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"numbers": ["{PHONE_NUMBER1}", "{PHONE_NUMBER2}"], "myfield": 1337}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/collection
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/collection',
'{"data": {"numbers": ["{PHONE_NUMBER1}", "{PHONE_NUMBER2}"], "myfield": 1337}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"success": {
"{PHONE_NUMBER1}": {
"_read_only": {
"created": 63628454912,
"modified": 63628454912,
"state": "reserved"
},
"id": "{PHONE_NUMBER1}",
"myfield": 1337,
"state": "reserved"
},
"{PHONE_NUMBER2}": {
"_read_only": {
"created": 63628454912,
"modified": 63628454912,
"state": "reserved"
},
"id": "{PHONE_NUMBER2}",
"myfield": 1337,
"state": "reserved"
}
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Patch public fields of a list of numbers
PATCH /v2/accounts/{ACCOUNT_ID}/phone_numbers/collection
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"numbers": ["{PHONE_NUMBER1}", "{PHONE_NUMBER2}"], "myfield": 2337}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/collection
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/collection',
'{"data": {"numbers": ["{PHONE_NUMBER1}", "{PHONE_NUMBER2}"], "myfield": 2337}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"success": {
"{PHONE_NUMBER1}": {
"_read_only": {
"created": 63628454912,
"modified": 63628454912,
"state": "reserved"
},
"id": "{PHONE_NUMBER1}",
"myfield": 2337,
"state": "reserved"
},
"{PHONE_NUMBER2}": {
"_read_only": {
"created": 63628454912,
"modified": 63628454912,
"state": "reserved"
},
"id": "{PHONE_NUMBER2}",
"myfield": 2337,
"state": "reserved"
}
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Add a list of numbers to the database
Note: set field "create_with_state" in payload to your desired number state (defaults to "reserved").
PUT /v2/accounts/{ACCOUNT_ID}/phone_numbers/collection
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"numbers": ["{PHONE_NUMBER1}", "{PHONE_NUMBER2}", "{PHONE_NUMBER3}"]}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/collection
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/collection',
'{"data":{"numbers": ["{PHONE_NUMBER1}", "{PHONE_NUMBER2}", "{PHONE_NUMBER3}"]}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Success Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"success": {
"{PHONE_NUMBER1}": {
"_read_only": {
"created": 63628454912,
"modified": 63628454912,
"state": "reserved"
},
"id": "{PHONE_NUMBER1}",
"state": "reserved"
},
"{PHONE_NUMBER2}": {
"_read_only": {
"created": 63628454912,
"modified": 63628454912,
"state": "reserved"
},
"id": "{PHONE_NUMBER2}",
"state": "reserved"
},
"{PHONE_NUMBER3}": {
"_read_only": {
"created": 63628454912,
"modified": 63628454912,
"state": "reserved"
},
"id": "{PHONE_NUMBER3}",
"state": "reserved"
}
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Failure
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"{PHONE_NUMBER2}": {
"cause": "{PHONE_NUMBER2}",
"code": 409,
"error": "number_exists",
"message": "number {PHONE_NUMBER2} already exists"
},
"{PHONE_NUMBER3}": {
"cause": "{PHONE_NUMBER3}",
"code": 409,
"error": "number_exists",
"message": "number {PHONE_NUMBER3} already exists"
}
},
"error": "400",
"message": "client error",
"request_id": "{REQUEST_ID}",
"status": "error"
}
List classifiers
GET /v2/accounts/{ACCOUNT_ID}/phone_numbers/classifiers
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/classifiers
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/classifiers', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"caribbean": {
"friendly_name": "Caribbean",
"pretty_print": "SS(###) ### - ###",
"regex": "^\\+?1((?:684|264|268|242|246|441|284|345|767|809|829|849|473|671|876|664|670|787|939|869|758|784|721|868|649|340)\\d{7})$"
},
"did_us": {
"friendly_name": "US DID",
"pretty_print": "SS(###) ### - ###",
"regex": "^\\+?1?([2-9][0-9]{2}[2-9][0-9]{6})$"
},
"emergency": {
"friendly_name": "Emergency Dispatcher",
"regex": "^(911)$"
},
"international": {
"friendly_name": "International",
"regex": "^(011\\d*)$|^(00\\d*)$"
},
"toll_us": {
"friendly_name": "US Toll",
"pretty_print": "SS(###) ### - ###",
"regex": "^\\+1(900\\d{7})$"
},
"tollfree_us": {
"friendly_name": "US TollFree",
"pretty_print": "SS(###) ### - ###",
"regex": "^\\+1((?:800|888|877|866|855)\\d{7})$"
},
"unknown": {
"friendly_name": "Unknown",
"regex": "^(.*)$"
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Fix issues
POST /v2/accounts/{ACCOUNT_ID}/phone_numbers/fix
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/fix
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/fix',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"cascade_quantity": 0,
"numbers": {
"+14152338421": {
"assigned_to": "{ACCOUNT_ID}",
"created": 63627334163,
"state": "in_service",
"updated": 63627447350
},
"+14155555555": {
"assigned_to": "{ACCOUNT_ID}",
"created": 63602230185,
"state": "in_service",
"updated": 63602230212,
"used_by": "callflow"
},
"+14158865100": {
"assigned_to": "{ACCOUNT_ID}",
"created": 63624719324,
"state": "in_service",
"updated": 63624719325
}
}
},
"page_size": 2,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Fix used_by field (and others) of a specific number
POST /v2/accounts/{ACCOUNT_ID}/phone_numbers/fix/{PHONE_NUMBER}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/fix/%2B15554445563
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/fix/%2B15554445563',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"_read_only": {
"created": 63635220353,
"features": [
"inbound_cnam",
"outbound_cnam"
],
"features_available": [
"cnam",
"e911",
"port",
"prepend"
],
"modified": 63635220353,
"state": "in_service",
"used_by": "callflow"
},
"cnam": {
"display_name": "My Main Num2",
"inbound_lookup": true
},
"features": [
"inbound_cnam",
"outbound_cnam"
],
"id": "+15554445563",
"state": "in_service",
"ui_metadata": {
"origin": "common",
"ui": "monster-ui",
"version": "3.23"
},
"used_by": "callflow"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Return which account a number belongs to
GET /v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}/identify
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}/identify
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}/identify', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Success Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"account_id": "009afc511c97b2ae693c6cc4920988e8",
"number": "{PHONE_NUMBER}"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Number not in service or account disabled
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"account_id": "009deaaadc97b2ae693c6cc4920988e8",
"cause": "not_in_service"
},
"error": "400",
"message": "client error",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Number not found or not enough privileges
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"message": "bad identifier",
"not_found": "The number could not be found"
},
"error": "404",
"message": "bad_identifier",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Create a number in the port_in state
PUT /v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}/port
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"blip": 432}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/%2B14145137345/port
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/%2B14145137345/port',
'{"data": {"blip": 432}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"_read_only": {
"created": 63644564835,
"features": [
"local"
],
"features_available": [
"cnam",
"e911",
"failover",
"port",
"prepend"
],
"modified": 63644564835,
"state": "port_in"
},
"blip": 432,
"features": [
"local"
],
"id": "+14145137345",
"state": "port_in"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Move a number to the reserved state
PUT /v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}/reserve
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}/reserve
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}/reserve',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Success Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"_read_only": {
"created": 63628556896,
"modified": 63628556896,
"state": "reserved"
},
"id": "{PHONE_NUMBER}",
"state": "reserved"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Number already in reserved state
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"code": 400,
"error": "no_change_required",
"message": "no change required"
},
"error": "400",
"message": "no_change_required",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Number does not exist
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"message": "bad identifier",
"not_found": "The number could not be found"
},
"error": "404",
"message": "bad_identifier",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Buy a number once searched for
Note: one is not charged if number is already in service.
PUT /v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}/activate
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}/activate
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}/activate',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Success
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"_read_only": {
"created": 63628027112,
"modified": 63628027112,
"state": "in_service"
},
"id": "{PHONE_NUMBER}",
"state": "in_service"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Number was not returned in previous search results or other error
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"code": 500,
"error": "unspecified_fault",
"message": "missing_provider_url"
},
"error": "500",
"message": "unspecified_fault",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Carrier fault
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"cause": "{PHONE_NUMBER}",
"code": 500,
"error": "unspecified_fault",
"message": "fault by carrier"
},
"error": "500",
"message": "unspecified_fault",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Classify a number
GET /v2/accounts/{ACCOUNT_ID}/phone_numbers/classifiers/{PHONE_NUMBER}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/classifiers/{PHONE_NUMBER}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/classifiers/{PHONE_NUMBER}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"e164": "+1{PHONE_NUMBER}",
"friendly_name": "US DID",
"name": "did_us",
"number": "{PHONE_NUMBER}",
"pretty_print": "SS(###) ### - ###",
"regex": "^\\+?1?([2-9][0-9]{2}[2-9][0-9]{6})$"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Buy a list of numbers
Note: numbers must have appeared as part of the results of a numbers search.
PUT /v2/accounts/{ACCOUNT_ID}/phone_numbers/collection/activate
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"numbers": ["{PHONE_NUMBER1}", "{PHONE_NUMBER2}"]}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/collection/activate
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/collection/activate',
'{"data":{"numbers": ["{PHONE_NUMBER1}", "{PHONE_NUMBER2}"]}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Success Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"success": {
"{PHONE_NUMBER1}": {
"_read_only": {
"created": 63628542222,
"modified": 63628542222,
"state": "in_service"
},
"id": "{PHONE_NUMBER1}",
"state": "in_service"
},
"{PHONE_NUMBER2}": {
"_read_only": {
"created": 63628542222,
"modified": 63628542222,
"state": "in_service"
},
"id": "{PHONE_NUMBER2}",
"state": "in_service"
}
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Number not found or other error
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"{PHONE_NUMBER2}": {
"code": 500,
"error": "unspecified_fault",
"message": "missing_provider_url"
}
},
"error": "400",
"message": "client error",
"request_id": "{REQUEST_ID}",
"status": "error"
}
E911
POST /v2/accounts/{ACCOUNT_ID}/phone_numbers/collection/activate
With a sample payload like below:
Sample Response:
{
"data": {
"used_by": "callflow",
"id": "{NUMBER}",
"e911": {
"caller_name": "{NAME}",
"postal_code": "{ZIP_CODE}",
"street_address": "{ADDRESS}",
"extended_address": "{EXTENDED}",
"locality": "{CITY}",
"region": "{STATE}"
}
}
}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{_ABOVE_SAMPLE_}' \
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{NUMBER}'
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{NUMBER}',
'{_ABOVE_SAMPLE_}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Responses
Invalid address
Sample Response:
{
"data": {
"address": {
"invalid": {
"cause": {
"caller_name": "{NAME}",
"postal_code": "{ZIP_CODE}",
"street_address": "{ADDRESS}",
"extended_address": "{EXTENDED}",
"locality": "{CITY}",
"region": "{STATE}"
},
"message": "Location is not geocoded"
}
}
},
"error": "400",
"message": "invalid data",
"status": "error"
}
Multiple choice
Sample Response:
{
"data": {
"multiple_choice": {
"e911": {
"cause": {
"postal_code": "{ZIP_CODE}",
"street_address": "{ADDRESS}",
"extended_address": "{EXTENDED}",
"locality": "{CITY}",
"region": "{STATE}"
},
"details": [{
"postal_code": "{ZIP_CODE}",
"street_address": "{ADDRESS}",
"extended_address": "{EXTENDED}",
"locality": "{CITY}",
"region": "{STATE}"
}, {
"postal_code": "{ZIP_CODE}",
"street_address": "{ADDRESS}",
"extended_address": "{EXTENDED}",
"locality": "{CITY}",
"region": "{STATE}"
}],
"message": "more than one address found"
}
}
},
"error": "400",
"message": "multiple_choice",
"status": "error"
}
Success
Sample Response:
{
"data": {
"used_by": "callflow",
"id": "{NUMBER}",
"e911": {
"street_address": "116 NATOMA ST",
"extended_address": "APT 116",
"caller_name": "Michel Mabel",
"locality": "SAN FRANCISCO",
"latitude": "37.786861",
"longitude": "-122.399484",
"location_id": "27578725",
"plus_four": "3745",
"postal_code": "94105",
"region": "CA",
"status": "PROVISIONED",
"legacy_data": {
"house_number": "116",
"streetname": "NATOMA ST",
"suite": "APT 116"
}
}
},
"status": "success"
}
Pivot API
About Pivot
The Pivot resource allows the client to query and inspect data related to the Pivot application (real-time call control).
Enabling in Crossbar
The Pivot endpoint is not loaded on start in a default Lumian installation.
- To enable at runtime:
sup crossbar_maintenance start_module cb_pivot
- To autostart on Crossbar boot:
- Navigate to
http://localhost:15984/_utils/document.html?system_config/crossbar - Edit the
autoload_moduleslist to include 'cb_pivot' - Click the green check box to the right of the input box
- Click 'Save Document' in top left of the screen
- Navigate to
!!! note
Adding cb_pivot to the crossbar system_config doc will not start the endpoint; only on restarting Crossbar will cb_pivot be loaded. Use the sup command above to start the endpoint at runtime.
Callflow Schema
See the Pivot callflow schema for details.
Debugging pivot attempts
You will need to edit the data object in the pivot callflow element to include a debug flag:
Sample Response:
{
"flow": {
"data": {
"method": "GET",
"req_format": "lumian",
"voice_url": "http://your.pivot.server/path/to/callflow.php",
"debug": true
},
"module": "pivot",
"children": {
}
}
}
All calls to this callflow will now store debug logs to the account's current MODb database.
Fetch a List of Debug UUIDs
GET /v2/accounts/{ACCOUNT_ID}/pivot/debug
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/pivot/debug
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/pivot/debug', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"call_id": "{UUID_1}",
"created": 63635231906,
"iteration": 1,
"node": "{PIVOT_SERVER}",
"status_code": "404",
"has_schema_errors": false,
"uri": "http://127.0.0.1/pivot/lumian_486.php?Language=en-us&Caller-ID-Number=user_suyt9r93ng&Caller-ID-Name=user_suyt9r93ng&Direction=inbound&Api-Version=2015-03-01&To-Realm={SIP_REALM}&To=4786&From-Realm={SIP_REALM}&From=user_suyt9r93ng&Account-ID={ACCOUNT_ID}&Call-ID={UUID_1}"
},
{
"call_id": "{UUID_2}",
"created": 63635230409,
"iteration": 1,
"node": "{PIVOT_SERVER}",
"has_schema_errors": true
}
],
"page_size": 3,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success",
}
Fetch Debug Logs for a UUID
GET /v2/accounts/{ACCOUNT_ID}/pivot/debug/{UUID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/pivot/debug/{UUID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/pivot/debug/{UUID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}"
,"data": [{"call_id": "829597750@10.26.0.158"
,"id": "b791e38c9641652a69e297dc9c3a8d66"
,"method": "get"
,"req_body": ""
,"req_headers": {}
,"uri": "http://{PIVOT_SERVER}/path/to/callflow.php?CallerNumber={CALLER_ID_NUMBER}&CallerName={CALLER_ID_NAME}&Direction=inbound&ApiVersion=2010-04-01&ToRealm={TO_SIP_REALM}&To={DIALED_NUMBER}&FromRealm={FROM_SIP_REALM}&From={SIP_FROM_USER}&AccountSid={ACCOUNT_ID}&CallSid=829597750%4010.26.0.158"
}
,{"call_id": "829597750@10.26.0.158"
,"id": "f071ae42d9bcebd158f263258e73b001"
,"resp_headers": {
"content-length": "303"
,"content-type": "text/html"
,"date": "fri, 30 may 2014 20:42:53 gmt"
,"server": "apache/2.4.7 (ubuntu)"
}
,"resp_status_code": "404"
}
,{"call_id": "829597750@10.26.0.158"
,"id": "79604993e4dbe962872a71fe6cbc9717"
,"resp_body": "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>404 Not Found</title>\n</head><body>\n<h1>Not Found</h1>\n<p>The requested URL /path/to/callflow.php was not found on this server.</p>\n<hr>\n<address>Apache/2.4.7 (Ubuntu) Server at {PIVOT_SERVER} Port 80</address>\n</body></html>\n"
}
]
,"request_id": "{REQUEST_ID}"
,"revision": "{REVISION}"
,"status": "success"
}
!!! note
You must URL-encode the call-id in the URL. Typically this would just mean converting @ to %40, but you'll need to take care depending on how your call-ids are constructed.
Number Port Requests
About Port Requests
Manage and track number port requests through the Port Requests API.
Table of Content
- About
- Port Request Listing
- Port Request Management
- Attachment Management
- Update Status
- Build an LOA PDF from a port request
Port request stats
A port request can be in one of seven states:
unconfirmed: A port request has been created, but the details have not been confirmed and the port process has not started.submitted: Indicates the number port is ready to be processed and sent to the losing carrier.pending: The port was submitted to the losing carrier.scheduled: The port is in progress and the losing carrier has been notified.completed: The port request has been finished, and numbers are activated.rejected: Something has gone wrong during the port process. The port can be resubmitted.canceled: The port request is definitely canceled and cannot be resubmitted.
Port states diagram
Port authority (Port Agent)
Port authority (sometimes called port agent or simply agent) is an account in Lumian system which is responsible for managing their sub account port requests. They are responsible to submitted and oversees port request to losing/winner carrier.
Master account is default port authority.
If you want to manage port request for your sub account, you have to white label your account and set "I will manage port request from my account" in Branding application, "Advanced" tab. If you select that option, you have to set an Email address for port "Support Contact" in the same section.
Schema
Schema for a port request
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
bill.account_number |
Account Number to identify account | string() |
false |
||
bill.btn |
Billing Telephone Number (BTN) to identify account | string() |
false |
||
bill.carrier |
The name of the losing carrier | string() |
false |
||
bill.locality |
The locality (city) of the billing address the losing carrier has on record | string() |
false |
||
bill.name |
The losing carrier billing/account name | string() |
false |
||
bill.pin |
Personal Identification Number (PIN) to identify account | string() |
false |
||
bill.postal_code |
The zip/postal code of the billing address the losing carrier has on record | string() |
false |
||
bill.region |
The region (state) of the billing address the losing carrier has on record | string() |
false |
||
bill.street_address |
The street name of the billing address the losing carrier has on record | string() |
false |
||
bill.street_number |
The street number of the billing address the losing carrier has on record | string() |
false |
||
bill.street_post_dir |
Street Post-Direction | string() |
false |
||
bill.street_pre_dir |
Street Pre-Direction | string() |
false |
||
bill.street_type |
The street type of the billing address the losing carrier has on record | string() |
false |
||
bill |
Billing information of the losing carrier | object() |
false |
||
comments |
The history of comments made on a port request | ["array(", "[#/definitions/comment](#comment)", ")"] |
false |
||
name |
A friendly name for the port request | string(1..128) |
true |
||
notifications.email.send_to.[] |
string() |
false |
|||
notifications.email.send_to |
A list or string of email recipient(s) | `string() | array(string())` | false |
|
notifications.email |
Inbound Email Notifications | object() |
false |
||
notifications |
Status notifications | object() |
false |
||
numbers./\+?[0-9]+/ |
object() |
false |
|||
numbers |
The numbers to port in | object() |
true |
||
reference_number |
Winning carrier reference number or order ID | string() |
false |
||
signee_name |
The name of the person authorizing the release of numbers from the losing carrier | string() |
false |
||
signing_date |
The date in Gregorian timestamp on which the document releasing the numbers from the losing carrier was signed | integer() |
false |
||
transfer_date |
Requested transfer date in Gregorian timestamp | integer() |
false |
||
winning_carrier |
The name of winning carrier | string() |
false |
List port requests
Port request API URL path has specific meaning:
/v2/port_requests: List port requests that the authenticated account is port authority for./v2/accounts/{ACCOUNT_ID}/port_requests: List only port request for a specific account./v2/accounts/{ACCOUNT_ID}/descendants/port_requests: List all sub-accounts port requests.
List port requests by type
You can issue GET requests to find all ports in a particular state.
All requests are not paginated, with the exception of the completed state. Use pagination toggles for date range as desired.
To do this add by_types query string to the request. If you don't set by_types, by default active port request will be shown. Possible values are:
all: Lists port requests in any stateactive: Lists port requests which are in these states:unconfirmedsubmittedpendingscheduledrejected
progressing: Lists port requests which are in these states:submittedpendingscheduled
suspended: Lists port requests which are in these states:unconfirmedrejected
completed: Lists port requests which are in these states:completedcanceled
last_submitted: Lists all port requests by their last transition to thesubmittedstate- Port requests states: List port requests bu their states:
unconfirmedsubmittedpendingscheduledcompletedrejectedcanceled
Example usage of by_type
Here an example of setting by_types:
/v2/port_requests?by_types=prgressing
/v2/accounts/{ACCOUNT_ID}/port_requests?by_types=prgressing
You can also specify multiple types by separating them by comma like example below:
/v2/port_requests?by_types=pending,scheduled,rejected
/v2/accounts/{ACCOUNT_ID}/port_requests?by_types=pending,scheduled,rejected
Search/list a port request by phone number
For finding a port request by a phone number set by_number in query string. Including an account ID in the URL will change how the port requests are searched:
/v2/port_requests?by_number={PHONE_NUMBER}: This will search for port request in the authenticated account and all its sub-accounts./v2/accounts/{ACCOUNT_ID}/port_requests: This will search in the{ACCOUNT_ID}and all its sub-account
Example request/response
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/port_requests?by_number={PHONE_NUMBER}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/port_requests?by_number={PHONE_NUMBER}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"account_id": "{ACCOUNT_ID}",
"created": 63630107130,
"id": "0684aa1e2785d62c76ce27d2451a1c26",
"name": "Porting 202.555.9000",
"numbers": {
"{PHONE_NUMBER}": {}
},
"port_state": "canceled",
"sent": false,
"updated": 63630120578,
"uploads": {
"file.pdf": {
"content_type": "application/pdf",
"length": 90931
}
}
}
],
"page_size": 1,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
List port requests that are managed by you
This lists all port requests that you (authenticated account) are managing and port authority for. See Port Authority for more details.
GET /v2/port_requests
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/port_requests
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/port_requests', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"account_id": "{ACCOUNT_ID}",
"account_name": "{ACCOUNT_NAME}",
"port_requests": [
{
"account_id": "{ACCOUNT_ID}",
"created": 63630097779,
"id": "462da37f8be11e46161fb40bc71173a9",
"name": "Porting 202.555.9000",
"numbers": {
"+12025559000": {}
},
"port_state": "unconfirmed",
"sent": false,
"updated": 63630097779,
"uploads": {}
}
]
}
],
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
List port requests for an account
This only lists port requests of a single account.
GET /v2/accounts/{ACCOUNT_ID}/port_requests
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Response is same as listing for agent.
List port requests of sub-accounts
GET /v2/accounts/{ACCOUNT_ID}/descendants/port_requests
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/descendants/port_requests
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/descendants/port_requests', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Response is same as listing for agent.
Listing all port requests by their last transition to the submitted state
GET /v2/accounts/{ACCOUNT_ID}/port_requests/last_submitted
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/last_submitted
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/last_submitted', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"id": "{PORT_REQUEST_ID}",
"transition": {
"authorization": {
"account": {
"id": "{AUTH_ACCOUNT_ID}",
"name": "{AUTH_ACCOUNT_NAME}"
},
"user": {
"id": "0d46906ff1eb36bff4d09b5b32fc14be",
"first_name": "John",
"last_name": "Doe"
}
},
"reason": "this was approved by Jane Doe",
"timestamp": 63664096014,
"transition": {
"new": "submitted",
"previous": "unconfirmed"
},
"type": "transition"
}
}
],
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success",
"timestamp": "2017-06-07T23:07:09",
"version": "4.1.12"
}
Listing transitions and comments
GET /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/timeline
This shows the port request's timeline as a sorted list of transitions and comments.
Admins are able to list every transitions and comments regardless of their privacy setting. Non admins only see transitions and public comments.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/timeline
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/timeline', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"authorization": {
"account": {
"id": "{AUTH_ACCOUNT_ID}",
"name": "{AUTH_ACCOUNT_NAME}"
},
"user": {
"id": "0d46906ff1eb36bff4d09b5b32fc14be",
"first_name": "John",
"last_name": "Doe"
}
},
"timestamp": 63663993575,
"transition": {
"new": "unconfirmed"
},
"type": "transition"
},
{
"account_id": "0d46906ff1eb36bff4d09b5b32fc14be",
"action_required": true,
"content": "the comment is private, and user is required to make an action port request",
"is_private": true,
"timestamp": 63664000760,
"user_id": "0d46906ff1eb36bff4d09b5b32fc14be"
},
{
"account_id": "0d46906ff1eb36bff4d09b5b32fc14be",
"content": "this is not private",
"action_required": false,
"is_private": false,
"timestamp": 63664000768,
"user_id": "0d46906ff1eb36bff4d09b5b32fc14be"
},
{
"authorization": {
"account": {
"id": "{AUTH_ACCOUNT_ID}",
"name": "{AUTH_ACCOUNT_NAME}"
},
"user": {
"id": "0d46906ff1eb36bff4d09b5b32fc14be",
"first_name": "John",
"last_name": "Doe"
}
},
"reason": "this was approved by Jane Doe",
"timestamp": 63664096014,
"transition": {
"new": "submitted",
"previous": "unconfirmed"
},
"type": "transition"
}
],
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success",
"timestamp": "2017-06-07T23:07:09",
"version": "4.1.12"
}
Port request management
Create a new port request
PUT /v2/accounts/{ACCOUNT_ID}/port_requests
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"numbers":{"{PHONE_NUMBER}":{}}, "name":"{PORT_REQUEST_NAME}"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests',
// '{"data":{"numbers":{"{PHONE_NUMBER}":{}}, "name":"{PORT_REQUEST_NAME}"}}',
{
'data': {
'numbers': {
'{PHONE_NUMBER}': {}
},
'name': '{PORT_REQUEST_NAME}'
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Responses
Success
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"id": "462da37f8be11e46161fb40bc71173a9",
"name": "{PORT_REQUEST_NAME}",
"numbers": {
"{PHONE_NUMBER}": {}
},
"port_state": "unconfirmed",
"uploads": {},
"_read_only": {
"port_authority": "{PORT_AUTHORITY_ACCOUNT_ID}",
"port_authority_name": "{PORT_AUTHORITY_ACCOUNT_NAME}"
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Failure: a port already exists for this number
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"{PHONE_NUMBER}": {
"type": {
"cause": "{PHONE_NUMBER}",
"message": "Number is on a port request already: 41ed5722d24bfc69bc479208b274be6b"
}
}
},
"error": "500",
"message": "invalid request",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Failure: an account already owns this number
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"{PHONE_NUMBER}": {
"type": {
"cause": "{PHONE_NUMBER}",
"message": "Number exists on the system already"
}
}
},
"error": "500",
"message": "invalid request",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Get port request details
GET /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"created": 63630097779,
"id": "{PORT_REQUEST_ID}",
"name": "Porting 202.555.9000",
"numbers": {
"+12025559000": {}
},
"port_state": "unconfirmed",
"sent": false,
"updated": 63630097779,
"uploads": {},
"_read_only": {
"port_authority": "{PORT_AUTHORITY_ACCOUNT_ID}",
"port_authority_name": "{PORT_AUTHORITY_ACCOUNT_NAME}"
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Edit a port request
POST /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"numbers":{"{PHONE_NUMBER}":{"state":"NY"}}, "name": "{PORT_REQUEST_NAME}"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}',
// '{"data":{"numbers":{"{PHONE_NUMBER}":{"state":"NY"}}, "name": "{PORT_REQUEST_NAME}"}}',
{
'data': {
'numbers': {
'{PHONE_NUMBER}': {
'state': 'NY'
}
},
'name': '{PORT_REQUEST_NAME}'
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"created": 63630097779,
"id": "{PORT_REQUEST_ID}",
"name": "{PORT_REQUEST_NAME}",
"numbers": {
"{PHONE_NUMBER}": {
"state": "NY"
}
},
"port_state": "unconfirmed",
"sent": false,
"updated": 63630104652,
"uploads": {},
"_read_only": {
"port_authority": "{PORT_AUTHORITY_ACCOUNT_ID}",
"port_authority_name": "{PORT_AUTHORITY_ACCOUNT_NAME}"
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Patch a port request
PATCH /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"your_custom_info":{"carrier_port_id": "apc-8535937-gtk123", "carrier_name": "ace phone co"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}',
'{"data":{"your_custom_info":{"carrier_port_id": "apc-8535937-gtk123", "carrier_name": "ace phone co"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"created": 63630097779,
"id": "{PORT_REQUEST_ID}",
"name": "{PORT_REQUEST_NAME}",
"numbers": {
"{PHONE_NUMBER}": {
"state": "NY"
}
},
"port_state": "unconfirmed",
"sent": false,
"updated": 63630104652,
"uploads": {},
"your_custom_info": {
"carrier_port_id": "apc-8535937-gtk123",
"carrier_name": "ace phone co"
},
"_read_only": {
"port_authority": "{PORT_AUTHORITY_ACCOUNT_ID}",
"port_authority_name": "{PORT_AUTHORITY_ACCOUNT_NAME}"
}
}
}
DELETE a port request
DELETE /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"id": "{PORT_REQUEST_ID}",
"name": "Porting 202.555.9000",
"numbers": {
"+12025559000": {
"state": "NY"
}
},
"port_state": "unconfirmed",
"_read_only": {
"port_authority": "{PORT_AUTHORITY_ACCOUNT_ID}",
"port_authority_name": "{PORT_AUTHORITY_ACCOUNT_NAME}"
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Attachment Management
List attachments on a port request
GET /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"file.pdf": {
"content_type": "application/pdf",
"length": 90931
},
"otherfile.pdf": {
"content_type": "application/pdf",
"length": 767684
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Add an attachment to a port request
Note: if ATTACHMENT_ID does not end with .pdf the extension will be appended.
PUT /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/pdf" \
--data-binary @/path/to/file.pdf \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments?filename={ATTACHMENT_ID}
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments?filename={ATTACHMENT_ID}',
'@/path/to/file.pdf',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/pdf'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Get an attachment from a port request
GET /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments/{ATTACHMENT_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Accept: application/pdf" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments/{ATTACHMENT_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments/{ATTACHMENT_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Accept': 'application/pdf'
}
});
Streams back the contents of the PDF file {ATTACHMENT_ID}.
Replace an attachment on a port request
POST /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments/{ATTACHMENT_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/pdf" \
--data-binary @/path/to/file.pdf \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments/{ATTACHMENT_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments/{ATTACHMENT_ID}',
'@/path/to/file.pdf',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/pdf'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Delete an attachment on a port request
DELETE /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments/{ATTACHMENT_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments/{ATTACHMENT_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments/{ATTACHMENT_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Updating a port request status
When PATCHing a port request a reason can be added to the transition with the following request value:
* reason: an optional string that can be used to describe the reason for the transition
This information will then be available in the timeline.
Note: request values can be set either in the query string or in the data payload.
Indicate a port is ready to be processed
PATCH /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/submitted
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/submitted?reason=this+was+approved+by+Jane+Doe
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/submitted',
'',
{
params: {
'reason': 'this was approved by Jane Doe'
},
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Success
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"created": 63630107130,
"id": "{PORT_REQUEST_ID}",
"name": "Porting 202.555.9000",
"numbers": {
"+12025559000": {}
},
"port_state": "submitted",
"sent": false,
"updated": 63630120443,
"uploads": {
"file.pdf": {
"content_type": "application/pdf",
"length": 90931
}
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Failure: charges have to be accepted
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"activation_charges": 10.0,
"number_services": {
"port": {
"activation_charges": 10.0
}
}
},
"error": "402",
"message": "accept charges",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Put port in pending
PATCH /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/pending
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/pending
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/pending',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Success
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"created": 63630107130,
"id": "{PORT_REQUEST_ID}",
"name": "Porting 202.555.9000",
"numbers": {
"+12025559000": {}
},
"port_state": "pending",
"sent": false,
"updated": 63630120502,
"uploads": {
"file.pdf": {
"content_type": "application/pdf",
"length": 90931
}
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Failure: target state illegal given current state
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"port_state": {
"enum": {
"cause": "pending",
"message": "Cannot move to new state from current state"
}
}
},
"error": "500",
"message": "invalid request",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Put port in progress (sent to losing carrier)
PATCH /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/scheduled
!!! note
- schedule_on is a required field for this state transition.
!!! note
- scheduled_date is an automatically added timestamp computed from the value of the schedule_on object.
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"schedule_on": {"timezone":"America/Los_Angeles", "date_time":"2017-06-24 12:00"}}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/scheduled
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/scheduled',
'{"data": {"schedule_on": {"timezone":"America/Los_Angeles", "date_time":"2017-06-24 12:00"}}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"created": 63630107130,
"id": "{PORT_REQUEST_ID}",
"name": "Porting 202.555.9000",
"numbers": {
"+12025559000": {}
},
"port_state": "scheduled",
"schedule_on": {
"date_time": "2017-06-24 12:00",
"timezone": "America/Los_Angeles"
},
"scheduled_date": 63658292400,
"sent": false,
"updated": 63630120528,
"uploads": {
"file.pdf": {
"content_type": "application/pdf",
"length": 90931
}
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Complete port, numbers will activate in the system, account will be billed
PATCH /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/completed
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/completed
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/completed',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"created": 63630107130,
"id": "{PORT_REQUEST_ID}",
"name": "Porting 202.555.9000",
"numbers": {
"+12025559000": {}
},
"port_state": "completed",
"sent": false,
"updated": 63630120570,
"uploads": {
"file.pdf": {
"content_type": "application/pdf",
"length": 90931
}
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Reject a port
PATCH /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/rejected
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/rejected
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/rejected',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"created": 63630107130,
"id": "{PORT_REQUEST_ID}",
"name": "Porting 202.555.9000",
"numbers": {
"+12025559000": {}
},
"port_state": "rejected",
"sent": false,
"updated": 63630120570,
"uploads": {
"file.pdf": {
"content_type": "application/pdf",
"length": 90931
}
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Cancel a port
PATCH /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/canceled
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/canceled
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/canceled',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"created": 63630107130,
"id": "{PORT_REQUEST_ID}",
"name": "Porting 202.555.9000",
"numbers": {
"+12025559000": {}
},
"port_state": "canceled",
"sent": false,
"updated": 63630120578,
"uploads": {
"file.pdf": {
"content_type": "application/pdf",
"length": 90931
}
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Build an LOA PDF from a port request
Download the generated Letter Of Authorization PDF file.
GET /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/loa
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Accept: application/x-pdf" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/loa
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/loa', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Accept': 'application/x-pdf'
}
});
Presence
About Presence
Lumian tracks presence subscriptions and those states can be accessed/manipulated via this API.
There are three main ways to access presence information:
- Devices
- Users
- Arbitrary extensions
List Subscriptions
GET /v2/accounts/{ACCOUNT_ID}/presence
It is possible to search/list all subscriptions for an account:
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/presence
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/presence', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"subscriptions": {
"{EXTENSION}": {
"dialog": {
"{CALL_ID}": {
"expires": 1820,
"from": "{SIP_USERNAME}@{ACCOUNT_REALM}",
"notify": {
"body": "undefined",
"reply": 0,
"sequence": 0
},
"stalker": "BLF-kamailio.lumian.net",
"timestamp": 63606201099,
"version": 1
}
}
},
"{SIP_USERNAME}": {
"dialog": {
"{CALL_ID}": {
"expires": 1820,
"from": "{SIP_USERNAME}@{ACCOUNT_REALM}",
"notify": {
"body": "undefined",
"reply": 0,
"sequence": 0
},
"stalker": "BLF-kamailio.lumian.net",
"timestamp": 63606201394,
"version": 1
}
}
}
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Reset presence state
Sometimes folks subscribe for parking slots or other values that are not represented in the Lumian REST API.
POST /v2/accounts/{ACCOUNT_ID}/presence/{EXTENSION}
Where {EXTENSION} could be *3101, 110011, or whatever other extensions are allowed.
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"action": "reset"}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/presence/{EXTENSION}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/presence/{EXTENSION}',
'{"data": {"action": "reset"}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Devices
This API will use the presence_id of the device, if present; otherwise it will use the SIP user name of the device.
Post To Reset Presence State
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"action":"reset"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/presence
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/presence',
'{"data":{"action":"reset"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Post To Update Presence State
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"action":"set","state":"{PRESENCE_STATE}"}}' \
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/presence'
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/presence',
'{"data":{"action":"set","state":"{PRESENCE_STATE}"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Users
This API will use the presence_id of the user is applicable; otherwise it will use all the user's devices' states.
Post To Reset Presence State
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"action":"reset"}}' \
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/presence'
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/presence',
'{"data":{"action":"reset"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Post To Update Presence State
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"action":"reset","state":"{PRESENCE_STATE}"}}' \
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/presence'
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/presence',
'{"data":{"action":"reset","state":"{PRESENCE_STATE}"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Queues
About Queues
When you have more callers than agents to handle those calls, you can create a call queue to put the callers on hold while agents process callers in the order they arrived in.
Schema
Call Queues - FIFO call queues for serializing callers connecting to agents
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
agent_ring_timeout |
In seconds, how long to ring an agent before progressing to the next agent available | integer() |
15 |
false |
|
agent_wrapup_time |
Pre-defined wait period applied after an agent handles a customer call | integer() |
0 |
false |
|
announce |
Media ID (or appropriate media URI) of media to play when caller is about to be connected. | string() |
false |
||
announcements.interval |
Time between announcements | integer() |
30 |
false |
|
announcements.media.in_the_queue |
Played after the numeric position | string() |
true |
||
announcements.media.increase_in_call_volume |
Played if the estimated wait time has increased since the previous wait time announcement | string() |
true |
||
announcements.media.the_estimated_wait_time_is |
Played before the estimated wait time media | string() |
true |
||
announcements.media.you_are_at_position |
Played before the numeric position | string() |
true |
||
announcements.media |
Custom prompts to be played for the announcements | object() |
false |
||
announcements.position_announcements_enabled |
Whether announcements of the caller's position in the queue should be played | boolean() |
false |
||
announcements.wait_time_announcements_enabled |
Whether announcements of the estimated wait time in the queue should be played | boolean() |
false |
||
announcements |
Configuration for periodic announcements to callers waiting in the queue | object() |
false |
||
caller_exit_key |
Key caller can press while on hold to exit the queue and continue in the callflow | `string('1' | '2' | '3' | '4' |
cdr_url |
An optional HTTP URL to POST the CDR | string() |
false |
||
connection_timeout |
In seconds, how long to try to connect the caller before progressing past the queue callflow action | integer() |
3600 |
false |
|
enter_when_empty |
Allows a caller to enter a queue and wait when no agents are available | boolean() |
true |
false |
|
max_priority |
Maximum possible priority level queue will support. Can not be redefined for existing queue. | integer() |
false |
||
max_queue_size |
How many callers are allowed to wait on hold in the queue (0 for no limit) | integer() |
0 |
false |
|
moh |
Media ID (or appropriate media URI) of media to play while caller is on hold. | string() |
false |
||
name |
A friendly name for the queue | string(1..128) |
true |
||
record_caller |
When enabled, a caller's audio will be recorded | boolean() |
false |
false |
|
recording_url |
An optional HTTP URL to PUT the call recording after the call ends (and should respond to GET for retrieving the audio data) | string() |
false |
||
ring_simultaneously |
The number of agents to try in parallel when connecting a caller | integer() |
1 |
false |
|
strategy |
The queue strategy for connecting agents to callers | `string('round_robin' | 'most_idle')` | round_robin |
false |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/queues
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"id": "37139638ff5b68f155d8445178524df1",
"name": "Support Queue"
}
],
"page_size": 1,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Create a queue
PUT /v2/accounts/{ACCOUNT_ID}/queues
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"name":"Support Queue"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues',
'{"data":{"name":"Support Queue"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"agent_ring_timeout": 15,
"agent_wrapup_time": 0,
"caller_exit_key": "#",
"connection_timeout": 3600,
"enter_when_empty": true,
"id": "37139638ff5b68f155d8445178524df1",
"max_queue_size": 0,
"name": "Support Queue",
"record_caller": false,
"ring_simultaneously": 1,
"strategy": "round_robin"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Remove a queue
DELETE /v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"agent_ring_timeout": 15,
"agent_wrapup_time": 0,
"caller_exit_key": "#",
"connection_timeout": 3600,
"enter_when_empty": true,
"id": "{QUEUE_ID}",
"max_queue_size": 0,
"name": "Support Queue",
"record_caller": false,
"ring_simultaneously": 1,
"strategy": "round_robin"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Details of a specific queue
GET /v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"agent_ring_timeout": 15,
"agent_wrapup_time": 0,
"agents": [],
"caller_exit_key": "#",
"connection_timeout": 3600,
"enter_when_empty": true,
"id": "{QUEUE_ID}",
"max_queue_size": 0,
"name": "Support Queue",
"record_caller": false,
"ring_simultaneously": 1,
"strategy": "round_robin"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Update a queue's properties
POST /v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}
PATCH /v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"name":"Support Queue", "max_queue_size": 7}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}',
'{"data": {"name":"Support Queue", "max_queue_size": 7}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"agent_ring_timeout": 15,
"agent_wrapup_time": 0,
"caller_exit_key": "#",
"connection_timeout": 3600,
"enter_when_empty": true,
"id": "93d35ae9f91cf2d5ee4e1bfe59dda029",
"max_queue_size": 7,
"name": "Support Queue",
"record_caller": false,
"ring_simultaneously": 1,
"strategy": "round_robin"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
List queues stats
GET /v2/accounts/{ACCOUNT_ID}/queues/stats
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/stats
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/stats', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"current_timestamp": 63642383800,
"stats": []
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Clear a queue's roster
DELETE /v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
List queue roster (which agents are assigned to the queue)
GET /v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [],
"page_size": 0,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Set the queue roster
curl -v -X POST -H "X-Auth-Token: {AUTH_TOKEN}" -H "Content-Type: application/json" http://server.com:8000/v1/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster -d '{"data": ["f3ced8ea7bccc352a2124e8a34351e81", "e154a97ec2942599865a1591a477fd19"]}'
Quickcall
About Quickcall
Quickcall allows you to create legs between endpoints (user, device, ...).
Target Call ID
If you know ahead of time that this new quickcall leg will be interacting with an existing call leg, you can supply the existing call-id to the API call to ensure the new leg will be created on the same media server as the existing call leg.
Endpoints supported
Supported endpoints for quickcalls:
| Endpoint Type | Endpoint Id |
|---|---|
users |
{USER_ID} |
devices |
{DEVICE_ID} |
Custom Application Vars
CAVs allow you to set custom data that will appear on subsequent call events (found in Webhook and Websocket payloads) as well as the final CDR.
You can specify CAVs in two way:
- As query-string parameters:
/quickcall/{NUMBER}?foo=bar - As POST body:
{"data":{"custom_application_vars":{"foo":"bar"}}}
Schema
Request options (query string in a GET or POST body):
| Key | Type | Description |
|---|---|---|
auto_answer |
boolean() |
Tells the SIP phone to auto-answer the call, if supported |
cid-name |
string() |
Set the caller ID name (defaults to "Device QuickCall") |
cid-number |
string() |
Set the caller ID number (defaults to the {PHONE_NUMBER}) |
custom_application_vars |
object() |
Custom data to include on the call (and events related to the call) |
ignore-early-media |
boolean() |
Toggle whether to ignore early media |
media |
string('bypass', 'process') |
Toggle whether to go peer-to-peer(bypass with the RTP |
number_filter |
boolean(), regex() |
If true, remove non-alphanumeric characters. If a regex, use the first capture group as the "number" to dial. |
target_call_id |
string() |
An existing call-id used to determine what media server to create the quickcall leg on |
timeout |
integer(3..) |
In seconds, how long to ring the device(s) (defaults to 30) |
Non-blocking Quickcall
This returns a 202 immediately. The drawback is that if no endpoints are found to originate to, there will be no channel events generated to let an external application know the quickcall failed.
GET /v2/accounts/{ACCOUNT_ID}/{ENDPOINTS}/{ENDPOINT_ID}/quickcall/{NUMBER}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/{ENDPOINTS}/{ENDPOINT_ID}/quickcall/{NUMBER}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/{ENDPOINTS}/{ENDPOINT_ID}/quickcall/{NUMBER}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Blocking Quickcall
This will return a 202 if the quickcall successfully originates (meaning a channel is started). It will return errors if the originate fails to start a channel or if there aren't any endpoints available.
POST /v2/accounts/{ACCOUNT_ID}/{ENDPOINTS}/{ENDPOINT_ID}/quickcall/{NUMBER}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/{ENDPOINTS}/{ENDPOINT_ID}/quickcall/{NUMBER}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/{ENDPOINTS}/{ENDPOINT_ID}/quickcall/{NUMBER}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Execute a quick call for a device
Ring the device; once answered, connect to {PHONE_NUMBER}
In this scenario, the device is considered the callee while the {PHONE_NUMBER} side is considered the caller (helpful to know when debugging a call!).
GET /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/quickcall/{PHONE_NUMBER}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/quickcall/{PHONE_NUMBER}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/quickcall/{PHONE_NUMBER}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"export_custom_channel_vars": [
"Account-ID",
"Retain-CID",
"Authorizing-ID",
"Authorizing-Type"
],
"custom_channel_vars": {
"authorizing_id": "{DEVICE_ID}",
"authorizing_type": "device",
"inherit_codec": "false",
"retain_cid": "true",
"account_id": "{ACCOUNT_ID}"
},
"continue_on_fail": false,
"dial_endpoint_method": "simultaneous",
"outbound_callee_id_number": "{DEVICE_CALLER_ID_NUMBER}",
"outbound_callee_id_name": "{DEVICE_CALLER_ID_NAME}",
"outbound_caller_id_number": "{E164_NUMBER}",
"outbound_caller_id_name": "Device QuickCall",
"media": "process",
"ignore_early_media": true,
"timeout": 30,
"endpoints": [
{
"outbound_call_id": "{CALL_ID}-quickcall",
"custom_channel_vars": {
"auto_answer": true,
"authorizing_id": "{DEVICE_ID}",
"owner_id": "{USER_ID}",
"account_id": "{ACCOUNT_ID}",
"media_encryption_enforce_security": false,
"sip_invite_domain": "{ACCOUNT_REALM}"
},
"custom_sip_headers": {
"x_kazoo_aor": "sip:{DEVICE_SIP_USER}@{ACCOUNT_REALM}"
},
"presence_id": "{PRESENCE_ID}",
"codecs": [
"PCMU",
"PCMA"
],
"endpoint_id": "{DEVICE_ID}",
"to_did": "{E164_NUMBER}",
"to_realm": "{ACCOUNT_REALM}",
"to_username": "{DEVICE_SIP_USER}",
"to_user": "{DEVICE_SIP_USER}",
"invite_format": "username"
}
],
"application_data": {
"route": "{PHONE_NUMBER}"
},
"application_name": "transfer"
},
"status": "success",
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}"
}
Execute a quick call for a user
Ring user's devices; once answered, connect to {PHONE_NUMBER}
In this scenario, the user's devices are considered the callee while the {PHONE_NUMBER} side is considered the caller (helpful to know when debugging a call!).
GET /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/quickcall/{PHONE_NUMBER}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/quickcall/{PHONE_NUMBER}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/quickcall/{PHONE_NUMBER}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"export_custom_channel_vars": [
"Account-ID",
"Retain-CID",
"Authorizing-ID",
"Authorizing-Type"
],
"custom_channel_vars": {
"authorizing_id": "{USER_ID}",
"authorizing_type": "user",
"inherit_codec": "false",
"retain_cid": "true",
"account_id": "{ACCOUNT_ID}"
},
"continue_on_fail": false,
"dial_endpoint_method": "simultaneous",
"outbound_callee_id_number": "{DEVICE_CALLER_ID_NUMBER}",
"outbound_callee_id_name": "{DEVICE_CALLER_ID_NAME}",
"outbound_caller_id_number": "{E164_NUMBER}",
"outbound_caller_id_name": "Device QuickCall",
"media": "process",
"ignore_early_media": true,
"timeout": 30,
"endpoints": [
{
"outbound_call_id": "{CALL_ID}-quickcall",
"custom_channel_vars": {
"auto_answer": true,
"authorizing_id": "{USER_ID}",
"owner_id": "{USER_ID}",
"account_id": "{ACCOUNT_ID}",
"media_encryption_enforce_security": false,
"sip_invite_domain": "{ACCOUNT_REALM}"
},
"custom_sip_headers": {
"x_kazoo_aor": "sip:{DEVICE_SIP_USER}@{ACCOUNT_REALM}"
},
"presence_id": "{PRESENCE_ID}",
"codecs": [
"PCMU",
"PCMA"
],
"endpoint_id": "{DEVICE_ID}",
"to_did": "{E164_NUMBER}",
"to_realm": "{ACCOUNT_REALM}",
"to_username": "{DEVICE_SIP_USER}",
"to_user": "{DEVICE_SIP_USER}",
"invite_format": "username"
}
],
"application_data": {
"route": "{PHONE_NUMBER}"
},
"application_name": "transfer"
},
"status": "success",
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}"
}
Failing Requests
If issued with a GET to an unregistered device (or a user with no available devices), quickcall will return the call setup information immediately but no channel events will be generated (no events for webhooks/websockets). This can lead external apps to not know if the quickcall was originated properly or not.
Therefore, it is advisable to use POST which will block the API request until the channel starts or the quickcall fails. An example of a failing quickcall (which generated no call events):
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"error_message": "DESTINATION_OUT_OF_ORDER",
"request": {
"app_name": "crossbar",
"app_version": "4.0.0",
"application_data": {
"route": "{EXTENSION}"
},
"application_name": "transfer",
"continue_on_fail": false,
"custom_channel_vars": {
"account_id": "{ACCOUNT_ID}",
"authorizing_id": "{DEVICE_ID}",
"authorizing_type": "device",
"inherit_codec": "false",
"retain_cid": "true"
},
"dial_endpoint_method": "simultaneous",
"endpoints": [
{
"codecs": [
"PCMU",
"PCMA"
],
"custom_channel_vars": {
"account_id": "{ACCOUNT_ID}",
"authorizing_id": "{DEVICE_ID}",
"authorizing_type": "device",
"auto_answer": true,
"media_encryption_enforce_security": false,
"sip_invite_domain": "{SIP_REALM}"
},
"custom_sip_headers": {
"x_kazoo_aor": "sip:{SIP_USERNAME}@{SIP_REALM}",
"x_kazoo_invite_format": "contact"
},
"ignore_completed_elsewhere": false,
"invite_format": "contact",
"outbound_call_id": "{CALL_ID}-quickcall",
"presence_id": "{SIP_USERNAME}@{SIP_REALM}",
"to_did": "{EXTENSION}",
"to_realm": "{SIP_REALM}",
"to_user": "{SIP_USERNAME}",
"to_username": "{SIP_USERNAME}"
}
],
"event_category": "resource",
"event_name": "originate_req",
"export_custom_channel_vars": [
"Account-ID",
"Retain-CID",
"Authorizing-ID",
"Authorizing-Type",
"Outbound-Callee-ID-Number",
"Outbound-Callee-ID-Name"
],
"ignore_early_media": true,
"media": "process",
"msg_id": "{MSG_ID}",
"node": "{NODE}",
"outbound_callee_id_name": "{DEVICE_CALLER_ID_NAME}",
"outbound_callee_id_number": "{DEVICE_CALLER_ID_NUMBER}",
"outbound_caller_id_name": "Device QuickCall",
"outbound_caller_id_number": "{EXTENSION}",
"server_id": "{API_AMQP_QUEUE}",
"system_log_id": "{LOG_ID}",
"timeout": 30
}
},
"error": "500",
"message": "quickcall initiation failed",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "error",
"timestamp": "{TIMESTAMP}",
"version": "4.2.2"
}
API abuse can occur either maliciously or on accident; either way, the API server needs to protect itself from clients consuming too many server resources simultaneously.
Token Buckets
Crossbar (and Lumian in general) has a token bucket facility for tracking how many tokens a particular bucket has left. A bucket will be created for each client based on the IP of the client and the account ID being manipulated. As a client makes requests against the APIs, tokens will be deducted from the bucket until the bucket is exhausted, at which point API requests will return an HTTP 429 error.
If you receive a 429, that means you're accessing the APIs too quickly and your bucket hasn't been replenished enough to permit the request to be processed.
Configuring API Costs
By default, every request costs 1 token (typically a bucket starts with 100 tokens which refill at 10 tokens per second). Administrators can optionally increase the cost of certain APIs (or methods on an API) to discourage heavy access patterns.
In the system_config/crossbar document, administrators can create a token_costs object to set the costs associated with a particular endpoint. Crossbar will check a series of keys, in order, to find the first one that returns a non-negative cost.
- If the account is defined in the URI:
- Check
{ACCOUNT_ID}.{ENDPOINT}.{HTTP_METHOD} - Check
{ACCOUNT_ID}.{ENDPOINT} - Check
{ACCOUNT_ID} - Check
{ENDPOINT}.{HTTP_METHOD} - Check
{ENDPOINT}
- Check
- If no account id is on the URI, just check steps 4 and 5 above.
Concretely, if the request is GET /v2/accounts/{ACCOUNT_ID}/callflows, Crossbar will check:
- Check
{ACCOUNT_ID}."callflows"."GET" - Check
{ACCOUNT_ID}."callflows" - Check
{ACCOUNT_ID} - Check
"callflows"."GET" - Check
"callflows"
Note: {HTTP_METHOD} is always in all-caps for the key.
Sample configuration
Using the request above, you can configure the costs in the crossbar config in a variety of ways:
All requests to
callflowscost the same{"_id":"crossbar" ,"default":{ "token_costs":{ "callflows":2 } } }
callflowsvary in cost depending on method:{"_id":"crossbar" ,"default":{ "token_costs":{ "callflows":{ "GET":1 ,"PUT":5 ,"POST":5 ,"DELETE":1 } } } }
Deduct flat amount for an account:
{"_id":"crossbar" ,"default":{ "token_costs":{ "{ACCOUNT_ID}":2 } } }
Deduct flat amount for an account for a specific endpoint:
{"_id":"crossbar" ,"default":{ "token_costs":{ "{ACCOUNT_ID}":{ "callflows":10 } } } }
Disable token costs
If an administrator prefers to not use rate-limiting, or wants to set a flat-rate for all requests, configure the token_costs with just a number (0 to disable):
Disable token buckets
{"_id":"crossbar" ,"default":{ "token_costs":0 } }
Flat cost across APIs - any integer > 0. This is how the default Crossbar operates.
{"_id":"crossbar" ,"default":{ "token_costs":1 } }
Configuring Token Bucket start parameters
To configure the token buckets themselves, look in the system_config/token_buckets document.
max_bucket_tokens: How many tokens to fill a bucket up to, defaulting to 100.tokens_fill_rate: How many tokens to add to a non-full bucket, defaulting to 10.tokens_fill_time: What time period to wait before addingtoken_fill_ratetokens, defaults to "second". Could also be "minute", "hour", or "day".
So the default bucket will have a maximum of 100 tokens, refilling at 10 tokens per second.
Per-Application configuration
An administrator can change the above parameters on a per-application basis. This would allow larger token limits for Crossbar-related buckets, and smaller limits for Callflow-related (for instance). Configure these per-application settings in the token_buckets document by creating an object with the application name as the key, and the parameters above as sub keys.
{"_id":"token_buckets" ,"default":{ "crossbar":{ "max_bucket_tokens":250 ,"tokens_fill_rate":10 ,"tokens_fill_time":"minute" } ,"callflow":{ "max_bucket_tokens":50 ,"tokens_fill_rate":5 ,"tokens_fill_time":"hour" } } }
Special Cases
There are some APIs that have extra rate limiting options for administrators to tweak.
Quickcall
Administrators can increase the cost of the quickcall API to keep call volume low from this endpoint.
Given a GET /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/quickcall/{NUMBER}
- Check
{ACCOUNT_ID}."devices"."GET"."quickcall" - Check
{ACCOUNT_ID}."devices"."quickcall" - Check
{ACCOUNT_ID}."quickcall" - Check
"devices"."GET"."quickcall" - Check
"devices"."quickcall"
So a configuration to make all quickcall requests cost 20 tokens would look like:
{"_id":"crossbar" ,"default":{ "token_costs":{ "devices":{ "quickcall":20 } } } }
Rate Limits
About Rate Limits
The rate-limits API allows setting per-second and per-minute incoming SIP packets rate limits for devices and whole accounts (realms) that can be used at SBC level. The system level packet rate limits can also be set to protect the whole cluster.
Modify Rate Limits Using API
Using Crossbar to modify rate limits is very simple. There are only three actions:
GET- Gets the current rate limits on the document (account or device)POST- Updates the rate limits on the document (account or device)DELETE- Removes the rate limits object from the document (account or device)
JSON object has self-describing structure. The name of the root key is rate_limits.
The application-level system-wide configuration resides in system_config/frontier document and its syntax is equal to the account-level documents.
Account-Level Document
Account-level document contains two sections:
- The
accountsection sets rate limits for the entire account - The
devicesection sets rate limits for devices inside the account (if not overwritten by device-level rate limits) - Both sections contain
registrations,invitesandtotal_packets" keys with integer values of possible number of packets withinper_minuteandper_secondsections
Doc Example
Sample Response:
{
"data": {
"account": {
"per_minute": {
"registrations": 100,
"invites": 100,
"total_packets": 1000
},
"per_second": {
"registrations": 5,
"invites": 5,
"total_packets": 20
}
},
"device": {
"per_minute": {
"registrations": 10,
"invites": 10,
"total_packets": 100
},
"per_second": {
"registrations": 2,
"invites": 4,
"total_packets": 10
}
}
}
}
Fetch Account's Rate Limits
GET /v2/accounts/{ACCOUNT_ID}/rate_limits
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/rate_limits
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/rate_limits', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Update Account's Rate Limits
POST /v2/accounts/{ACCOUNT_ID}/rate_limits
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"account": {"per_minute": {"total_packets": 3000},"per_second": {"total_packets": 50}},"device": {"per_minute": {"total_packets": 300},"per_second": {"total_packets": 5}}}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/rate_limits
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/rate_limits',
'{"data": {"account": {"per_minute": {"total_packets": 3000},"per_second": {"total_packets": 50}},"device": {"per_minute": {"total_packets": 300},"per_second": {"total_packets": 5}}}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Remove Account's Rate Limits
DELETE /v2/accounts/{ACCOUNT_ID}/rate_limits
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/rate_limits
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/rate_limits', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Device-Level Document
Device-level document contains is one level "higher" and contains only the "device" part which contains registrations, invites and total_packets keys with integer values of possible number of packets within per_minute and per_second sections.
Device-Level Example
Sample Response:
{
"data": {
"per_minute": {
"registrations": 60,
"invites": 60,
"total_packets": 180
},
"per_second": {
"registrations": 2,
"invites": 4,
"total_packets": 7
}
}
}
Fetch Device's Rate Limits
GET /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/rate_limits
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/rate_limits
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/rate_limits', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Update Device's Rate Limits
POST /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/rate_limits
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"per_minute": {"registrations": 60,"invites": 60,"total_packets": 180},"per_second": {"registrations": 2,"invites": 4,"total_packets": 7}}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/rate_limits
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/rate_limits',
'{"data": {"per_minute": {"registrations": 60,"invites": 60,"total_packets": 180},"per_second": {"registrations": 2,"invites": 4,"total_packets": 7}}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Remove Device's Rate Limits
DELETE /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/rate_limits
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/rate_limits
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/rate_limits', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Call Rates
About Rates
System operators can create multiple ratedecks and assign those ratedecks to their accounts or sub-accounts via service plans.
If no ratedeck has been assigned, the system ratedeck will be used (backwards-compatible operation).
Flow is:
- System admin creates a ratedeck CSV and uploads it using the
tasksAPI endpoint. a. Optionally assign aratedeck_nameto each row to add rates to different ratedeck databases - Create a service plan for ratedecks a. Add the service plan to account(s)
- When
{ACCOUNT_ID}has a rate-able call, Lumianhotornotapplication will lookup what ratedeck database to use a. If using the trie algorithm,hotornotwill find the PID with that ratedeck's trie and query it b. Otherwise, use the view of the ratedeck database to query for rates
Schema
Defines a rate for a given prefix
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
account_id |
Reseller's account ID | string() |
false |
||
caller_id_numbers |
String of caller id prefixes separated by ':' | string() |
false |
||
carrier |
Friendly name for the carrier providing this rate | string() |
false |
||
description |
Friendly description of the rate | string() |
false |
||
direction.[] |
`string('inbound' | 'outbound')` | false |
||
direction |
Apply this rate based on the direction of the call (relative to FreeSWITCH) | `array(string('inbound' | 'outbound'))` | false |
|
internal_rate_cost |
The per-min rate charged by the upstream provider | number() |
false |
||
iso_country_code |
Country code this rate applies to | string() |
false |
||
options.[] |
string() |
false |
|||
options |
List of options this rate is good for, to be matched against a customer's options | array(string()) |
false |
||
prefix |
E.164 prefix (ignoring the +) | integer() |
true |
||
rate_cost |
The per-min rate charged to the downstream customer | number() |
true |
||
rate_increment |
The time slice, in seconds, to bill in. | integer() |
false |
||
rate_minimum |
The minimum time slice, in seconds to bill a call | integer() |
false |
||
rate_name |
Friendly name of the rate | string() |
false |
||
rate_nocharge_time |
If the call duration is shorter than this threshold (seconds), the call is not billed | integer() |
false |
||
rate_suffix |
Suffix applied to rate name | string() |
false |
||
rate_surcharge |
The upfront cost of connecting the call | number() |
false |
||
rate_version |
Rate version | string() |
false |
||
ratedeck_id |
ID of the ratedeck this rate belongs to | string() |
false |
||
routes.[] |
string() |
false |
|||
routes |
List of regexps that match valid DIDs for this rate | array(string()) |
false |
||
weight |
Ordering against other rates, 1 being most preferred, 100 being least preferred | integer() |
false |
List All Rates
GET /v2/rates
Sample Request:
curl -v -X GET \
-H "Accept: application/json" \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/rates
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/rates', {
headers: {
'Accept': 'application/json',
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"cost": 0.1,
"description": "Default US Rate",
"id":"{RATE_ID}",
"prefix": "1",
"surcharge": 0
}
],
"page_size": 1,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Switch the Accept header to text/csv to get the page as a CSV.
Upload a Ratedeck CSV
Uploading CSVs has moved to using the 'tasks' API, which provides a more generic interface. See the rates task documentation for more details on uploading rates.
Deprecated version
POST /v2/rates
For bulk uploading. CSV rows can be formatted in the following ways:
Prefix, ISO, Desc, RatePrefix, ISO, Desc, InternalRate, RatePrefix, ISO, Desc, Surcharge, InternalRate, RatePrefix, ISO, Desc, InternalSurcharge, Surcharge, InternalRate, RatePrefix, ISO, Desc, InternalSurcharge, Surcharge, Internal_rate, Rate, Routes, RateIncrement, RateMinimum, Direction
A US-1 row might look like:
1, "US-1", "US default rate", 0.01
This API will return an HTTP 202 and process the CSV in a background process.
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: text/csv" \
--data-binary @/path/to/rates.csv \
http://{SERVER}:8000/v2/rates
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/rates',
'@/path/to/rates.csv',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'text/csv'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data":"attempting to insert rates from the uploaded document",
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Create a new rate
PUT /v2/rates
The routes key will be populated for you, using the prefix, unless you specify the routes list here.
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{ \
"prefix":"1", \
"iso_country_code": "US", \
"description": "Default US Rate", \
"rate_cost": 0.1 \
}}' \
http://{SERVER}:8000/v2/rates
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/rates',
'{"data":{ \\\n "prefix":"1", \\\n "iso_country_code": "US", \\\n "description": "Default US Rate", \\\n "rate_cost": 0.1 \\\n }}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"description": "Default US Rate",
"id": "561d9c4c75950235d5565d138752452c",
"iso_country_code": "US",
"prefix": "1",
"rate_cost": 0.1,
"rate_increment": 60,
"rate_minimum": 60,
"rate_nocharge_time": 0,
"rate_surcharge": 0,
"routes": [
"^\\+?1.+$"
]
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Remove a rate
DELETE /v2/rates/{RATE_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/rates/{RATE_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/rates/{RATE_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token":"{AUTH_TOKEN}",
"data": {
"description": "Default US Rate",
"id": "{RATE_ID}",
"iso_country_code": "US",
"prefix": "1",
"rate_cost": 0.1,
"rate_increment": 60,
"rate_minimum": 60,
"rate_nocharge_time": 0,
"rate_surcharge": 0
},
"request_id":"{REQUEST_ID}",
"revision":"{REVISION}",
"status":"success"
}
Fetch a rate
GET /v2/rates/{RATE_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/rates/{RATE_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/rates/{RATE_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"description": "Default US Rate",
"id": "{RATE_ID}",
"iso_country_code": "US",
"prefix": "1",
"rate_cost": 0.1,
"rate_increment": 60,
"rate_minimum": 60,
"rate_nocharge_time": 0,
"rate_surcharge": 0,
"routes": [
"^\\+?1.+$"
]
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Patch a rate's properties
PATCH /v2/rates/{RATE_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"description": "Default North America Rate"}}' \
http://{SERVER}:8000/v2/rates/{RATE_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/rates/{RATE_ID}',
'{"data": {"description": "Default North America Rate"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"description": "Default North America Rate",
"id": "{RATE_ID}",
"iso_country_code": "US",
"prefix": "1",
"rate_cost": 0.1,
"rate_increment": 60,
"rate_minimum": 60,
"rate_nocharge_time": 0,
"rate_surcharge": 0,
"routes": [
"^\\+?1.+$"
]
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Change a rate doc
POST /v2/rates/{RATE_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{ \
"description": "Default North America Rate", \
"iso_country_code": "US", \
"prefix": "1", \
"rate_cost": 0.1, \
"rate_increment": 60, \
"rate_minimum": 60, \
"rate_nocharge_time": 0, \
"rate_surcharge": 0, \
"routes": ["^\\+?1.+$"] \
}}' \
http://{SERVER}:8000/v2/rates/{RATE_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/rates/{RATE_ID}',
'{"data":{ \\\n "description": "Default North America Rate", \\\n "iso_country_code": "US", \\\n "prefix": "1", \\\n "rate_cost": 0.1, \\\n "rate_increment": 60, \\\n "rate_minimum": 60, \\\n "rate_nocharge_time": 0, \\\n "rate_surcharge": 0, \\\n "routes": ["^\\\\+?1.+$"] \\\n }}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"description": "Default North America Rate",
"id": "{RATE_ID}",
"iso_country_code": "US",
"prefix": "1",
"rate_cost": 0.1,
"rate_increment": 60,
"rate_minimum": 60,
"rate_nocharge_time": 0,
"rate_surcharge": 0,
"routes": [
"^\\+?1.+$"
]
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Rate a phone number
This API requires that the backend app hotornot is running.
GET /v2/rates/number/{PHONE_NUMBER}
The {PHONE_NUMBER} must be reconcilable (see your reconcile_regex for that criteria).
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/rates/number/{PHONE_NUMBER}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/rates/number/{PHONE_NUMBER}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Success Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"Base-Cost": 0.1,
"E164-Number": "+{PHONE_NUMBER}",
"Prefix": "1",
"Rate": 0.1,
"Rate-Description": "Default US Rate",
"Rate-Increment": "60",
"Rate-Minimum": "60",
"Surcharge": 0.0
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Error: unrateable phone number
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"message": "No rate found for this number"
},
"error": "500",
"message": "No rate found for this number",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Call Recordings
About Recordings
Recordings endpoint provides a way to access call recordings.
Fetch recordings
GET /v2/accounts/{ACCOUNT_ID}/recordings
GET /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/recordings
Lists the call recording with pagination and filtering.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/recordings
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/recordings', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch recording media or document
GET /v2/accounts/{ACCOUNT_ID}/recordings/{RECORDING_ID}
Gets a specific recording document.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/recordings/{RECORDING_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/recordings/{RECORDING_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Gets a specific recording document attachment if available.
Mind the Accept header in example below.
For clients that do not support setting the Accept header, a query string parameter can be included: ?accept=audio/mpeg.
Optional parameter inline can be either true or false.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Accept: audio/mpeg" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/recordings/{RECORDING_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/recordings/{RECORDING_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Accept': 'audio/mpeg'
}
});
Remove a recording
DELETE /v2/accounts/{ACCOUNT_ID}/recordings/{RECORDING_ID}
This will delete the metadata document. If the binary data is stored on the metadata document (instead of on a storage provider), it will also be deleted. Recordings stored on storage providers will not be deleted.
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/recordings/{RECORDING_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/recordings/{RECORDING_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Registrations
About Registrations
The Registrations API provides an easy way to see and manage current registrations.
Flush All Account's Registrations
DELETE /v2/accounts/{ACCOUNT_ID}/registrations
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/registrations
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/registrations', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": "ok",
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
List Account's Registrations
GET /v2/accounts/{ACCOUNT_ID}/registrations
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/registrations
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/registrations', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{"account_name": "{ACCOUNT_NAME}",
"account_realm": "{ACCOUNT_REALM}",
"authorizing_id": "{DEVICE_ID}",
"authorizing_type": "device",
"call_id": "792957271@10.26.0.158",
"contact": "sip:{SIP_USERNAME}@{IP.AD.DR.ESS}:{PORT}...",
"contact_ip": "{IP.AD.DR.ESS}",
"contact_port": "{PORT}",
"event_timestamp": 63581321366,
"expires": 257,
"from_host": "{ACCOUNT_REALM}",
"from_user": "{SIP_USERNAME}",
"network_ip": "undefined",
"network_port": "undefined",
"original_contact": "sip:{SIP_USERNAME}@{IP.AD.DR.ESS}:{PORT}...",
"owner_id": "{USER_ID}",
"proxy_ip": "{KAMAILIO_IP}",
"proxy_port": "{KAMAILIO_PORT}",
"realm": "{ACCOUNT_REALM}",
"suppress_unregister_notify": true,
"to_host": "{ACCOUNT_REALM}",
"to_user": "{SIP_USERNAME}",
"user_agent": "Yealink SIP-T38G 38.0.0.115",
"username": "{SIP_USERNAME}"
}
],
"page_size": 1,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Flush A Specific Device's Registration
DELETE /v2/accounts/{ACCOUNT_ID}/registrations/{USERNAME}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/registrations/{USERNAME}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/registrations/{USERNAME}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": "ok",
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Fetch Account Registration Count
GET /v2/accounts/{ACCOUNT_ID}/registrations/count
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/registrations/count
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/registrations/count', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"count": 4
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Resource Selectors
About Resource Selectors
Resource selectors is a new way to route Offnet-calls. Old way used regex rules and "flags" for select proper resources (gateways). With new "resource selectors" you have several small modules, which can be organized in "chain" (rules).
Schema
Schema for resource selector document
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
name |
Selector name | string() |
true |
||
resource |
Resource ID | string() |
true |
||
selector |
Selector data | string() |
true |
||
start_time |
Start time (Gregorian seconds) | integer() |
false |
||
stop_time |
Stop time (Gregorian seconds) | integer() |
false |
||
value |
Extra selector data | string() |
false |
Fetch
GET /v2/resource_selectors/rules
Sample Request:
curl -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
http://{SERVER}:8000/v2/resource_selectors/rules
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/resource_selectors/rules', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
});
Sample Response:
{
"data": {
"rules": [
{
"get_resources": {}
},
{
"filter_list": {
"value_a": "request:Flags",
"value_b": "resource:flags",
"action": "keep"
}
},
{
"filter_regex": {
"value_a": "number",
"value_b": "resource:rules",
"action": "keep",
"mode": "empty_fail"
}
},
{
"filter_regex": {
"value_a": "cid_number",
"value_b": "resource:cid_rules",
"action": "keep",
"mode": "empty_ok"
}
},
{
"order": {
"value": "resource:weight_cost",
"direction": "ascend"
}
}
],
"id": "resource_selector_rules"
},
"revision": "{REVISION_ID}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Update rules
POST /v2/resource_selectors/rules
Sample Request:
curl -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data": {"rules": [ \
{"get_resources":{}}, \
{"filter_list": {"value_a": "request:Flags", "value_b": "resource:flags", "action": "keep"}} \
]}}' \
http://{SERVER}:8000/v2/resource_selectors/rules
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/resource_selectors/rules',
'{"data": {"rules": [ \\\n {"get_resources":{}}, \\\n {"filter_list": {"value_a": "request:Flags", "value_b": "resource:flags", "action": "keep"}} \\\n ]}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Sample Response:
{
"data": {
"rules": [
{
"get_resources": {}
},
{
"filter_list": {
"value_a": "request:Flags",
"value_b": "resource:flags",
"action": "keep"
}
},
],
"id": "resource_selector_rules"
},
"revision": "{REVISION_ID}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Database selectors
Database selectors - selectors stored in special database. Name of this database account/XX/XX/XXXXXXXXXXXXXXXXXXXXXXXXXXXX-selectors, where XXX...XXX - Account ID. System-wide selectors database use Master Account ID.
Each selector is separate document:
Sample Response:
{
"_id": "00066509d2648ede97e30635aa5ba097",
"_rev": "1-5c13654b7a5521778791e6657789bb56",
"pvt_type": "resource_selector",
"name": "prefix",
"selector": "7495",
"resource": "RES-4",
"value": "0.37"
}
- name - all selectors with same name used for filtering/sorting resources
- selector - this value used for filtering/sorting
- resource - Resource ID
- value - additional value, which can be used for sorting
List selectors
List selectors names
GET /v2/accounts/{ACCOUNT_ID}/resource_selectors/name
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_selectors/name
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_selectors/name', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": [
{
"lcr2": 12
},
{
"lcr": 36039
}
],
"revision": "{REVISION_ID}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Here we see 2 selectors, lcr with 12 documents and lcr2 with 36039 documents.
GET /v2/accounts/{ACCOUNT_ID}/resource_selectors/name/{SELECTOR_NAME}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_selectors/name/lcr2
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_selectors/name/lcr2', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": [
{
"RES-4": 1
},
{
"RES-3": 8
},
{
"RES-2": 3
}
],
"revision": "{REVISION_ID}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
List resources
GET /v2/accounts/{ACCOUNT_ID}/resource_selectors/resource
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_selectors/resource
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_selectors/resource', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": [
{
"RES-4": 36040
},
{
"RES-3": 8
},
{
"RES-2": 3
}
],
"revision": "{REVISION_ID}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
In this example we see resources RES-2 with 3 documents, RES-3 with 8 documents and RES-4 with 1 document.
GET /v2/accounts/{ACCOUNT_ID}/resource_selectors/resource/{RESOURCE_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_selectors/resource/RES-4
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_selectors/resource/RES-4', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": [
{
"lcr2": 1
},
{
"lcr": 36039
}
],
"revision": "{REVISION_ID}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Show selectors
GET /v2/accounts/{ACCOUNT_ID}/resource_selectors/resource/{RESOURCE_ID}/name/{SELECTOR_NAME}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_selectors/resource/RES-4/name/lcr
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_selectors/resource/RES-4/name/lcr', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": [
{
"74956785833": "0.20"
},
{
"74999055927": "0.30"
},
...
"74991234",
"74951234",
...
{
"7495": "0.40"
},
{
"7499": "0.40"
}
],
"revision": "{REVISION_ID}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Here we see selectors for resource RES-4 with selector name lcr. Resulted list can be simple list of strings or list of objects, its depending if there additional value or not.
Manage selectors
Manage (import/delete) resource selectors made via Lumian tasks (CSV file).
Category resource_selectors, action import or delete.
CSV columns:
* mandatory
* name
* selector
* resource
* optional
* stat_time
* stop_time
* value
Resource Templates
About Resource Templates
Schema
Fetch
GET /v2/accounts/{ACCOUNT_ID}/resource_templates
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_templates
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_templates', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create
PUT /v2/accounts/{ACCOUNT_ID}/resource_templates
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_templates
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_templates',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Fetch
GET /v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Change
POST /v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Patch
PATCH /v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove
DELETE /v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Resources
About Resources
Resources represent external assets such as TDM hardware, SIP trunks, trans-coders, and other remote termination/originating call services or equipment.
There are two levels of resources, global (or system-wide), and per-account (bring your own carrier). The JSON format for both is identical; only their location in the Lumian database structure defines whether they are globally available or not.
When interacting with an account's resources, the URL structure is as one would expect: /v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID}. To modify the global resources, simply omit /accounts/{ACCOUNT_ID} from the URL (your auth token must have super-duper admin privileges).
To perform bulk resource operations use the collections endpoints.
There are two deprecated API endpoints, global_resources and local_resources. These should continue to work as before, but it is recommended to use resources instead, using the presence of an account id to toggle whether the resource is global or not.
About Adding Bulk Numbers
It is possible to add numbers, in bulk, to an account using the Jobs API below. If a job fails to run, there is a recovery process that runs periodically to attempt to resume stalled jobs.
You can configure how frequently the system checks for failed jobs in system_config/crossbar.resources, using the job_recover_timeout_s key (defaults to 6 hours).
You can configure how what is considered a 'stalled' job by defining how old the job is (the last time the job document was modified) relative to the current time. Configure in system_config/crossbar.resources, using the job_recover_threshold_s key (defaults to 1 hour). If a job is not completed, and hasn't been modified in over an hour, there's a good chance the job executor died. A new job executor will be started to pick up where the old one left off.
Schema
Schema for resources
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
caller_id_options.type |
Caller ID type to choose | `string('internal' | 'external' | 'emergency')` | |
caller_id_options |
Caller ID options | object() |
false |
||
cid_rules.[] |
string() |
false |
|||
cid_rules |
Regexps to match against caller ID | array(string()) |
false |
||
classifiers./.+/.emergency |
Determines if the resource represents emergency services | boolean() |
false |
false |
|
classifiers./.+/.enabled |
Determines if the resource is currently enabled | boolean() |
true |
false |
|
classifiers./.+/.prefix |
A string to prepend to the dialed number or capture group of the matching rule | string(0..64) |
false |
||
classifiers./.+/.regex |
regexp to match against dialed number | string() |
false |
||
classifiers./.+/.suffix |
A string to append to the dialed number or capture group of the matching rule | string(0..64) |
false |
||
classifiers./.+/.weight_cost |
A value between 0 and 100 that determines the order of resources when multiple can be used | integer() |
50 |
false |
|
classifiers./.+/ |
object() |
false |
|||
classifiers |
Resource classifiers to use as rules when matching against dialed numbers | object() |
false |
||
emergency |
Determines if the resource represents emergency services | boolean() |
false |
false |
|
enabled |
Determines if the resource is currently enabled | boolean() |
true |
false |
|
flags.[] |
string() |
false |
|||
flags |
A list of flags that can be provided on the request and must match for the resource to be eligible | array(string()) |
[] |
false |
|
flat_rate_blacklist |
Regex for determining if a number should not be eligible for flat-rate trunking | string() |
false |
||
flat_rate_whitelist |
Regex for determining if the number is eligible for flat-rate trunking | string() |
false |
||
format_from_uri |
When set to true requests to this resource will have a reformatted SIP From Header | boolean() |
false |
||
formatters |
Schema for request formatters | object() |
false |
||
from_account_realm |
When formatting SIP From on outbound requests, use the calling account's SIP realm | boolean() |
false |
false |
|
from_uri_realm |
When formatting SIP From on outbound requests this can be used to override the realm | string() |
false |
||
gateway_strategy |
The strategy of choosing gateways from list: sequential or random | `string('sequential' | 'random')` | false |
|
gateways.[].bypass_media |
The resource gateway bypass media mode | boolean() |
false |
||
gateways.[].caller_id_type |
The type of caller id to use | `string('internal' | 'external' | 'emergency')` | |
gateways.[].channel_selection |
Automatic selection of the channel within the span: ascending starts at 1 and moves up; descending is the opposite | `string('ascending' | 'descending')` | ascending |
false |
gateways.[].codecs.[] |
`string('G729' | 'PCMU' | 'PCMA' | 'G722_16' | |
gateways.[].codecs |
A list of single list codecs supported by this gateway (to support backward compatibility) | `array(string('G729' | 'PCMU' | 'PCMA' | 'G722_16' |
gateways.[].custom_sip_headers.in |
Custom SIP Headers to be applied to calls inbound to Lumian from the endpoint | #/definitions/custom_sip_headers | false |
||
gateways.[].custom_sip_headers.out |
Custom SIP Headers to be applied to calls outbound from Lumian to the endpoint | #/definitions/custom_sip_headers | false |
||
gateways.[].custom_sip_headers.^[a-zA-z0-9_\-]+$ |
The SIP header to add | string() |
false |
||
gateways.[].custom_sip_headers |
A property list of SIP headers | object() |
false |
||
gateways.[].custom_sip_interface |
The name of a custom SIP interface | string() |
false |
||
gateways.[].enabled |
Determines if the resource gateway is currently enabled | boolean() |
true |
false |
|
gateways.[].endpoint_type |
What type of endpoint is this gateway | `string('sip' | 'freetdm' | 'skype' | 'amqp')` |
gateways.[].force_port |
Allow request only from this port | boolean() |
false |
false |
|
gateways.[].format_from_uri |
When set to true requests to this resource gateway will have a reformatted SIP From Header | boolean() |
false |
||
gateways.[].from_uri_realm |
When formatting SIP From on outbound requests this can be used to override the realm | string() |
false |
||
gateways.[].invite_format |
The format of the DID needed by the underlying hardware/gateway | `string('route' | 'username' | 'e164' | 'npan' |
gateways.[].invite_parameters.dynamic.[] |
`string() | string() | string('zone') | object()` | |
gateways.[].invite_parameters.dynamic |
A list of properties that, if found on the inbound call, should be added as an INVITE parameter | array() |
false |
||
gateways.[].invite_parameters.static.[] |
string() |
false |
|||
gateways.[].invite_parameters.static |
A list of static values that should be added as INVITE parameters | array(string()) |
false |
||
gateways.[].invite_parameters |
object() |
false |
|||
gateways.[].media.fax_option |
Is T.38 Supported? | boolean() |
false |
||
gateways.[].media.rtcp_mux |
RTCP protocol messages mixed with RTP data | boolean() |
false |
||
gateways.[].media |
The media parameters for the resource gateway | object() |
false |
||
gateways.[].password |
SIP authentication password | string(0..32) |
false |
||
gateways.[].port |
This resource gateway port | integer() |
5060 |
false |
|
gateways.[].prefix |
A string to prepend to the dialed number or capture group of the matching rule | string(0..64) |
false |
||
gateways.[].progress_timeout |
The progress timeout to apply to the resource gateway | integer() |
false |
||
gateways.[].realm |
This resource gateway authentication realm | string(0..64) |
false |
||
gateways.[].route |
A statically configured SIP URI to route all call to | string() |
false |
||
gateways.[].server |
This resource gateway server | string(1..128) |
true |
||
gateways.[].skype_interface |
The name of the Skype interface to route the call over | string() |
false |
||
gateways.[].skype_rr |
Determines whether to round-robin calls amongst all interfaces (overrides "skype_interface" setting) | boolean() |
true |
false |
|
gateways.[].span |
The identity of the hardware on the media server | string() |
false |
||
gateways.[].suffix |
A string to append to the dialed number or capture group of the matching rule | string(0..64) |
false |
||
gateways.[].username |
SIP authentication username | string(0..32) |
false |
||
gateways |
A list of gateways available for this resource | array(object()) |
true |
||
grace_period |
The amount of time, in seconds, to wait before starting another resource | integer() |
5 |
false |
|
ignore_flags |
When set to true this resource is used if the rules/classifiers match regardless of flags | boolean() |
false |
||
media |
Media options for resources | #/definitions/endpoint.media | false |
||
name |
A friendly name for the resource | string(1..128) |
true |
||
require_flags |
When set to true this resource is ignored if the request does not specify outbound flags | boolean() |
false |
||
rules.[] |
string() |
false |
|||
rules |
A list of regular expressions of which one must match for the rule to be eligible, they can optionally contain capture groups | array(string()) |
[] |
false |
|
rules_test.[] |
string() |
false |
|||
rules_test |
A list of regular expressions of which if matched denotes a test rule | array(string()) |
[] |
false |
|
weight_cost |
A value between 0 and 100 that determines the order of resources when multiple can be used | integer() |
50 |
false |
custom_sip_headers
Custom SIP headers applied to an INVITE
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
^[a-zA-z0-9_\-]+$ |
The SIP header to add | string() |
false |
endpoint.media
Schema for endpoint media options
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
audio.codecs.[] |
`string('OPUS' | 'CELT@32000h' | 'G7221@32000h' | 'G7221@16000h' | |
audio.codecs |
A list of audio codecs the endpoint supports | `array(string('OPUS' | 'CELT@32000h' | 'G7221@32000h' | 'G7221@16000h' |
audio |
The audio media parameters | object() |
{} |
false |
|
bypass_media |
Default bypass media mode (The string type is deprecated, please use this as a boolean) | `boolean() | string('true' | 'false' | 'auto')` |
encryption.enforce_security |
Is Encryption Enabled? | boolean() |
false |
false |
|
encryption.methods.[] |
`string('zrtp' | 'srtp')` | false |
||
encryption.methods |
Supported Encryption Types | `array(string('zrtp' | 'srtp'))` | [] |
false |
encryption |
Encryption Parameters | object() |
{} |
false |
|
fax_option |
Is T.38 Supported? | boolean() |
false |
||
ignore_early_media |
The option to determine if early media from the endpoint should always be ignored | boolean() |
false |
||
progress_timeout |
The progress timeout to apply to the endpoint (seconds) | integer() |
false |
||
video.codecs.[] |
`string('H261' | 'H263' | 'H264' | 'VP8')` | |
video.codecs |
A list of video codecs the endpoint supports | `array(string('H261' | 'H263' | 'H264' | 'VP8'))` |
video |
The video media parameters | object() |
{} |
false |
formatters
Schema for request formatters
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
^[[:alnum:]_]+$ |
Key to match in the route request JSON | `array(#/definitions/formatters.format_options) | #/definitions/formatters.format_options` | false |
formatters.format_options
Schema for formatter options
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
direction |
Only apply the formatter on the relevant request direction | `string('inbound' | 'outbound' | 'both')` | |
match_invite_format |
Applicable on fields with SIP URIs. Will format the username portion to match the invite format of the outbound request. | boolean() |
false |
||
prefix |
Prepends value against the result of a successful regex match | string() |
false |
||
regex |
Matches against the value, with optional capture group | string() |
false |
||
strip |
If set to true, the field will be stripped from the payload | boolean() |
false |
||
suffix |
Appends value against the result of a successful regex match | string() |
false |
||
value |
Replaces the current value with the static value defined | string() |
false |
INVITE Parameters
The INVITE parameters object defines both static and dynamic parameters that should be added to the request URI.
Static parameters are added 'as-is' and can be any format. However, they should follow the SIP standard for the header field format and should not include a semi-colon.
Dynamic parameters obtain the value from properties of the initiating call (requestor) if present, and are ignored if not. Dynamic parameters can be defined either as a string or an object. When defined as a string the property is extracted from the requestor and if found the resulting value used without modification as an INVITE parameter. When defined as an object both a tag as well as a key property must be defined. The key property is used to extract the value from the requestor and the tag is appended as the INVITE parameter name. By default the INVITE parameter name and value are separated by an equals sign but this can be overridden by providing a separator property.
For example, if a resource gateway contains the following object:
"invite_parameters": {
"dynamic": [
"custom_channel_vars.pass-through",
{
"tag": "id",
"key": "custom_channel_vars.account_id"
}
],
"static": [
"npid"
]
}
and assuming the requesting call has pass-through (with value pass-through=0288) as well as account_id (with value XXXX) custom channel variables it will result in an INVITE request URI such as:
INVITE sip:+14158867900@10.26.0.88;npid;id=XXXX;pass-through=0288 SIP/2.0
rules_test.[]
The rules_test object defines an array of regular expressions for test patterns of the given resource.
For example, if the resource handles emergency routes in North America:
"rules_test": [
"^\\+{0,1}(933)$"
],
defining 933 as a test route, will inform teletype this emergency call is a test and will be reflected as such in the notification.
Fetch
GET /v2/accounts/{ACCOUNT_ID}/resources
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{"enabled": true,
"id": "{RESOURCE_ID}",
"name": "Carrier1",
"weight": "50"
},
{"enabled": true,
"id": "{RESOURCE_ID}",
"name": "Carrier2",
"weight": "50"
}
],
"page_size": 2,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION_ID}",
"status": "success"
}
Create a new resource
PUT /v2/accounts/{ACCOUNT_ID}/resources
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"name":"Carrier 3", "gateways":[]}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources',
// '{"data":{"name":"Carrier 3", "gateways":[]}}',
{
'data': {
'name': 'Carrier 3',
'gateways': []
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"emergency": false,
"enabled": true,
"flags": [],
"gateways": [],
"grace_period": 5,
"id": "{RESOURCE_ID}",
"media": {
"audio": {
"codecs": ["PCMU"]
},
"video": {
"codecs": []
}
},
"name": "Carrier 3",
"rules": [],
"weight_cost": 50
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION_ID}",
"status": "success"
}
Remove a resource
DELETE /v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"caller_id_options": {
"type": "external"
},
"emergency": false,
"enabled": true,
"flags": [],
"gateways": [
{
"channel_selection": "ascending",
"codecs": ["PCMU", "PCMA"],
"custom_sip_headers": {},
"emergency": false,
"enabled": true,
"endpoint_type": "sip",
"format_from_uri": false,
"invite_format": "route",
"password": "DrWoody",
"prefix": "+1",
"progress_timeout": "6",
"realm": "carrier1.com",
"server": "carrier1.com",
"skype_rr": true,
"suffix": "100",
"username": "blazemore"
}
],
"grace_period": 5,
"id": "{RESOURCE_ID}",
"media": {
"audio": {
"codecs": ["PCMU"]
},
"video": {
"codecs": []
}
},
"name": "Carrier 3",
"peer": false,
"rules": [
"^\\+{0,1}1{0,1}(\\d{10})$"
],
"type": "local",
"weight_cost": "50"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION_ID}",
"status": "success"
}
Fetch a resource
GET /v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"caller_id_options": {
"type": "external"
},
"emergency": false,
"enabled": true,
"flags": [],
"gateways": [
{
"channel_selection": "ascending",
"codecs": ["PCMU", "PCMA"],
"custom_sip_headers": {},
"emergency": false,
"enabled": true,
"endpoint_type": "sip",
"format_from_uri": false,
"invite_format": "route",
"password": "DrWoody",
"prefix": "+1",
"progress_timeout": "6",
"realm": "carrier1.com",
"server": "carrier1.com",
"skype_rr": true,
"suffix": "100",
"username": "blazemore"
}
],
"grace_period": 5,
"id": "{RESOURCE_ID}",
"media": {
"audio": {
"codecs": ["PCMU"]
},
"video": {
"codecs": []
}
},
"name": "Carrier 3",
"peer": false,
"rules": [
"^\\+{0,1}1{0,1}(\\d{10})$"
],
"type": "local",
"weight_cost": "50"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION_ID}",
"status": "success"
}
Change a resource
POST /v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{...ResourceData...}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID}',
'{"data":{...ResourceData...}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"caller_id_options": {
"type": "external"
},
"emergency": false,
"enabled": true,
"flags": [],
"gateways": [
{
"channel_selection": "ascending",
"codecs": ["PCMU", "PCMA"],
"custom_sip_headers": {},
"emergency": false,
"enabled": true,
"endpoint_type": "sip",
"format_from_uri": false,
"invite_format": "route",
"password": "DrWoody",
"prefix": "+1",
"progress_timeout": "6",
"realm": "carrier1.com",
"server": "carrier1.com",
"skype_rr": true,
"suffix": "100",
"username": "blazemore"
}
],
"grace_period": 5,
"id": "{RESOURCE_ID}",
"media": {
"audio": {
"codecs": ["PCMU"]
},
"video": {
"codecs": []
}
},
"name": "Carrier 3",
"peer": false,
"rules": [
"^\\+{0,1}1{0,1}(\\d{10})$"
],
"type": "local",
"weight_cost": "50"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION_ID}",
"status": "success"
}
Patch a resource
PATCH /v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"custom_sip_headers":{"X-Reseller-ID":"a1b2c3"}}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID}',
{
'data': {
'custom_sip_headers': {
'X-Reseller-ID': 'a1b2c3'
}
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"caller_id_options": {
"type": "external"
},
"custom_sip_headers": {
"X-Reseller-ID": "a1b2c3"
},
"emergency": false,
"enabled": true,
"flags": [],
"gateways": [
{
"channel_selection": "ascending",
"codecs": ["PCMU", "PCMA"],
"custom_sip_headers": {},
"emergency": false,
"enabled": true,
"endpoint_type": "sip",
"format_from_uri": false,
"invite_format": "route",
"password": "DrWoody",
"prefix": "+1",
"progress_timeout": "6",
"realm": "carrier1.com",
"server": "carrier1.com",
"skype_rr": true,
"suffix": "100",
"username": "blazemore"
}
],
"grace_period": 5,
"id": "{RESOURCE_ID}",
"media": {
"audio": {
"codecs": ["PCMU"]
},
"video": {
"codecs": []
}
},
"name": "Carrier 3",
"peer": false,
"rules": [
"^\\+{0,1}1{0,1}(\\d{10})$"
],
"type": "local",
"weight_cost": "50"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION_ID}",
"status": "success"
}
Fetch a listing of jobs
Do note you can use the created_from and created_to flags to change to time period queried.
The keys failures and successes represent the count of how many numbers failed and succeeded, respectively.
GET /v2/accounts/{ACCOUNT_ID}/resources/jobs
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/jobs
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/jobs', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"failures": 0,
"successes": 2,
"id": "201408-394de70ecf6f8252",
"status": "pending",
"timestamp": 63575950041,
"resource_id":"{RESOURCE_ID}"
},
{
"failures": 0,
"successes": 1,
"id": "201408-70766ed00a24",
"status": "pending",
"timestamp": 63575878379,
"resource_id":"{RESOURCE_ID}"
}
]
"page_size": 2,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"start_key": 63573276761,
"status": "success"
}
Create a new job
PUT /v2/accounts/{ACCOUNT_ID}/resources/jobs
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"numbers":["+12223334444", "+23334445555"], "resource_id":"{RESOURCE_ID}"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/jobs
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/jobs',
// '{"data":{"numbers":["+12223334444", "+23334445555"], "resource_id":"{RESOURCE_ID}"}}',
{
'data': {
'numbers': [
'+12223334444',
'+23334445555'
],
'resource_id': '{RESOURCE_ID}'
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"errors": {},
"id": "201408-39512771f9d2d499",
"resource_id":"{RESOURCE_ID}",
"numbers": [
"+12223334444"
],
"successes": {}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Fetch a job's status
GET /v2/accounts/{ACCOUNT_ID}/resources/jobs/{JOB_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/jobs/{JOB_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/jobs/{JOB_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"resource_id": "{RESOURCE_ID}",
"errors": {},
"id": "201408-394de70ecf6f8252",
"numbers": [
"3148096310"
],
"status": "pending",
"successes": {},
"timestamp": 63575950041
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Create a new collection of resources
PUT /v2/accounts/{ACCOUNT_ID}/resources/collection
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":[{...RESOURCE...}, {...RESOURCE...}]}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/collection
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/collection',
'{"data":[{...RESOURCE...}, {...RESOURCE...}]}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Change a collection
POST /v2/accounts/{ACCOUNT_ID}/resources/collection
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"numbers":["+12223334444", "+23334445555"], "resource_id":"{RESOURCE_ID}"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/collection
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/collection',
// '{"data":{"numbers":["+12223334444", "+23334445555"], "resource_id":"{RESOURCE_ID}"}}',
{
'data': {
'numbers': [
'+12223334444',
'+23334445555'
],
'resource_id': '{RESOURCE_ID}'
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data":{
"errors":{
"{RESOURCE_ID}": "{ERROR_MESSAGE}"
},
"successes":{
"{RESOURCE_ID}": "{RESOURCE_DOC}"
}
}
}
Working with reverse proxies (HAProxy, Nginx, etc)
Configuring list allowed proxies
Set list in system_config/crossbar, key reverse_proxies.
Values can be:
- single ip address ("192.168.0.1");
- single ip address in CIDR notation ("192.168.0.1/32")
- network in CIDR notation ("192.168.0.0/24")
Configuration reverse proxy
Reverse proxy must set "X-Forwarded-For" header.
- HAProxy
- Nginx + add proxy_set_header X-Forwarded-For $remote_addr;
- Apache 2.2
JSON Schema
Lumian uses JSON Schemas to validate incoming data from clients.
Any fields that aren't defined in the JSON schema will be stored, unmodified, along side the validated fields (assuming all is well).
This excludes Lumian-managed private fields (top-level keys prefixed with "_" or "pvt_").
This is the API endpoint to inspect all JSON Schemas.
List All Available Schema
The default fetch will retrieve only the documents meant for the APIs to operate on (doc and system_config schemas). Lumian also has the internal JSON APIs available as JSON schemas, which can be fetched via /v2/schemas?internals=true.
GET /v2/schemas
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/schemas
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/schemas', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
"access_lists",
"account_rate_limits",
"accounts",
"acls",
"allotments",
"api_auth",
"app",
"audit_logs",
"blacklists",
"bookkeepers",
"call_waiting",
"caller_id",
"callflows",
"callflows.collect_dtmf",
"callflows.conference",
"callflows.language",
"callflows.lookupcidname",
"callflows.manual_presence",
"callflows.nomorobo",
"callflows.pivot",
"callflows.record_call",
"callflows.response",
"callflows.ring_group",
"callflows.send_dtmf",
"callflows.tts",
"callflows.voicemail",
"cccps",
"cdr",
"clicktocall",
"conferences",
"connectivity",
"device_rate_limits",
"devices",
"dialplans",
"directories",
"domain_hosts",
"domains",
"faxbox",
"faxes",
"ledgers",
"limits",
"list_entries",
"lists",
"media",
"menus",
"metaflows",
"notifications",
"notify.callback",
"phone_numbers",
"port_requests",
"profile",
"provisioner_v5",
"queue_update",
"queues",
"rates",
"resource_jobs",
"resources",
"service_plans",
"shared_auth",
"sms",
"temporal_rules",
"temporal_rules_sets",
"token_restrictions",
"trunkstore",
"ubiquiti_auth",
"user_auth",
"user_auth_recovery",
"users",
"vmboxes",
"webhook_attempts",
"webhooks",
"whitelabels"
],
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Fetch the schema definitions
GET /v2/schemas/{SCHEMA_NAME}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/schemas/acls
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/schemas/acls', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "",
"data": {
"$schema": "http://json-schema.org/draft-04/schema#",
"additionalProperties": false,
"description": "Access Control List entries",
"id": "acls",
"properties": {
"cidr": {
"description": "Classless Inter-Domain Routing IP notation for use on the ACL",
"type": "string"
},
"description": {
"description": "Will be added as a comment for quick identification later",
"maxLength": 30,
"type": "string"
},
"network-list-name": {
"description": "The trusted list should represent anything that can issue calls without authorization. The authoritative list should indicate inter-network routing equipment (SBC, etc).",
"enum": [
"authoritative",
"trusted"
],
"type": "string"
},
"type": {
"default": "allow",
"description": "Allow or deny this CIDR",
"enum": [
"allow",
"deny"
],
"type": "string"
}
},
"required": [
"cidr",
"network-list-name",
"type"
],
"type": "object"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Perform a validation
Test your request data against the validation schema (without performing a database operation).
PUT /v2/schemas/{SCHEMA_NAME}/validation
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{...}}' \
http://{SERVER}:8000/v2/schemas/{SCHEMA_NAME}/validation
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/schemas/{SCHEMA_NAME}/validation',
'{"data":{...}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token":"",
"data":{...},
"request_id":"{REQUEST_ID}",
"revision":"{REVISION}",
"status":"success"
}
Search
About Search
The Search API allows query a value on databases. You can query different type of entity commonly like accounts (on accounts database), users, devices, callflows, numbers. It possible to search for any document base on it's ID.
Generally you have to provide which document type to search, which field in the document should be searched and a value to search with. How to specify these query parameters is depend on you want to search with a single value or multiple values.
Databases To Search On, Fields To Search With
Search for accounts is done on accounts database. The parameters that you can search with are:
name: Account's namerealm: Account's realmid: Account's ID
For other type of documents search is done on Account's database. The parameters to search with are:
name:namefield of the document if it has one or the ID of the documentname_and_number: search either bynamefield or bynumbersnumber: search bynumbersfield, usually used to search callflow.
Document Types
You have to specify what kind of piece of information is you're looking for (t query string parameter). Typically you're interested to search for an account.
Frequent types are:
accountcallflowdevicedirectoryfaxboxlimitsmediamenuuservmbox
Create Custom Search Views (Advanced)
Search in Lumian is possible with specific CouchDB view with design document ID search in account's database and accounts database. View index defined in this design document are exposing the common fields (name, id, etc...) in documents for search.
With that in mind, a system administrator can create a custom index to expose extra fields out of document to view. This requires full understanding of how to write CouchDB design documents and a bit of the internal structure of the document in the database. You can look at {ACCOUNT_DB}/_design/search to see how Lumian default search view is implemented.
It's require to name your custom search view index name prefixed with search_by_{YOUR_CUSTOM_VIEW_NAME}, which conventionally {YOUR_CUSTOM_VIEW_NAME} is the name of the field in the document that you're creating this view for.
Search with Single Value
To look up a single value in the specified field. These should defined in request query string.
GET /v2/accounts/{ACCOUNT_ID}/search
Query String Parameters
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
t |
document type | string |
true |
|
q |
the field to look in for value | string |
true |
|
v |
value to search for | string or boolean |
true |
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/6134cc9aa43ffaee3e3f0c9a84113d6e/search?t=account&q=name&v=nat
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/6134cc9aa43ffaee3e3f0c9a84113d6e/search', {
params: {
't': 'account'
},
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Response
Sample Response:
{
"page_size": 1,
"start_key": "g2wAAAADbQAAACA2MTM0Y2M5YWE0M2ZmYWVlM2UzZjBjOWE4NDExM2Q2ZW0AAAAHYWNjb3VudG0AAAAHbmF0ZmZmMGo",
"data": [
{
"id": "a391d64a083b99232f6d2633c47432e3",
"descendants_count": 2,
"name": "natalie",
"realm": "natalie.lumian.net"
}
],
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Searching for an Account
If you're searching for an account you can remove /accounts/{ACCOUNT_ID} from the URL.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/search?t=account&q=name&v=nat
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/search', {
params: {
't': 'account'
},
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Multi Search
To search with multiple values in a single shot. Search parameters should defined in request query string.
GET /v2/accounts/{ACCOUNT_ID}/search/multi
Query String Parameters
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
t |
document type | string |
true |
|
by_{view_name} |
the values to search for in {view_name} results |
string |
true |
Here {view_name} is referring in what field is available to search. See above.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/accounts/6134cc9aa43ffaee3e3f0c9a84113d6e/v2/search/multi?t=account&by_name=test&by_realm=test&by_id=test
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/accounts/6134cc9aa43ffaee3e3f0c9a84113d6e/v2/search/multi', {
params: {
't': 'account'
},
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Response
Sample Response:
{
"data": {
"name": [
{
"id": "a391d64a083b99232f6d2633c47432e3",
"descendants_count": 2,
"name": "test",
"realm": "test.lumian.net"
}
],
"realm": [
{
"id": "a391d64a083b99232f6d2633c47432e3",
"descendants_count": 2,
"name": "test",
"realm": "test.lumian.net"
}
]
},
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Searching for Account
If you're searching for account you can remove /accounts/{ACCOUNT_ID} from the URL.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/search/multi?t=account&by_name=test&by_realm=test
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/search/multi', {
params: {
't': 'account'
},
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Security Configuration
Crossbar API to configure authentication for an account.
About Security
Crossbar authenticator modules can have their own account's version configuration to control some aspect of them like enabling/disabling the module or use multi factor authenticator for that specific module.
!!! note
This API endpoint is only configuring the authentication for a account, for configuring the system, you should use system_configs instead as super duper admin. System config category is crossbar.auth.
How Crossbar is looking for authentication configuration
Configuration is the merged result of the account's configuration and all its parent's account up to the first reseller, then the system config itself. So the account inherits parent and reseller account and system config.
Enable Multi Factor Authentication for a Crossbar auth module
If you want to use multi factor authentication for a module, set the multi_factor.enabled to true. You can control if the multi factor settings can be applied to the account's children by multi_factor.include_subaccounts.
When setting configuration_id of the multi-factor, you have to set the Account ID which contains the that configuration.
Only a parent Account or the same Account can set configuration_id and account_id unless multi_factor.include_subaccounts is true and a descendant account can use its parent configuration_id.
See Multi Factor Authentication API documentation.
Account Auth Configuration Schema
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
cb_api_auth |
#/definitions/auth_module_config | false |
||
cb_auth |
#/definitions/auth_module_config | false |
||
cb_ip_auth |
#/definitions/auth_module_config | false |
||
cb_ubiquiti_auth |
#/definitions/auth_module_config | false |
||
cb_user_auth |
#/definitions/auth_module_config | false |
Auth Module Configuration Schema
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
enabled |
whether or not this authentication module is enabled | boolean |
false |
|
log_failed_attempts |
should log failed logging attempts | boolean |
false |
|
log_successful_attempts |
should log successful logging attempts | boolean |
false |
|
multi_factor |
control multi factor authentications for this module | object |
false |
|
multi_factor.account_id |
ID of the account that contains the multi factor configuration | string |
false |
|
multi_factor.configuration_id |
document ID contains the multi factor configuration | string |
false |
|
multi_factor.enabled |
turn on/off multi factor authentications for this module | boolean |
false |
|
multi_factor.include_subaccounts |
should this multi factor authentication settings be applied when used by sub-accounts | boolean |
false |
|
token_auth_expiry_s |
expiration period of the JWT token (seconds) | integer |
false |
Get a List of Available Auth Module
List of all available auth module to be configured.
GET /v2/security
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/security
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/security', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"data": {
"available_auth_modules": [
"cb_api_auth",
"cb_auth",
"cb_ip_auth",
"cb_ubiquiti_auth",
"cb_user_auth"
]
},
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Fetch All Configurations
Get all configured authenticator module on the account alongside the default settings of merged result of account itself and its parents, reseller and system.
GET /v2/accounts/{ACCOUNT_ID}/security
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/security
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/security', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"data": {
"account": {},
"inherited_config": {
"auth_modules": {
"cb_user_auth": {
"enabled": true,
"token_auth_expiry_s": 3600,
"log_failed_attempts": true,
"log_successful_attempts": true,
"multi_factor": {
"enabled": false,
"_read_only": {
"name": "Default System Provider",
"provider_name": "duo"
}
}
},
"cb_api_auth": {
"enabled": true,
"token_auth_expiry_s": 3600,
"log_failed_attempts": true,
"log_successful_attempts": true
},
"cb_auth": {
"enabled": true,
"token_auth_expiry_s": 3600,
"log_failed_attempts": true,
"log_successful_attempts": true
},
"cb_ip_auth": {
"enabled": true,
"token_auth_expiry_s": 3600,
"log_failed_attempts": true,
"log_successful_attempts": true
},
"cb_ubiquiti_auth": {
"enabled": true,
"token_auth_expiry_s": 3600,
"log_failed_attempts": true,
"log_successful_attempts": true
}
}
}
},
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Change
Customize modules config for the account. Set what settings you want here, crossbar always get the merged config from account and hierarchy.
POST /v2/accounts/{ACCOUNT_ID}/security
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{ "data": { "auth_modules" :{ "cb_user_auth": { "token_auth_expiry_s": 604800 }, "cb_api_auth": { "enabled": false } } } }' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/security
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/security',
'{ "data": { "auth_modules" :{ "cb_user_auth": { "token_auth_expiry_s": 604800 }, "cb_api_auth": { "enabled": false } } } }',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Response
Sample Response:
{
"data": {
"auth_modules": {
"cb_user_auth": {
"token_auth_expiry_s": 604800
},
"cb_api_auth": {
"enabled": false
}
},
"id": "configs_crossbar.auth"
},
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Patch
Patch field(s) of config for the account customization.
PATCH /v2/accounts/{ACCOUNT_ID}/security
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{ "data": { "auth_modules" :{ "cb_api_auth": { "enabled": true } } } }' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/security
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/security',
'{ "data": { "auth_modules" :{ "cb_api_auth": { "enabled": true } } } }',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Responses
Sample Response:
{
"data": {
"auth_modules": {
"cb_user_auth": {
"token_auth_expiry_s": 604800
},
"cb_api_auth": {
"enabled": false
}
},
"id": "configs_crossbar.auth"
},
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Remove
Delete account's auth config.
DELETE /v2/accounts/{ACCOUNT_ID}/security
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/security
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/security', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"data": {
"auth_modules": {
"cb_user_auth": {
"token_auth_expiry_s": 604800
},
"cb_api_auth": {
"enabled": false
}
},
"id": "configs_crossbar.auth"
},
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Set Multi Factor Configuration for a Authentication Module
POST /v2/accounts/{ACCOUNT_ID}/security
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{ "data": { "auth_modules" :{ "cb_user_auth": { "multi_factor": { "enabled": true, "configuration_id": "c757665dca55edba2395df3ca6423f4f", "account_id": "a391d64a083b99232f6d2633c47432e3" } } } } }' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/security
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/security',
'{ "data": { "auth_modules" :{ "cb_user_auth": { "multi_factor": { "enabled": true, "configuration_id": "c757665dca55edba2395df3ca6423f4f", "account_id": "a391d64a083b99232f6d2633c47432e3" } } } } }',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Responses
Sample Response:
{
"data": {
"auth_modules": {
"cb_user_auth": {
"multi_factor": {
"enabled": true,
"configuration_id": "c757665dca55edba2395df3ca6423f4f",
"account_id": "a391d64a083b99232f6d2633c47432e3",
"_read_only": {
"name": "a nice day",
"provider_name": "duo"
}
}
}
}
},
"id": "configs_crossbar.auth"
},
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Get a List of All Login Attempts
GET /v2/accounts/{ACCOUNT_ID}/security/attempts
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/security/attempts
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/security/attempts', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"page_size": 1,
"data": [
{
"id": "201707-5e9c6dc29efb34d87c0a06e8f613b1fd",
"auth_type": "jwt_auth_token",
"auth_module": "cb_user_auth",
"status": "success",
"message": "authentication resulted in token creation",
"timestamp": 63667032239,
"client_ip": "10.1.0.2"
}
],
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Get a Login Attempt Details
GET /v2/accounts/{ACCOUNT_ID}/security/attempts/{ATTEMPT_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/security/attempts/201707-5e9c6dc29efb34d87c0a06e8f613b1fd
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/security/attempts/201707-5e9c6dc29efb34d87c0a06e8f613b1fd', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"data": {
"auth_type": "jwt_auth_token",
"status": "success",
"auth_module": "cb_user_auth",
"message": "authentication resulted in token creation",
"client_headers": {
"host": "10.1.0.2:8000",
"connection": "keep-alive",
"content-length": "82",
"accept": "application/json, text/javascript, */*; q=0.01",
"x-auth-token": "undefined",
"user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.61 Safari/537.36",
"origin": "http://127.0.0.1:3000",
"content-type": "application/json",
"dnt": "1",
"referer": "http://127.0.0.1:3000/",
"accept-encoding": "gzip, deflate",
"accept-language": "en-US,en;q=0.8"
},
"client_ip": "10.1.0.2",
"crossbar_request_id": "a6edc00018ebd9c7c991fbddf3677fcb",
"timestamp": 63667032239,
"metadata": {
"owner_id": "0528dc7bbbf94bcc5df7d74d808a4ec0",
"account_id": "6134cc9aa43ffaee3e3f0c9a84113d6e"
},
"id": "201707-5e9c6dc29efb34d87c0a06e8f613b1fd"
},
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Service Plans
About Service Plans
Handle the service plans you can subscribe to.
Service Plan Schema
Describes services offered to sub-accounts
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
bookkeepers |
#/definitions/bookkeepers | false |
||
category |
Optional category used for grouping service plans | string() |
false |
|
description |
Describes the service plan offering | string() |
false |
|
manual_recurring |
Monthly recurring items | array(object()) |
false |
|
manual_recurring.[].name |
A friendly name for the item | string() |
false |
|
manual_recurring.[].quantity |
How many of the item are allowed | integer() |
false |
|
manual_recurring.[].rates |
Item's rate | number() |
false |
|
name |
A friendly name for the service plan | string(1..128) |
true |
|
plan./.+/ |
Category name | object() |
false |
|
plan |
Outlines the service plan for various services | object() |
true |
bookkeepers
The bookkeeper modules provided by Lumian
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
braintree |
object() |
false |
||
local |
object() |
false |
service_plan.category
Describes a service plan category
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
.+ |
Item name | object() |
false |
|
_all.exceptions.[] |
string() |
false |
||
_all.exceptions |
Items that are not included in this item plan | array(string()) |
false |
|
_all |
Applies item rules to any item in this category | object() |
false |
service_plan.item
Describes a service plan item
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
activation_charge |
What to charge when activating an Item | number() |
false |
|
as |
Count Item as if it was another Item | string() |
false |
|
cascade |
Whether to count quantities among all sub-accounts or just the account | boolean() |
false |
|
cumulative_discount |
Whether to give a discount based on quantities of the account and all sub-accounts | boolean() |
false |
|
cumulative_discount_rate |
How much of a discount to apply | number() |
false |
|
discounts.cumulative.maximum |
The most number of Items to apply discount to | integer() |
false |
|
discounts.cumulative.rate |
The discount to apply, up to maximum Items (if applicable) | number() |
false |
|
discounts.cumulative |
object() |
false |
||
discounts |
object() |
false |
||
markup_type |
How rate for this usage is calculated | string('fixed_price' or 'percentage' or 'rate') |
false |
|
minimum |
The minimum quantity to charge for, if 'quantity' is less than 'minimum' | integer() |
false |
|
name |
Friendly name for this Item | string() |
false |
|
quantity |
How many of the item are allowed | integer() |
false |
|
rate |
The rate to charge | number() |
false |
|
rates./^[0-9]+$/ |
The rate to charge when under the quantity indicated in the key | number() |
false |
|
rates |
Tiers of rates based on quantities | object() |
false |
|
single_discount |
Whether to give a discount to the account | boolean() |
false |
|
single_discount_rate |
How much of a discount to apply, per-item | number() |
false |
Available Fields To Customize
Get a list of fields that can be customize for each service plan.
GET /v2/service_plans/editable
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/service_plans/editable
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/service_plans/editable', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"data": {
"devices": {
"_all": {
"activation_charge": {},
"as": {},
"discounts": {
"maximum": {},
"rate": {}
},
"exceptions": {},
"minimum": {},
"rate": {}
},
"landline": {
"activation_charge": {},
"discounts": {
"maximum": {},
"rate": {}
},
"minimum": {},
"rate": {}
}
"..."
},
"limits": {
"_all": {
"activation_charge": {},
"as": {},
"discounts": {
"maximum": {},
"rate": {}
},
"exceptions": {},
"minimum": {},
"rate": {}
}
"..."
},
"number_services": {
"_all": {
"activation_charge": {},
"as": {},
"discounts": {
"maximum": {},
"rate": {}
},
"exceptions": {},
"minimum": {},
"rate": {}
},
"cnam": {
"activation_charge": {},
"discounts": {
"maximum": {},
"rate": {}
},
"minimum": {},
"rate": {}
}
"..."
},
"phone_numbers": {
"_all": {
"activation_charge": {},
"as": {},
"discounts": {
"maximum": {},
"rate": {}
},
"exceptions": {},
"minimum": {},
"rate": {}
},
"did_us": {
"activation_charge": {},
"discounts": {
"maximum": {},
"rate": {}
},
"minimum": {},
"rate": {}
}
"..."
},
"ui_apps": {
"_all": {
"activation_charge": {},
"discounts": {
"maximum": {},
"rate": {}
},
"minimum": {},
"rate": {},
"exceptions": {},
"as": {}
},
"accounts": {
"activation_charge": {},
"discounts": {
"maximum": {},
"rate": {}
},
"minimum": {},
"rate": {}
}
"..."
},
"users": {
"_all": {
"activation_charge": {},
"as": {},
"discounts": {
"maximum": {},
"rate": {}
},
"exceptions": {},
"minimum": {},
"rate": {}
},
"admin": {
"activation_charge": {},
"discounts": {
"maximum": {},
"rate": {}
},
"minimum": {},
"rate": {}
}
"..."
}
},
"revision": "{REVISION}",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "{STATUS}",
"auth_token": "{AUTH_TOKEN}"
}
Fetch
GET /v2/accounts/{ACCOUNT_ID}/service_plans
Useful for resellers.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"page_size": 1,
"data": [
{
"id": "some_plan_id",
"name": "Reseller Test plan",
"description": "Some description"
}
],
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Adding/Removing multiple service plans on an account
POST /v2/accounts/{ACCOUNT_ID}/service_plans
Useful for resellers.
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {
"add": ["plan1", "plan2"],
"delete": ["plan3"]
}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans',
'{"data": {\n "add": ["plan1", "plan2"],\n "delete": ["plan3"]\n }}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"data": {}, // Merge of the Service plans if any left
"status": "success"
}
Removing service plan from an account
DELETE /v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID}
Useful for resellers.
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Retrieving one of your service plans.
GET /v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID}
Useful for resellers.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": {
"bookkeepers": {
"braintree": {
"devices": {
"sip_devices": {
"addon": "sip_device",
"discounts": {
"cumulative": "discount_did_us"
},
"plan": "SIP_Services"
}
},
"limits": {
"inbound_trunks": {
"addon": "inbound_trunk",
"plan": "SIP_Services"
},
"twoway_trunks": {
"addon": "twoway_trunk",
"plan": "SIP_Services"
}
},
"number_services": {
"e911": {
"addon": "e911",
"plan": "SIP_Services"
}
},
"phone_numbers": {
"did_us": {
"addon": "did_us",
"plan": "SIP_Services"
},
"tollfree_us": {
"addon": "tollfree_us",
"plan": "SIP_Services"
}
}
}
},
"description": "",
"id": "plan_macpie",
"name": "Macpies plan",
"plan": {
"devices": {
"_all": {
"activation_charge": 3,
"as": "sip_devices",
"discounts": {
"cumulative": {
"maximum": 20,
"rate": 5
}
},
"exceptions": [
"cellphone",
"landline"
],
"name": "SIP Device",
"rate": 5
}
},
"limits": {
"inbound_trunks": {
"name": "Inbound Trunk",
"rate": 6.99
},
"twoway_trunks": {
"name": "Two-Way Trunk",
"rate": 29.99
}
},
"number_services": {
"e911": {
"cascade": true,
"discounts": {
"single": {
"rate": 5
}
},
"name": "E911 Service",
"rate": 2
},
"inbound_cnam": {
"activation_charge": 1,
"name": "Inbound CNAM Update",
"rate": 2
},
"outbound_cnam": {
"activation_charge": 5,
"name": "Outbound CNAM Update",
"rate": 1
},
"port": {
"activation_charge": 10,
"name": "Port Request"
}
},
"phone_numbers": {
"did_us": {
"activation_charge": 3,
"cascade": true,
"name": "US DID",
"rate": 2
},
"tollfree_us": {
"cascade": true,
"name": "US Tollfree",
"rate": 4.99
}
},
"users": {
"_all": {
"activation_charge": 3,
"as": "user",
"cascade": true,
"exceptions": [],
"name": "User",
"rate": 5
}
}
}
},
"status": "success"
}
Adding service plan to an account.
POST /v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"id":"{PLAN_ID}"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID}',
'{"data": {"id":"{PLAN_ID}"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"data": {...},
"status": "success"
}
Override a plan
POST /v2/accounts/{ACCOUNT_ID}/service_plans/override
!!! note Must be super duper admin
Note: _all override payload.
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {
"overrides": {
"{PLAN_ID}": {
"whitelabel": {
"_all": {
"activation_charge": 700
}
}
}
}
}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/override
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/override',
'{"data": {\n "overrides": {\n "{PLAN_ID}": {\n "whitelabel": {\n "_all": {\n "activation_charge": 700\n }\n }\n }\n }\n }}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"data": {
"whitelabel": {
"_all": {
"name": "Whitelabel",
"as": "whitelabel",
"exceptions": [],
"activation_charge": 700,
"cascade": true,
"rate": 300
}
}
},
"status": "success"
}
Retrieving your current plan
GET /v2/accounts/{ACCOUNT_ID}/service_plans/current
This will retrieve the service plan currently applied on your account.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/current
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/current', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": {
"account_quantities": {
"number_services": {},
"phone_numbers": {
"did_us": 4
},
"devices": {
"sip_device": 1,
"softphone": 2
},
"limits": {
"twoway_trunks": 10,
"inbound_trunks": 10
},
"users": {
"admin": 1,
"user": 1
},
"ips": {
"dedicated": 0
}
},
"cascade_quantities": {},
"plans": {
"plan_dedicated_install": {
"account_id": "a0f3b6f2c5c0c95240993acd1bd6e762"
}
},
"billing_id": "1760753c8d022d650418fbbe6a1a10e0",
"reseller": false,
"reseller_id": "a0f3b6f2c5c0c95240993acd1bd6e762",
"dirty": false,
"in_good_standing": true,
"items": {
"number_services": {
"port": {
"category": "number_services",
"item": "port",
"quantity": 0,
"single_discount": false,
"single_discount_rate": 0.0,
"cumulative_discount": 0,
"cumulative_discount_rate": 0.0
},
"outbound_cnam": {
"category": "number_services",
"item": "outbound_cnam",
"quantity": 0,
"rate": 1.0,
"single_discount": false,
"single_discount_rate": 0.0,
"cumulative_discount": 0,
"cumulative_discount_rate": 0.0
},
"inbound_cnam": {
"category": "number_services",
"item": "inbound_cnam",
"quantity": 0,
"rate": 2.0,
"single_discount": false,
"single_discount_rate": 0.0,
"cumulative_discount": 0,
"cumulative_discount_rate": 0.0
},
"e911": {
"category": "number_services",
"item": "e911",
"quantity": 0,
"rate": 2.0,
"single_discount": false,
"single_discount_rate": 5.0,
"cumulative_discount": 0,
"cumulative_discount_rate": 0.0
}
},
"devices": {
"sip_devices": {
"category": "devices",
"item": "sip_devices",
"quantity": 3,
"rate": 5.0,
"single_discount": true,
"single_discount_rate": 0.0,
"cumulative_discount": 3,
"cumulative_discount_rate": 5.0
}
},
"phone_numbers": {
"tollfree_us": {
"category": "phone_numbers",
"item": "tollfree_us",
"quantity": 0,
"rate": 4.9900000000000002132,
"single_discount": false,
"single_discount_rate": 0.0,
"cumulative_discount": 0,
"cumulative_discount_rate": 0.0
},
"did_us": {
"category": "phone_numbers",
"item": "did_us",
"quantity": 4,
"rate": 2.0,
"single_discount": true,
"single_discount_rate": 0.0,
"cumulative_discount": 0,
"cumulative_discount_rate": 0.0
}
},
"users": {
"user": {
"category": "users",
"item": "user",
"quantity": 2,
"rate": 5.0,
"single_discount": true,
"single_discount_rate": 0.0,
"cumulative_discount": 0,
"cumulative_discount_rate": 0.0
}
},
"limits": {
"twoway_trunks": {
"category": "limits",
"item": "twoway_trunks",
"quantity": 10,
"rate": 29.989999999999998437,
"single_discount": true,
"single_discount_rate": 0.0,
"cumulative_discount": 0,
"cumulative_discount_rate": 0.0
},
"inbound_trunks": {
"category": "limits",
"item": "inbound_trunks",
"quantity": 10,
"rate": 6.9900000000000002132,
"single_discount": true,
"single_discount_rate": 0.0,
"cumulative_discount": 0,
"cumulative_discount_rate": 0.0
}
}
}
},
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Listing Service Plans available to you
GET /v2/accounts/{ACCOUNT_ID}/service_plans/available
This api will list the services plan that can be applied to your account
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/available
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/available', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"page_size": 1,
"data": [
{
"id": "some_plan_id",
"name": "Test plan",
"description": "Some description"
}
],
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Retrieving a plan
GET /v2/accounts/{ACCOUNT_ID}/service_plans/available/{PLAN_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/available/{PLAN_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/available/{PLAN_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": {
"name": "Test plan",
"description": "Some description",
"plan": {
"phone_numbers": {
"did_us": {
"name": "US DID",
"rate": 2,
"activation_charge": 3,
"cascade": true
},
"tollfree_us": {
"name": "US Tollfree",
"rate": 4.9900000000000002132,
"cascade": true
}
},
"number_services": {
"outbound_cnam": {
"name": "Outbound CNAM Update",
"activation_charge": 5,
"rate": 1
},
"inbound_cnam": {
"rate": 2,
"name": "Inbound CNAM Update",
"activation_charge": 1
},
"port": {
"name": "Port Request",
"activation_charge": 10
},
"e911": {
"name": "E911 Service",
"rate": 2,
"cascade": true,
"discounts": {
"single": {
"rate": 5
}
}
}
},
"limits": {
"twoway_trunks": {
"name": "Two-Way Trunk",
"rate": 29.989999999999998437
},
"inbound_trunks": {
"name": "Inbound Trunk",
"rate": 6.9900000000000002132
}
},
"devices": {
"_all": {
"name": "SIP Device",
"as": "sip_devices",
"exceptions": ["cellphone", "landline"],
"activation_charge": 3,
"rate": 5,
"discounts": {
"cumulative": {
"maximum": 20,
"rate": 5
}
}
}
},
"users": {
"_all": {
"name": "User",
"as": "user",
"exceptions": [],
"activation_charge": 3,
"cascade": true,
"rate": 5
}
}
},
"bookkeepers": {
"braintree": {
"phone_numbers": {
"did_us": {
"plan": "SIP_Services",
"addon": "did_us"
},
"tollfree_us": {
"plan": "SIP_Services",
"addon": "tollfree_us"
}
},
"number_services": {
"e911": {
"plan": "SIP_Services",
"addon": "e911"
}
},
"limits": {
"twoway_trunks": {
"plan": "SIP_Services",
"addon": "twoway_trunk"
},
"inbound_trunks": {
"plan": "SIP_Services",
"addon": "inbound_trunk"
}
},
"devices": {
"sip_devices": {
"plan": "SIP_Services",
"addon": "sip_device",
"discounts": {
"cumulative": "discount_did_us"
}
}
}
}
},
"id": "some_plan_id"
},
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Services
About Services
Fetch and inspect account's service.
Schema
Get Account Service
GET /v2/accounts/{ACCOUNT_ID}/services
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Update the Account Billing ID
POST /v2/accounts/{ACCOUNT_ID}/services
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {
"billing_id":"{BILLING_ID}"
}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services',
'{"data": {\n "billing_id":"{BILLING_ID}"\n }}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Get Account Service Status
GET /v2/accounts/{ACCOUNT_ID}/services/status
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/status
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/status', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch Service Audit Logs
GET /v2/accounts/{ACCOUNT_ID}/services/audit
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/audit
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/audit', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch
GET /v2/accounts/{ACCOUNT_ID}/services/audit/{AUDIT_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/audit/{AUDIT_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/audit/{AUDIT_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Get service changes summary per day
Using this API you can a list of services changes (additions/removal/usage) summary per day.
GET /v2/accounts/{ACCOUNT_ID}/services/audit_summary
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/audit_summary
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/audit_summary', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Example
Request:
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/audit_summary?created_from=63721540230&created_to=63722160516
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/audit_summary', {
params: {
'created_from': '63721540230'
},
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Response:
Sample Response:
{
"data": {
"per-minute-voip": [
{
"2019-04-03": {
"last_timestamp": 63721549284,
"quantity": 300,
"sum_quantity": true,
"unit": "sec"
}
},
{
"2019-04-08": {
"last_timestamp": 63721972845,
"quantity": 60,
"sum_quantity": true,
"unit": "sec"
}
},
{
"2019-04-09": {
"last_timestamp": 63722073234,
"quantity": 780,
"sum_quantity": true,
"unit": "sec"
}
},
{
"2019-04-10": {
"last_timestamp": 63722156725,
"quantity": 1500,
"sum_quantity": true,
"unit": "sec"
}
},
{
"2019-04-11": {
"last_timestamp": 63722239192,
"quantity": 960,
"sum_quantity": true,
"unit": "sec"
}
}
],
"phone_number": [
{
"2019-04-04": {
"addition": 1,
"last_timestamp": 63721611287,
"quantity": 53,
"removal": 0,
"sum_quantity": false
}
}
],
"sip_device": [
{
"2019-04-09": {
"addition": 2,
"last_timestamp": 63722066155,
"quantity": 42,
"removal": 2,
"sum_quantity": false
}
},
{
"2019-04-10": {
"addition": 1,
"last_timestamp": 63722076464,
"quantity": 43,
"removal": 0,
"sum_quantity": false
}
}
],
"user": [
{
"2019-04-03": {
"addition": 1,
"last_timestamp": 63721540230,
"quantity": 84,
"removal": 0,
"sum_quantity": false
}
},
{
"2019-04-09": {
"addition": 1,
"last_timestamp": 63722056079,
"quantity": 85,
"removal": 0,
"sum_quantity": false
}
},
{
"2019-04-11": {
"addition": 1,
"last_timestamp": 63722160516,
"quantity": 85,
"removal": 1,
"sum_quantity": false
}
}
]
},
"revision": "{REVISION}",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Get changes summary per day for a single service category
Using this API you can a list of changes (additions/removal/usage) summary per day for a single service category.
GET /v2/accounts/{ACCOUNT_ID}/services/audit_summary/{SOURCE_SERVICE}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/audit_summary/{SOURCE_SERVICE}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/audit_summary/{SOURCE_SERVICE}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Example
Request:
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/audit_summary/user?created_from=63721540230&created_to=63722160516
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/audit_summary/user', {
params: {
'created_from': '63721540230'
},
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Response:
Sample Response:
{
"data": [
{
"2019-04-11": {
"addition": 1,
"last_timestamp": 63722160516,
"quantity": 85,
"removal": 1,
"sum_quantity": false
}
},
{
"2019-04-09": {
"addition": 1,
"last_timestamp": 63722056079,
"quantity": 85,
"removal": 0,
"sum_quantity": false
}
},
{
"2019-04-03": {
"addition": 1,
"last_timestamp": 63721540230,
"quantity": 84,
"removal": 0,
"sum_quantity": false
}
}
],
"revision": "{REVISION}",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE_HASH}",
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Change
POST /v2/accounts/{ACCOUNT_ID}/services/{PLAN_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/{PLAN_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/{PLAN_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove
DELETE /v2/accounts/{ACCOUNT_ID}/services/{PLAN_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/{PLAN_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/{PLAN_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch
GET /v2/accounts/{ACCOUNT_ID}/services/manual
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/manual
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/manual', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Change
POST /v2/accounts/{ACCOUNT_ID}/services/manual
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/manual
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/manual',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Patch
PATCH /v2/accounts/{ACCOUNT_ID}/services/manual
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/manual
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/manual',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Fetch
GET /v2/accounts/{ACCOUNT_ID}/services/overrides
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/overrides
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/overrides', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Change
POST /v2/accounts/{ACCOUNT_ID}/services/overrides
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/overrides
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/overrides',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Patch
PATCH /v2/accounts/{ACCOUNT_ID}/services/overrides
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/overrides
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/overrides',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Change
POST /v2/accounts/{ACCOUNT_ID}/services/quote
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/quote
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/quote',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Change
POST /v2/accounts/{ACCOUNT_ID}/services/reconciliation
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/reconciliation
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/reconciliation',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Change
POST /v2/accounts/{ACCOUNT_ID}/services/synchronization
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/synchronization
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/synchronization',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Change
POST /v2/accounts/{ACCOUNT_ID}/services/topup
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/topup
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/topup',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Fetch
GET /v2/accounts/{ACCOUNT_ID}/services/summary
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/summary
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/summary', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch
GET /v2/accounts/{ACCOUNT_ID}/services/available
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/available
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/available', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch
GET /v2/accounts/{ACCOUNT_ID}/services/editable
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/editable
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/editable', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Shared Authentication
About Shared Authentication
Schema
Provides a local auth-token via a shared auth-token
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
shared_auth |
The shared token | string(64) |
true |
Fetch
GET /v2/shared_auth
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/shared_auth
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/shared_auth', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create
PUT /v2/shared_auth
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/shared_auth
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/shared_auth',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Signup
About Signup
Schema
Create
Skels
About Skels
Description of the skel module goes here.
Schema
Fetch
GET /v2/accounts/{ACCOUNT_ID}/skels
More description if needed!
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/skels
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/skels', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": [
{
"name": "John",
"email": "john@email.com",
"stuff": [
"stuff1"
],
"age": 30,
"city": "San Francisco",
"zipcode": 94109
},
{
"name": "Jane",
"email": "Jane@email.com",
"stuff": [
"stuff2"
],
"age": 28,
"city": "San Francisco",
"zipcode": 94109
}
],
"page_size": 2,
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Create a resource
PUT /v2/accounts/{ACCOUNT_ID}/skels
More description if needed!
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": { \
"name": "Jane", \
"email": "Jane@email.com", \
"stuff": ["stuff2"], \
"age": 28, \
"city": "San Francisco", \
"zipcode": 94109 \
}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/skels
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/skels',
'{"data": { \\\n "name": "Jane", \\\n "email": "Jane@email.com", \\\n "stuff": ["stuff2"], \\\n "age": 28, \\\n "city": "San Francisco", \\\n "zipcode": 94109 \\\n }}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"data": {
"name": "Jane",
"email": "Jane@email.com",
"stuff": [
"stuff2"
],
"age": 28,
"city": "San Francisco",
"zipcode": 94109
},
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Delete a resource
DELETE /v2/accounts/{ACCOUNT_ID}/skels/{THING}
More description if needed!
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/skels/{THING}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/skels/{THING}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": {},
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Get a resource
GET /v2/accounts/{ACCOUNT_ID}/skels/{THING}
More description if needed!
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/skels/{THING}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/skels/{THING}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": {
"name": "Jane",
"email": "Jane@email.com",
"stuff": [
"stuff2"
],
"age": 28,
"city": "San Francisco",
"zipcode": 94109
},
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
Update a resource
POST /v2/accounts/{ACCOUNT_ID}/skels/{THING}
PATCH /v2/accounts/{ACCOUNT_ID}/skels/{THING}
More description if needed!
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": { \
"name": "Jane", \
"email": "jane@email.com", \
"stuff": ["some new stuff"], \
"age": 29, \
"city": "San Francisco", \
"zipcode": 94109 \
}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/skels/{THING}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/skels/{THING}',
'{"data": { \\\n "name": "Jane", \\\n "email": "jane@email.com", \\\n "stuff": ["some new stuff"], \\\n "age": 29, \\\n "city": "San Francisco", \\\n "zipcode": 94109 \\\n }}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"data": {
"name": "Jane",
"email": "jane@email.com",
"stuff": [
"some new stuff"
],
"age": 29,
"city": "San Francisco",
"zipcode": 94109
},
"request_id": "{REQUEST_ID}",
"status": "success",
"auth_token": "{AUTH_TOKEN}"
}
SMS
About SMS
Lumian offers API-based message services for inbound and outbound messages. Outbound messages sent through the Lumian API must be sent from a telephone number assigned to your Lumian account with an active messaging feature to be eligible for use.
Schema
SMS document
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
body |
text message | string(1..700) |
true |
|
from |
caller-id-number, taken from user if absent | string() |
false |
|
to |
callee-id-number | string() |
true |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/sms
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/sms
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/sms', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create
PUT /v2/accounts/{ACCOUNT_ID}/sms
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"from": "+15555555555", "to": "+14444444444", "body": "Hello"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/sms
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/sms',
'{"data": {"from": "+15555555555", "to": "+14444444444", "body": "Hello"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"success": true,
"reason": "SUCCESS",
"detail": "SUCCESS",
"result": {
"referenceId": "d88231b5-13b3-4fb2-8528-bc7164309389",
"from": "15555555555",
"text": "Hello",
"messageType": "SMS",
"resultResponses": [
{
"to": "14444444444",
"status": "SUCCESS"
}
]
}
}
Fetch
GET /v2/accounts/{ACCOUNT_ID}/sms/{SMS_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/sms/{SMS_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/sms/{SMS_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Remove
DELETE /v2/accounts/{ACCOUNT_ID}/sms/{SMS_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/sms/{SMS_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/sms/{SMS_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Storage
About Storage
Storage plans allow an account to control where data related to their account is stored. This can be critical when compliance with regulations is required.
A storage plan has three main components:
attachments: configuration for where to store attachments (binary data typically, like voicemails or faxes)connections: connection information to various third-party storage sitesplan: a description of the storage plan(s) for the account.
Attachments
Rather than storing binary data like voicemails, received faxes, and call recordings, in the Lumian databases, it can be convenient to store them in third-party storage services like Amazon S3, Google Drive, etc. This keeps the binary data in a place that an account or user maintains control over. Lumian keeps a pointer to the location when it needs to fetch the binary data (such as when you call into your voicemail box).
The attachments object configures storage back-ends - for instance, if you want to store to S3, you'll add your AWS secret and key and your S3 bucket information here.
Connections
Connections can be used to point to an alternative CouchDB instance for storing the JSON documents or attachments (for instance: putting CDRs in their own cluster). These can be specified in the storage plans.
Plans
Plans determine what to do with certain classes of databases:
account: where to store account datamodb: where to store temporal data, like CDRs or voicemailssystem: where to store system data, like prompts
Within the database classification, you can define things like the connection to use when reading/writing, what types of documents should be stored/retrieved, etc.
Enabling the storage endpoint
Crossbar must have the storage endpoint enabled first:
sup crossbar_maintenance start_module cb_storage
Schema
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
^_ |
Ignores CouchDB fields prefixed by underscores | `string() | integer() | boolean() | object()` |
^pvt_ |
Ignores Lumian private fields prefixed by pvt_ | `string() | integer() | boolean()` | |
attachments |
Defines where and how to store attachments. Keys are 32-character identifiers to be used in storage plans | #/definitions/storage.attachments | false |
||
connections |
Describes alternative connections to use (such as alternative CouchDB instances | #/definitions/storage.connections | false |
||
id |
ID of the storage document | string() |
false |
||
plan |
Describes how to store documents depending on the database or document type | #/definitions/storage.plan | false |
storage.attachment.aws
schema for AWS attachment entry
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
handler |
What AWS service to use | string('s3') |
true |
||
settings.bucket |
Bucket name to store data to | string(6..63) |
true |
||
settings.bucket_access_method |
how to access the host. | `string('auto' | 'vhost' | 'path')` | |
settings.bucket_after_host |
use bucket after host as part of url | boolean() |
false |
||
settings.host |
the s3 host, leave empty for default | string(1..) |
false |
||
settings.key |
AWS Key to use | string(1..128) |
true |
||
settings.port |
port to use | integer() |
false |
||
settings.region |
the region where the bucket is located | string(1..) |
false |
||
settings.scheme |
scheme to use to access host | `string('http' | 'https')` | false |
|
settings.secret |
AWS Secret to use | string(1..128) |
true |
||
settings |
AWS API settings | object() |
true |
storage.attachment.azure
schema for azure attachment entry
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
handler |
What handler module to use | string('azure') |
true |
||
settings.account |
the azure account name | string() |
true |
||
settings.container |
the azure container where the files should be saved | string() |
true |
||
settings.key |
the azure api key | string() |
true |
||
settings |
Settings for the Azure account | object() |
true |
storage.attachment.dropbox
schema for dropbox attachment entry
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
handler |
What handler module to use | string('dropbox') |
true |
||
settings.oauth_doc_id |
Doc ID in the system 'auth' database | string(1..) |
true |
||
settings |
Settings for the Dropbox account | object() |
true |
storage.attachment.google_drive
schema for google drive attachment entry
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
handler |
What handler module to use | string('google_drive') |
true |
||
settings.folder_id |
Folder ID in which to store the file, if any | string() |
false |
||
settings.oauth_doc_id |
Doc ID in the system 'auth' database | string(1..) |
true |
||
settings |
Settings for the Google Drive account | object() |
true |
storage.attachment.google_storage
schema for google storage attachment entry
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
handler |
What handler module to use | string('google_storage') |
true |
||
settings |
Settings for the Google Storage account | object() |
true |
storage.attachment.http
schema for HTTP(s) attachment entry
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
handler |
The handler interface to use | string('http') |
true |
||
settings.base64_encode_data |
Toggles whether to base64-encode the attachment data | boolean() |
false |
false |
|
settings.send_multipart |
Toggle whether to send multipart payload when storing attachment - will include metadata JSON if true | boolean() |
false |
||
settings.url |
The base HTTP(s) URL to use when creating the request | string() |
true |
||
settings.verb |
The HTTP verb to use when sending the data | `string('post' | 'put')` | put |
false |
settings |
HTTP server settings | object() |
true |
storage.attachment.onedrive
schema for OneDrive attachment entry
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
handler |
What handler module to use | string('onedrive') |
true |
||
settings.oauth_doc_id |
Doc ID in the system 'auth' database | string(1..) |
true |
||
settings |
Settings for the OneDrive account | object() |
true |
storage.attachments
Defines where and how to store attachments. Keys are 32-character identifiers to be used in storage plans
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
^[a-z0-9]{32}$.name |
Friendly name for this configuration | string() |
false |
||
^[a-z0-9]{32}$.settings.field_list |
list of fields to compose destination url | ["array(", "[#/definitions/storage.attachments.field](#storageattachments.field)", ")"] |
false |
||
^[a-z0-9]{32}$.settings.field_separator |
toplevel, field separator to compose destination url | string() |
false |
||
^[a-z0-9]{32}$.settings.folder_base_path |
base folder path | string() |
false |
||
^[a-z0-9]{32}$.settings |
Settings all handlers implement | object() |
false |
||
^[a-z0-9]{32}$ |
Configuration for the supported storage backends | object() |
false |
storage.attachments.field
field used when composing destination url
| Key | Description | Type | Default | Required | Support Level |
|---|
storage.connection.couchdb
schema for CouchDB connection entry
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
driver |
string('lumian_couch') |
true |
|||
name |
string() |
false |
|||
settings.connect_options.keepalive |
boolean() |
false |
|||
settings.connect_options |
object() |
false |
|||
settings.connect_timeout |
integer() |
false |
|||
settings.credentials.password |
integer() |
true |
|||
settings.credentials.username |
string() |
true |
|||
settings.credentials |
object() |
false |
|||
settings.ip |
string() |
true |
|||
settings.max_pipeline_size |
integer() |
false |
|||
settings.max_sessions |
integer() |
false |
|||
settings.pool.name |
string() |
true |
|||
settings.pool.size |
integer() |
true |
|||
settings.pool |
object() |
false |
|||
settings.port |
integer() |
true |
|||
settings |
object() |
true |
storage.connections
Describes alternative connections to use (such as alternative CouchDB instances
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
^([a-z,0-9]){32}$ |
#/definitions/storage.connection.couchdb | false |
|||
local |
object() |
false |
storage.plan
Describes how to store documents depending on the database or document type
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
account |
schema for database storage plan | #/definitions/storage.plan.database | false |
||
modb |
schema for database storage plan | #/definitions/storage.plan.database | false |
||
system |
schema for database storage plan | #/definitions/storage.plan.database | false |
storage.plan.database
schema for database storage plan
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
attachments |
schema for attachment ref type storage plan | #/definitions/storage.plan.database.attachment | false |
||
connection |
string() |
false |
|||
database.create_options |
object() |
false |
|||
database |
object() |
false |
|||
types.call_recording |
schema for document type storage plan | #/definitions/storage.plan.database.document | false |
||
types.fax |
schema for document type storage plan | #/definitions/storage.plan.database.document | false |
||
types.mailbox_message |
schema for document type storage plan | #/definitions/storage.plan.database.document | false |
||
types.media |
schema for document type storage plan | #/definitions/storage.plan.database.document | false |
||
types |
object() |
false |
storage.plan.database.attachment
schema for attachment ref type storage plan
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
handler |
string() |
false |
|||
params.folder_path |
folder path | string() |
false |
||
params |
object() |
false |
|||
stub |
boolean() |
false |
storage.plan.database.document
schema for document type storage plan
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
attachments |
schema for attachment ref type storage plan | #/definitions/storage.plan.database.attachment | false |
||
connection |
string() |
false |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/storage
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"attachments": {
"{UUID}": {
"handler": "s3",
"name": "S3 Storage",
"settings": {
"bucket": "{S3_BUCKET}",
"key": "{AWS_ACCESS_KEY}",
"secret": "{AWS_SECRET_KEY}"
}
}
},
"id": "{ACCOUNT_ID}",
"plan": {
"modb": {
"types": {
"mailbox_message": {
"attachments": {
"handler": "{UUID}"
}
}
}
}
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Create
PUT /v2/accounts/{ACCOUNT_ID}/storage
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
For instance, setting up your HTTP server to receive new voicemails for the account:
Sample Response:
{
"data": {
"attachments": {
"{UUID}": {
"handler": "http",
"name": "My HTTP server",
"settings": {
"url": "http://my.http.server:37635/some_prefix",
"verb": "post"
}
}
},
"plan": {
"modb": {
"types": {
"mailbox_message": {
"attachments": {
"handler": "{UUID}"
}
}
}
}
}
}
}
Change
POST /v2/accounts/{ACCOUNT_ID}/storage
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Patch
PATCH /v2/accounts/{ACCOUNT_ID}/storage
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove
DELETE /v2/accounts/{ACCOUNT_ID}/storage
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch
GET /v2/accounts/{ACCOUNT_ID}/storage/plans
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create
PUT /v2/accounts/{ACCOUNT_ID}/storage/plans
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Fetch
GET /v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Change
POST /v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Patch
PATCH /v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove
DELETE /v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Skipping attachment settings validation
When a storage plan is PUT/POSTed to Crossbar, Lumian will attempt to use the attachments' settings and store a small text file to verify that files can be stored remotely. Lumian will then issue a GET request to read the file back to test retrieval.
For "dumb" storage backends this is typically a non-issue as storing/retrieving files is what the backend does!
For "smart" backends, where a custom handler (like an HTTP web app) is accepting the files, adding code to handle this test file's storage/retrieval could place an unnecessary burden on the backend or be redundant after the first test if using the same destination for all accounts. As such, a request parameter can be included to skip this portion of the validation:
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{...}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage?validate_settings=false
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage',
'{"data":{...}}',
{
params: {
'validate_settings': 'false'
},
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
!!! danger If the storage backend is unable to process the storage request, you could lose the data attempting to be stored.
Enabling This Feature
By default, Lumian will not allow clients to skip settings validation. Clients that include the validate_settings request parameter on these systems will receive a 400 validation error indicating attachment storage settings must be tested.
Sysadmins can allow clients by setting a system_config flag: sup kzs_plan allow_validation_overrides
Disabling it later is similar: sup kzs_plan disallow_validation_overrides
URL formatting
It is possible to craft the URLs used by the handler based on the JSON document and attachment being saved by specifying a field_list array of objects that will help Lumian map values to the generated URL:
Sample Response:
{UUID}:{
"handler":"{HANDLER}",
"settings":{
"field_list":[
{"arg":"account_id"}
,{"arg":"id"}
,{"arg":"attachment"}
],
"url":"http://base.your.domain/"
}
}
In this case (the default for the HTTP handler) the URL provided in the handler's settings will be appended with /{ACCOUNT_ID}/{DOC_ID}/{ATTACHMENT_NAME}.
Field Options
list of fields to compose destination url
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
arg |
a argument passed to the handler | `string('account_id' | 'db' | 'id' | 'attachment')` |
const |
a constant value added to the string | string() |
false |
||
field |
a field from the metadata document | string() |
false |
||
group |
group the inner fields definitions with an empty separator | array() |
false |
Examples
Given a base URL of http://my_server.com/storage, an attachment call.mp3 being stored in the account000 account on the abc123 doc defined below:
Sample Response:
{"_id":"abc123"
,"foo":"bar"
,"bing":"bang"
}
We can create the following generated URLs:
| URL | field_list | |
| http://my_server.com/storage/account000/abc123/call.mp3 | [{"arg":"account_id"}, {"arg":"id"}, {"arg":"attachment"}] | |
| http://my_server.com/storage?path=/account000/abc123/call.mp3 | [{"const":"?path="}, {"arg":"account_id"}, {"arg":"id"}, {"arg":"attachment"}] | |
| http://my_server.com/storage/bar/call.mp3 | [{"field":"foo"}, {"arg":"attachment"}] | |
| http://my_server.com/storage/account001_call.mp3 | [{"group":[{"arg":"account_id"}, {"const":"_"}, {"arg":"attachment"}]}] | |
Global Storage settings
If you are the super-duper admin you can setup storage policy across your cluster by using the URL /v2/storage instead of per-account.
The validation request will arrive with /system_data/{DOC_ID}/{ANAME} on the end of the URL.
If you need to revert back to the standard settings you can run sup kzs_plan reset_system_dataplan; and changes will be removed and the initial version reinstalled.
Tasks - Background Jobs
Lumian Tasks enables listing, adding, starting & removing generic background tasks.
Schema
Input data to go through as part of a background task
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
file_name |
Human-readable name of a task's input file | string() |
false |
||
records |
List the rows of input data | array(object()) |
false |
Fetch
GET /v2/tasks
Sample Request:
curl -v -X GET \
http://{SERVER}:8000/v2/tasks?category=services&action=blipblop
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/tasks', {
params: {
'category': 'services'
}
});
Response Error: No such category and/or action
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"message": "invalid request"
},
"error": "500",
"message": "invalid request",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Success Response
Sample Request:
curl -v -X GET \
http://{SERVER}:8000/v2/tasks?category=services&action=descendant_quantities
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/tasks', {
params: {
'category': 'services'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"tasks": {
"descendant_quantities": {
"description": "List per-month descendant accounts quantities",
"doc": "Attempts to create a month-on-month listing of quantities used by descendant accounts.\nThis task returns the following fields:\n* `account_id`: a sub-account of the creator of this task.\n* `year`: integral year as 4 characters.\n* `month`: integral month as 2 characters (left-padded with a zero).\n* `category`: name of the quantity's category.\n* `item`: name of the category's item.\n* `quantity_bom`: integral quantity's value or empty.\n* `quantity_eom`: integral quantity's value or empty.\nNote: some beginning-of-month and end-of-month quantities documents may be missing.\nNote: when both an account's BoM & EoM documents for a given month are missing, no rows are a created for this month.\nNote: in all other cases the documents' value is printed verbatim: if unset the empty string is returned.\nE.g.: an integer quantity (such as 1, 10 or 0 (zero)) represents was the system has. If no quantity was found, the empty value is used.\n"
}
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
List all tasks
GET /v2/accounts/{ACCOUNT_ID}/tasks
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"account_id": "{ACCOUNT_ID}",
"auth_account_id": "{AUTH_ACCOUNT_ID}",
"action": "add",
"category": "number_management",
"created": 63632526992,
"file_name": "my_input_for_add.csv",
"id": "e5c92c4b50bcec520d5d7e1ce1b869",
"status": "pending",
"total_count": 1
},
{
"account_id": "{ACCOUNT_ID}",
"auth_account_id": "{AUTH_ACCOUNT_ID}",
"action": "add",
"category": "number_management",
"created": 63632526924,
"end_timestamp": 63632526969,
"id": "7c17c051d6553f0329d9f8c47b253c",
"node": "whistle_apps@qwd",
"start_timestamp": 63632526968,
"status": "success",
"success_count": 1,
"total_count": 1
}
],
"page_size": 2,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Add a new task
PUT /v2/accounts/{ACCOUNT_ID}/tasks
!!! note
There are tasks that run against system resources, only for use by the super duper admin (like rate uploading), which can omit /accounts/{ACCOUNT_ID} from the URI. Leaving the account in the URI should have no impact.
- With CSV input data:
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: text/csv" \
--data-binary @path/to/your/file.csv \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks?category={CATEGORY}&action={ACTION}&file_name={FILE_NAME}
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks?category={CATEGORY}',
'@path/to/your/file.csv',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'text/csv'
}
}
);
- With JSON input data:
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"records":[{RECORDS}], "file_name":"{FILE_NAME}"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks?category={CATEGORY}&action={ACTION}
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks?category={CATEGORY}',
'{"data": {"records":[{RECORDS}], "file_name":"{FILE_NAME}"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
- Without input data:
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks?category={CATEGORY}&action={ACTION}
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks?category={CATEGORY}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Responses
Success
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"_read_only": {
"account_id": "{ACCOUNT_ID}",
"auth_account_id": "{AUTH_ACCOUNT_ID}",
"action": "{ACTION}",
"category": "{CATEGORY}",
"id": "edfb48ea9617fa6832e43ce676c53f",
"submit_timestamp": 63632025993,
"total_count": "{RECORDS_COUNT}"
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Unknown category
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
"{CATEGORY}"
],
"error": "404",
"message": "bad identifier",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Unknown action
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
"{ACTION}"
],
"error": "404",
"message": "bad identifier",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Bad CSV format
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"csv": {
"format": {
"message": "Empty CSV or some row(s) longer than others or header missing"
}
}
},
"error": "500",
"message": "invalid request",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Bad input field name
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"attachment": {
"type": {
"unknown_fields": [
"wef"
]
}
}
},
"error": "500",
"message": "invalid request",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Missing mandatory fields
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"attachment": {
"type": {
"missing_mandatory_fields": [
"number",
"account_id"
]
}
}
},
"error": "500",
"message": "invalid request",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Rows or records missing values for mandatory fields
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"attachment": {
"type": {
"missing_mandatory_values": [
",+14157215234",
"009afc511c97b2ae693c6cc4920988e8,"
]
}
}
},
"error": "500",
"message": "invalid request",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Remove a completed task
DELETE /v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Success
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"_read_only": {
"account_id": "{ACCOUNT_ID}",
"auth_account_id": "{AUTH_ACCOUNT_ID}",
"action": "add",
"category": "number_management",
"end_timestamp": 63632524230,
"failure_count": 2,
"id": "{TASK_ID}",
"node": "whistle_apps@qwd",
"start_timestamp": 63632524230,
"status": "failure",
"submit_timestamp": 63632524207,
"success_count": 0,
"total_count": 2
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Task not found
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
"{TASK_ID}"
],
"error": "404",
"message": "bad identifier",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Task is running
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"cause": "{TASK_ID}",
"message": "bad identifier"
},
"error": "404",
"message": "bad_identifier",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Get a specific task's details
GET /v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Success
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"_read_only": {
"account_id": "{ACCOUNT_ID}",
"auth_account_id": "{AUTH_ACCOUNT_ID}",
"action": "list",
"category": "number_management",
"created": 63633924886,
"failure_count": 0,
"id": "{TASK_ID}",
"node": "whistle_apps@qwd",
"start_timestamp": 63633924909,
"status": "executing",
"success_count": 50,
"csvs":["in.csv"]
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Task does not exist
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
"{TASK_ID}"
],
"error": "404",
"message": "bad identifier",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Start a task
PATCH /v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Responses
Success
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"_read_only": {
"account_id": "{ACCOUNT_ID}",
"auth_account_id": "{AUTH_ACCOUNT_ID}",
"action": "add",
"category": "number_management",
"id": "{TASK_ID}",
"node": "whistle_apps@qwd",
"start_timestamp": 63632456149,
"status": "executing",
"submit_timestamp": 63632456101,
"total_count": 2
}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Task already started
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"cause": "{TASK_ID}",
"message": "bad identifier",
"reason": "task already started"
},
"error": "404",
"message": "bad_identifier",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Task does not exist
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"cause": "{TASK_ID}",
"message": "bad identifier"
},
"error": "404",
"message": "bad_identifier",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Stop a running task
Tasks that are processing can be stopped.
Note that they cannot be started again.
PATCH /v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}/stop
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}/stop
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}/stop',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Success Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"_read_only": {
"account_id": "{ACCOUNT_ID}",
"action": "list_all",
"auth_account_id": "{AUTH_ACCOUNT_ID}",
"category": "number_management",
"created": 63669534312,
"end_timestamp": 63669534747,
"failure_count": 0,
"id": "{TASK_ID}",
"start_timestamp": 63669534746,
"status": "stopped",
"success_count": 0
}
},
"node": "{NODE}",
"page_size": 1,
"request_id": "{REQUEST_ID}",
"revision": "{REV}",
"status": "success",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}"
}
Task is not running
A task that was not yet started or that has already finished cannot be stopped.
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"cause": "{TASK_ID}",
"message": "bad identifier",
"reason": "task is not running"
},
"error": "404",
"message": "bad_identifier",
"node": "{NODE}",
"page_size": 1,
"request_id": "{REQUEST_ID}",
"status": "error",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}"
}
Retrieve a task's CSVs
When you GET /v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}, the JSON will include a "csvs":[...]" array with input and output CSVs as appropriate. Use the name(s) in the array to specify which you would like to receive.
GET /v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Accept: text/csv" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}?csv_name=in.csv
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}', {
params: {
'csv_name': 'in.csv'
},
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Accept': 'text/csv'
}
});
You can also use the old way:
GET /v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}/input
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}/input
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}/input', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Success Response
Streams back the task's input in CSV format.
Task does not exist or did not have any input data
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"cause": "{TASK_ID}",
"message": "bad identifier"
},
"error": "404",
"message": "bad_identifier",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Retrieve a task's output CSV
GET /v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}
Sample Request:
curl -v -X GET \
-H "Accept: text/csv" \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}?csv_name=out.csv
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}', {
params: {
'csv_name': 'out.csv'
},
headers: {
'Accept': 'text/csv',
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Or the old way:
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}/output
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID}/output', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Success Response
Streams back the task's output in CSV format.
Task does not exist or output not yet in database
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"cause": "{TASK_ID}",
"message": "bad identifier"
},
"error": "404",
"message": "bad_identifier",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Templates
About Templates
Schema
Fetch
GET /v2/templates
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/templates
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/templates', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create
PUT /v2/templates/{TEMPLATE_NAME}
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/templates/{TEMPLATE_NAME}
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/templates/{TEMPLATE_NAME}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove
DELETE /v2/templates/{TEMPLATE_NAME}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/templates/{TEMPLATE_NAME}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/templates/{TEMPLATE_NAME}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Temporal Rules
About Temporal Rules
Temporal rules provide a flexible way to configure time-based Call routing, e.g. open hours, holidays, close hours, etc...
Schema
Schema for a temporal rules
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
cycle |
The recurrence cycle for this rule | `string('date' | 'daily' | 'weekly' | 'monthly' |
days |
The recurrence days for this rule | array(integer()) |
false |
supported |
|
enabled |
Whether the rule is enabled | boolean() |
false |
||
flags.[] |
string() |
false |
supported |
||
flags |
Flags set by external applications | array(string()) |
false |
supported |
|
interval |
The recurrence interval for this rule | integer() |
1 |
false |
supported |
month |
The recurrence month for this rule | integer() |
false |
supported |
|
name |
A friendly name for the temporal rule | string(1..128) |
true |
supported |
|
ordinal |
The recurrence ordinal for this rule | `string('every' | 'first' | 'second' | 'third' |
start_date |
The date that any recurrence should be calculated as starting on | integer() |
62586115200 |
false |
supported |
time_window_start |
Seconds from the start of a day to consider this rule valid | integer() |
false |
supported |
|
time_window_stop |
Seconds from the start of a day to stop considering this rule valid | integer() |
false |
supported |
|
wdays.[] |
`string('monday' | 'tuesday' | 'wednesday' | 'wensday' | |
wdays |
The recurrence weekdays for this rule | `array(string('monday' | 'tuesday' | 'wednesday' | 'wensday' |
Notes on fields
enabled
Unless you need to override a time of day rule (for example keep an office open longer) keep the property unset.
start_date
It is recommended that a start date always be set to some time in the past if this control is not required to ensure it takes effect on the next cycle.
Setting this property is especially important when using an interval other than 1. For example if the rule should be applied every other year and the start date is in 2010, then it will be active on 2010, 2012, 2014, etc. However, if the start date was in 2011 then it will be active on 2011, 2013, 2015, etc.
ordinal
Not all months have a fifth occurrence of a weekday; the rule is ignored if that is the case.
cycle
When cycle is date, the rule only considers start_date and matches it against the current day.
days
The days array is only valid when cycle is yearly or monthly.
Fetch
GET /v2/accounts/{ACCOUNT_ID}/temporal_rules
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token":"{AUTH_TOKEN}",
"status":"success",
"request_id":"{REQUEST_ID}",
"revision":"{REVISION}",
"data":[
{
"id":"{TEMPORAL_RULE_ID}",
"name":"Business Hours"
},
{
"id":"{TEMPORAL_RULE_ID}",
"name":"Holiday"
}
]
}
Create
PUT /v2/accounts/{ACCOUNT_ID}/temporal_rules
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"time_window_start":0,"time_window_stop":86400,"days":[25],"name":"Christmas","cycle":"yearly","start_date":62586115200,"month":12,"ordinal":"every","interval":1}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules',
'{"data":{"time_window_start":0,"time_window_stop":86400,"days":[25],"name":"Christmas","cycle":"yearly","start_date":62586115200,"month":12,"ordinal":"every","interval":1}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Sample Response:
{
"auth_token":"{AUTH_TOKEN}",
"status":"success",
"request_id":"{REQUEST_ID}",
"revision":"{REVISION}",
"data":{
"time_window_start":0,
"time_window_stop":86400,
"days":[25],
"name":"Christmas",
"cycle":"yearly",
"start_date":62586115200,
"month":12,
"ordinal":"every",
"interval":1
}
}
Fetch
GET /v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Change
POST /v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Patch
PATCH /v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove
DELETE /v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Temporal Rules Sets
About Temporal Rules Sets
A temporal rule set is a collection of temporal rules that can be used in a callflow to match more that one rule. And can also be re-used.
Schema
Schema for a temporal rules sets
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
flags.[] |
string() |
false |
supported |
||
flags |
Flags set by external applications | array(string()) |
false |
supported |
|
name |
A friendly name for the temporal rule set | string(1..128) |
true |
supported |
|
temporal_rules.[] |
string() |
false |
supported |
||
temporal_rules |
Temporal Rules | array(string()) |
false |
supported |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/temporal_rules_sets
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules_sets
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules_sets', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create a new rule set
PUT /v2/accounts/{ACCOUNT_ID}/temporal_rules_sets
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data": {"name": "July","temporal_rules": ["{RULE_ID}","{RULE_ID}"]}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules_sets
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules_sets',
// '{"data": {"name": "July","temporal_rules": ["{RULE_ID}","{RULE_ID}"]}}',
{
'data': {
'name': 'July',
'temporal_rules': [
'{RULE_ID}',
'{RULE_ID}'
]
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Fetch a rule set
GET /v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Change a rule set
POST /v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data": {"name": "July","temporal_rules": ["{RULE_ID}","{RULE_ID}"]}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET}',
// '{"data": {"name": "July","temporal_rules": ["{RULE_ID}","{RULE_ID}"]}}',
{
'data': {
'name': 'July',
'temporal_rules': [
'{RULE_ID}',
'{RULE_ID}'
]
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Patch a rule set
PATCH /v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET}',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove a rule set
DELETE /v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Token Authentication
Authentication tokens are generated using one of the authentication endpoints exposed by Crossbar. See User Authentication and API Authentication as examples of generating authentication tokens.
About Token Authentication
Once you have an authentication token, you can access various Crossbar resource endpoints to manipulate the system or your account (provided you have the access).
Authentication tokens refresh their pvt_modified timestamp each time they are used in an API request. Once an authentication token's pvt_modified timestamp has passed a configurable timeout (usually one hour), it is automatically cleaned up by the system and no longer valid.
Token Restrictions
The authentication token can be created with restrictions on what resource URIs (and HTTP methods) can be accessed by the requestor. This payload is added to the authentication payload used in any of the authentication methods provided (User, API, etc).
For example, when creating an authentication token via API key, include the following object to restrict the resultant authentication token to read-only:
Sample Response:
{
"data": {
"api_key": "{API_KEY}",
"restrictions": {
"get": [
"#"
]
}
}
}
AMQP binding tokens are used (# and *) to denote wildcards. An example with more fine-grained restrictions:
Sample Response:
{
"data": {
"api_key": "{API_KEY}",
"restrictions": {
"delete": [
"accounts/{ACCOUNT_ID}/users/*"
],
"get": [
"accounts/{ACCOUNT_ID}/users",
"accounts/{ACCOUNT_ID}/users/*",
"accounts/{ACCOUNT_ID}/users/*/*"
],
"post": [
"accounts/{ACCOUNT_ID}/users/*"
],
"put": [
"accounts/{ACCOUNT_ID}/users"
]
}
}
}
This would restrict the authentication token to only be able to access {ACCOUNT_ID}'s users resource and perform all of the CRUD actions (as well as quickcall and channel listings for a user). We can simply this restrictions object by using * for the method and # to match any URI with /users:
Sample Response:
{
"data": {
"api_key": "{API_KEY}",
"restrictions": {
"*": [
"accounts/{ACCOUNT_ID}/users/#"
]
}
}
}
Here the # matches 0 or more segments after /users.
Delete an authentication token
DELETE /v2/token_auth
If you'd like to invalidate an authentication token programmatically (versus letting the system expire the token), you can issue a DELETE:
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/token_auth
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/token_auth', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Check auth token validity
GET /v2/token_auth
This will tell you whether the auth token constitutes valid credentials.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/token_auth
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/token_auth', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Response when invalid
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"message": "invalid credentials"
},
"error": "401",
"message": "invalid_credentials",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Response when OK
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"account_id": "{ACCOUNT_ID}",
"account_name": "{ACCOUNT_NAME}",
"apps": [
],
"id": "{AUTH_TOKEN}",
"is_reseller": false,
"language": "en-us",
"method": "cb_user_auth",
"owner_id": "8e248327b85591955749e53ea45b6baa",
"reseller_id": "6b71cb72c876b5b1396a335f8f8a2594"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Token Restrictions
About Token Restrictions
Token restrictions - set of rules saved in auth token document. These rules grant access to API URIs.
If the token document doesn't have any rules then this module won't apply any restrictions to request.
These rules are created when the system creates an auth token.
Rules can be loaded from system template or account template.
System template located in system_config/crossbar.token_restrictions.
Account template located in {ACCOUNT_DB}/token_restrictions.
How it works?
When you make request to Crossbar (API), the system loads rules from auth token (used for authentication) and tries to apply the rules to URI (/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/).
More information about URI structure can be found here.
If Crossbar doesn't find a match for all parameters (endpoint name, account id, endpoint arguments, HTTP method), then it halts the request and returns a 403 error.
Full Example
The following is a full example for reference. It is a rule for only allowing accounts to read/update their account configs (effectively barring them from deleting the account or creating sub-accounts.
Sample Response:
{
"cb_user_auth": {
"user":{
"accounts":[
{
"rules": {
"*": ["GET", "POST", "PATCH"]
}
}
]
}
}
}
Place this on an account, as an admin, thusly:
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"restrictions":{"cb_user_auth": {"user":{"accounts":[{"rules": {"*": ["GET", "POST", "PATCH"]}}]}}}}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}',
'{"data":{"restrictions":{"cb_user_auth": {"user":{"accounts":[{"rules": {"*": ["GET", "POST", "PATCH"]}}]}}}}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Now, when someone logs into this account (via user_auth) and who's user_doc is of type user (and not admin), they will be unable to create sub-accounts, and will receive an error response like this:
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"cause": "access denied by token restrictions",
"message": "forbidden"
},
"error": "403",
"message": "forbidden",
"node": "ghw5cA1GROHLEa43HETSKg",
"request_id": "{REQUEST_ID}",
"status": "error",
"timestamp": "2017-06-07T23:16:25",
"version": "4.0.0"
}
The following sections break down what's happening here.
Template structure
Each template can have different rules for different authentication methods and user privilege levels.
Sample Response:
{
"AUTH_METHOD_1": {
"PRIV_LEVEL_1": {
"ENDPOINT_RULES"
},
"PRIV_LEVEL_2": {
"ENDPOINT_RULES"
},
...
},
"AUTH_METHOD_2": {
"PRIV_LEVEL_1": {
"ENDPOINT_RULES"
}
},
...
}
AUTH_METHOD_#- name of authentication method (cb_api_auth,cb_user_auth, etc) which created this auth token.PRIV_LEVEL_#- name of privilege level of authenticated user (admin,user, etc). This level is set inpriv_levelproperty of user document. If authentication method doesn't have a user associated (such ascb_api_auth) then selectadminset of rules.ENDPOINT_RULES- set of rules which will be saved in auth token document.
Auth method and priv level can be matched with "catch all" term - "_". If no exact match for auth method or priv level is found, the system will look for the 'catch all' rules, if any.
The rules are loaded into the auth token document when it is created (after successful authentication) and will be applied to any request using the auth token created.
Example template:
Sample Response:
{
"cb_user_auth": {
"admin": {
"RULES_FOR_ADMIN"
},
"user": {
"RULES_FOR_USER"
}
},
"_": {
"admin": {
"RULES_FOR_ADMIN"
},
"_": {
"CATCH_ALL_RULES"
}
}
}
Rules structure (saved in token document)
Sample Response:
{
"ENDPOINT_1": [
{
"allowed_accounts": [
"ACCOUNT_ID_1",
"ACCOUNT_ID_2"
],
"rules": {
"ARG_1": [
"VERB_1",
"VERB_2"
],
"ARG_2": [
"VERB_3"
]
...
}
},
{
"allowed_accounts": [
"ACCOUNT_ID_3"
],
"rules": {
"ARG_1": [
"VERB_1"
],
...
}
}
],
"ENDPOINT_2": [
{
"rules": {
"ARG_1": [
"_"
]
}
}
],
...
}
ENDPOINT_#- API endpoints ("devices","users","callflows", etc)ACCOUNT_ID_#- any appropriate account IDARG_#- arguments for endpoint separated by/VERB_#- any appropriate HTTP method ("GET","PUT", etc)
Match order
Endpoint match
At this step module compare resource from URI with resource names in token restrictions.
If URI is /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/{MODIFIER}/ then endpoint will be users, and {USER_ID}, {MODIFIER} are arguments of this endpoint.
Rules applied to the last endpoint in URI.
You can use "catch all" ("_") endpoint name. First tries exact endpoint name: if not found, try the catch-all (if it exists).
Sample Response:
{
"account": [
{ ... },
{ ... }
],
"users": [
{ ... },
{ ... }
],
"_": [
{ ... }
]
}
If a match is not found for the endpoint, this request is halted and a 403 error returned.
Each endpoint contains a list of objects with rules. Appropriate object is selected by "allowed_account" parameter.
Account match
After Crossbar finds the endpoint it tries to find rules for the requested account.
Sample Response:
{
"devices": [
{
"allowed_accounts": [
"{ACCOUNT_1_ID}",
"{ACCOUNT_2_ID}",
"{AUTH_ACCOUNT_ID}"
],
"rules": {
...
}
},
{
"allowed_accounts": [
"{DESCENDANT_ACCOUNT_ID}"
],
"rules": {
...
}
}
]
}
List of account IDs set in parameter "allowed_accounts". You can write exact IDs or one of the following special macros:
"{AUTH_ACCOUNT_ID}"- match request account id to the account of the auth token"{DESCENDANT_ACCOUNT_ID}"- match any descendants of the auth account"_"- match any account. If the"allowed_accounts"parameter is missing, it is treated as"_"(match any account).
The first endpoint-rule object matched to the requested account will be used in the next step of argument matching.
Endpoint arguments match
Endpoint arguments matched with parameter "rules".
Sample Response:
{
"devices": [
{
"allowed_accounts": [
"{ACCOUNT_ID}"
],
"rules": {
"/": [ ... ],
"{DEVICE_ID}": [ ... ],
"{DEVICE_ID}/sync": [ ... ],
"*": [ ... ]
}
}
]
}
The search is performed in the order in which they appear in the rules for first match. No more search after that.
Rule keys
| Key | Description |
|---|---|
/ |
match empty argument list (or used as separator between other keys) |
* |
match any single, non-empty argument |
# |
match any count of arguments (or zero arguments) |
string |
match exact string |
Examples:
/ - match empty argument list
Matches
/v2/accounts/{ACCOUNT_ID}/devices
Doesn't Match
/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/quickcall/{DID}
* - match any single, non-empty argument
Matches
/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_1_ID}/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_2_ID}- etc
Doesn't Match
/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync
# - match any arguments (or no arguments)
Matches
/v2/accounts/{ACCOUNT_ID}/devices/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync- etc
{DEVICE_ID} - exact match
Matches
/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}
Doesn't Match
/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_1_ID}/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_2_ID}- etc
For matching more than one argument, you can use / to delineate how to process the arguments. You can mix and match special characters, explicit strings, etc.
{DEVICE_ID}/quickcall/{DID} - match exact list of arguments
Matches
/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/quickcall/{DID}
Doesn't Match
/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/quickcall/{DID_2}
*/*/* - match exactly three arguments
Matches
/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/quickcall/{DID}
Doesn't Match
/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync
{DEVICE_ID}/# - matches {DEVICE_ID} plus all arguments
Matches
/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/quickcall/{DID}- etc
HTTP method match
If endpoint matching fails to find a match, Crossbar will try to match the HTTP method used.
Sample Response:
{
"devices": [
{
"allowed_accounts": [
"{ACCOUNT_ID}"
],
"rules": {
"/": [
"GET",
"PUT"
],
"{DEVICE_ID}": [
"_"
],
"#": [
"GET"
]
}
}
]
}
List can contain any valid HTTP method ("GET", "PUT", "POST", "PATCH", "DELETE") or the "catch all" - "_".
Schema
Schema for token restrictions
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
restrictions./^\w+$/./^\w+$/./^\w+$/.[].allowed_accounts.[] |
string() |
false |
|||
restrictions./^\w+$/./^\w+$/./^\w+$/.[].allowed_accounts |
Account allowed to match this item | array(string()) |
false |
||
restrictions./^\w+$/./^\w+$/./^\w+$/.[].rules./^[\w/#*]+$/.[] |
`string('GET' | 'PUT' | 'POST' | 'PATCH' | |
restrictions./^\w+$/./^\w+$/./^\w+$/.[].rules./^[\w/#*]+$/ |
verbs | `array(string('GET' | 'PUT' | 'POST' | 'PATCH' |
restrictions./^\w+$/./^\w+$/./^\w+$/.[].rules |
Rules applied to endpoint parameters | object() |
false |
||
restrictions./^\w+$/./^\w+$/./^\w+$/ |
array(object()) |
false |
|||
restrictions./^\w+$/./^\w+$/ |
Level of user privilege. '_' matches any priv level | object() |
false |
||
restrictions./^\w+$/ |
Name of authentication method used when creating token. '_' matches any auth method | object() |
false |
||
restrictions |
object() |
false |
Fetch
DELETE /v2/accounts/{ACCOUNT_ID}/token_restrictions
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/token_restrictions
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/token_restrictions', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch account's token restrictions
GET /v2/accounts/{ACCOUNT_ID}/token_restrictions
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/token_restrictions
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/token_restrictions', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Change account's token restrictions
POST /v2/accounts/{ACCOUNT_ID}/token_restrictions
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d @data.txt \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/token_restrictions
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/token_restrictions',
'@data.txt',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
File data.txt contains this restrictions:
adminhas full accessoperatorcan view/create/update devices (but not delete), full access to callflows, all other API restrictedaccountantcan only view transactions, all other API restrictedusercan only view devices and other users. all other API restricted
Sample Response:
{
"data": {
"restrictions": {
"_": {
"admin": {
"_": [
{
"rules": {
"#": [
"_"
]
}
}
]
},
"operator": {
"devices": {
"rules": {
"#": [
"GET",
"POST",
"PUT"
]
}
},
"callflows": {
"rules": {
"#": [
"_"
]
}
},
"_": {
"rules": {
"#": [
"GET"
]
}
}
},
"accountant": {
"transactions": {
"rules": {
"#": [
"GET"
]
}
},
"_": {
"rules": {
"#": []
}
}
},
"user": {
"users": {
"rules": {
"#": [
"GET"
]
},
"devices": {
"rules": {
"#": [
"GET"
]
},
"_": {
"rules": {
"#": []
}
}
}
}
}
}
}
}
}
Transactions
About
The transactions endpoint allows you to list debits and credits made to a specified account.
List Transactions
GET /v2/accounts/{ACCOUNT_ID}/transactions
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/transactions
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/transactions', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{"description": "monthly rollup",
"id": "09dd02e20e07dbb65401802ba20cfb32",
"amount": 10.179999999999999716,
"reason": "database_rollup",
"type": "credit",
"created": 63598331974,
"version": 2,
"code": 9999
}
,{"metadata": {
"auth_account_id": "{AUTH_ACCOUNT_ID}"
},
"id": "7dd1c20894587e9cbacb2d7fa2de80ab",
"amount": 1.0,
"reason": "admin_discretion",
"type": "debit",
"created": 63598591394,
"version": 2,
"code": 3005
}],
"request_id": "{REQUEST_ID}",
"status": "success"
}
Fetch
GET /v2/accounts/{ACCOUNT_ID}/transactions/{TRANSACTION_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/transactions/{TRANSACTION_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/transactions/{TRANSACTION_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create
PUT /v2/accounts/{ACCOUNT_ID}/transactions/sale
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/transactions/sale
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/transactions/sale',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Create
PUT /v2/accounts/{ACCOUNT_ID}/transactions/refund
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/transactions/refund
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/transactions/refund',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
User Authentication
About User Authentication
Using your user name and password, along with an account identifier, will instruct Crossbar to create an authentication token to be used on subsequent requests requiring authentication.
Schema
Provides an auth-token via user credentials
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
account_name |
The account name of the user | string(1..128) |
false |
||
account_realm |
The account realm of the user | string(4..253) |
false |
||
credentials |
A hash of the uses credentials | string(1..64) |
true |
||
method |
The hash method | `string('md5' | 'sha')` | md5 |
false |
phone_number |
A phone number assigned to the users account | string(1..64) |
false |
Create
PUT /v2/user_auth
Sample Request:
curl -v -X PUT \
-H "Content-Type: application/json" \
-d '{"data":{"credentials":"{CREDENTIALS_HASH}", "account_name":"{ACCOUNT_NAME"}, "method":[md5|sha]}}' \
http://{SERVER}:8000/v2/user_auth
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/user_auth',
'{"data":{"credentials":"{CREDENTIALS_HASH}", "account_name":"{ACCOUNT_NAME"}, "method":[md5|sha]}}',
{
headers: {
'Content-Type': 'application/json'
}
}
);
Where {CREDENTIALS_HASH} is MD5 or SHA1 hash of {username}:{password}.
Creating MD5 User/Pass credentials hash
Sample Request:
$ echo -n 'john@example.com:m32c6NfqYEt' | md5sum
82a2dc91686ec828a67152d45a5c5ef7 -
Responses
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"account_id": "{ACCOUNT_ID}",
"apps": [],
"is_reseller": true,
"language": "en-US",
"owner_id": "{OWNER_ID}",
"reseller_id": "{RESELLER_ID}"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Fetch Token Auth Information
GET /v2/user_auth/{AUTH_TOKEN}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/user_auth/{AUTH_TOKEN}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/user_auth/{AUTH_TOKEN}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": {
"account_id": "{ACCOUNT_ID}",
"owner_id": "{USER_ID}",
"method": "cb_user_auth",
"id": "{AUTH_TOKEN}",
"reseller_id": "{RESELLER_ID}",
"is_reseller": false,
"account_name": "{ACCOUNT_NAME}",
"language": "en-us",
"apps": [{
"id": "8bda62bf7ccf8f8acc219d5d2c515376",
"name": "accounts",
"api_url": "http://192.168.0.2:8000/v2/",
"label": "Accounts Manager"
}, {
"id": "99d5f033f0a4176640f9bf1c4e81abed",
"name": "numbers",
"api_url": "http://192.168.0.2:8000/v2/",
"label": "Number Manager"
}, {
"id": "0306d5162bad2c7a951b6842483f73cd",
"name": "voip",
"api_url": "http://192.168.0.2:8000/v2/",
"label": "Smart PBX"
}]
},
"auth_token": "{AUTH_TOKEN}",
"status": "success"
}
Password Recovery
Sometimes it is necessary to recover a password. Similar to user authentication, you can supply the account realm, the account name, or a phone number associated with the account to send a password reset to the user's email. This email will contain a link that one then click to verify identity & proceed with recovery.
Schema
| Key | Description | Type | Default | Required |
|---|---|---|---|---|
account_name |
The account name of the user | string(1..64) |
false |
|
account_realm |
The account realm of the user | string(1..64) |
false |
|
phone_number |
A phone number assigned to the user's account | string(1..64) |
false |
|
username |
The user's API username | string(1..254) |
true |
PUT /v2/user_auth/recovery
Sample Request:
curl -v -X PUT \
-H "content-type: application/json" \
-d '{"data":{"username":"API_USERNAME", "account_realm":"ACCOUNT_REALM", "ui_url": "{UI_URL}"}}' \
http://{SERVER}:8000/v2/user_auth/recovery
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/user_auth/recovery',
// '{"data":{"username":"API_USERNAME", "account_realm":"ACCOUNT_REALM", "ui_url": "{UI_URL}"}}',
{
'data': {
'username': 'API_USERNAME',
'account_realm': 'ACCOUNT_REALM',
'ui_url': '{UI_URL}'
}
},
{
headers: {
'content-type': 'application/json'
}
}
);
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Execute link from email account recovery
Send the {RESET_ID} collected in the recovery-email.
POST /v2/user_auth/recovery
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"reset_id": "{RESET_ID}"}}' \
http://{SERVER}:8000/v2/user_auth/recovery
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/user_auth/recovery',
'{"data": {"reset_id": "{RESET_ID}"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Responses
Success
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Unknown {RESET_ID}
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"user": {
"not_found": {
"cause": "{RESET_ID}",
"message": "The provided reset_id did not resolve to any user"
}
}
},
"error": "500",
"message": "invalid request",
"request_id": "{REQUEST_ID}",
"status": "error"
}
Impersonate a User
You can impersonate as another user in your sub account if you're already is logged in as an admin in your master account. This features a useful way to login as your customer to debug/test issues with the user system's point of view.
PUT /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/user_auth
Sample Request:
curl -v -X PUT \
-H "Content-Type: application/json" \
-d '{ "action": "impersonate_user", "data": {} }' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/user_auth
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/user_auth',
// '{ "action": "impersonate_user", "data": {} }',
{
'action': 'impersonate_user',
'data': {}
},
{
headers: {
'Content-Type': 'application/json'
}
}
);
Responses
A standard Crossbar authentication token.
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"account_id": "{ACCOUNT_ID}",
"apps": [],
"is_reseller": true,
"language": "en-US",
"owner_id": "{OWNER_ID}",
"reseller_id": "{RESELLER_ID}"
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Users
About Users
Users represent just that, your users of the system. You can assign multiple devices to a user, put the user in a callflow, and all devices will ring.
Schema
Schema for a user
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
call_forward.direct_calls_only |
Determines if the calls that are not directly sent to the device should be forwarded | boolean() |
false |
false |
|
call_forward.enabled |
Determines if the call forwarding should be used | boolean() |
false |
false |
|
call_forward.failover |
Enable the call-forwarding parameters if the device is offline | boolean() |
false |
false |
|
call_forward.ignore_early_media |
The option to determine if early media from the call forwarded number should ignored | boolean() |
true |
false |
|
call_forward.keep_caller_id |
Determines if the caller id is kept when the call is forwarded, if not the devices caller id is used | boolean() |
true |
false |
supported |
call_forward.number |
The number to forward calls to | string(0..35) |
false |
supported |
|
call_forward.require_keypress |
Determines if the callee is prompted to press 1 to accept the call | boolean() |
true |
false |
|
call_forward.substitute |
Determines if the call forwarding replaces the device | boolean() |
true |
false |
|
call_forward |
The device call forward parameters | object() |
false |
||
call_recording |
endpoint recording settings | #/definitions/call_recording | false |
||
call_restriction |
Device level call restrictions for each available number classification | object() |
{} |
false |
|
call_waiting |
Parameters for server-side call waiting | #/definitions/call_waiting | false |
||
caller_id |
The device caller ID parameters | #/definitions/caller_id | false |
||
caller_id_options.outbound_privacy |
Determines what appears as caller id for offnet outbound calls. Values: full - hides name and number; name - hides only name; number - hides only number; none - hides nothing | `string('full' | 'name' | 'number' | 'none')` |
caller_id_options |
custom properties for configuring caller_id | object() |
false |
||
contact_list.exclude |
If set to true the device is excluded from the contact list | boolean() |
false |
supported |
|
contact_list |
Contact List Parameters | object() |
{} |
false |
|
dial_plan |
A list of rules used to modify dialed numbers | #/definitions/dialplans | false |
||
directories |
Provides the mappings for what directory the user is a part of (the key), and what callflow (the value) to invoke if the user is selected by the caller. | object() |
false |
||
do_not_disturb.enabled |
Is do-not-disturb enabled for this user? | boolean() |
false |
||
do_not_disturb |
DND Parameters | object() |
false |
||
email |
The email of the user | string(3..254) |
false |
supported |
|
enabled |
Determines if the user is currently enabled | boolean() |
true |
false |
supported |
feature_level |
The user level for assigning feature sets | string() |
false |
||
first_name |
The first name of the user | string(1..128) |
true |
supported |
|
flags.[] |
string() |
false |
supported |
||
flags |
Flags set by external applications | array(string()) |
false |
supported |
|
formatters |
Schema for request formatters | object() |
false |
||
hotdesk.enabled |
Determines if the user has hotdesking enabled | boolean() |
false |
false |
|
hotdesk.id |
The users hotdesk id | string(0..15) |
false |
||
hotdesk.keep_logged_in_elsewhere |
Determines if user should be able to login to multiple phones simultaneously | boolean() |
false |
false |
|
hotdesk.pin |
The users hotdesk pin number | string(4..15) |
false |
||
hotdesk.require_pin |
Determines if user requires a pin to change the hotdesk state | boolean() |
false |
false |
|
hotdesk |
The user hotdesk parameters | object() |
{} |
false |
|
language |
The language for this user | string() |
false |
supported |
|
last_name |
The last name of the user | string(1..128) |
true |
supported |
|
media |
Configure audio/video/etc media options for this user | #/definitions/endpoint.media | false |
||
metaflows |
The device metaflow parameters | #/definitions/metaflows | false |
||
music_on_hold.media_id |
The ID of a media object that should be used as the music on hold | string(0..128) |
false |
||
music_on_hold |
The music on hold parameters used if not a property of the device owner | object() |
{} |
false |
|
password |
The GUI login password | string() |
false |
supported |
|
presence_id |
Static presence ID (used instead of SIP username) | string() |
false |
supported |
|
priv_level |
The privilege level of the user | `string('user' | 'admin')` | user |
false |
profile |
User's profile data | #/definitions/profile | false |
||
pronounced_name.media_id |
The ID of a media object that should be used as the music on hold | string(0..128) |
false |
||
pronounced_name |
Name pronounced by user to introduce himself to conference members | object() |
false |
||
require_password_update |
UI flag that the user should update their password. | boolean() |
false |
false |
|
ringtones.external |
The alert info SIP header added when the call is from internal sources | string(0..256) |
false |
||
ringtones.internal |
The alert info SIP header added when the call is from external sources | string(0..256) |
false |
||
ringtones |
Ringtone Parameters | object() |
{} |
false |
|
timezone |
User's timezone | string() |
false |
supported |
|
username |
The GUI login username - alpha-numeric, dashes, at symbol, periods, plusses, and underscores allowed | string(1..256) |
false |
supported |
|
verified |
Determines if the user has been verified | boolean() |
false |
false |
|
vm_to_email_enabled |
Determines if the user would like voicemails emailed to them | boolean() |
true |
false |
|
voicemail.notify.callback |
Schema for a callback options | #/definitions/notify.callback | false |
||
voicemail.notify |
object() |
false |
|||
voicemail |
object() |
false |
call_recording
endpoint recording settings
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
any |
settings for any calls to/from the endpoint | #/definitions/call_recording.source | false |
||
inbound |
settings for inbound calls to the endpoint | #/definitions/call_recording.source | false |
||
outbound |
settings for outbound calls from the endpoint | #/definitions/call_recording.source | false |
call_recording.parameters
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
enabled |
is recording enabled | boolean() |
false |
||
format |
What format to store the recording on disk | `string('mp3' | 'wav')` | false |
|
record_min_sec |
The minimum length, in seconds, the recording must be to be considered successful. Otherwise it is deleted | integer() |
false |
||
record_on_answer |
Recording should start on answer | boolean() |
false |
||
record_on_bridge |
Recording should start on bridge | boolean() |
false |
||
record_sample_rate |
What sampling rate to use on the recording | integer() |
false |
||
time_limit |
Time limit, in seconds, for the recording | integer() |
false |
||
url |
The URL to use when sending the recording for storage | string() |
false |
call_recording.source
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
any |
settings for calls from any network | #/definitions/call_recording.parameters | false |
||
offnet |
settings for calls from offnet networks | #/definitions/call_recording.parameters | false |
||
onnet |
settings for calls from onnet networks | #/definitions/call_recording.parameters | false |
call_waiting
Parameters for server-side call waiting
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
enabled |
Determines if server side call waiting is enabled/disabled | boolean() |
false |
caller_id
Defines caller ID settings based on the type of call being made
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
asserted.name |
The asserted identity name for the object type | string(0..35) |
false |
||
asserted.number |
The asserted identity number for the object type | string(0..35) |
false |
||
asserted.realm |
The asserted identity realm for the object type | string() |
false |
||
asserted |
Used to convey the proven identity of the originator of a request within a trusted network. | object() |
false |
||
emergency.name |
The caller id name for the object type | string(0..35) |
false |
||
emergency.number |
The caller id number for the object type | string(0..35) |
false |
||
emergency |
The caller ID used when a resource is flagged as 'emergency' | object() |
false |
||
external.name |
The caller id name for the object type | string(0..35) |
false |
||
external.number |
The caller id number for the object type | string(0..35) |
false |
||
external |
The default caller ID used when dialing external numbers | object() |
false |
||
internal.name |
The caller id name for the object type | string(0..35) |
false |
||
internal.number |
The caller id number for the object type | string(0..35) |
false |
||
internal |
The default caller ID used when dialing internal extensions | object() |
false |
dialplans
Permit local dialing by converting the dialed number to a routable form
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
system.[] |
string() |
false |
|||
system |
List of system dial plans | array(string()) |
false |
endpoint.media
Schema for endpoint media options
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
audio.codecs.[] |
`string('OPUS' | 'CELT@32000h' | 'G7221@32000h' | 'G7221@16000h' | |
audio.codecs |
A list of audio codecs the endpoint supports | `array(string('OPUS' | 'CELT@32000h' | 'G7221@32000h' | 'G7221@16000h' |
audio |
The audio media parameters | object() |
{} |
false |
|
bypass_media |
Default bypass media mode (The string type is deprecated, please use this as a boolean) | `boolean() | string('true' | 'false' | 'auto')` |
encryption.enforce_security |
Is Encryption Enabled? | boolean() |
false |
false |
|
encryption.methods.[] |
`string('zrtp' | 'srtp')` | false |
||
encryption.methods |
Supported Encryption Types | `array(string('zrtp' | 'srtp'))` | [] |
false |
encryption |
Encryption Parameters | object() |
{} |
false |
|
fax_option |
Is T.38 Supported? | boolean() |
false |
||
ignore_early_media |
The option to determine if early media from the endpoint should always be ignored | boolean() |
false |
||
progress_timeout |
The progress timeout to apply to the endpoint (seconds) | integer() |
false |
||
video.codecs.[] |
`string('H261' | 'H263' | 'H264' | 'VP8')` | |
video.codecs |
A list of video codecs the endpoint supports | `array(string('H261' | 'H263' | 'H264' | 'VP8'))` |
video |
The video media parameters | object() |
{} |
false |
formatters
Schema for request formatters
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
^[[:alnum:]_]+$ |
Key to match in the route request JSON | `array(#/definitions/formatters.format_options) | #/definitions/formatters.format_options` | false |
formatters.format_options
Schema for formatter options
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
direction |
Only apply the formatter on the relevant request direction | `string('inbound' | 'outbound' | 'both')` | |
match_invite_format |
Applicable on fields with SIP URIs. Will format the username portion to match the invite format of the outbound request. | boolean() |
false |
||
prefix |
Prepends value against the result of a successful regex match | string() |
false |
||
regex |
Matches against the value, with optional capture group | string() |
false |
||
strip |
If set to true, the field will be stripped from the payload | boolean() |
false |
||
suffix |
Appends value against the result of a successful regex match | string() |
false |
||
value |
Replaces the current value with the static value defined | string() |
false |
metaflow
A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
children./.+/ |
A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to | #/definitions/metaflow | false |
||
children |
Children metaflows | object() |
false |
||
data |
The data/arguments of the metaflow module | object() |
{} |
false |
|
module |
The name of the metaflow module to execute at this node | string(1..64) |
true |
metaflows
Actions applied to a call outside of the normal callflow, initiated by the caller(s)
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
binding_digit |
What DTMF will trigger the collection and analysis of the subsequent DTMF sequence | `string('1' | '2' | '3' | '4' |
digit_timeout |
How long to wait between DTMF presses before processing the collected sequence (milliseconds) | integer() |
false |
||
listen_on |
Which leg(s) of the call to listen for DTMF | `string('both' | 'self' | 'peer')` | |
numbers./^[0-9]+$/ |
A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to | #/definitions/metaflow | false |
||
numbers |
A list of static numbers with their flows | object() |
false |
||
patterns./.+/ |
A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to | #/definitions/metaflow | false |
||
patterns |
A list of patterns with their flows | object() |
false |
notify.callback
Schema for a callback options
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
attempts |
How many attempts without answer will system do | integer() |
false |
||
disabled |
Determines if the system will call to callback number | boolean() |
false |
||
interval_s |
How long will system wait between call back notification attempts | integer() |
false |
||
number |
Number for callback notifications about new messages | string() |
false |
||
schedule |
Schedules interval between callbacks | array(integer()) |
false |
||
timeout_s |
How long will system wait for answer to callback | integer() |
false |
profile
Defines user extended properties
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
addresses.[].address |
To specify the address | string() |
false |
||
addresses.[].types |
To specify types of the address | array() |
false |
||
addresses |
To specify the components of the addresses | array(object()) |
false |
||
assistant |
To specify the user's assistant | string() |
false |
||
birthday |
To specify the birth date of the user | string() |
false |
||
nicknames.[] |
string() |
false |
|||
nicknames |
To specify the text corresponding to the nickname of the user | array(string()) |
false |
||
note |
To specify supplemental information or a comment that is associated with the user | string() |
false |
||
role |
To specify the function or part played in a particular situation by the user | string() |
false |
||
sort-string |
To specify the family name or given name text to be used for national-language-specific sorting of the FN and N types | string() |
false |
||
title |
To specify the position or job of the user | string() |
false |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/users
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"email": "user1@account_realm.com",
"features": [
"caller_id",
"vm_to_email"
],
"first_name": "User",
"id": "{USER_ID}",
"last_name": "One",
"priv_level": "admin",
"timezone": "America/Los_Angeles",
"username": "user1@account_realm.com"
},
{
"email": "user2@account_realm.com",
"features": [
"caller_id",
"vm_to_email"
],
"first_name": "User",
"id": "{USER_ID}",
"last_name": "Two",
"priv_level": "user",
"timezone": "America/Los_Angeles",
"username": "user2@account_realm.com"
}
],
"page_size": 2,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Create a new user
PUT /v2/accounts/{ACCOUNT_ID}/users
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"first_name":"User", "last_name":"Three"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users',
// '{"data":{"first_name":"User", "last_name":"Three"}}',
{
'data': {
'first_name': 'User',
'last_name': 'Three'
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Responses
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"call_restriction": {},
"caller_id": {},
"contact_list": {},
"dial_plan": {},
"enabled": true,
"first_name": "User",
"hotdesk": {
"enabled": false,
"keep_logged_in_elsewhere": false,
"require_pin": false
},
"id": "{USER_ID}",
"last_name": "Three",
"media": {
"audio": {
"codecs": [
"PCMU"
]
},
"encryption": {
"enforce_security": false,
"methods": []
},
"video": {
"codecs": []
}
},
"music_on_hold": {},
"priv_level": "user",
"profile": {},
"require_password_update": false,
"ringtones": {},
"verified": false,
"vm_to_email_enabled": true
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Remove a user
This request will return the current JSON object of the now-deleted user.
DELETE /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"call_restriction": {},
"caller_id": {},
"contact_list": {},
"dial_plan": {},
"enabled": false,
"first_name": "User",
"hotdesk": {
"enabled": false,
"keep_logged_in_elsewhere": false,
"require_pin": false
},
"id": "{USER_ID}",
"last_name": "Three",
"media": {
"audio": {
"codecs": [
"PCMU"
]
},
"encryption": {
"enforce_security": false,
"methods": []
},
"video": {
"codecs": []
}
},
"music_on_hold": {},
"priv_level": "user",
"profile": {},
"require_password_update": false,
"ringtones": {},
"verified": false,
"vm_to_email_enabled": true
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Fetch a user
GET /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Responses
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"call_restriction": {},
"caller_id": {},
"contact_list": {},
"dial_plan": {},
"enabled": true,
"first_name": "User",
"hotdesk": {
"enabled": false,
"keep_logged_in_elsewhere": false,
"require_pin": false
},
"id": "{USER_ID}",
"last_name": "Three",
"media": {
"audio": {
"codecs": [
"PCMU"
]
},
"encryption": {
"enforce_security": false,
"methods": []
},
"video": {
"codecs": []
}
},
"music_on_hold": {},
"priv_level": "user",
"profile": {},
"require_password_update": false,
"ringtones": {},
"verified": false,
"vm_to_email_enabled": true
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Patch a user's doc
PATCH /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"enabled":false}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}',
{
'data': {
'enabled': false
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Responses
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"call_restriction": {},
"caller_id": {},
"contact_list": {},
"dial_plan": {},
"enabled": false,
"first_name": "User",
"hotdesk": {
"enabled": false,
"keep_logged_in_elsewhere": false,
"require_pin": false
},
"id": "{USER_ID}",
"last_name": "Three",
"media": {
"audio": {
"codecs": [
"PCMU"
]
},
"encryption": {
"enforce_security": false,
"methods": []
},
"video": {
"codecs": []
}
},
"music_on_hold": {},
"priv_level": "user",
"profile": {},
"require_password_update": false,
"ringtones": {},
"verified": false,
"vm_to_email_enabled": true
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Change the user doc
This requires posting the full user's document in the request body
Sync: See the documentation on device sync for more info on check-sync. One can add the field "sync": true to the JSON document in order to attempt a check-sync on every registered device this user has.
POST /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"first_name":"User","last_name":"Three","call_restriction":{},"caller_id":{},"contact_list":{},"dial_plan":{},"enabled":false,"hotdesk":{"enabled":false,"keep_logged_in_elsewhere":false,"require_pin":false},"media":{"audio":{"codecs":["PCMU"]},"encryption":{"enforce_security":false,"methods":[]},"video":{"codecs":[]}},"music_on_hold":{},"priv_level":"user","profile":{},"require_password_update":false,"ringtones":{},"verified":false,"vm_to_email_enabled":true}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}',
{
'data': {
'first_name': 'User',
'last_name': 'Three',
'call_restriction': {},
'caller_id': {},
'contact_list': {},
'dial_plan': {},
'enabled': false,
'hotdesk': {
'enabled': false,
'keep_logged_in_elsewhere': false,
'require_pin': false
},
'media': {
'audio': {
'codecs': [
'PCMU'
]
},
'encryption': {
'enforce_security': false,
'methods': []
},
'video': {
'codecs': []
}
},
'music_on_hold': {},
'priv_level': 'user',
'profile': {},
'require_password_update': false,
'ringtones': {},
'verified': false,
'vm_to_email_enabled': true
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Responses
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"call_restriction": {},
"caller_id": {},
"contact_list": {},
"dial_plan": {},
"enabled": false,
"first_name": "User",
"hotdesk": {
"enabled": false,
"keep_logged_in_elsewhere": false,
"require_pin": false
},
"id": "{USER_ID}",
"last_name": "Three",
"media": {
"audio": {
"codecs": [
"PCMU"
]
},
"encryption": {
"enforce_security": false,
"methods": []
},
"video": {
"codecs": []
}
},
"music_on_hold": {},
"priv_level": "user",
"profile": {},
"require_password_update": false,
"ringtones": {},
"verified": false,
"vm_to_email_enabled": true
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Fetch (or create) a vCard
vCard is a file format typically used in emails as a form of business card. Lumian currently generates a 3.0 compatible vCard.
GET /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/vcard
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Accept: text/x-vcard" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/vcard
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/vcard', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Accept': 'text/x-vcard'
}
});
Responses
Sample Response:
BEGIN:VCARD
VERSION:3.0
FN:User Three
N:Three;User
END:VCARD
Remove the photo from the user
DELETE /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch the user's photo, if any
Set the Accept header to either application/base64 or application/octet-stream to retrieve the picture's contents.
If the result is successful, you will want to pipe the response into a file.
GET /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo
Sample Request:
curl -v -X GET \
-H "Accept: application/base64" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo
[binary data]
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo', {
headers: {
'Accept': 'application/base64'
}
})
Create or change the user's photo
Use application/octet-stream as the content type.
POST /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo
Sample Request:
curl -v -X POST \
-H "Content-Type: application/octet-stream" \
--data-binary @/path/to/image.jpg \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo',
'@/path/to/image.jpg',
{
headers: {
'Content-Type': 'application/octet-stream'
}
}
);
Responses
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Quickcalls
See the quickcall docs for how to perform this action.
Voicemail
About Voicemail
Voicemail boxes store messages, recorded from the caller, for the voicemail box owner to listen to at a later time.
Differences between Lumian version 3.x and 4.x
As of Lumian 4.0 all new voicemail messages will be stored in the account MODbs.
Regarding this change voicemail API will no longer returns the messages array when fetching mailbox settings.
The existing /messages API should be used to manage messages in a voicemail box.
For more information about voicemail changes see documentation for lumian_voicemail.
Schema
Schema for a voicemail box
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
announcement_only |
Determine if the mailbox should only play announcements | boolean() |
false |
false |
unsupported |
check_if_owner |
Determines if when the user calls their own voicemail they should be prompted to sign in | boolean() |
true |
false |
supported |
delete_after_notify |
Move the voicemail to delete folder after the notification has been sent | boolean() |
false |
false |
supported |
flags.[] |
string() |
false |
supported |
||
flags |
Flags set by external applications | array(string()) |
false |
supported |
|
include_message_on_notify |
Whether or not to include the attachment when sending a new voicemail to email notification | boolean() |
true |
false |
supported |
include_transcription_on_notify |
Whether or not to include the transcription when sending a new voicemail to email notification | boolean() |
true |
false |
supported |
is_setup |
Determines if the user has completed the initial configuration | boolean() |
false |
false |
supported |
is_voicemail_ff_rw_enabled |
callflow allow fastforward and rewind during voicemail message playback | boolean() |
false |
false |
|
mailbox |
The voicemail box number | string(1..30) |
true |
supported |
|
media.unavailable |
The ID of a media object that should be used as the unavailable greeting | string(32) |
false |
supported |
|
media |
The media (prompt) parameters | object() |
{} |
false |
supported |
media_extension |
Voicemail audio format | `string('mp3' | 'mp4' | 'wav')` | mp3 |
name |
A friendly name for the voicemail box | string(1..128) |
true |
supported |
|
not_configurable |
Determines if the user can configure this voicemail. | boolean() |
false |
false |
supported |
notify.callback |
Schema for a callback options | #/definitions/notify.callback | false |
||
notify |
object() |
false |
supported |
||
notify_email_addresses.[] |
string() |
false |
supported |
||
notify_email_addresses |
List of email addresses to send notifications to (in addition to owner's email, if any) | array(string()) |
[] |
false |
supported |
oldest_message_first |
Play older voicemail messages before new ones | boolean() |
false |
false |
supported |
owner_id |
The ID of the user object that 'owns' the voicemail box | string(32) |
false |
supported |
|
pin |
The pin number for the voicemail box | string(4..6) |
false |
supported |
|
require_pin |
Determines if a pin is required to check the voicemail from the users devices | boolean() |
false |
false |
supported |
save_after_notify |
Move the voicemail to save folder after the notification has been sent (This setting will override delete_after_notify) | boolean() |
false |
false |
supported |
seek_duration_ms |
callflow fastforward and rewind seek duration | integer() |
10000 |
false |
|
skip_envelope |
Determines if the envelope should be skipped | boolean() |
false |
false |
beta |
skip_greeting |
Determines if the greeting should be skipped | boolean() |
false |
false |
supported |
skip_instructions |
Determines if the instructions after the greeting and prior to composing a message should be played | boolean() |
false |
false |
supported |
timezone |
The default timezone | string(5..32) |
false |
supported |
|
transcribe |
Transcribe voicemail using ASR engine | boolean() |
false |
false |
supported |
notify.callback
Schema for a callback options
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
attempts |
How many attempts without answer will system do | integer() |
false |
||
disabled |
Determines if the system will call to callback number | boolean() |
false |
||
interval_s |
How long will system wait between call back notification attempts | integer() |
false |
||
number |
Number for callback notifications about new messages | string() |
false |
||
schedule |
Schedules interval between callbacks | array(integer()) |
false |
||
timeout_s |
How long will system wait for answer to callback | integer() |
false |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/vmboxes
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"id": "3a63acc3694ba189947235ae4727941b",
"name": "VMBox 0",
"mailbox": "3000",
"owner_id": "f1d98a5df729f95cd208ee9430e3b21b",
"messages": 4
}
],
"revision": "{REVISION}",
"request_id": "{REQUEST_ID}",
"status": "success"
}
Create a new voicemail box
PUT /v2/accounts/{ACCOUNT_ID}/vmboxes
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data": {"name": "VMBox 0", "require_pin": true, "is_setup": false, "pin": "0000", "mailbox": "3000", "timezone": "America/Los_Angeles", "check_if_owner": true, "delete_after_notify": false, "not_configurable": false, "notify_email_addresses": [], "save_after_notify": false, "skip_greeting": false, "skip_instructions": false, "owner_id": "f1d98a5df729f95cd208ee9430e3b21b", "media":{}}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes',
// '{"data": {"name": "VMBox 0", "require_pin": true, "is_setup": false, "pin": "0000", "mailbox": "3000", "timezone": "America/Los_Angeles", "check_if_owner": true, "delete_after_notify": false, "not_configurable": false, "notify_email_addresses": [], "save_after_notify": false, "skip_greeting": false, "skip_instructions": false, "owner_id": "f1d98a5df729f95cd208ee9430e3b21b", "media":{}}}',
{
'data': {
'name': 'VMBox 0',
'require_pin': true,
'is_setup': false,
'pin': '0000',
'mailbox': '3000',
'timezone': 'America/Los_Angeles',
'check_if_owner': true,
'delete_after_notify': false,
'not_configurable': false,
'notify_email_addresses': [],
'save_after_notify': false,
'skip_greeting': false,
'skip_instructions': false,
'owner_id': 'f1d98a5df729f95cd208ee9430e3b21b',
'media': {}
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"name": "VMBox 0",
"require_pin": true,
"is_setup": false,
"pin": "0000",
"mailbox": "3000",
"timezone": "America/Los_Angeles",
"check_if_owner": true,
"delete_after_notify": false,
"not_configurable": false,
"notify_email_addresses": [],
"save_after_notify": false,
"skip_greeting": false,
"skip_instructions": false,
"id": "3a63acc3694ba189947235ae4727941b",
"owner_id": "f1d98a5df729f95cd208ee9430e3b21b",
"media": {}
},
"revision": "{REVISION}",
"request_id": "{REQUEST_ID}",
"status": "success"
}
list all voicemail messages on an account
GET /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages?paginate=true
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages', {
params: {
'paginate': 'true'
},
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"0e820108c0f4ca391500f3be1b02bdfa": {
"timestamp": 63630058722,
"from": "1001@aeac33.sip.lumian.net",
"to": "1000@aeac33.sip.lumian.net",
"caller_id_number": "1001",
"caller_id_name": "userb userb",
"call_id": "79959ZDNmM2I5ZTliMzA0NzA4N2FjNjlmODA5OWVkZjUxZWU",
"folder": "new",
"length": 3140,
"media_id": "201605-6aadef09f6fcf5fd8bcdfca312e923ba"
}
},
{
"0e820108c0f4ca391500f3be1b02bdfa": {
"timestamp": 63630058413,
"from": "1002@aeac33.sip.lumian.net",
"to": "1000@aeac33.sip.lumian.net",
"caller_id_number": "1002",
"caller_id_name": "userd userd",
"call_id": "79959MmNiMmJiMTIxODhjZjk0ZDhmOGNkMjJkN2MwNGQyNWY",
"folder": "new",
"length": 5500,
"media_id": "201605-f0c3c16551a5ff7b5753a381892e2e01"
}
}
],
"next_start_key": [],
"page_size": 50,
"revision": "{REVERSION}",
"request_id": "{REQUEST_ID}",
"status": "success"
}
Remove a voicemail box
DELETE /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"name": "VMBox 0",
"require_pin": true,
"is_setup": false,
"pin": "0000",
"mailbox": "3000",
"timezone": "America/Los_Angeles",
"check_if_owner": true,
"delete_after_notify": false,
"not_configurable": false,
"notify_email_addresses": [],
"save_after_notify": false,
"skip_greeting": false,
"skip_instructions": false,
"id": "3a63acc3694ba189947235ae4727941b",
"owner_id": "f1d98a5df729f95cd208ee9430e3b21b",
"media": {}
},
"revision": "{REVISION}",
"request_id": "{REQUEST_ID}",
"status": "success"
}
Fetch a voicemail box
GET /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"name": "VMBox 0",
"require_pin": true,
"is_setup": false,
"pin": "0000",
"mailbox": "3000",
"timezone": "America/Los_Angeles",
"check_if_owner": true,
"delete_after_notify": false,
"not_configurable": false,
"notify_email_addresses": [],
"save_after_notify": false,
"skip_greeting": false,
"skip_instructions": false,
"id": "3a63acc3694ba189947235ae4727941b",
"owner_id": "f1d98a5df729f95cd208ee9430e3b21b",
"media": {}
},
"revision": "{REVISION}",
"request_id": "{REQUEST_ID}",
"status": "success"
}
Patch a voicemail box
PATCH /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"some_key":"some_value"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}',
'{"data":{"some_key":"some_value"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"name": "VMBox 0",
"require_pin": true,
"is_setup": false,
"pin": "0000",
"mailbox": "3000",
"timezone": "America/Los_Angeles",
"check_if_owner": true,
"delete_after_notify": false,
"not_configurable": false,
"notify_email_addresses": [],
"save_after_notify": false,
"skip_greeting": false,
"skip_instructions": false,
"id": "3a63acc3694ba189947235ae4727941b",
"owner_id": "f1d98a5df729f95cd208ee9430e3b21b",
"media": {},
"some_key": "some_value"
},
"revision": "{REVISION}",
"request_id": "{REQUEST_ID}",
"status": "success"
}
Change a voicemail box's settings
POST /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data": {"name": "VMBox 0", "require_pin": true, "is_setup": false, "pin": "0000", "mailbox": "3000", "timezone": "America/Los_Angeles", "check_if_owner": true, "delete_after_notify": false, "not_configurable": false, "notify_email_addresses": [], "save_after_notify": false, "skip_greeting": false, "skip_instructions": false, "owner_id": "f1d98a5df729f95cd208ee9430e3b21b", "media":{}}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes \
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes',
// '{"data": {"name": "VMBox 0", "require_pin": true, "is_setup": false, "pin": "0000", "mailbox": "3000", "timezone": "America/Los_Angeles", "check_if_owner": true, "delete_after_notify": false, "not_configurable": false, "notify_email_addresses": [], "save_after_notify": false, "skip_greeting": false, "skip_instructions": false, "owner_id": "f1d98a5df729f95cd208ee9430e3b21b", "media":{}}}',
{
'data': {
'name': 'VMBox 0',
'require_pin': true,
'is_setup': false,
'pin': '0000',
'mailbox': '3000',
'timezone': 'America/Los_Angeles',
'check_if_owner': true,
'delete_after_notify': false,
'not_configurable': false,
'notify_email_addresses': [],
'save_after_notify': false,
'skip_greeting': false,
'skip_instructions': false,
'owner_id': 'f1d98a5df729f95cd208ee9430e3b21b',
'media': {}
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"name": "VMBox 0",
"require_pin": true,
"is_setup": false,
"pin": "0000",
"mailbox": "3000",
"timezone": "America/Los_Angeles",
"check_if_owner": true,
"delete_after_notify": false,
"not_configurable": false,
"notify_email_addresses": [],
"save_after_notify": false,
"skip_greeting": false,
"skip_instructions": false,
"id": "3a63acc3694ba189947235ae4727941b",
"owner_id": "f1d98a5df729f95cd208ee9430e3b21b",
"media": {}
},
"revision": "{REVISION}",
"request_id": "{REQUEST_ID}",
"status": "success"
}
Create a new voicemail message
There are two methods for creating a new voicemail message - they differ in how you attach the media file.
In the first method, you can create a voicemail document first in one request and then put the media file into the document with a second request using /messages/{VM_MSG_ID} API endpoint.
PUT /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d {"data":{"caller_id_name":"someone","caller_id_number":"6001","folder":"new","from":"someone@farfaraway.com"}} \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages
import axios from 'axios';
const response = await axios.put(
'http://{data:caller_id_number:6001}',
'{data:caller_id_name:someone}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"timestamp": 63630058722,
"from": "someone@farfaraway.com",
"to": "1000@sip.somewhere.com",
"caller_id_number": "6001",
"caller_id_name": "someone",
"call_id": "79959ZDNmM2I5ZTliMzA0NzA4N2FjNjlmODA5OWVkZjUxZWU",
"folder": "new",
"length": 3140,
"media_id": "201605-fadnew0mf6fcfgfd8bcdfca312e924bq"
},
"revision": "{REVISION}",
"request_id": "{REQUEST_ID}",
"status": "success"
}
And then you can use PUT method on /messages/201605-fadnew0mf6fcfgfd8bcdfca312e924bq to add the media to file (see PUT method for a message below).
In the second method, you can use a single PUT request and send a multipart content-type to add both the JSON metadata about the message and the media file itself, in a single request.
Sample Request:
curl -v -X PUT \
-H "Content-Type: multipart/mixed" \
-F "content=@message.json; type=application/json" \
-F "content=@voice.mp3; type=audio/mp3" \
-H 'X-Auth-Token: {AUTH_TOKEN}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/messages
import axios from 'axios';
import FormData from 'form-data';
import * as fs from 'fs';
const form = new FormData();
form.append('content', fs.readFileSync('message.json'), 'message.json');
form.append('content', fs.readFileSync('voice.mp3'), 'voice.mp3');
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/messages',
form,
{
headers: {
...form.getHeaders(),
'Content-Type': 'multipart/mixed',
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
The response is same as above.
Remove all or a list of messages from a voicemail box
DELETE /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages
Deleting all message is easy, just use DELETE method on message API endpoint to delete all account's messages.
Optional payload for deleting a group of messages:
- One can apply a filter to delete all messages in a particular folder(e.g. new or saved) by adding a query string
?folder=savedto the URL or set it in the payload as{"data": {"folder": "saved"}} - Or providing an array of message ids, e.g
{"data": {"messages": [MSG_ID1, MSG_ID2, ...]}}.
!!! note If you didn't move voicemail messages to the new format already, messages that are in old format will be moved to the new MODB format, which will cause their message id to change to the new format.
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"succeeded": ["201605-6aadef09f6fcf5fd8bcdfca312e923ba"],
"failed": [{"201605-49be0985ea3a33046f8073083517d27b":"not_found"}]
},
"revision": "{REVISION}",
"request_id": "{REQUEST_ID}",
"status": "success"
}
Fetch all messages for a voicemail box
GET /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"timestamp": 63630058722,
"from": "1001@aeac33.sip.lumian.net",
"to": "1000@aeac33.sip.lumian.net",
"caller_id_number": "1001",
"caller_id_name": "userb userb",
"call_id": "79959ZDNmM2I5ZTliMzA0NzA4N2FjNjlmODA5OWVkZjUxZWU",
"folder": "new",
"length": 3140,
"media_id": "201605-6aadef09f6fcf5fd8bcdfca312e923ba"
},
{
"timestamp": 63630058413,
"from": "1002@aeac33.sip.lumian.net",
"to": "1000@aeac33.sip.lumian.net",
"caller_id_number": "1002",
"caller_id_name": "userd userd",
"call_id": "79959MmNiMmJiMTIxODhjZjk0ZDhmOGNkMjJkN2MwNGQyNWY",
"folder": "new",
"length": 5500,
"media_id": "201605-f0c3c16551a5ff7b5753a381892e2e01"
}
],
"revision": "{REVISION}",
"request_id": "{REQUEST_ID}",
"status": "success"
}
Change a list of messages
POST /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages
Provide an array of message ids, e.g {"data": {"messages": ["MSG_ID1", "MSG_ID2", "MSG_ID3"]}} you can do following change operations on them. It will return two objects: the first is all the message ids that were successfully changed and the second one is those that failed with the reasons.
Change the folder of messages: set the folder that messages should move to (e.g. new or saved) by adding a query string
?folder=savedto the URL or set it in the payload as{"data": {"folder": "saved"}}.Move messages to another voicemail box: set the destination voicemail box ID in payload like:
{"data": {"source_id": "{NEW_VM_BOX_ID}"}}Copy messages to a single or a list of voicemail boxes set the destination voicemail box ID in payload like:
{"data": {"source_id": ["{NEW_VM_BOX_ID}"]}}
!!! note If you didn't move voicemail messages to the new format already, messages that are in old format will be moved to the new MODB format, which will cause their message id to change to the new format.
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data": {"folder": "saved", "messages": ["MSG_ID1", "MSG_ID2", "MSG_ID3"]}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages',
// '{"data": {"folder": "saved", "messages": ["MSG_ID1", "MSG_ID2", "MSG_ID3"]}}',
{
'data': {
'folder': 'saved',
'messages': [
'MSG_ID1',
'MSG_ID2',
'MSG_ID3'
]
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"succeeded": ["201605-6aadef09f6fcf5fd8bcdfca312e923ba"],
"failed": [{"201605-49be0985ea3a33046f8073083517d27b":"not_found"}]
},
"revision": "{REVISION}",
"request_id": "{REQUEST_ID}",
"status": "success"
}
Fetch the raw audio of a list of messages as a ZIP file
POST /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/raw
You can provide a list of voicemail message ID in the payload and get raw audio of them in a single ZIP file.
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-H "Accept: application/zip" \
-d '{"data": {"messages": ["MSG_ID1", "MSG_ID2", "MSG_ID3"]}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/raw
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/raw',
// '{"data": {"messages": ["MSG_ID1", "MSG_ID2", "MSG_ID3"]}}',
{
'data': {
'messages': [
'MSG_ID1',
'MSG_ID2',
'MSG_ID3'
]
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json',
'Accept': 'application/zip'
}
}
);
Remove a message from the voicemail box
DELETE /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/{VM_MSG_ID}
!!! note If you didn't move voicemail messages to the new format already, messages that are in old format will be moved to the new MODB format, which will cause their message id to change to the new format.
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/201605-6aadef09f6fcf5fd8bcdfca312e923ba
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/201605-6aadef09f6fcf5fd8bcdfca312e923ba', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"timestamp": 63630058722,
"from": "1001@aeac33.sip.lumian.net",
"to": "1000@aeac33.sip.lumian.net",
"caller_id_number": "1001",
"caller_id_name": "userb userb",
"call_id": "79959ZDNmM2I5ZTliMzA0NzA4N2FjNjlmODA5OWVkZjUxZWU",
"folder": "new",
"length": 3140,
"media_id": "201605-6aadef09f6fcf5fd8bcdfca312e923ba",
"transcription": {
"result": "success",
"text": "This is a test of the voicemail transcription."
}
},
"revision": "{REVISION}",
"request_id": "{REQUEST_ID}",
"status": "success"
}
Fetch a message from the voicemail box
GET /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/{VM_MSG_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/201605-6aadef09f6fcf5fd8bcdfca312e923ba
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/201605-6aadef09f6fcf5fd8bcdfca312e923ba', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
!!! note
If message doesn't have a folder assign to it by any chance, it will be set to new by this method. Please also refer to the note for change the folder of a message regards of possible change of message id.
Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"timestamp": 63630058722,
"from": "1001@aeac33.sip.lumian.net",
"to": "1000@aeac33.sip.lumian.net",
"caller_id_number": "1001",
"caller_id_name": "userb userb",
"call_id": "79959ZDNmM2I5ZTliMzA0NzA4N2FjNjlmODA5OWVkZjUxZWU",
"folder": "new",
"length": 3140,
"media_id": "201605-6aadef09f6fcf5fd8bcdfca312e923ba",
"transcription": {
"result": "success",
"text": "This is a test of the voicemail transcription."
}
},
"revision": "{REVISION}",
"request_id": "{REQUEST_ID}",
"status": "success"
}
Change a message
Change the folder of a message: set the folder that message should move to (e.g. new or saved) by adding a query string
?folder=savedto the URL or set it in the payload as{"data": {"folder": "saved"}}.Move a message to another voicemail box: set the destination voicemail box ID in payload like:
{"data": {"source_id": "{NEW_VM_BOX_ID}"}}Copy a message to a single or a list of voicemail boxes set the destination voicemail box ID in payload like:
{"data": {"source_id": ["{NEW_VM_BOX_ID}"]}}
POST /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/{VM_MSG_ID}
!!! note If you didn't move voicemail messages to the new format already, messages that are in old format will be moved to the new MODB format, which will cause their message id to change to the new format.
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"folder": "saved"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/201605-6aadef09f6fcf5fd8bcdfca312e923ba
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/201605-6aadef09f6fcf5fd8bcdfca312e923ba',
'{"data": {"folder": "saved"}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"timestamp": 63630058722,
"from": "1001@aeac33.sip.lumian.net",
"to": "1000@aeac33.sip.lumian.net",
"caller_id_number": "1001",
"caller_id_name": "userb userb",
"call_id": "79959ZDNmM2I5ZTliMzA0NzA4N2FjNjlmODA5OWVkZjUxZWU",
"folder": "saved",
"length": 3140,
"media_id": "201605-6aadef09f6fcf5fd8bcdfca312e923ba",
"transcription": {
"result": "success",
"text": "This is a test of the voicemail transcription."
}
},
"revision": "{REVISION}",
"request_id": "{REQUEST_ID}",
"status": "success"
}
Fetch the raw audio of the message
GET /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/{VM_MSG_ID}/raw
!!! note
If message doesn't have a folder assign to it by any chance, it will be set to new by this method. Please also refer to the note for change the folder of a message regards of possible change of message id.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/201605-6aadef09f6fcf5fd8bcdfca312e923ba/raw
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/201605-6aadef09f6fcf5fd8bcdfca312e923ba/raw', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Add a new voicemail media file to a message
If you added a message based on the first method mentioned above (using PUT method on /messages), you can use this to upload the media file for the created message.
!!! note If there's already a media file attachment inside the message document it will be removed and replaced with the new media file!
PUT /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/{VM_MSG_ID}/raw
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: multipart/mixed" \
-F "content=@voice.mp3; type=audio/mp3" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/201605-fadnew0mf6fcfgfd8bcdfca312e924bq/raw
import axios from 'axios';
import FormData from 'form-data';
import * as fs from 'fs';
const form = new FormData();
form.append('content', fs.readFileSync('voice.mp3'), 'voice.mp3');
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/201605-fadnew0mf6fcfgfd8bcdfca312e924bq/raw',
form,
{
headers: {
...form.getHeaders(),
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'multipart/mixed'
}
}
);
Response
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"timestamp": 63630058722,
"from": "someone@farfaraway.com",
"to": "1000@sip.somewhere.com",
"caller_id_number": "6001",
"caller_id_name": "someone",
"call_id": "79959ZDNmM2I5ZTliMzA0NzA4N2FjNjlmODA5OWVkZjUxZWU",
"folder": "new",
"length": 3140,
"media_id": "201605-fadnew0mf6fcfgfd8bcdfca312e924bq"
},
"revision": "{REVISION}",
"request_id": "{REQUEST_ID}",
"status": "success"
}
Webhooks
About Webhooks
Webhooks allow Lumian to send HTTP requests to a third-party web server, alerting that server of events occurring within Lumian. Typically, events would be fired for new calls, when a call is answered, and when a call is finished, though other events will be added in the future.
Schema
Web Hooks are subscriptions to allowed events that, when the event occurs, the event data is sent to the uri set in the Web Hook document.
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
custom_data |
These properties will be added to the event and will overwrite existing values. | object() |
false |
||
enabled |
Is the webhook enabled and running | boolean() |
true |
false |
|
format |
What Body format to use when sending the webhook. only valid for 'post' & 'put' verbs | `string('form-data' | 'json')` | form-data |
false |
hook |
The trigger event for a request being made to 'callback_uri'. | string() |
true |
supported |
|
http_verb |
What HTTP method to use when contacting the server | `string('get' | 'post' | 'put')` | post |
include_internal_legs |
Whether to filter out call legs that are internal to the system (loopback) | boolean() |
true |
false |
|
include_subaccounts |
Should the webhook be fired for subaccount events. | boolean() |
false |
supported |
|
name |
A friendly name for the webhook | string() |
true |
supported |
|
retries |
Retry the request this many times (if it fails) | integer() |
2 |
false |
supported |
uri |
The 3rd party URI to call out to an event | string() |
true |
supported |
Fetch
GET /v2/webhooks
Sample Request:
curl -v -X GET \
-H "Content-Type:application/json" \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/webhooks
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/webhooks', {
headers: {
'Content-Type': 'application/json',
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"description": "Events when calls end",
"id": "channel_destroy",
"name": "channel_destroy"
},
{
"description": "Events when new calls start",
"id": "channel_create",
"name": "channel_create"
},
{
"description": "Events for when the channel is answered by the endpoint",
"id": "channel_answer",
"name": "channel_answer"
},
{
"description": "Receive notifications when objects in Lumian are changed",
"id": "object",
"modifiers": {
"action": {
"description": "A list of object actions to handle",
"items": [
"doc_created",
"doc_edited",
"doc_deleted"
],
"type": "array"
},
"type": {
"description": "A list of object types to handle",
"items": [
"account",
"callflow",
"device",
"faxbox",
"media",
"user",
"vmbox"
],
"type": "array"
},
"types": {
"description": "A list of object types to handle",
"items": {
"type": "string"
},
"type": "array"
}
},
"name": "object"
}
],
"page_size": 4,
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Get sample payloads of all webhook events
GET /v2/webhooks/samples
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/webhooks/samples
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/webhooks/samples', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Example
Request:
Sample Request:
curl -H 'Content-Type: application/json' 'http://{SERVER}:8000/v2/webhooks/samples'
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/webhooks/samples', {
headers: {
'Content-Type': 'application/json'
}
});
Response:
Sample Response:
{
"data": [
"webhooks_channel_answer",
"webhooks_channel_bridge",
"webhooks_channel_create",
"webhooks_channel_destroy",
"webhooks_notifications",
"webhooks_object",
"webhooks_parking"
],
"revision": "{REVISION}",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success"
}
Get sample payloads of a webhook event
GET /v2/webhooks/samples/{SAMPLE_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/webhooks/samples/{SAMPLE_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/webhooks/samples/{SAMPLE_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
You can use regular Crossbar query string filters to narrow down the samples, for example:
Sample Request:
curl -H 'Content-Type: application/json' 'http://{SERVER}:8000/v2/webhooks/samples/webhook_notifications?filter_event_name=missed_call'
curl -H 'Content-Type: application/json' 'http://{SERVER}:8000/v2/webhooks/samples/webhook_object?filter_action=doc_created'
Example
Request:
Sample Request:
curl -s -H 'Content-Type: application/json' 'http://{SERVER}:8000/v2/webhooks/samples/webhooks_parking'
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/webhooks/samples/webhooks_parking', {
headers: {
'Content-Type': 'application/json'
}
});
Response:
Sample Response:
{
"page_size": 1,
"data": [
{
"account_id": "5a2d994fbae69b1d6b01eb9f0e7dfe62",
"call_id": "OWU4NzEwOTgyZWNiMjM0MzI0NjRkZDc4MWVmMjEyOWI",
"callee_id_name": "Test Name",
"callee_id_number": "5355543456",
"caller_id_Number": "+15555432345",
"caller_id_name": "Superman",
"event_name": "PARK_PARKED",
"parking_slot": 1
}
],
"revision": "{REVISION}",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}",
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success"
}
List webhooks
GET /v2/accounts/{ACCOUNT_ID}/webhooks
Any webhooks with disable_reason in the summary has been auto-disabled.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create webhook
PUT /v2/accounts/{ACCOUNT_ID}/webhooks
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data": { \
"name": "New Calls", \
"uri": "http://my.{SERVER}/calls/new.php", \
"http_verb": "post", \
"hook": "channel_create", \
"retries":3 \
}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks',
'{"data": { \\\n "name": "New Calls", \\\n "uri": "http://my.{SERVER}/calls/new.php", \\\n "http_verb": "post", \\\n "hook": "channel_create", \\\n "retries":3 \\\n }}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Get details of the webhook
GET /v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Edit webhook
POST /v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID}
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data": { \
"name": "New Calls", \
"uri": "http://my.{SERVER}/calls/new_calls.php", \
"http_verb": "post", \
"hook": "channel_create", \
"retries": 3 \
}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID}
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID}',
'{"data": { \\\n "name": "New Calls", \\\n "uri": "http://my.{SERVER}/calls/new_calls.php", \\\n "http_verb": "post", \\\n "hook": "channel_create", \\\n "retries": 3 \\\n }}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Patch webhook
PATCH /v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID}
You can also patch an existing webhook:
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"data":{"enabled":true}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID}
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID}',
{
'data': {
'enabled': true
}
},
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/json'
}
}
);
Delete a webhook
DELETE /v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID}
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID}
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
List Webhook Attempts
Webhooks tracks attempts to send the hook payloads to your URIs. You can get a listing of the more recent attempts to help debug what went wrong.
GET /v2/accounts/{ACCOUNT_ID}/webhooks/attempts
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks/attempts
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks/attempts', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": [
{
"client_error": "nxdomain",
"hook_id": "{HOOK_ID}",
"reason": "lumian http client error",
"result": "failure",
"retries left": 2,
"timestamp": 63590996563
},
{
"hook_id": "{HOOK_ID}",
"result": "success",
"timestamp": 63590996562
}
],
"page_size": 2,
"request_id": "{REQUEST_ID}",
"status": "success"
}
List attempts for a specific attempt
GET /v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID}/attempts
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID}/attempts
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID}/attempts', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Re-enable auto-disabled hooks in bulk
Webhooks will auto-disable failing hooks (if Lumian can't reach your server, or you take too long to respond with 200 OK, for instance). Especially if you're a reseller with webhooks in your client accounts, it can be tedious to have to iterate through all your accounts and re-enable each hook. Fortunately, you can perform this bulk-enable action against an account or an account and its descendants.
Enable an account's hooks
PATCH /v2/accounts/{ACCOUNT_ID}/webhooks
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"re-enable":true}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks',
'{"data":{"re-enable":true}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Enable an account's and descendant accounts' hooks
PATCH /v2/accounts/{ACCOUNT_ID}/descendants/webhooks
Sample Request:
curl -v -X PATCH \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data":{"re-enable":true}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/descendants/webhooks
import axios from 'axios';
const response = await axios.patch(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/descendants/webhooks',
'{"data":{"re-enable":true}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
Hook Payload
Here's what you can expect to receive when a webhook fires to your server:
Base Payload
- hook_event: The type of hook being fired
- call_direction: "inbound" or "outbound", relative to Lumian
- timestamp: Gregorian timestamp of the event
- account_id: ID of the account generating the event
- request: SIP Request
- to: SIP To
- from: SIP From
- call_id: SIP Call ID
- other_leg_call_id: If bridged, the Call ID of the other leg
- caller_id_name: Caller ID Name
- caller_id_number: Caller ID Number
- callee_id_name: Callee Name
- callee_id_number: Callee Number
Most of these fields should be present on all payloads.
Hook Specific
- channel_create
- hook_event: channel_create
- channel_answer
- hook_event: channel_answer
- channel_destroy
- hook_event: channel_destroy
- hangup_cause: SIP Hangup Cause (NORMAL_CLEARING, ORIGINATOR_CANCEL, etc)
- hangup_code: SIP Hangup Code (404, 503, etc)
- doc
- hook_event: doc
- action: doc_created, doc_updated, doc_deleted
- type: user, vmbox, callflow, account, device, faxbox, media
Hook Specific Custom Data
To restrict the kind of document or the action or both. You can set the custom data to:
Sample Response:
{
"type": "user",
"action": "doc_edited"
}
Websockets
About Websockets
Fetch information about what bindings can be subscribed to, what sockets are active, and the active bindings of a socket.
Available Websocket Bindings
Lists all available Websocket bindings.
GET /v2/websockets
Sample Request:
curl -v -X GET \
http://{SERVER}:8000/v2/websockets
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/websockets');
Response
Sample Response:
{
"data": {
"call": [
"call.CHANNEL_CREATE.{CALL_ID}",
"call.CHANNEL_ANSWER.{CALL_ID}",
"call.CHANNEL_DESTROY.{CALL_ID}",
"call.CHANNEL_HOLD.{CALL_ID}",
"call.CHANNEL_UNHOLD.{CALL_ID}",
"call.CHANNEL_BRIDGE.{CALL_ID}",
"call.PARK_PARKED.{CALL_ID}",
"call.PARK_RETRIEVED.{CALL_ID}",
"call.PARK_ABANDONED.{CALL_ID}"
],
"conference": [
"conference.event.{CONFERENCE_ID}.{CALL_ID}",
"conference.command.{CONFERENCE_ID}"
],
"fax": [
"fax.status.{FAX_ID}",
"fax.object.{ACTION}"
],
"object": [
"object.doc_created.account",
"object.doc_created.callflow",
"object.doc_created.device",
"object.doc_created.faxbox",
"object.doc_created.media",
"object.doc_created.user",
"object.doc_created.vmbox",
"object.doc_created.fax",
"object.doc_created.mailbox_message",
"object.doc_created.call_recording",
"object.doc_edited.account",
"object.doc_edited.callflow",
"object.doc_edited.device",
"object.doc_edited.faxbox",
"object.doc_edited.media",
"object.doc_edited.user",
"object.doc_edited.vmbox",
"object.doc_edited.fax",
"object.doc_edited.mailbox_message",
"object.doc_edited.call_recording",
"object.doc_deleted.account",
"object.doc_deleted.callflow",
"object.doc_deleted.device",
"object.doc_deleted.faxbox",
"object.doc_deleted.media",
"object.doc_deleted.user",
"object.doc_deleted.vmbox",
"object.doc_deleted.fax",
"object.doc_deleted.mailbox_message",
"object.doc_deleted.call_recording"
]
},
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}"
}
Fetch Socket IDs
GET /v2/accounts/{ACCOUNT_ID}/websockets
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/websockets
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/websockets', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{
"data": [
{"bindings":["object.doc_created.user"]
,"websocket_session_id":"{SOCKET_ID}"
,"timestamp":{CONNECTION_TIMESTAMP}
,"destination":"{WS_SERVER}"
,"source":"{CLIENT_IP}"
}
],
"status": "success"
}
Fetch Socket's Bindings
GET /v2/accounts/{ACCOUNT_ID}/websockets/{SOCKET_ID}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/websockets/{SOCKET_ID}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/websockets/{SOCKET_ID}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Sample Response:
{"data":{
"bindings": ["{CLIENT_BINDING}"],
"timestamp":{CONNECTION_TIMESTAMP},
"destination":"{BLACKHOLE_SERVER}",
"source":"{CLIENT_IP}",
"websocket_session_id": "{SOCKET_ID}"
},
"status": "success"
}
Whitelabel
About Whitelabel
Schema
Whitelabel settings
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
company_name |
The company name to display to users | string() |
false |
supported |
|
domain |
This is the whitelabeled domain that users will be entering to reach the UI | string() |
false |
supported |
|
fake_api_url |
This is a whitelabeled API URL, primarily used by the developer application | string() |
false |
beta |
|
hide_credits |
When checked this hides the credits | boolean() |
false |
false |
beta |
hide_powered |
When checked this hides the powered by Lumian on the bottom right | boolean() |
false |
false |
supported |
hide_registration |
When checked this hides the ability to register for a new account | boolean() |
false |
false |
beta |
inbound_trunks_price |
The price to show for inbound trunks, this is currently only for display purposes | string() |
false |
beta |
|
nav.help |
The URL to use when the help link is clicked | string() |
false |
supported |
|
nav.learn_more |
The URL to use when the 'Learn More!' link is clicked | string() |
false |
supported |
|
nav |
Properties related to navigation in the UI | object() |
false |
||
outbound_trunks_price |
The price to show for outbound trunks, this is currently only for display purposes | string() |
false |
beta |
|
port.authority |
The account ID(s) to be used for administrating port requests | `string() | array(string())` | false |
|
port.features |
The URL to use when the features link is clicked | string() |
false |
supported |
|
port.loa |
The URL to use when the LOA link is clicked | string() |
false |
supported |
|
port.resporg |
The URL to use when the resporg link is clicked | string() |
false |
supported |
|
port.support_email |
The support email address to display to the user | string() |
false |
supported |
|
port.terms |
The URL to use when the terms and conditions link is clicked | string() |
false |
supported |
|
port |
Parameters related to white-labeling port requests | object() |
false |
||
sso_providers |
["array(", "[#/definitions/sso_provider](#sso_provider)", ")"] |
false |
|||
twoway_trunks_price |
The price to show for twoway trunks, this is currently only for display purposes | string() |
false |
beta |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/whitelabel
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Create
PUT /v2/accounts/{ACCOUNT_ID}/whitelabel
Sample Request:
curl -v -X PUT \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel
import axios from 'axios';
const response = await axios.put(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Change
POST /v2/accounts/{ACCOUNT_ID}/whitelabel
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Remove
DELETE /v2/accounts/{ACCOUNT_ID}/whitelabel
Sample Request:
curl -v -X DELETE \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel
import axios from 'axios';
const response = await axios.delete('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch
GET /v2/accounts/{ACCOUNT_ID}/whitelabel/{WHITELABEL_DOMAIN}
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/{WHITELABEL_DOMAIN}
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/{WHITELABEL_DOMAIN}', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch
GET /v2/accounts/{ACCOUNT_ID}/whitelabel/domains
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/domains
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/domains', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Change
POST /v2/accounts/{ACCOUNT_ID}/whitelabel/domains
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/domains
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/domains',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Fetch
GET /v2/accounts/{ACCOUNT_ID}/whitelabel/welcome
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/welcome
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/welcome', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Change
POST /v2/accounts/{ACCOUNT_ID}/whitelabel/welcome
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/welcome
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/welcome',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Fetch
GET /v2/accounts/{ACCOUNT_ID}/whitelabel/icon
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/icon
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/icon', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Change
POST /v2/accounts/{ACCOUNT_ID}/whitelabel/icon
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/icon
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/icon',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Fetch
GET /v2/accounts/{ACCOUNT_ID}/whitelabel/logo
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/logo
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/logo', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Change
POST /v2/accounts/{ACCOUNT_ID}/whitelabel/logo
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/logo
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/logo',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Fetch
GET /v2/accounts/{ACCOUNT_ID}/whitelabel/{WHITELABEL_DOMAIN}/welcome
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/{WHITELABEL_DOMAIN}/welcome
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/{WHITELABEL_DOMAIN}/welcome', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch
GET /v2/accounts/{ACCOUNT_ID}/whitelabel/{WHITELABEL_DOMAIN}/icon
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/{WHITELABEL_DOMAIN}/icon
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/{WHITELABEL_DOMAIN}/icon', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Fetch
GET /v2/accounts/{ACCOUNT_ID}/whitelabel/{WHITELABEL_DOMAIN}/logo
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/{WHITELABEL_DOMAIN}/logo
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/{WHITELABEL_DOMAIN}/logo', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
Whitelabeling
Whitelabling is one of the core functionality of the Lumian which allows to make your own brand.
Schema
Whitelabel settings
| Key | Description | Type | Default | Required | Support Level |
|---|---|---|---|---|---|
company_name |
The company name to display to users | string() |
false |
supported |
|
domain |
This is the whitelabeled domain that users will be entering to reach the UI | string() |
false |
supported |
|
fake_api_url |
This is a whitelabeled API URL, primarily used by the developer application | string() |
false |
beta |
|
hide_credits |
When checked this hides the credits | boolean() |
false |
false |
beta |
hide_powered |
When checked this hides the powered by Lumian on the bottom right | boolean() |
false |
false |
supported |
hide_registration |
When checked this hides the ability to register for a new account | boolean() |
false |
false |
beta |
inbound_trunks_price |
The price to show for inbound trunks, this is currently only for display purposes | string() |
false |
beta |
|
nav.help |
The URL to use when the help link is clicked | string() |
false |
supported |
|
nav.learn_more |
The URL to use when the 'Learn More!' link is clicked | string() |
false |
supported |
|
nav |
Properties related to navigation in the UI | object() |
false |
||
outbound_trunks_price |
The price to show for outbound trunks, this is currently only for display purposes | string() |
false |
beta |
|
port.authority |
The account ID(s) to be used for administrating port requests | `string() | array(string())` | false |
|
port.features |
The URL to use when the features link is clicked | string() |
false |
supported |
|
port.loa |
The URL to use when the LOA link is clicked | string() |
false |
supported |
|
port.resporg |
The URL to use when the resporg link is clicked | string() |
false |
supported |
|
port.support_email |
The support email address to display to the user | string() |
false |
supported |
|
port.terms |
The URL to use when the terms and conditions link is clicked | string() |
false |
supported |
|
port |
Parameters related to white-labeling port requests | object() |
false |
||
sso_providers |
["array(", "[#/definitions/sso_provider](#sso_provider)", ")"] |
false |
|||
twoway_trunks_price |
The price to show for twoway trunks, this is currently only for display purposes | string() |
false |
beta |
Fetch
GET /v2/accounts/{ACCOUNT_ID}/whitelabel/domains
When you white label Lumian's services, DNS settings are needed to make sure your hostname maps appropriate for the various DNS entries (CNAM, A, NAPTR, etc). If the system admin has configured their settings on the backend, you can query Crossbar to show you what your settings should map to.
You have two options on the request for what domain to use:
- If you've already configured your whitelabel domain for the account, the API will use that value.
- If you specify
domain=some.realm.comon the request,some.realm.comwill be used instead.
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/domains?domain=some.realm.com
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/domains', {
params: {
'domain': 'some.realm.com'
},
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
});
OR
Sample Request:
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {"domain": "some.realm.com"}}' \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/domains
import axios from 'axios';
const response = await axios.get('http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/domains', {
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
},
data: '{"data": {"domain": "some.realm.com"}}'
});
Assuming your whitelabel domain is "mydomain.com" you should receive a payload similar to:
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"A": {
"us-central.mydomain.com": {
"mapping": [
"166.78.105.67"
],
"name": "Secondary Proxy",
"zone": "us-central"
},
"us-east.mydomain.com": {
"mapping": [
"8.36.70.3"
],
"name": "Primary Proxy",
"zone": "us-east"
},
"us-west.mydomain.com": {
"mapping": [
"8.30.173.3"
],
"name": "Tertiary Proxy",
"zone": "us-west"
}
},
"CNAM": {
"api.mydomain.com": {
"mapping": [
"api.zswitch.net"
],
"name": "API"
},
"portal.mydomain.com": {
"mapping": [
"ui.zswitch.net"
],
"name": "Web GUI"
}
},
"MX": {},
"NAPTR": {
"proxy-central.mydomain.com": {
"mapping": [
"10 100 \"S\" \"SIP+D2U\" \"\" _sip._udp.proxy-central.mydomain.com."
],
"name": "Central NAPTR"
},
"proxy-east.mydomain.com": {
"mapping": [
"10 100 \"S\" \"SIP+D2U\" \"\" _sip._udp.proxy-east.mydomain.com."
],
"name": "East NAPTR"
},
"proxy-west.mydomain.com": {
"mapping": [
"10 100 \"S\" \"SIP+D2U\" \"\" _sip._udp.proxy-west.mydomain.com."
],
"name": "West NAPTR"
}
},
"SRV": {
"_sip._udp.proxy-east.mydomain.com": {
"mapping": [
"10 10 7000 us-east.mydomain.com.",
"15 15 7000 us-central.mydomain.com.",
"20 20 7000 us-west.mydomain.com."
],
"name": "East SRV"
}
},
"TXT": {}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
Here you can see which DNS records are supported and where they should point to access the Lumian cluster.
Testing your domains
POST /v2/accounts/{ACCOUNT_ID}/whitelabel/domains
Lumian will attempt to validate your whitelabel settings if you send it a POST to do so:
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/domains
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel/domains',
'',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}'
}
}
);
Similar to the GET, you can include a domain= parameter in the request to test your domains before you create the whitelabel document. A sample response is below:
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"A": {
"us-central.r1.244.com": {
"actual": [
"{IP_ADDRESS}"
],
"expected": [
"166.78.105.67"
]
},
"us-east.r1.244.com": {
"actual": [
"{IP_ADDRESS}"
],
"expected": [
"8.36.70.3"
]
},
"us-west.r1.244.com": {
"actual": [
"{IP_ADDRESS}"
],
"expected": [
"8.30.173.3"
]
}
},
"CNAM": {
"api.r1.244.com": {
"actual": [],
"expected": [
"api.zswitch.net"
]
},
"portal.r1.244.com": {
"actual": [],
"expected": [
"ui.zswitch.net"
]
}
},
"MX": {},
"NAPTR": {
"proxy-central.r1.244.com": {
"actual": [],
"expected": [
"10 100 \"S\" \"SIP+D2U\" \"\" _sip._udp.proxy-central.r1.244.com."
]
},
"proxy-east.r1.244.com": {
"actual": [],
"expected": [
"10 100 \"S\" \"SIP+D2U\" \"\" _sip._udp.proxy-east.r1.244.com."
]
},
"proxy-west.r1.244.com": {
"actual": [],
"expected": [
"10 100 \"S\" \"SIP+D2U\" \"\" _sip._udp.proxy-west.r1.244.com."
]
}
},
"SRV": {
"_sip._udp.proxy-east.r1.244.com": {
"actual": [],
"expected": [
"10 10 7000 us-east.r1.244.com.",
"15 15 7000 us-central.r1.244.com.",
"20 20 7000 us-west.r1.244.com."
]
}
},
"TXT": {}
},
"request_id": "{REQUEST_ID}",
"revision": "{REVISION}",
"status": "success"
}
You should be able to compare your hosts in each DNS type against the expected values configured by the system admin and adjust your DNS settings as appropriate.
Configuring the Domains (System Administrators only)
System administrators can set/update the domains object that is used when resellers whitelabel the service. The generic format of the JSON object is:
Sample Response:
{
"{DNS_RECORD_TYPE}":{
"{WHITELABEL_ABLE_DOMAIN}":{
"mapping":["{IP_ADDRESS}", "{SRV_RECORD}", "{NAPTR_RECORD}"],
"name":"Friendly name",
"zone":"{Lumian_ZONE}"
}
}
}
{DNS_RECORD_TYPE}: In all uppercase, the DNS record type. "CNAM", "A", "SRV", "MX", etc, that you have defined.{WHITELABEL_ABLE_DOMAIN}: The template for what the hostname will look like when whitelabeled. The only template parameter is{{domain}}, which will be replaced by the whitelabel domain of the reseller.mapping: This is a list of records the reseller should use when configuring their DNS entries for this DNS record type. It could be a list of IP addresses for CNAM or A, or listings of NAPTR/SRV records. Again, the mappings can use the{{domain}}placeholder for the whitelabeled domain.{Lumian_ZONE}: what zone this host is located in. If using dedicated IPs for the reseller, this will help when building the IP addresses usable by the reseller. Currently, however, this is purely informational.
To set the system domains object, the API is:
POST /v2/whitelabel/domains
Sample Request:
curl -v -X POST \
-H "X-Auth-Token: {AUTH_TOKEN}" \
-d '{"data": {DOMAINS_OBJECT}}' \
http://{SERVER}:8000/v2/whitelabel/domains
import axios from 'axios';
const response = await axios.post(
'http://{SERVER}:8000/v2/whitelabel/domains',
'{"data": {DOMAINS_OBJECT}}',
{
headers: {
'X-Auth-Token': '{AUTH_TOKEN}',
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
If you receive a 400 when POSTing with a response like:
Sample Response:
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"domains": {
"required": {
"message": "The domains schema is missing, unable to validate request"
}
}
},
"error": "400",
"message": "invalid data",
"request_id": "{REQUEST_ID}",
"status": "error"
}
You will need to run sup kapps_maintenance refresh system_schemas to ensure the domains schema is available.