NAV Navbar
Logo
shell javascript

Introduction

Welcome to the SIPINK VoIP API! You can use our API to access SIPINK VoIP API endpoints, where you can use to get information about users, create accounts, edit accounts, extensions and much more.

We have language bindings in Shell, Javascript. Please note that his UI is advanced enough to create your own GUI system, which you are allowed to resell if you wish.

Authentication

Schema

Key Description Type Default Required
account_name The account name of the user string(1..128) false
account_realm The account realm of the user string(1..64) 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

Auth Token

Create

curl -v -X PUT \
    -H "Content-Type: application/json" \
    -d '{"data":{"credentials":"{CREDENTIALS_HASH}", "account_name":"{ACCOUNT_NAME"}, "method":{MD5_OR_SHA1}}' \
    http://{SERVER}:8000/v2/user_auth

 #Json 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"
}

Create a new Authentication Token

Using your username and password, along with an account identifier, will instruct SIPINK to create an authentication token to be used on subsequent requests requiring authentication.

  1. Select the hashing method and create your credentials hash:
    • MD5: 'echo -n “{USERNAME}:{PASSWORD}” | md5sum’
    • SHA1: 'echo -n “{USERNAME}:{PASSWORD}” | sha1sum’
  2. Select an account identifier (any one of the three will suffice):
    • Account Name (“account_name”)
    • SIP Realm (“realm”)
    • A Phone Number assigned to the account (“phone_number”)
  3. Send the HTTP PUT

The response will contain, among other things:

PUT /v2/user_auth

Fetch Token Auth

Fetch

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/user_auth/{AUTH_TOKEN}

 #Json 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"
}

Allows you to quickly grab information about the user, used for such things such as GUI etc.

GET /v2/user_auth/{AUTH_TOKEN}

Password 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

Recovering

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
{
    "auth_token": "{AUTH_TOKEN}",
    "data": {},
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}
curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -d '{"data": {"reset_id": "{RESET_ID}"}}'
    http://{SERVER}:8000/v2/user_auth/recovery

#success

{
    "auth_token": "{AUTH_TOKEN}",
    "data": {},
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

{
    "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"
}

#Unknown {RESET_ID}


Send the {RESET_ID} collected in the recovery-email.

'POST /v2/user_auth/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.

PUT /v2/user_auth/recovery

User_Auth

Create

# PUT /v2/user_auth
curl -v -X PUT \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/user_auth

Fetch

# GET /v2/user_auth/{AUTH_TOKEN}
curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/user_auth/{AUTH_TOKEN}

Change

# POST /v2/user_auth/recovery
curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/user_auth/recovery

Create Recover

# PUT /v2/user_auth/recovery
curl -v -X PUT \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/user_auth/recovery

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

Key Description Type Default Required
call_forward The device call forward parameters object false
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
call_forward.number The number to forward calls to string(0..35) false
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_restriction Device level call restrictions for each available number classification object {} false
call_waiting false
caller_id The device caller ID parameters object {} false
contact_list object {} false
contact_list.exclude If set to true the device is excluded from the contact list boolean false
dial_plan A list of rules used to modify dialed numbers object {} 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 object false
do_not_disturb.enabled Is do-not-disturb enabled for this user? boolean false
email The email of the user string(1..254) false
enabled Determines if the user is currently enabled boolean true false
feature_level The user level for assigning feature sets string false
first_name The first name of the user string(1..128) true
hotdesk The user hotdesk parameters 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 mutliple 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
language The language for this user string false
last_name The last name of the user string(1..128) true
media The device media parameters object {} false
media.audio The audio media parameters object {} false
media.audio.codecs A list of audio codecs the device supports array(string('OPUS', ..... 'speex')) PCMU false
media.audio.codecs.[] string false
media.bypass_media Default bypass media mode boolean, string('true', 'false', 'auto') false
media.encryption object {} false
media.encryption.enforce_security boolean false false
media.encryption.methods array(string('zrtp', 'srtp')) [] false
media.encryption.methods.[] string false
media.fax_option Support T.38 boolean false
media.ignore_early_media The option to determine if early media from the device should always be ignored boolean false
media.progress_timeout The progress timeout to apply to the device integer false
media.video The video media parameters object {} false
media.video.codecs A list of video codecs the device supports array(string('H261', 'H263', 'H264', 'VP8')) [] false
media.video.codecs.[] string false
metaflows The device metaflow parameters false
music_on_hold The music on hold parameters used if not a property of the device owner object {} 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
presence_id Static presence ID (used instead of SIP username) string false
priv_level The privilege level of the user string('user', 'admin') user false
profile User’s profile data object {} false
pronounced_name Name pronounced by user to introduce himself to conference members object false
pronounced_name.media_id The ID of a media object that should be used as the music on hold string(0..128) false
require_password_update UI flag that the user should update their password. boolean false false
ringtones object {} 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
timezone User’s timezone string false
username The GUI login username - alpha-numeric, dashes, at symbol, periods, plusses, and underscores allowed string(1..256) false
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

Fetch summary of users in account

GET /v2/accounts/{ACCOUNT_ID}/users

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN} \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users
{
    "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

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
{
    "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}

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}
{
    "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}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN} \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}
{
    "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}

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}
{
    "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}

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}
{
    "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. Kazoo currently generates a 3.0 compatible vCard.

GET /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/vcard

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
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

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN} \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo

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

curl -v -X GET \
    -H "Accept: application/base64" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo
[binary data]

Create or change the user’s photo

Use application/octet-stream as the content type.

POST /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo

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
{
    "auth_token": "{AUTH_TOKEN}",
    "data": {},
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Execute a quick call

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!).

Query string options:

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})
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.
timeout integer(3..) In seconds, how long to ring the device(s) (defaults to 30)

GET /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/quickcall/{PHONE_NUMBER}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/quickcall/{PHONE_NUMBER}
{
  "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}"
}

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 fowarding), among others, can be represented by SIPINK devices.

Schema

Key Description Type Default Required
call_forward The device call forward parameters object false
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
call_forward.number The number to forward calls to string(0..15) false
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_restriction Device level call restrictions for each available number classification object {} false
call_waiting #/definitions/call_waiting false
caller_id The device caller ID parameters object {} false
contact_list object {} false
contact_list.exclude If set to true the device is excluded from the contact list boolean 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 object {} false
do_not_disturb object false
do_not_disturb.enabled Is do-not-disturb enabled for this device? boolean false
enabled Determines if the device is currently enabled boolean true false
exclude_from_queues Do not ring this device when calling user/agent in queue boolean false false
language The language for the device string false
media The device media parameters object {} false
media.audio The audio media parameters object {} false
media.audio.codecs A list of audio codecs the device supports array(string('OPUS', 'CELT@32000h', 'G7221@32000h', 'G7221@16000h', 'G722', 'speex@32000h', 'speex@16000h', 'PCMU', 'PCMA', 'G729', 'GSM', 'CELT@48000h', 'CELT@64000h', 'G722_16', 'G722_32', 'CELT_48', 'CELT_64', 'Speex', 'speex')) PCMU false
media.audio.codecs.[] string false
media.bypass_media Default bypass media mode boolean, string('true', 'false', 'auto') false
media.encryption object {} false
media.encryption.enforce_security boolean false false
media.encryption.methods array(string('zrtp', 'srtp')) [] false
media.encryption.methods.[] string false
media.fax_option Support T.38 boolean false
media.ignore_early_media The option to determine if early media from the device should always be ignored boolean false
media.progress_timeout The progress timeout to apply to the device integer false
media.video The video media parameters object {} false
media.video.codecs A list of video codecs the device supports array(string('VP8', 'H264', 'H263', 'H261')) [] false
media.video.codecs.[] string false
metaflows The device metaflow parameters #/definitions/metaflows false
music_on_hold The music on hold parameters used if not a property of the device owner object {} 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
mwi_unsolicitated_updates When true enables unsolicitated mwi notifications boolean true false
name A friendly name for the device string(1..128) true
outbound_flags List of flags (features) this device requires when making outbound calls array(string) false
outbound_flags.[] string 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
provision Provision data object false
provision.feature_keys object false
provision.feature_keys.^[0-9]+$ object false
provision.feature_keys.^[0-9]+$.type Feature key type string('presence', 'parking', 'personal_parking', 'speed_dial') true
provision.feature_keys.^[0-9]+$.value Feature key value string, integer true
register_overwrite_notify When true enables overwrite notifications boolean false false
ringtones object {} 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
sip object {} false
sip.custom_sip_headers A property list of SIP headers beging with the prefix 'X-’ 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
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', 'route') username false
sip.ip IP address for this device string false
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
sip.realm The realm this device should use, overriding the account realm. Should rarely be necessary. string false
sip.route The SIP URL used if the invite format is 'route’ string false
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
suppress_unregister_notifications When true disables deregister notifications boolean false false
timezone Device’s timezone string false

Fetch summary of devices in account

GET /v2/accounts/{ACCOUNT_ID}/devices

curl -v -X GET \
    -X "X-Auth-Token: {AUTH_TOKEN} \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices
{
    "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

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
{
    "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_unsolicitated_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}

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}
{
    "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_unsolicitated_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}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}
{
    "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_unsolicitated_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}

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_unsolicitated_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}
{
    "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_unsolicitated_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}

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}
{
    "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_unsolicitated_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"
}

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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/status
{
    "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. SIPINK will generate the NOTIFY packet if the device is registered.

POST /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync

curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync
{
    "auth_token": "{AUTH_TOKEN}",
    "data": "sync request sent",
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Execute a quick call

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!).

Query string options:

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})
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.
timeout integer(3..) In seconds, how long to ring the device(s) (defaults to 30)

GET /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/quickcall/{PHONE_NUMBER}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/quickcall/{PHONE_NUMBER}
{
  "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_sipink_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}"
}

Adding Ringtones

You can setup internal and external ringtones by adding this:

{
    "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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/devices
{
    "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

    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
{
    "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_unsolicitated_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"
}

Accounts

About Accounts

Accounts are the container for most things in sipink. They typically represent an office, business, family, etc. sipink 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

Key Description Type Default Required
call_restriction Account level call restrictions for each available number classification object {} false
call_waiting #/definitions/call_waiting false
caller_id The account default caller ID parameters object {} false
dial_plan A list of default rules used to modify dialed numbers object {} false
do_not_disturb object false
do_not_disturb.enabled The default value for do-not-disturb boolean false
enabled Determines if the account is currently enabled boolean true false
language The language for this account string en-us false
metaflows #/definitions/metaflows false
music_on_hold The default music on hold parameters object {} false
music_on_hold.media_id The ID of a media object that should be used as the default music on hold string(0..128) false
name A friendly name for the account string(1..128) true
org Full legal name of the organization string false
preflow Each property provides functionality that can be applied to calls using the callflow application object {} false
preflow.always The ID of a callflow to always execute prior to processing the callflow with numbers/patterns matching the request string false
realm The realm of the account, ie: ‘account1.sipink.com’ string(4..253) false
ringtones object {} 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
timezone The default timezone string(5..32) America/Los_Angeles false
voicemail object false
voicemail.notify object false
voicemail.notify.callback #/definitions/notify.callback false

Create a new child account

Puts the created account under the account of the owner of the {AUTH_TOKEN}. This is a shortcut for PUT /v2/accounts/{AUTH_ACCOUNT_ID}

PUT /v2/accounts

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
{
    "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.sipink.com",
        "reseller_id": "undefined",
        "ringtones": {},
        "superduper_admin": false,
        "timezone": "America/Los_Angeles",
        "wnm_allow_additions": false
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Remove an account

DELETE /v2/accounts/{ACCOUNT_ID}

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}
{
    "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.sipink.com",
        "reseller_id": "undefined",
        "ringtones": {},
        "superduper_admin": false,
        "timezone": "America/Los_Angeles",
        "wnm_allow_additions": false
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Fetch the account doc

GET /v2/accounts/{ACCOUNT_ID}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}
{
    "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.sipink.com",
        "reseller_id": "undefined",
        "ringtones": {},
        "superduper_admin": false,
        "timezone": "America/Los_Angeles",
        "wnm_allow_additions": false
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Patch the account doc

PATCH /v2/accounts/{ACCOUNT_ID}

curl -v -X PATCH \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -d '{"data":{"some_key":"some_value"}}' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}
{
    "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.sipink.com",
        "reseller_id": "undefined",
        "ringtones": {},
        "some_key":"some_value",
        "superduper_admin": false,
        "timezone": "America/Los_Angeles",
        "wnm_allow_additions": false
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Change the account doc

POST /v2/accounts/{ACCOUNT_ID}

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.sipink.com","reseller_id": "undefined","ringtones": {},"some_key":"some_value","superduper_admin": false,"timezone": "America/Los_Angeles","wnm_allow_additions": false}}' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}
{
    "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.sipink.com",
        "reseller_id": "undefined",
        "ringtones": {},
        "some_key":"some_value",
        "superduper_admin": false,
        "timezone": "America/Los_Angeles",
        "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}

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}
{
    "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.sipink.com",
        "reseller_id": "undefined",
        "ringtones": {},
        "superduper_admin": false,
        "timezone": "America/Los_Angeles",
        "wnm_allow_additions": false
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Fetch the parent account IDs

GET /v2/accounts/{ACCOUNT_ID}/parents

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/parents
{
    "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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tree
{
    "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 sipink 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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
     http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/api_key
{
    "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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/siblings
{
    "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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/descendants
{
    "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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/children
{
    "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

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/reseller

Promote a reseller

Requires superduper admin auth token

PUT /v2/accounts/{ACCOUNT_ID}/reseller

curl -v -X PUT \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/reseller

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

curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -d '{"data": {"to": "{ACCOUNT_ID_DESTINATION}"}}' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/move
{
    "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.sipink.com",
        "reseller_id": "undefined",
        "ringtones": {},
        "superduper_admin": false,
        "timezone": "America/Los_Angeles",
        "wnm_allow_additions": false
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

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

Key Description Type Default Required
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
caller_exit_key Key caller can press while on hold to exit the queue and continue in the callflow string('1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '0', '#') # false
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

List queues

GET /v2/accounts/{ACCOUNT_ID}/queues

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues
{
    "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

curl -v -X PUT \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -d '{"data":{"name":"Support Queue"}}' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues
{
    "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}

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}
{
    "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}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}
{
    "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}

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}
{
    "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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/stats
{
    "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

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster
{
    "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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster
{
    "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”]}’

Authentication

Schema

Key Description Type Default Required
account_name The account name of the user string(1..128) false
account_realm The account realm of the user string(1..64) 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

Auth Token

Create

curl -v -X PUT \
    -H "Content-Type: application/json" \
    -d '{"data":{"credentials":"{CREDENTIALS_HASH}", "account_name":"{ACCOUNT_NAME"}, "method":{MD5_OR_SHA1}}' \
    http://{SERVER}:8000/v2/user_auth

 #Json 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"
}

Create a new Authentication Token

Using your username and password, along with an account identifier, will instruct SIPINK to create an authentication token to be used on subsequent requests requiring authentication.

  1. Select the hashing method and create your credentials hash:
    • MD5: 'echo -n “{USERNAME}:{PASSWORD}” | md5sum’
    • SHA1: 'echo -n “{USERNAME}:{PASSWORD}” | sha1sum’
  2. Select an account identifier (any one of the three will suffice):
    • Account Name (“account_name”)
    • SIP Realm (“realm”)
    • A Phone Number assigned to the account (“phone_number”)
  3. Send the HTTP PUT

The response will contain, among other things:

PUT /v2/user_auth

Fetch Token Auth

Fetch

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/user_auth/{AUTH_TOKEN}

 #Json 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"
}

Allows you to quickly grab information about the user, used for such things such as GUI etc.

GET /v2/user_auth/{AUTH_TOKEN}

Password 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

Recovering

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
{
    "auth_token": "{AUTH_TOKEN}",
    "data": {},
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}
curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -d '{"data": {"reset_id": "{RESET_ID}"}}'
    http://{SERVER}:8000/v2/user_auth/recovery

#success

{
    "auth_token": "{AUTH_TOKEN}",
    "data": {},
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

{
    "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"
}

#Unknown {RESET_ID}


Send the {RESET_ID} collected in the recovery-email.

'POST /v2/user_auth/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.

PUT /v2/user_auth/recovery

User_Auth

Create

# PUT /v2/user_auth
curl -v -X PUT \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/user_auth

Fetch

# GET /v2/user_auth/{AUTH_TOKEN}
curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/user_auth/{AUTH_TOKEN}

Change

# POST /v2/user_auth/recovery
curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/user_auth/recovery

Create Recover

# PUT /v2/user_auth/recovery
curl -v -X PUT \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/user_auth/recovery

CDRs

About CDRs

CDRs (Call Detail Records) provide a summary view of a call leg.

Schema

Key Description Type Default Required
app_name The sipink application that issued the CDR string false
app_version The internal sipink 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 string 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
custom_channel_vars sipink-specific key/value pairs set on the channel object false
custom_sip_headers A property list of SIP headers beging with the prefix ‘X-’ 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 string false
fax_bad_rows string false
fax_ecm_used string false
fax_result_code string false
fax_result_text string false
fax_success string false
fax_total_pages string false
fax_transfer_rate string false
fax_transferred_pages string false
from Built by sipink, depending on direction, to represent the From user 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
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
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 sipink this is the processed request URI string false
ringing_seconds How many seconds the leg was ringing (pre-answer) string false
timestamp UTC timestamp, in gregorian seconds, of when the CDR was generated string false
to Built by sipink, depending on direction, to represent the To user string false
to_uri The To SIP URI string false
user_agent User agent header from SIP packet string false

Fetch a summary of CDRs

GET /v2/accounts/{ACCOUNT_ID}/cdrs

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs

Get a time range of CDRs (using gregorian seconds for timestamps):

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}

Get CDRs as CSV:

curl -v -X GET \
    -H "Accept: text/csv" \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs

Fetch a CDR’s details

GET /v2/accounts/{ACCOUNT_ID}/cdrs/{CDR_ID}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs/{CDR_ID}

Fetch interaction summary

GET /v2/accounts/{ACCOUNT_ID}/cdrs/interaction

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs/interaction

Crossbar cdrs was extended to provide simplified interaction call detail records. It groups all CDRs that interacted with eachouther to form a list of calls.

GET /v2/accounts/{ACCOUNT_ID}/cdrs/legs/{INTERACTION_ID}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs/legs/{INTERACTION_ID}

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.

sipink-specific properties

These are properties set by sipink 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:

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

Fax-specific Properties

These properties may exist on a CDR for a fax request (inbound or outbound):

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:

Schema

Key Description Type Default Required
cidrs Classless Inter-Domain Routing IP notation for use on the access lists array(string) true
cidrs.[] 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

Remove account-level access lists

DELETE /v2/accounts/{ACCOUNT_ID}/access_lists

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/access_lists

Fetch account-level access lists

GET /v2/accounts/{ACCOUNT_ID}/access_lists

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/access_lists
{
    "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

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
{
    "auth_token": "{AUTH_TOKEN}",
    "data": {
        "cidrs": [
            "127.0.0.3/32"
        ],
        "order": "allow,deny"
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Remove device-level access lists

DELETE /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/access_lists

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/access_lists

Fetch device-level access lists

GET /v2/accounts/{ACCOUNT_ID}/access_lists

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/access_lists
{
    "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}/access_lists

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}/access_lists
{
    "auth_token": "{AUTH_TOKEN}",
    "data": {
        "cidrs": [
            "127.0.0.3/32"
        ],
        "order": "deny,allow"
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Allotments

About Allotments

Schema

Key Description Type Default Required

Get allotments configuration for a given account

GET /v2/accounts/{ACCOUNT_ID}/allotments

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/allotments
{
    "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"
}

ExplanĐ°tion

Each object have name (outbound_national) which build from direction (inbound or outbound) and classificator from number_manager configuration.

Properties:

Examples

“increment”, “minimum” and “no_consume_time”

      "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”

      "Class1": {
           "amount": 600,
           "group_consume": [
               "Class2"
           ]
       },
       "Class2": {
           "amount": 600,
           "group_consume": [
               "Class1"
           ]
       }

Here we have 2 classifiers which share same counter. If Class1 already counsmed 400 seconds and Class2 consumed 150 seconds, next call with classifier Class2 (or Class1) will have 50 free seconds.

Little more complex example:

      "Class1": {
           "amount": 600,
           "group_consume": [
               "Class2",
               "Class3"
           ]
       },
       "Class2": {
           "amount": 120,
           "group_consume": [
               "Class1"
           ]
       },
       "Class3": {
           "amount": 300,
           "group_consume": [
                "Class2"
           ]
       }

So if we already have counsumed calls: Class1 - 300 Class2 - 60 Class3 - 180

As result next call wil 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)

Update allotments configuration for a given account

POST /v2/accounts/{ACCOUNT_ID}/allotments

curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/allotments
{
    "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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/allotments/consumed
{
    "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.

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}`
{
    "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.

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/allotments/consumed?created_from={TIMESTAMP}`

or

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/allotments/consumed?created_to={TIMESTAMP}`

Response:

{
    "data": {
        "outbound_local": {
            "consumed": 180,
            "consumed_to": month2_end_timestamp,
            "consumed_from": month2_start_timestamp,
            "cycle": "monthly"
        },
        "outbound_national": {
            "consumed": 60,
            "consumed_to": week4_end_timestamp,
            "consumed_from": week4_start_timestamp,
            "cycle": "weekly"
        }
    },
    "status": "success",
}
                                 {TIMESTAMP}
                                     ||
----+--------------------+-----------||-------+--------------------+--------
    | week3              | week4     ||       | week5              | week6
----+------------+-------+-----------||-------+--------------------+--------
 month1          | month2            ||
-----------------+-------------------||-------------------------------------

Give it a REST

Crossbar is the REST API server, from which developers can build applications that configure sipink’s myriad services and functionalities.

Basic URI Structure

/{VERSION}/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID}

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}:

  1. First, strip the version off the URI
    • Version: v2
    • URI Remaining: /accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}
  2. 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}
  3. 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}
  4. Repeat parsing. devices is a REST endpoint:
    • Version: v2
    • Modules: {accounts: [{ACCOUNT_ID}], devices: []}
    • Remaining URI: /{DEVICE_ID}
  5. Repeat parsing. {DEVICE_ID} is an argument:
    • Version: v2
    • Modules: {accounts: [{ACCOUNT_ID}], devices: [{DEVICE_ID}]}

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:

PATCH

Some resources are beginning to support the PATCH verb, allowing partial updates instead of requiring the request to include the full version of the document. /users/{USER_ID}, for instance, now supports PATCH:

curl -v -X PATCH -H “Content-Type: application/json” -H “X-Auth-Token: {AUTH_TOKEN}” ‘http://crossbar.server.com:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}’ -d ’{“data”:{“vm_to_email_enabled”:true}}’

This cURL request will patch the user’s doc 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:

  1. As part of the request envelope: {"data":{...},"verb":"PUT"}
  2. 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.

Authentication Tokens

Most APIs require the client to have authenticated and received a token usable on subsequent requests. Crossbar provides a couple ways to receive an authentication token:

  1. User Authentication
  2. API Key Authentication

Request Envelope

When issuing a PUT or POST, a request body is needed. When submitting a JSON (the most common body), Crossbar expects a request envelope with a few bits of metadata:

Sample Request Envelope

{“data”:{“foo”:“bar”} ,“auth_token”:“{AUTH_TOKEN}” ,“verb”:“delete” }

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.

Sample Response Envelope

{“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).

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:

curl -v -H “X-Auth-Token: {AUTH_TOKEN}” -H “Content-Type: application/json” http://{SERVER_URL}:8000/v2/accounts/{ACCOUNT_ID}/cdrs {“auth_token”: “{AUTH_TOKEN}” ,“data”: [{CDR_OBJECT} ,{CDR_OBJECT} ,… ] ,“next_start_key”: 63566193143 ,“page_size”: 25 ,“request_id”: “{REQUEST_ID}” ,“revision”: “{REVISION}” ,“start_key”: 63565345339 ,“status”: “success” }

The pagination response keys are next_start_key, page_size, and start_key.

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).

Requesting a page

Using the next_start_key value, let’s request the next page of CDRs:

curl -v -H “X-Auth-Token: {AUTH_TOKEN}” -H “Content-Type: application/json” http://{SERVER_URL}:8000/v2/accounts/{ACCOUNT_ID}/cdrs?start_key=63566193143 {“auth_token”: “{AUTH_TOKEN}” ,“data”: [{CDR_OBJECT} ,{CDR_OBJECT} ,… ] ,“next_start_key”: 63566542092 ,“page_size”: 25 ,“request_id”: “{REQUEST_ID}” ,“revision”: “{REVISION}” ,“start_key”: 63566193143 ,“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.

&tip 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.

Disabling Pagination

If you want to disable pagination for a request, simply include paginate=false on the query string.

Pretty Printing

If needed the json response from the server can be pretty printed

Include pretty printing inside the header

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}/

If the client cannot use headers the options can be included inside the url

curl -v -H “X-Auth-Token: {AUTH_TOKEN}” -H “Content-Type: application/json” http://{SERVER_URL}:8000/v2/accounts/{ACCOUNT_ID}?pretty_print=true

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.

Structure

The structure is really simple:

Ex:

{
    "name": "Main Blacklist",
    "numbers": {
        "+14151234567": {
        }
    }
}

When you upload numbers they will be converted to e164 format.

Usage

Once you created your blacklists using the api you can apply them to the account by adding the blacklist ids to the account, like the following:

"blacklists": [
    "dbfc14854a06bab3014898b6b4e1ffa0", // Main blacklist
    "davb14854a06bab3542132b6b4e1ffa0"  // Secondary blacklist
]

Crossbar

Using Crossbar to modify Blacklist is very simple:

Account Blacklist URI

/v2/accounts/{ACCOUNT_ID}/blacklists

GET - Fetch account blacklists:

curl -v -X GET -H “X-Auth-Token: {AUTH_TOKEN}” http://server:8000/v2/accounts/{ACCOUNT_ID}/blacklists

curl -v -X GET -H “X-Auth-Token: {AUTH_TOKEN}” http://server:8000/v2/accounts/{ACCOUNT_ID}/blacklists/{ID}

PUT - Add account blacklists:

curl -v -X PUT -H “X-Auth-Token: {AUTH_TOKEN}” -H “Content-Type: application/json” http://server:8000/v2/accounts/{ACCOUNT_ID}/blacklists -d ’{“data”: {“name”: “Main Blacklist”,“numbers”: {“+14151234567”: {}}}}’

POST - Update account blacklists:

curl -v -X POST -H “X-Auth-Token: {AUTH_TOKEN}” -H “Content-Type: application/json” http://server:8000/v2/accounts/{ACCOUNT_ID}/blacklists/{ID} -d ’{“data”: {“name”: “Main Blacklist”,“numbers”: {“+14151234567”: {}}}}’

DELETE - Remove account blacklists:

curl -v -X DELETE -H “X-Auth-Token: {AUTH_TOKEN}” http://server:8000/v2/accounts/{ACCOUNT_ID}/blacklists/{ID}

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 sipink’s braintree modules.

Test out braintree using sandbox account before deploying it in production as the module is considered NOT PRODUCTION READY.

Schema

Schemas for Braintree requests can be viewed here.

Client Token

Client Token is a new way of adding payment method where the credit card information is not sent to sipink servers and is directly handled by braintree for compliance issues

See how it works - https://developers.braintreepayments.com/start/hello-server/ruby

alt tag

Fetch

GET /v2/accounts/{ACCOUNT_ID}/braintree/client_token

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/client_token
    {
        "auth_token": "{AUTH_TOKEN}"
        "data": {
            "client_token": "{BRAINTREE_CLIENT_TOKEN}"
        },
        "request_id": "{REQUEST_ID}",
        "revision": "{REVISION}",
        "status": "success"
    }

Fetch

GET /v2/accounts/{ACCOUNT_ID}/braintree/credits

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/credits
    {
            "auth_token": "{AUTH_TOKEN}"
            "data": {
                "amount": 500.0,
                "billing_account_id": "31a05ddba6a9df166c7d50fc4b683606"
            },
            "request_id": "{REQUEST_ID}",
            "revision": "{REVISION}",
            "status": "success"
     }

Create

PUT /v2/accounts/{ACCOUNT_ID}/braintree/credits

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
    {
        "auth_token": "{AUTH_TOKEN}",
        "data": {
            "description": "credit addition from credit card",
            "sub_account_id": "22f1b082e505064cc930e944bf9a0728",
            "sub_account_name": "romana",
            "bookkeeper_info": {
                "card": {
                    "id": "7gz3qw",
                    "bin": "411111",
                    "card_type": "Visa",
                    "default": false,
                    "expiration_month": "11",
                    "expiration_year": "2020",
                    "expired": false,
                    "customer_location": "US",
                    "last_four": "1111"
                },
                "customer": {
                    "id": "31a05ddba6a9df166c7d50fc4b657854",
                    "first_name": "John",
                    "last_name": "Doe",
                    "company": "ACME Corp",
                    "phone": "9122475533"
                },
                "id": "0gmy6jrw",
                "status": "submitted_for_settlement",
                "type": "sale",
                "currency_code": "USD",
                "amount": "20.00",
                "merchant_account_id": "romanat",
                "order_id": "a6268d1a31a76d53857fae0d",
                "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": "XJ3YL9",
                "processor_response_code": "1000",
                "processor_response_text": "Approved",
                "tax_exempt": false,
                "add_ons": [

                ],
                "discounts": [

                ],
                "is_api": true,
                "is_automatic": false,
                "is_recurring": false
            },
            "order_id": "a6268d1a31a76d53857fae0d310552ab",
            "id": "80591de5690374ebba7adc4ffaaf51c1"
        },
        "request_id": "{REQUEST_ID}",
        "revision": "{REVISION}",
        "status": "success"
    }

Fetch

GET /v2/accounts/{ACCOUNT_ID}/braintree/transactions

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/transactions
    {
        "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": {REOCCURING_SUBSCRIPTION}
        }],
        "request_id": "{REQUEST_ID}",
        "revision": "{REVISION}",
        "status": "success"
    }

Fetch

GET /v2/accounts/{ACCOUNT_ID}/braintree/addresses

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/addresses
    {
        "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"
    }

Create

PUT /v2/accounts/{ACCOUNT_ID}/braintree/addresses

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
    {
        "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"
    }

Fetch

GET /v2/accounts/{ACCOUNT_ID}/braintree/cards

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/cards
    {
        "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"
    }

Create

PUT /v2/accounts/{ACCOUNT_ID}/braintree/cards

To add a credit card the the information about a credit card can be sent in the request or payment_token_nonce

With Payment Method Nonce shell 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 { "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 shell 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 { "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" }

Fetch

GET /v2/accounts/{ACCOUNT_ID}/braintree/customer

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/customer
    {
        "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"
    }

Change

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 shell {"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 shell {"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 shell {"data":{ "first_name": "John", "last_name": "Doe", "company": "ACME CORP", "phone": "6000000000", "credit_card":{ "payment_method_nonce":"valid-nonce" } } }

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
    {
        "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

GET /v2/accounts/{ACCOUNT_ID}/braintree/transactions/{TRANSACTION_ID}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/transactions/{TRANSACTION_ID}
    {
        "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": {REOCCURING_SUBSCRIPTION}
        },
        "request_id": "{REQUEST_ID}",
        "revision": "{REVISION}",
        "status": "success"
    }

Remove

DELETE /v2/accounts/{ACCOUNT_ID}/braintree/addresses/{ADDRESS_ID}

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/addresses/{ADDRESS_ID}
    {
        "auth_token": "{AUTH_TOKEN}",
        "data": { },
        "request_id": "{REQUEST_ID}",
        "revision": "{REVISION}",
        "status": "success"
    }

Fetch

GET /v2/accounts/{ACCOUNT_ID}/braintree/addresses/{ADDRESS_ID}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/addresses/{ADDRESS_ID}
    {
        "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"
    }

Change

POST /v2/accounts/{ACCOUNT_ID}/braintree/addresses/{ADDRESS_ID}

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}
    {
        "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

DELETE /v2/accounts/{ACCOUNT_ID}/braintree/cards/{CARD_ID}

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/cards/{CARD_ID}
    {
        "auth_token": "{AUTH_TOKEN}",
        "data": { },
        "request_id": "{REQUEST_ID}",
        "revision": "{REVISION}",
        "status": "success"
    }

Fetch

GET /v2/accounts/{ACCOUNT_ID}/braintree/cards/{CARD_ID}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/cards/{CARD_ID}
    {
        "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"
    }

Change

POST /v2/accounts/{ACCOUNT_ID}/braintree/cards/{CARD_ID}

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}
    {
        "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"
    }

Callflows

About Callflows

Callflows are the instructions sipink uses to process a call. A callflow includes a list of numbers or regex patterns used by sipink 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

Key Description Type Default Required
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
featurecode.name string(1..128) false
featurecode.number string(1..30) false
flow A callflow node defines a module to execute, data to provide to that module, and zero or more children to branch to object true
flow.children Children callflows object {} false
flow.data The data/arguments of the callflow module object {} true
flow.module The name of the callflow module to excute at this node string(1..64) true
metaflow Actions applied to a call outside of the normal callflow, initiated by the caller(s) #/definitions/metaflows false
numbers A list of static numbers that the callflow should execute for array(string(1..36)) [] false
numbers.[] string false
patterns A list of regular expressions that the callflow should execute for, with optional capture groups array(string(1..)) [] false
patterns.[] string false

Fetch an account’s callflows

GET /v2/accounts/{ACCOUNT_ID}/callflows

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows

Create a new callflow

PUT /v2/accounts/{ACCOUNT_ID}/callflows

curl -v -X PUT \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows

Remove a callflow

DELETE /v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}

Fetch a callflow’s details

GET /v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}

Patch a callflow object

PATCH /v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}

curl -v -X PATCH \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}

Change a callflow object

POST /v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}

curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID}

Call_inspector

About Call_inspector

The Call Inspector Crossbar resource allows the client to query and inspect data related to the Call Inspector application.

More info on Call Inspector.

The Call Inspector endpoint is not loaded on start in a default sipink installation.

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

List SIP dialogues recorded

GET /v2/accounts/{ACCOUNT_ID}/call_inspector

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/call_inspector
{
    "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}

Note: {CHUNKS} is an array of JSON-formated chunks.

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/call_inspector/{CALL_ID}
{
    "auth_token": "{AUTH_TOKEN}",
    "data": {
        "analysis": [],
        "messages": {CHUNKS}
    }
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Call priorities

Call priorities are designed to help processing important or VIP calls with special care (including “pushing’ them through queues). Generally, the higher (larger) priority of a call, the faster it should be answered.

Priority support in Callflows

There is a call-priority call time variable that can be set using cf_set_variable module:

Usage example for cf_set_variable module:

"flow”: { “data”: { “variable”: “call_priority”, “value”: “6”, “channel”: “a” }, “module”: “set_variable”, “children”: { } }

The corresponding module cf_branch_variable forks a callflow to branches depending on variable value. If some key in child branch matches the value, the callflow will go that way.

As for now cf_set_variable and cf_branch_variable modules only support call_priority variable.

Usage example for cf_branch_variable module:

“flow”: { “data”: { “variable”: “call_priority” }, “module”: “branch_variable”, “children”: { “7”: { “data”: { “id”: “2e7a812a6e9405ad99ea1493123df03a”, “timeout”: “20” }, “module”: “device”, “children”: {} }, “_”: { “data”: { “id”: “4f18af4f889a368e8153232a7e891209”, “timeout”: “20”, }, “module”: “device”, “children”: {} } } }

Call priority support in ACDC

ACDC application respects call_priority value in calls and “pushes” the call through the queue until it matches queued call with higher priority (in fact, RabbitMQ queue priorities are used).

There are two ways to process a prioritized call with ACD queue:

Some installation requirements exist for call priorities to work with ACDC:

For example:

{ “data”: { “max_priority”: 10, “name”: “10_priority_queue” } }

Configuration example for broker with enabled rabbitmq_priority_queue:

[root@… ~]# cat /etc/sipink/rabbitmq/enabled_plugins [rabbitmq_management,rabbitmq_priority_queue].

WARNING

The following things are really DANGEROUS and should be avoided:

If you need to do something from the list above please refer to the manual.

Channels

About 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).

Fetch active channels system wide.

For superduper admin only. Be sure to set system_config->crossbar.channels->system_wide_channels_list flag to true.

GET /v2/channels

curl -v -X GET \
    -H "Content-Type: application/json" \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/channels

Fetch active channels for an account

GET /v2/accounts/{ACCOUNT_ID}/channels

curl -v -X GET \
    -H "Content-Type: application/json" \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/channels
{
    "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

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

GET /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/channels

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

Fetch a channel’s details

GET /v2/accounts/{ACCOUNT_ID}/channels/{UUID}

curl -v -X GET \
    -H "Content-Type: application/json" \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/channels/{UUID}

Execute an application against a Channel

Schema

Key Description Type Default Required
action What to execute on the channel string('transfer', 'hangup', 'callflow', 'intercept') true
action.transfer Transfers the {UUID} leg to the target extension/DID and places the other leg on hold
target The extension/DID to transfer the {UUID} to string()
takeback_dtmf DTMF to cancel the transfer string("0".."9","*","#")
moh media_id for Music on Hold while transferring string()
ringback ringback to play to the transferor string()
action.callflow Executes a callflow ID on the {UUID}
id Callflow ID to execute string()
action.hangup Hangup the {UUID}
action.intercept Intercept {UUID} to target and hangup the other leg
target_type Type of target string('device', 'user') true
target_id Id of device to which current channel will be bridged string() true
unbridged_only Intercept only unbridged channel boolean() true

POST /v2/accounts/{ACCOUNT_ID}/channels/{UUID}

curl -v -X POST \
    -H "Content-Type: application/json" \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -d '{"data": {"action": "transfer", "target": "2600", "takeback_dtmf": "*1", "moh": "media_id" }}' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/channels/{UUID}

Put a feature on a channel

currently only metaflow is supported

Metaflow

Metaflow feature is a metaflow object which validates with its json schema.

. reasoning The POST action required 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, ie, the children node is also processed.

PUT /v2/accounts/{ACCOUNT_ID}/channels/{UUID}

curl -v -X PUT \
    -H "Content-Type: application/json" \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -d '{"data": {"action": "metaflow", "data": { "module", "hangup" }}' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/channels/{UUID}

Conferences

About Conferences

Conferences documents are enriched with realtime information, namely: number of members, number of moderators, duration of the conference, conference locked status. The realtime information is added to conference document under _read_only key (to avoid accident document update).

Schema

Key Description Type Default Required
conference_numbers Defines conference numbers that can be used by members or moderators array(string) [] false
conference_numbers.[] string false
focus This is a read-only property indicating the media server hosting the conference string false
member Defines the discovery properties for a member object {} false
member.join_deaf Determines if a member will join deaf boolean false false
member.join_muted Determines if a member will join muted boolean true false
member.numbers Defines the conference number(s) for members array(string) [] false
member.numbers.[] string false
member.pins Defines the pin number(s) for members array(string) [] false
member.pins.[] string false
moderator Defines the discovery properties for a moderator 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 Defines the conference number(s) for moderators array(string) [] false
moderator.numbers.[] string false
moderator.pins Defines the pin number(s) for moderators array(string) [] false
moderator.pins.[] string false
name A friendly name for the conference string(1..128) false
owner_id The user ID who manages this conference string(32) false
play_name Do we need to announce new conference members? boolean false false
profile The XML profile name used to configure the conference string false

Fetch

GET /v2/accounts/{ACCOUNT_ID}/conferences

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences

Create

PUT /v2/accounts/{ACCOUNT_ID}/conferences

curl -v -X PUT \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences

Remove

DELETE /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}

Fetch

GET /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}

Patch

PATCH /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}

curl -v -X PATCH \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}

Change

POST /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}

curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}

Perform an action on conference

PUT /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}

curl -v -X PUT \
    -d '{"data": {"action": {CONFERENCE_ACTION}}}' \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}

CONFERENCE_ACTION: lock, unlock

Fetch

GET /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants

Perform an action on participants

PUT /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants

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

PARTICIPANTS_ACTION: mute/unmute/deaf/undeaf/kick

Perform an action on participant

PUT /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID}/participants/{PARTICIPANT_ID}

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}

PARTICIPANT_ACTION: mute/unmute/deaf/undeaf/kick

List of conferences example

[
  {
    "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

{
  "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": "sipink-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

Actions

Actions are JSON objects in format:

{
    "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

{
  "custom_channel_vars": {
    "account_id": "9d351ad7ffd6f846313af9eed3bb7b85",
    "authorizing_id": "6507f40b09a61fbb8b025dbad9316eb5",
    "authorizing_type": "device",
    "owner_id": "32d8788da9506b4b1991d5bb86d27b0a",
    "presence_id": "1000@kamailio.sipink",
    "fetch_id": "56507071-a216-4e0a-a28f-ff3bd9c86ac3",
    "bridge_id": "934800819",
    "precedence": 5,
    "realm": "kamailio.sipink",
    "username": "sip1",
    "call_interaction_id": "63635497023-3e247b2e"
  },
  "channel_presence_id": "1000@kamailio.sipink",
  "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.sipink",
  "call_id": "934800819",
  "event": "add-member",
  "node": "sipink_apps@jh460",
  "msg_id": "a6fbbf034b5cd3af",
  "event_name": "participant_event",
  "event_category": "conference",
  "app_version": "4.0.0",
  "app_name": "ecallmgr",
  "routing_key": "participant_event"
}

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 orlast names (versus having to know the user’s extension).

Schema

Key Description Type Default Required
confirm_match When one match is found, require caller to confirm the match before connecting boolean true false
max_dtmf Cap the number of DTMF characters collected from a caller, 0 for unlimited integer 0 false
min_dtmf How many DTMF characters to collect from a caller before processing the directory integer 3 false
name The name of the directory string(1..) true
sort_by What field to sort on in matching documents when a caller enters characters string('first_name', 'last_name') last_name false
users The list of users associated with this directory array(string) [] false
users.[] string false

Fetch

GET /v2/accounts/{ACCOUNT_ID}/directories

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/directories

Create

PUT /v2/accounts/{ACCOUNT_ID}/directories

curl -v -X PUT \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/directories

Remove

DELETE /v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID}

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID}

Fetch a directory listing

GET /v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID}

Fetch a directory as a PDF

It is possible to fetch the directory as a PDF for download (such as a company direcotry, a sales department directory, etc)

GET /v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -H "Accept: application/pdf"
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID}

If your client doesn’t support setting the Accept header, you can append ?accept=pdf to the URI and sipink will pretend you sent the proper Accept header.

Patch

PATCH /v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID}

curl -v -X PATCH \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID}

Change

POST /v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID}

curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID}

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

Key Description Type Default Required
attempts The number of attempts made, this will be set by the system and reset automaticly on put/post integer 0 false
document Parameters related to the storage of a fax document object 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 reteive 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
from_name The sender name for the fax string false
from_number The sender number for the fax string true
notifications Status notifications object false
notifications.email Email notifications object false
notifications.email.send_to A list or string of email recipent(s) string, array(string) false
notifications.sms SMS notifications object false
notifications.sms.send_to A list or string of sms recipent(s) string, array(string) false
retries The number of times to retry integer 1 false
to_name The recipient name for the fax string false
to_number The recipient number for the fax string true
tx_result The result of a transmission attempt object false
tx_result.error_message A description of any error that occured 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 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 submition to completion integer 0 false

Processing States

State Description
attaching_files A fax job was submitted via the api (with a multipart/related content type) or smtp and we are in the process of attaching the files to the fax job.
pending Fax waiting to be picked up by the fax sending job
failed If we can’t retrieve the fax document via a requests URL, the state will be “failed” and the error text will contain “could not retrieve file, http response
processing Faxes that are actively picked up by the fax worker and are being processed
completed Faxes that are finished sending
failed Faxes that did not successfully send after all allotted retries are in state “failed”. We pass-thru the FreeSWITCH error code in this case.

Sending Outbound Faxes

This section details APIs for manipulating job processing of outgoing faxes.

Create an outgoing fax

There are two methods for creating an outgoing fax - they differ in how you attach the fax file for processing.

In the first method, you can create a fax document that includes a URL which contains the fax document to send. The fax document is fetched by the fax_jobs worker and distributed to fax_worker processes. You can fetch the status of the created job using the faxes/outgoing/{FAX_ID} API.

PUT /v2/accounts/{ACCOUNT_ID}/faxes

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
{
    "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 multipart 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.

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

Create an outgoing fax (Alias)

This is identical to the PUT /faxes above.

PUT /v2/accounts/{ACCOUNT_ID}/faxes/outgoing

curl -v -X PUT \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outgoing

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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outgoing
{
    "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}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outgoing/{FAX_JOB_ID}
{
    "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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox

Fetch a fax from the outbox folder

GET /v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}

Resubmit a fax from the outbox folder

PUT /v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}

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}

Fetch the fax payload

GET /v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}/attachment

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}/attachment

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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/smtplog

GET /v2/accounts/{ACCOUNT_ID}/faxes/smtplog/{ATTEMPT_ID}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/smtplog/{ATTEMPT_ID}

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}

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}

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

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}/attachment

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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox

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}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}

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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}/attachment

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}

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}

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

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}/attachment

APIs under active development

Receiving Inbound Faxes

Fetch

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. Ticket #

GET /v2/accounts/{ACCOUNT_ID}/faxes/incoming

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/incoming

Fetch an incoming fax job

GET /v2/accounts/{ACCOUNT_ID}/faxes/incoming/{FAX_ID}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/incoming/{FAX_ID}

Groups

About Groups

Schema

Key Description Type Default Required
endpoints Endpoints included into group object {} true
music_on_hold The music on hold parameters object {} false
music_on_hold.media_id The ID of a media object that should be used as music on hold string(0..128) false
name A friendly name for the group string(1..128) true

Get groups for a given account

GET /v2/accounts/{ACCOUNT_ID}/groups

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/groups
{
    "data": [
        {
            "id": "18ccfd6cea456cbdd38133e5aa726ec4",
            "name": "Group Name",
            "features": [],
            "endpoints": 2
        }
    ],
    "status": "success"
}

Create a group for a given account

PUT /v2/accounts/{ACCOUNT_ID}/groups

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
{
    "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}

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID}
{
    "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}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID}
{
    "data": {
        "music_on_hold": {},
        "name": "Test group",
        "endpoints": {
            "df9274b450ea6795cdb381055c3f9b45": {
                "type": "user",
                "weight": 1
            },
            "dd03d7442a4bec5c092ea6a0e6d579ef": {
                "type": "device",
                "weight": 2
            }
        },
        "ui_metadata": {
            "ui": "sipink-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}

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}
{
    "data": {
        "music_on_hold": {},
        "name": "Test group 2",
        "endpoints": {
            "df9274b450ea6795cdb381055c3f9b45": {
                "type": "user",
                "weight": 1
            },
            "dd03d7442a4bec5c092ea6a0e6d579ef": {
                "type": "device",
                "weight": 2
            }
        },
        "ui_metadata": {
            "ui": "sipink-ui"
        },
        "id": "1743724cd775bf6994380dbc79c1af09"
    },
    "status": "success"
}

Ledgers

About Ledgers

Schema

Key Description Type Default Required
account Account info object false
account.id Account ID string false
account.name Account name string false
amount Ledger amount integer false
description Useful description for ledger string false
metadata Metadata for ledger document object false
period Period of ledger object false
period.end Period end integer false
period.start Period start integer false
source Origin of ledger object true
source.id Source ID string true
source.service Source service string true
usage Usage for ledger object true
usage.quantity Usage quantity integer true
usage.type Usage type string true
usage.unit Usage unit string true

List current Ledgers

List current ledgers and value for an account.

GET /v2/accounts/{ACCOUNT_ID}/ledgers

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers
{
    "data": {
        "per-minute-voip": -825,
        "support": -148
    },
    "request_id": "{REQUEST_ID}",
    "status": "success",
    "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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/{LEDGER_ID}
{
    "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}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/{LEDGER_ID}/{LEDGER_ENTRY_ID}
{
    "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

curl -v -X PUT \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/debit
{
    "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
}

Limits

About Limits

Schema

Key Description Type Default Required
allow_prepay Determines if the account would like to allow per-minute calls if they have credit boolean true false
burst_trunks The number of two-way, flat-rate trunks used only if no other trunks are available integer false
calls A hard limit for the total number calls integer false
inbound_trunks The number of inbound, flat-rate trunks integer false
outbound_trunks The number of outbound, flat-rate trunks integer false
resource_consuming_calls A hard limit for the number of resource consuming calls integer false
twoway_trunks The number of two-way, flat-rate trunks integer false

Get limits for a given account

GET /v2/accounts/{ACCOUNT_ID}/limits

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/limits
{
    "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):

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
{
    "data": {
        "twoway_trunks": 0,
        "inbound_trunks": 11,
        "id": "limits",
        "allow_prepay": true,
        "outbound_trunks": 5
    },
    "status": "success",
}

Now with API v2:

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

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.

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": trye
    }}' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/limits
{
    "data": {
        "twoway_trunks": 0,
        "inbound_trunks": 11,
        "id": "limits",
        "allow_prepay": true,
        "outbound_trunks": 5
    },
    "status": "success",
}

Lists

Schema

Key Description Type Default Required
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

Get all lists (doesn’t return entries)

GET /v2/accounts/{ACCOUNT_ID}/lists

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists

Add new list (beware: no entries)

PUT /v2/accounts/{ACCOUNT_ID}/lists

curl -v -X PUT \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -d '{"data": {"name": "list name"}}' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists

Delete list and its entries

DELETE /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}

Get list properties (doesn’t return entries)

GET /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}

Updating list (without entries)

PATCH /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}

curl -v -X PATCH \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -d '{"data": {"description": "desc"}}' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}

Rewrite list

POST /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}

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}

Delete all entries from list

DELETE /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries

Get list entries

GET /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries

Add an entry to a list

PUT /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries

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

Delete entry from the list

DELETE /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}

List entry properties

GET /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}

Update list entry

PATCH /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}

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}

Replace list entry

POST /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}

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}

Add photo to List entry

POST /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}/photo

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

List entry vcard

GET /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID}/vcard

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

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}

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 sipink UI.

Media

About Media

Uploading media for custom music on hold, IVR prompts, or TTS (if a proper TTS engine is enabled).

sipink 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 superduper 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:

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).

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:

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.

sipink can be configured to normalize uploaded media files. This can fix things like:

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:

  1. Open system_config/crossbar.media document, create or update the key normalize_media to true.
  2. Flush the kapps_config cache, 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

Key Description Type Default Required
content_length Length, in bytes, of the file integer false
content_type Used to override the automatic upload type string('audio/mp3', 'audio/mpeg', 'audio/mpeg3', 'audio/x-wav', 'audio/wav', 'audio/ogg', 'video/x-flv', 'video/h264', 'video/mpeg', 'video/quicktime', 'video/mp4', 'video/webm') false
description A breif description of the media update, usally the original file name string(1..128) false
language The language of the media file or text string en-us false
media_source Defines the source of the media string('recording', 'upload', 'tts') upload false
name A friendly name for the media string(1..128) true
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
source_type If the media was generated from a callflow module, this is the module name string false
streamable Determines if the media can be streamed boolean true false
tts Text-to-speech options used to create audio files from text object {} false
tts.text The text to be converted into audio string(1..) false
tts.voice The voice to be used during the conversion string('female/en-US', 'male/en-US', 'female/en-CA', 'female/en-AU', 'female/en-GB', 'male/en-GB', 'female/es-US', 'male/es-US', 'female/us-US', 'female/zh-CN', 'male/zh-CN', 'female/zh-HK', 'female/zh-TW', 'female/ja-JP', 'male/ja-JP', 'female/ko-KR', 'male/ko-KR', 'female/da-DK', 'female/de-DE', 'male/de-DE', 'female/ca-ES', 'female/es-ES', 'male/es-ES', 'female/fi-FI', 'female/fr-CA', 'male/fr-CA', 'female/fr-FR', 'male/fr-FR', 'female/it-IT', 'male/it-IT', 'female/nb-NO', 'female/nl-NL', 'female/pl-PL', 'female/pt-BR', 'female/pt-PT', 'male/pt-PT', 'female/ru-RU', 'male/ru-RU', 'female/sv-SE', 'female/hu-HU', 'female/cs-CZ', 'female/tr-TR', 'male/tr-TR', 'male/ru-RU/Vladimir', 'female/ru-RU/Julia', 'female/ru-RU/Anna', 'female/ru-RU/Viktoria', 'male/ru-RU/Alexander', 'female/ru-RU/Maria', 'female/ru-RU/Lidia') female/en-US false

Get a listing of media files

GET /v2/accounts/{ACCOUNT_ID}/media

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media

Create a nee media object (required before uploading the actual media data)

PUT /v2/accounts/{ACCOUNT_ID}/media

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
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
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:

{
    "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

DELETE /v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID}

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}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID}

Update metadata

POST /v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID}

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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media/prompts
{
    "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.

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media/languages
{
    "data": [{ "en": 3
               ,"missing": 1
             }
            ],
}

Get the raw media file

GET /v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID}/raw

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

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
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.

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media/prompts/{PROMPT_ID}
{
    "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}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media/languages/{LANGUAGE}
{
    "data":["media_id_1", "media_id_2",...]
}

To get the IDs of the media docs missing a language:

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, IVRs, what ever you call them, allow you to create branches in the callflow based on the caller’s input.

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":

{“module”:“menu” ,“data”:{…} ,“children”:{ “1”:{“module”:“…”,…} ,“2”:{“module”:“…”,…} “timeout”:{“module”:“…”,…} }

If no “timeout” child is specified, the menu is retried (until retries are exceeded).

Metaflows allow functionality to be executed on an in-progress call, triggered by DTMFs from the caller/callee. 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.

Metaflow structure

Any document can be amended with a “metaflows” top-level key; however, at the moment sipink only processes a “metaflows” key on: the account doc, a callflow doc, a user doc, or a device doc.

Let’s take a peek

Inside the “metaflows” object should be a familiar couple of keys, plus a couple metaflows-specific options:

Numbers

The keys in the numbers object represent the DTMF sequence to match, minus the binding_digit. If the caller presses ’*234’, the numbers object will be searched for a key of ‘234’.

The value of each key is the metaflow object to run on a match. It mirrors the callflow’s action format:

Patterns

The keys in the patterns object represent regular expressions to be matched against the collected DTMF sequence (minus the binding_digit as well). The collected DTMFs and the captures (if any) will be included in the data payload.

First, an example patterns object:

“patterns”:{ “^1([0-9]{4})$”:{ “module”:“callflow” ,“data”:{} } }

This regex will match 1 and any four digits (let’s say 2001). The data object will go from empty to:

“data”:{ “collected”:“12001” ,“captured”:[“2001”] }

The callflow metaflow module, in this case, would look at the “captured” list and take the first element. Using that, it would look up a callflow and, if found, ask a callflow app to execute that extension’s callflow against the call (why, I’m not sure yet, but it is there).

Binding Digit

What DTMF triggers a metaflow collection? Typically this would be ’*’ or ’#’, but could ostensibly be any DTMF.

“binding_digit”:“*”

There is also a global flag in system_config/konami key use_fast_rearm which allows immediate retries of failed entries; defaults to 'false’. When 'true’, the binding digit will typically reset the previous input allowing the user to start over at any time if they made a mistake. This also means you can’t have the binding digit in the number sequence that follows, because the binding digit will discard the prior digits. For example if your binding digit is ’’ and you have “123*456” number configured when you dial “*123*456” it will activate metaflow “456”, not “123*456”. An exception to this rule when you need a double binding digit, so binding digit ’’ and number “” is a valid shortcut. Another valid example is binding digit ’’ and number “123”, so when you dial “123” the first ’’ is the binding digit that arms metaflows, but the second ’’ is part of the number and will be treated as “123”, not as just “123”.

Digit Timeout

How long to wait, in milliseconds, for the next DTMF. Once this timeout expires, the available metaflows will be searched, first numbers then patterns, for one that matches.

“digit_timeout_ms”:800

Listen On

Most of the time, a metaflow will only be concerned with receiving the DTMF from the call leg of the user/device configured with a metaflow. This is the “self” option (and the default if left unspecified). A metaflow can alternatively listen only to the other leg of the call using “peer”, or to both sides of the call using “both”.

“listen_on”:“self”

Putting it together

Remember, this “metaflows” object can be put on any account, callflow, user, or device doc.

“metaflows”:{ “numbers”:{ “234”:{ “module”:“play” ,“data”:{“id”:“media_id”} } ,“82824646”:{ “module”:“tts” ,“data”:{“text”:“hello world”} } } ,“patterns”:{ “^1([0-9]{4})$”:{ “module”:“callflow” ,“data”:{} } } ,“binding_digit”:“*” ,“digit_timeout_ms”:800 ,“listen_on”:“self” }

Crossbar

Using Crossbar to modify metaflows is very simple. There are only three actions:

There are two URIs used to manipulate metaflows

Account Metaflow URI

/v1/accounts/{ACCOUNT_ID}/metaflows

This URI is used to manipulate the metaflows available to anyone in the account.

GET - Fetch account metaflows:

curl -v -X GET -H “X-Auth-Token: {AUTH_TOKEN}” http://server:8000/v1/accounts/{ACCOUNT_ID}/metaflows

POST - Update account metaflows:

curl -v -X POST -H “X-Auth-Token: {AUTH_TOKEN}” -H “Content-Type: application/json” http://server:8000/v1/accounts/{ACCOUNT_ID}/metaflows -d ’{“data”:{“numbers”:{“2”:{“module”:“tts”,“data”:{“text”:“2 pressed”}}},“binding_digit”:“*”,“patterns”: {“^1(\d+)$”: {“module”: “callflow”}}}}’

DELETE - Remove account metaflows:

curl -v -X DELETE -H “X-Auth-Token: {AUTH_TOKEN}” http://server:8000/v1/accounts/{ACCOUNT_ID}/metaflows

Callflow/User/Device/etc Metaflow URI

/v1/accounts/{ACCOUNT_ID}/{THINGS}/{THING_ID}/metaflows

Here, {THINGS} would be “callflows”, “users”, “devices”, etc, and {THING_ID} would be a callflow, user, device, or whatever id. Let’s look at adding metaflows to a device.

GET - Fetch device metaflows:

curl -v -X GET -H “X-Auth-Token: {AUTH_TOKEN}” http://server:8000/v1/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/metaflows

POST - Update device metaflows:

curl -v -X POST -H “X-Auth-Token: {AUTH_TOKEN}” -H “Content-Type: application/json” http://server:8000/v1/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/metaflows -d ’{“data”:{“numbers”:{“2”:{“module”:“tts”,“data”:{“text”:“2 pressed”}}},“binding_digit”:“*”}}’

DELETE - Remove device metaflows:

curl -v -X GET -H “X-Auth-Token: {AUTH_TOKEN}” http://server:8000/v1/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/metaflows

Configuration

Metaflows can be configured to be started without needing to attach them to a device, user, etc. You can configure default metaflows on an account or across the system.

To start a metaflow handler for an account: sup kapps_account_config set {ACCOUNT_ID} metaflows default_metaflow true

To start a metaflow for all accounts: sup kapps_config set_default metaflows default_metaflow true

Now, this in and of itself isn’t too useful

Notifications

Allow managing templates for notification emails.

About Notifications

Example structure:

{
    "enabled": true,
    "from": "peter@email.com",
    "macros": {
        "user.first_name": {
            "description": "If the voicemail box has an owner id, this is the first name of that user.  Not always present",
            "friendly_name": "First Name",
            "i18n_label": "first_name"
        },
        "user.last_name": {
            "description": "If the voicemail box has an owner id, this is the first name of that user.  Not always present",
            "friendly_name": "Last Name",
            "i18n_label": "last_name"
        }
    },
    "subject": "Hello {{user.first_name}}, you received a new voicemail!",
    "template_charset": "utf-8",
    "to": {
        "email_addresses": [
            "peter@email.com"
        ],
        "type": "admins"
    }
}

In addition to the JSON data, templates in various formats can be uploaded (such as from a WYSIWYG tool). Currently supported are plaintext and HTML documents.

The macros object is a per-template, system-defined set of macros you can use in your templates. You cannot configure this via the API.

Schema

Key Description Type Default Required
bcc Bcc email field object false
bcc.email_addresses BCC Email Addresses array() false
bcc.type string('original', 'specified', 'admins') false
category Category of the template, for grouping purposes string(1..) false
cc CC email field object false
cc.email_addresses CC Email Addresses array(string) false
cc.email_addresses.[] string false
cc.type string('original', 'specified', '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 array(string) false
to.email_addresses.[] string false
to.type string('original', 'specified', 'admins') false

Crossbar

Using Crossbar to modify notifications is very simple:

To modify an account notification, the requester must be a reseller of that account or the master account.

Account Temporal Rules Sets URI

Fetch available notification templates from the system

GET /v2/notifications

This is the first request to make to see what templates exist on the system to override

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications
{
        "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"
                 }
                 ,...
             }
            }
            ,{...}
        ]
        "request_id": "{REQUEST_ID}",
        "revision": "{REVISION}",
        "status": "success"
}

To see what notification templates an account overrides, include the account ID in the URI:

GET /v2/accounts/{ACCOUNT_ID}/notifications

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications
{
    "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
        }
    ],
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

The key account_overridden will exist on any templates that are account-specific.

Fetch a notification’s configuration

Using the ID from the system listing above, get the template JSON. 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).

curl -v -X GET -H “X-Auth-Token: {AUTH_TOKEN}” http://server:8000/v2/notifications/{NOTIFICATION_ID} { “auth_token”: “{AUTH_TOKEN}”, “data”: { “id”: “{NOTIFICATION_ID}” ,“macros”:{…} ,“templates”: { “text/html”: { “length”: 600 } ,“text/plain”: { “length”: 408 } } }, “request_id”: “{REQUEST_ID}”, “revision”: “{REVISION}”, “status”: “success” }

Performing a GET with an account ID will return the notification object, again with the account_overridden flag added if it is account-specific; lack of the key indicates it is the system default notification.

Create a notification template

Now that you’ve fetched the system default template, modify and PUT it back to the account.

PUT /v2/accounts/{ACCOUNT_ID}/notifications

curl -v -X PUT \
    -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 recieved a new voicemail!",
        "enabled": true,
        "template_charset": "utf-8"
    }}' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications
{
    "auth_token": "{AUTH_TOKEN}",
    "data": {
        "enabled": true,
        "from": "reseller@resellerdomain.com",
        "id": "{NOTIFICATION_ID}",
        "macros": {
            "user.first_name": {
                "description": "If the voicemail box has an owner id, this is the first name of that user. Not always present",
                "friendly_name": "First Name",
                "i18n_label": "first_name"
            },
            "user.last_name": {
                "description": "If the voicemail box has an owner id, this is the last name of that user. Not always present",
                "friendly_name": "Last Name",
                "i18n_label": "last_name"
            }
        },
        "subject": "Hello {{user.first_name}}, you recieved a new voicemail!",
        "template_charset": "utf-8",
        "to": {
            "email_addresses": [
                "user@account.com"
            ],
            "type": "users"
        }
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

This request will fail if id does not already exist in the system defaults. To create a new system notification template, a superduper admin can use the above PUT, but to /v2/notifications instead of a specific account.

Fetch a specific notification

Now that you’ve created an account-specific notification, you can fetch it to feed into a WYSIWYG editor or for other purposes:

GET /v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}
{
    "auth_token": "{AUTH_TOKEN}",
    "data": {
        "id": "{NOTIFICATION_ID}",
        ...
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Update a notification’s config

Similar to the PUT, POST will update an existing config:

POST /v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}

Omit /accounts/{ACCOUNT_ID} to update the system’s version.

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 recieved 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}

Remove a notification template

DELETE /v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}

Omit the /accounts/{ACCOUNT_ID} to remove the system default.

DELETE /v2/notifications/{NOTIFICATION_ID}

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}

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.

Get notification template:

GET /v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}

When you GET a notification config (Accept of application/json), get a templates list of Content-Type atttributes. Use those to fetch a specific template by setting the Accept header:

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -H 'Accept: text/html' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}
curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -H 'Accept: text/plain' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}

Note that the only difference is the Accept attribute. This will determine which attachment is returned in the payload. If you specify a non-existent Accept MIME type, expect to receive a 406 Not Acceptable error.

For clients that do not support setting the Accept header, a querystring parameter can be included (eg http://server:8000/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}

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}
curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -H 'Content-Type: text/html' \
    -d '<div>
            <p>Some Html and {{macro.key}} replaced on render</p>
       </div>' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}

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

curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -H 'Content-Type: application/json' \
    -d '{"data": {
        "to": {"email_addresses": ["me@sipink.com"]},
        "from": "sipink@sipink.com",
        "subject": "Testing NOTIFICATION",
        "html": "SSUyNTIwJTI1dTI2NjElMjUyMFVuaWNvZGUlMjUyMQ==",
        "plain": "You just recieved an email! It was sent to {{user.email}}",
        "enabled": true
        }}' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID}/preview

Operations considerations

In versions sipink prior to 3.19, notification templates were managed and processed by the notify app.

All accounts will continue to be processed by the notify app until the Crossbar notification APIs are accessed for the first time (for instance, when using the Branding App in Monster). Once a client has accessed the APIs, a flag is set on the account telling the notify app to ignore processing and instructs the teletype app to process it instead. This allows admins to run both notify and teletyple concurrently without sending multiple copies of each notification.

Get the notification(s) SMTP log

GET /v2/accounts/{ACCOUNT_ID}/notifications/smtplog

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -H 'Content-Type: text/plain' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/smtplog

Get a notification’s SMTP log

GET /v2/accounts/{ACCOUNT_ID}/notifications/smtplog/{SMTP_LOG_ID}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/smtplog/{SMTP_LOG_ID}
{
  "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=&quot;urn:uuid:00000000-0000-1000-8000-000B826C4283&quot;\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=&quot;urn:uuid:00000000-0000-1000-8000-000B826C4283&quot;</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

Send a message to all reseller’s children or to a particular account.

POST /v2/accounts/{ACCOUNT_ID}/notifications/customer_update/message

Send message to all reseller’s accounts:

curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -H 'Content-Type: text/plain' \
    -d '{} \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/customer_update/message
curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -H 'Content-Type: text/plain' \
    -d '{} \
    http://{SERVER}:8000/v2/accounts/{SENDER(RESELLER)_ACCOUNT_ID}/notifications/customer_update/message

Send message to a particular acount:

curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -H 'Content-Type: text/plain' \
    -d '{"data": {"recipient_id": "33ca3929ed585e0e423eb39e4ffe1452"}}' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/customer_update/message
curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -H 'Content-Type: text/plain' \
    -d '{"data": {"recipient_id": "33ca3929ed585e0e423eb39e4ffe1452"}}' \
    http://{SERVER}:8000/v2/accounts/{SENDER(RESELLER)_ACCOUNT_ID}/notifications/customer_update/message

You can send a message to all users, admins only or a particular user within an account. Just add a user_type field to your payload:

All users:

{
    "data": {"user_type": "all_users"}
}

Particular user:

{
    "data": {"user_type": "{ACCOUNT_ID}"}
}

Admin privileged users only. Default. Could be omitted:

{
    "data": {"user_type": "admins_only"}
}

You can send a message with changed subject, html and plain text templates by providing full notification document payload:

{
    "data": {
        "recipient_id": "33ca3929ed585e0e423eb39e4ffe1452",
        "user_type": "3d9b564d5c95d52d81a2e49ea0c57941",
        "id": "customer_update",
        "account_overridden": true,
        "enabled": true,
        "category": "user",
        "friendly_name": "Customer update",
        "from": "info@onnet.su",
        "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,\nOnNet Innovations Limited.",
        "templates": {
            "text/html": {
                "length": 161
            },
            "text/plain": {
                "length": 136
            }
        },
    }
}

Onboarding

Used to create new accounts without being signed in.

NOTICE

This API has been deprecated and is no longer maintained by the sipink core team. The prefered 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

Taken from https://sipink.atlassian.net/browse/sipink-63

PUT to /v1/onboard

{
    "data": {
        "account": {
            "available_apps": [
                "voip",
                "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"
                        }
                    },
                    "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"
}

Phone Numbers

About Phone_numbers

The sipink mobile API set: manage numbers.

Schema

Key Description Type Default Required
cnam object false
cnam.display_name string(1..15) false
cnam.inbound_lookup boolean false
e911 object false
e911.activated_time The time stamp e911 was provisioned string false
e911.caller_name The name that will show to emergency services string 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 Legacy E911 information object 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.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.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 true
e911.status The e911 provisioning system status for this service address string('INVALID', 'GEOCODED', 'PROVISIONED', 'REMOVED', 'ERROR') false
e911.street_address The street address where the number is in service string true
porting Porting (in) information for the phone number 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 An array of comments array(string) false
porting.comments.[] 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

Search for numbers

Looks for numbers using the carrier module set up for your account.

GET /v2/phone_numbers?prefix={PREFIX}&quantity={QUANTITY}&offset={OFFSET}&country={COUNTRY}

curl -v -X GET \
    http://{SERVER}:8000/v2/phone_numbers?prefix=415&quantity=2
{
    "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

GET /v2/accounts/{ACCOUNT_ID}/phone_numbers?prefix={PREFIX}&quantity={QUANTITY}&offset={OFFSET}

curl -v -X GET \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers?prefix=555&quantity=3&offset=6
{
    "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"
}

List an 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

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

    "auth_token": "{AUTH_TOKEN}",
    "data": {
        "casquade_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"
}

Per-number CRUD operations

Remove a number from the account owning it

DELETE /v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}

Response

Success

{
    "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

{
    "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}

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}?hard=true

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}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}

Response

Success

{
    "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

Possible reasons for failure:

{
    "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}

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}
{
    "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}",
        "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: payload is facultative.

PUT /v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}

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}

Response

Success

{
    "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

Number already exists

{
    "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".

{
    "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

{
    "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

This API check if the numbers are still available for purchase.

POST /v2/accounts/{ACCOUNT_ID}/phone_numbers/check

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

Response

Success

{
    "auth_token": "{AUTH_TOKEN}",
    "data": {
        "{PHONE_NUMBER1}": "success",
        "{PHONE_NUMBER2}": "error"
    }
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Failure

When server encounters an error "data": {} is returned.

It may be due to:

{
    "auth_token": "{AUTH_TOKEN}",
    "data": {},
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Get locality information for a collection of numbers

POST /v2/accounts/{ACCOUNT_ID}/phone_numbers/locality

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

Responses

Success

{
    "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

{
    "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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/prefix?city={CITY}

Responses

Success


Country or city not found

{
    "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

{
    "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

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
{
    "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

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
{
    "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

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
{
    "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"
}

Add a list of numbers to the database

PUT /v2/accounts/{ACCOUNT_ID}/phone_numbers/collection

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

Responses

Success

{
    "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

{
    "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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/classifiers
{
    "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

curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/fix
{
    "auth_token": "{AUTH_TOKEN}",
    "data": {
        "casquade_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"
}

Return which account a number belongs to

GET /v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}/identify

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}/identify

Responses

Success

{
    "auth_token": "{AUTH_TOKEN}",
    "data": {
        "account_id": "009afc511c97b2ae693c6cc4920988e8",
        "number": "{PHONE_NUMBER}"
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Number not found or not enough privileges

{
    "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

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
{
    "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

curl -v -X PUT \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}/reserve

Responses

Success

{
    "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

{
    "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

{
    "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

curl -v -X PUT \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER}/activate

Responses

Success

{
    "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

{
    "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

{
    "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}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/classifiers/{PHONE_NUMBER}
{
    "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

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

Responses

Success

{
    "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

{
    "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

Request

{
    "data": {
        "used_by": "callflow",
        "id": "{{NUMBER}}",
        "e911": {
            "caller_name": "{{NAME}}",
            "postal_code": "{{ZIP_CODE}}",
            "street_address": "{{ADDRESS}}",
            "extended_address": "{{EXTENDED}}",
            "locality": "{{CITY}}",
            "region": "{{STATE}}"
        }
    }
}

Response

Invalid address

{
    "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

{
    "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

{
    "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

About Pivot

The Pivot Module resource allows the client to query and inspect data related to the Pivot application (real-time call control).

Enabling in Pivot

The Pivot endpoint is not loaded on start in a default sipink installation. You would need to request it using the SIPINK support.

Callflow Schema

Any pivot callflow node must obey this schema.

Key Description Type Default Required
cdr_url Optional URL to send the CDR to at the end of the call string false
debug Store debug logs related to processing this Pivot call boolean false false
method What HTTP verb to send the request(s) with string('get', 'post', 'GET', 'POST') get false
req_format What format of Pivot will the your server respond with string('sipink', 'twiml') sipink false
voice_url What URL to request the initial Pivot callflow string true

Debugging pivot attempts

You will need to edit the “data” object in the “pivot” callflow element to include a “debug” flag:

    "flow": {
      "data": {
        "method": "GET",
        "req_format": "sipink",
        "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 debugged UUIDs

GET /v2/accounts/{ACCOUNT_ID}/pivot/debug

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/pivot/debug
{
    "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/sipink_4786.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}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/pivot/debug/{UUID}
{
    "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.

Port Requests

Manage and track number port requests through the Port Requests API.

A port request can be in one of five states:

List port requests

GET /v2/accounts/{ACCOUNT_ID}/port_requests

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests
{
    "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"
}

Get a port request by phone number

GET /v2/accounts/{ACCOUNT_ID}/port_requests

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests?by_number={PHONE_NUMBER}
{
    "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"
}

Listing by port state

You can issue GET requests to find all ports in a particular state too.

All requests are not paginated, with the exception of the completed state. Use pagination toggles for date range as desired.

Listing by unconfirmed port

GET /v2/accounts/{ACCOUNT_ID}/port_requests/unconfirmed

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/unconfirmed
{
    "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": {}
                }
            ]
        }
    ],
    "page_size": 1,
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Listing by submitted port

GET /v2/accounts/{ACCOUNT_ID}/port_requests/submitted

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/submitted
{
    "auth_token": "{AUTH_TOKEN}",
    "data": [
        {
            "account_id": "{ACCOUNT_ID}",
            "account_name": "{ACCOUNT_NAME}",
            "port_requests": [
                {
                    "account_id": "009afc511c97b2ae693c6cc4920988e8",
                    "created": 63630130298,
                    "id": "c320d6506f1afcd715a1a49bac019c51",
                    "name": "My port req1",
                    "numbers": {
                        "+12025559042": {}
                    },
                    "port_state": "submitted",
                    "sent": false,
                    "updated": 63630130376,
                    "uploads": {}
                }
            ]
        }
    ],
    "page_size": 1,
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Listing by pending port

GET /v2/accounts/{ACCOUNT_ID}/port_requests/pending

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/pending
{
    "auth_token": "{AUTH_TOKEN}",
    "data": [
        {
            "account_id": "{ACCOUNT_ID}",
            "account_name": "{ACCOUNT_NAME}",
            "port_requests": [
                {
                    "account_id": "009afc511c97b2ae693c6cc4920988e8",
                    "created": 63630130298,
                    "id": "c320d6506f1afcd715a1a49bac019c51",
                    "name": "My port req1",
                    "numbers": {
                        "+12025559042": {}
                    },
                    "port_state": "pending",
                    "sent": false,
                    "updated": 63630130450,
                    "uploads": {}
                }
            ]
        }
    ],
    "page_size": 1,
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Listing by scheduled port

GET /v2/accounts/{ACCOUNT_ID}/port_requests/scheduled

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/scheduled
{
    "auth_token": "{AUTH_TOKEN}",
    "data": [
        {
            "account_id": "{ACCOUNT_ID}",
            "account_name": "{ACCOUNT_NAME}",
            "port_requests": [
                {
                    "account_id": "009afc511c97b2ae693c6cc4920988e8",
                    "created": 63630130298,
                    "id": "c320d6506f1afcd715a1a49bac019c51",
                    "name": "My port req1",
                    "numbers": {
                        "+12025559042": {}
                    },
                    "port_state": "scheduled",
                    "sent": false,
                    "updated": 63630130490,
                    "uploads": {}
                }
            ]
        }
    ],
    "page_size": 1,
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Listing by completed port

GET /v2/accounts/{ACCOUNT_ID}/port_requests/completed

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/completed
{
    "auth_token": "{AUTH_TOKEN}",
    "data": [],
    "page_size": 0,
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "start_key": [
        "009afc511c97b2ae693c6cc4920988e8",
        "completed",
        63630130530
    ],
    "status": "success"
}

Listing by rejected port

GET /v2/accounts/{ACCOUNT_ID}/port_requests/rejected

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/rejected
{
    "auth_token": "{AUTH_TOKEN}",
    "data": [
        {
            "account_id": "{ACCOUNT_ID}",
            "account_name": "{ACCOUNT_NAME}",
            "port_requests": [
                {
                    "account_id": "009afc511c97b2ae693c6cc4920988e8",
                    "created": 63630130298,
                    "id": "c320d6506f1afcd715a1a49bac019c51",
                    "name": "My port req1",
                    "numbers": {
                        "+12025559042": {}
                    },
                    "port_state": "rejected",
                    "sent": false,
                    "updated": 63630130557,
                    "uploads": {}
                }
            ]
        }
    ],
    "page_size": 1,
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Listing by canceled port

GET /v2/accounts/{ACCOUNT_ID}/port_requests/canceled

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/canceled
{
    "auth_token": "{AUTH_TOKEN}",
    "data": [
        {
            "account_id": "{ACCOUNT_ID}",
            "account_name": "{ACCOUNT_NAME}",
            "port_requests": [
                {
                    "account_id": "009afc511c97b2ae693c6cc4920988e8",
                    "created": 63630107130,
                    "id": "0684aa1e2785d62c76ce27d2451a1c26",
                    "name": "Porting 202.555.9000",
                    "numbers": {
                        "+12025559000": {}
                    },
                    "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}",
    "start_key": [
        "009afc511c97b2ae693c6cc4920988e8",
        "canceled",
        63630129922
    ],
    "status": "success"
}

List port requests of self and sub accounts

GET /v2/accounts/{ACCOUNT_ID}/descendants/port_requests

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/descendants/port_requests
{
    "auth_token": "{AUTH_TOKEN}",
    "data": [],
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Get port request for account and descendants

GET /v2/accounts/{ACCOUNT_ID}/descendants/port_requests

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/descendants/port_requests?by_number={PHONE_NUMBER}
{
    "auth_token": "{AUTH_TOKEN}",
    "data": [
        {
            "bill": {
                "address": "116, natoma street",
                "locality": "San Francisco",
                "name": "John Doe",
                "postal_code": "95109",
                "region": "Ca"
            },
            "carrier": "PACIFIC BELL",
            "created": 63597642009,
            "id": "84e0a824c6b74fe1e3ec48962a600ef2",
            "name": "Port request test",
            "notifications": {
                "email": {
                    "send_to": "someone@sipink.com"
                }
            },
            "numbers": {
                "{PHONE_NUMBER}": {}
            },
            "port_state": "submitted",
            "sent": false,
            "transfer_date": 63598114800,
            "updated": 63597642011,
            "uploads": {
                "bill.pdf": {
                    "content_type": "application/pdf",
                    "length": 8304
                },
                "loa.pdf": {
                    "content_type": "application/pdf",
                    "length": 59196
                }
            }
        }
    ],
    "page_size": 1,
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Create a new port request

PUT /v2/accounts/{ACCOUNT_ID}/port_requests

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

Success

{
    "auth_token": "{AUTH_TOKEN}",
    "data": {
        "id": "462da37f8be11e46161fb40bc71173a9",
        "name": "{PORT_REQUEST_NAME}",
        "numbers": {
            "{PHONE_NUMBER}": {}
        },
        "port_state": "unconfirmed"
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Failure: a port already exists for this number

{
    "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

{
    "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"
}

List port request details

GET /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}
{
    "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": {}
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Edit a port request

POST /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}

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}
{
    "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": {}
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

DELETE a port request

DELETE /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}
{
    "auth_token": "{AUTH_TOKEN}",
    "data": {
        "id": "{PORT_REQUEST_ID}",
        "name": "Porting 202.555.9000",
        "numbers": {
            "+12025559000": {
                "state": "NY"
            }
        },
        "port_state": "unconfirmed"
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

List attachments on a port request

GET /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments
{
    "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

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}'
{
    "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}

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}

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}

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}
{
    "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}

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}
{
    "auth_token": "{AUTH_TOKEN}",
    "data": {},
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Indicate a port is ready to be processed

PATCH /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/submitted

curl -v -X PATCH \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/submitted

Success

{
    "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

{
    "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

curl -v -X PATCH \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/pending

Success

{
    "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

{
    "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

curl -v -X PATCH \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/scheduled
{
    "auth_token": "{AUTH_TOKEN}",
    "data": {
        "created": 63630107130,
        "id": "{PORT_REQUEST_ID}",
        "name": "Porting 202.555.9000",
        "numbers": {
            "+12025559000": {}
        },
        "port_state": "scheduled",
        "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

curl -v -X PATCH \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/completed
{
    "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

curl -v -X PATCH \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/rejected
{
    "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

curl -v -X PATCH \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/canceled
{
    "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

GET /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/loa

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

Streams back the contents of the generated Letter Of Authorization PDF.

Presence

About Presence

sipink tracks presence subscriptions and those states can be accessed/manipulated via this API.

There are three main ways to access presence information:

Schema

GET /v2/accounts/{ACCOUNT_ID}/presence

It is possible to search/list all subscriptions for an account:

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/presence
{
     "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.sipink.com",
                         "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.sipink.com",
                         "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 sipink REST API.

POST /v2/accounts/{ACCOUNT_ID}/presence/{EXTENSION}

Where {EXTENSION} could be *3101, 110011, or whatever other extensions are allowed.

curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -d '{"data": {"reset": true}' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/presence/{EXTENSION}

Devices

This API will use the `presence_id’ of the device, if present; otherwise it will use the SIP username of the device.

POST to reset presence state

curl -v -X POST http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/presence -d ’{“data”:{“reset”:true}}’

Users

This API will use the presence_id of the user is applicable; otherwise it will reset all the user’s devices’ states

POST to reset presence state

curl -v -X POST http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/presence -d ’{“data”:{“reset”:true}}’

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 sipink 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.

Concretely, if the request is GET /v2/accounts/{ACCOUNT_ID}/callflows, Crossbar will check:

  1. Check {ACCOUNT_ID}."callflows"."GET"
  2. Check {ACCOUNT_ID}."callflows"
  3. Check {ACCOUNT_ID}
  4. Check "callflows"."GET"
  5. 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:

  1. All requests to callflows cost the same

    {“_id”:“crossbar” ,“default”:{ “token_costs”:{ “callflows”:2 } } }

  2. callflows vary in cost depending on method:

    {“_id”:“crossbar” ,“default”:{ “token_costs”:{ “callflows”:{ “GET”:1 ,“PUT”:5 ,“POST”:5 ,“DELETE”:1 } } } }

  3. Deduct flat amount for an account:

    {“id”:“crossbar” ,“default”:{ “token_costs”:{ “{ACCOUNTID}”:2 } } }

  4. Deduct flat amount for an account for a specifc endpoint:

    {“id”:“crossbar” ,“default”:{ “token_costs”:{ “{ACCOUNTID}”:{ “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):

  1. Disable token buckets

    {“id”:“crossbar” ,“default”:{ “tokencosts”:0 } }

  2. Flat cost across APIs - any integer > 0. This is how the default Crossbar operates.

    {“id”:“crossbar” ,“default”:{ “tokencosts”:1 } }

Configuring Token Bucket start parameters

To configure the token buckets themselves, look in the system_config/token_buckets document.

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”:{ “maxbucket_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}

  1. Check {ACCOUNT_ID}."devices"."GET"."quickcall"
  2. Check {ACCOUNT_ID}."devices"."quickcall"
  3. Check {ACCOUNT_ID}."quickcall"
  4. Check "devices"."GET"."quickcall"
  5. 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 } } } }

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.

Crossbar

Using Crossbar to modify rate_limits is very simple. There are only three actions:

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.

Example

{
    "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
            }
        }
    }
}

Example

{
    "data": {
        "per_minute": {
            "registrations": 60,
            "invites": 60,
            "total_packets": 180
        },
        "per_second": {
            "registrations": 2,
            "invites": 4,
            "total_packets": 7
        }
    }
}

Account rate limits URI

/v1/accounts/{ACCOUNT_ID}/rate_limits

This URI is used to manipulate the rate limits for the entire account

GET - Fetch account rate limits:

curl -v -X GET -H “X-Auth-Token: {AUTH_TOKEN}” http://server:8000/v1/accounts/{ACCOUNT_ID}/rate_limits

POST - Update account rate limits:

curl -v -X POST -H “X-Auth-Token: {AUTH_TOKEN}” -H “Content-Type: application/json” http://server:8000/v1/accounts/{ACCOUNT_ID}/rate_limits -d ’{“data”: {“account”: {“per_minute”: {“total_packets”: 3000},“per_second”: {“total_packets”: 50}},“device”: {“per_minute”: {“total_packets”: 300},“per_second”: {“total_packets”: 5}}}}’

DELETE - Remove account rate limits:

curl -v -X DELETE -H “X-Auth-Token: {AUTH_TOKEN}” http://server:8000/v1/accounts/{ACCOUNT_ID}/rate_limits

Device rate limits URI

/v1/accounts/{ACCOUNT_ID}/{THINGS}/{THING_ID}/rate_limits

Here, {THINGS} would be “accounts” or “devices” and {THING_ID} would be a device or account id. Let’s look at adding rate limits to a device.

GET - Fetch device rate limits:

curl -v -X GET -H “X-Auth-Token: {AUTH_TOKEN}” http://server:8000/v1/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/rate_limits

POST - Update device rate limits:

curl -v -X POST -H “X-Auth-Token: {AUTH_TOKEN}” -H “Content-Type: application/json” http://server:8000/v1/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/rate_limits -d ’{“data”: {“per_minute”: {“registrations”: 60,“invites”: 60,“total_packets”: 180},“per_second”: {“registrations”: 2,“invites”: 4,“total_packets”: 7}}}’

DELETE - Remove device rate limits:

curl -v -X GET -H “X-Auth-Token: {AUTH_TOKEN}” http://server:8000/v1/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/rate_limits

Registrations

About Registrations

The Registrations API provides an easy way to see and manage current registrations.

Schema

Flush all registrations

DELETE /v2/accounts/{ACCOUNT_ID}/registrations

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/registrations
{
     "auth_token": "{AUTH_TOKEN}",
     "data": "ok",
     "request_id": "{REQUEST_ID}",
     "revision": "{REVISION}",
     "status": "success"
}

Fetch account registrations

GET /v2/accounts/{ACCOUNT_ID}/registrations

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/registrations
{
     "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}"
          }
          ,...
      ],
      "request_id": "{REQUEST_ID}",
      "revision": "{REVISION}",
      "status": "success"
}

Flush a specific device’s registration

DELETE /v2/accounts/{ACCOUNT_ID}/registrations/{USERNAME}

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/registrations/{USERNAME}
{
     "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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/registrations/count
{
     "auth_token": "{AUTH_TOKEN}",
     "data": {
         "count": 4
     },
     "request_id": "{REQUEST_ID}",
     "revision": "{REVISION}",
     "status": "success"
}

Schemas

About Schemas

sipink 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 sipink-managed private fields (top-level keys prefixed with “” and “pvt”).

Schema

Fetch a listing of available schemas

GET /v2/schemas

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/schemas
{
    "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}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/schemas/acls
{
    "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": [
            "cird",
            "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

curl -v -X PUT \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -d '{"data":{...}}'
    http://{SERVER}:8000/v2/schemas/{SCHEMA_NAME}/validation
{
    "auth_token":"",
    "data":{...},
    "request_id":"{REQUEST_ID}",
    "revision":"{REVISION}",
    "status":"success"
}

Search

The Search API allows queries on databases.

You can search for accounts by:

Schema

Fetch search results

GET /v2/search

GET /v2/accounts/{ACCOUNT_ID}/search

t = document type q = view name * all views must be defined in design/search * the view used is q=name => searchby_[name] v = value to search

database - the search api will search in the accountdb if API with /accounts/{ACCOUNT_ID}/ is used otherwise will search the accounts database using authenticated account

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/search?t=account&q=name&v=nat
curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/xxxxxxx/search?t=user&q=name&v=j
{
    "data": [
        {
            "id": "4c004a584ca5fda8084a5bcb24430ab9",
            "name": "Natoma Office",
            "realm": "eb0dcc.sip.90e9.com"
        }
    ],
    "page_size": 1,
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "start_key": [
        "5ba01ad7ad1611d436b1860d8c552897",
        "account",
        "nat"
    ],
    "status": "success"
}

GET /v2/search/multi

GET /v2/accounts/{ACCOUNT_ID}/search/multi

t = document type by_{view_name} = value

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/search/multi?t=account&by_name=test&by_realm=test&by_id=test
{
    "data": {
        "realm": [{
            "id": "8b77383bbdaebab09abc6372503335a5eab9a4f",
            "descendants_count": 1,
            "name": "test_account",
            "realm": "test.sip.sipink.com"
        }],
        "name": [{
            "id": "8b77383bbdaebab09abc6372503335a5eab9a4f",
            "descendants_count": 1,
            "name": "test_account",
            "realm": "test.sip.sipink.com"
        }, {
            "id": "3977383bbdaebab09abc6372503335a5eab9a4f",
            "descendants_count": 0,
            "name": "test_account_2",
            "realm": "62b63f.sip.sipink.com"
        }],
        "id": []
    },
    "status": "success",
}

Service_plans

About Service_plans

Handle the service plans you can subscribe to.

Schema

Key Description Type Default Required
bookkeepers object false
description Describes the service plan offering string false
name A friendly name for the service plan string(1..128) true
plan Outlines the service plan for various services object true

Retrieving your service plans.

GET /v2/accounts/{ACCOUNT_ID}/service_plans

Useful for resellers.

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans
{
    "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.

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
{
    "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.

curl -v -X DELETE \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID}

Retrieving one of your service plans.

GET /v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID}

Useful for resellers.

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID}
{
    "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}

curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -d '{"data":{"id":"service_plan_id"}' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID}
{
    "data": {...}
    "status": "success"
}

Override a plan

POST /v2/accounts/{ACCOUNT_ID}/service_plans/override

Must be super duper admin

Note: _all override payload.

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
{
    "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 retreive the service plan currenlty applied on your account.

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/current
{
    "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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/available
{
    "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}

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/available/{PLAN_ID}
{
    "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

Schema

Fetch the current services

GET /v2/accounts/{ACCOUNT_ID}/services

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services

Update the billing ID

POST /v2/accounts/{ACCOUNT_ID}/services

curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -d '{"data": {
        "billing_id":"{BILLING_ID}"
    }}' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services

Fetch the audit logs for the account

GET /v2/accounts/{ACCOUNT_ID}/services/audit

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/services/audit

The SUP API is meant to mirror command-line interactions with the SUP tool. It will only run on the local API server.

You must be super_duper_admin to access the SUP endpoint.

Activation

To update the running Crossbar system with this endpoint, issue the following sup command:

sup crossbar_maintenance start_module cb_sup

If you want this endpoint to load by default, modify the crossbar doc in the system_config database, and add cb_sup to the autoload_modules list.

URL mapping

Remember that SUP commands follow the format of:

sup module_maintenace function [arg1, arg2,…]

The Crossbar URL is similarly constructed:

/v1/sup/module/[function[/arg1/arg2/…]]

The important differences are:

Examples

Command line Crossbar
sup sipink_maintenance syslog_level debug curl /v1/sup/sipink/syslog_level/debug

Backgroud Jobs

sipink Tasks enables listing, adding, starting & removing generic background tasks.

Schema

Key Description Type Default Required
file_name Human-readable name of a task’s input file string false
records List the rows of input data array(object) false

List available tasks

GET /v2/tasks

No such category and/or action

curl -v -X GET \
    http://{SERVER}:8000/v2/tasks?category=services&action=blipblop
{
    "auth_token": "{AUTH_TOKEN}",
    "data": {
        "message": "invalid request"
    },
    "error": "500",
    "message": "invalid request",
    "request_id": "{REQUEST_ID}",
    "status": "error"
}

Success

curl -v -X GET \
    http://{SERVER}:8000/v2/tasks?category=services&action=descendant_quantities
{
    "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

curl -v -X GET \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks
{
    "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

With CSV input data:

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}

With JSON input data:

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}

Without input data:

curl -v -X PUT \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks?category={CATEGORY}&action={ACTION}

Success

{
    "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

{
    "auth_token": "{AUTH_TOKEN}",
    "data": [
        "{CATEGORY}"
    ],
    "error": "404",
    "message": "bad identifier",
    "request_id": "{REQUEST_ID}",
    "status": "error"
}

Unknown action

{
    "auth_token": "{AUTH_TOKEN}",
    "data": [
        "{ACTION}"
    ],
    "error": "404",
    "message": "bad identifier",
    "request_id": "{REQUEST_ID}",
    "status": "error"
}

Bad CSV format

{
    "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

{
    "auth_token": "{AUTH_TOKEN}",
    "data": {
        "attachment": {
            "type": {
                "unknown_fields": [
                    "wef"
                ]
            }
        }
    },
    "error": "500",
    "message": "invalid request",
    "request_id": "{REQUEST_ID}",
    "status": "error"
}

Missing mandatory fields

{
    "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

{
    "auth_token": "{AUTH_TOKEN}",
    "data": {
        "attachment": {
            "type": {
                "missing_mandatory_values": [
                    ",+14157215234",
                    "009afc511c97b2ae693c6cc4920988e8,"
                ]
            }
        }
    },
    "error": "500",
    "message": "invalid request",
    "request_id":