Devices

Devices

About Devices

Devices are the endpoints assigned to an account that serve that account’s needs. Devices like fax machines, SIP phones, soft phone clients, and cell phones (via call forwarding), among others, can be represented by Kazoo devices.

Schema

A device be it a SIP phone or landline number

KeyDescriptionTypeDefaultRequiredSupport Level
addressesDevice addressesobject()false
call_failoverThe device call failover parameters, to replace the device with an extension/phone number when device is offline.#/definitions/call_failoverfalse
call_forwardCall forward settings#/definitions/call_forwardfalse
call_limitsSchema for call limits#/definitions/call_limitsfalse
call_recordingendpoint recording settings#/definitions/call_recordingfalse
call_restrictionDevice level call restrictions for each available number classificationobject(){}false
call_waitingParameters for server-side call waiting#/definitions/call_waitingfalse
caller_idThe device caller ID parameters#/definitions/caller_idfalse
caller_id_optionscustom properties for configuring caller_id#/definitions/caller_id_optionsfalse
contact_list.excludeIf set to true the device is excluded from the contact listboolean()falsesupported
contact_listContact List Parametersobject(){}false
device_typeArbitrary device type used by the UI and billing systemstring()false
dial_planA list of rules used to modify dialed numbers#/definitions/dialplansfalse
do_not_disturb.enabledIs do-not-disturb enabled for this device?boolean()false
do_not_disturbDND Parametersobject()false
enabledDetermines if the device is currently enabledboolean()truefalsesupported
exclude_from_queuesDo not ring this device when calling user/agent in queueboolean()falsefalse
flags.[]string()falsesupported
flagsFlags set by external applicationsarray(string())falsesupported
formattersSchema for request formatters#/definitions/formattersfalse
hotdesk.users./^[a-zA-Z0-9]{32}$/user-specific hotdesk settingsobject()false
hotdesk.usersThe user(s) currently hotdesked into the deviceobject()false
hotdeskThe hotdesk status of this deviceobject()false
languageThe language for the devicestring()falsesupported
mac_addressThe MAC Address of the device (if applicable)string()falsesupported
mediaConfigure audio/video/etc media options for this device#/definitions/endpoint.mediafalse
metaflowsThe device metaflow parameters#/definitions/metaflowsfalse
mobile.mdnThe MDN - mobile device numberstring()false
mobileKAZOO devices that integrate with mobile providersobject()false
music_on_hold.media_idThe ID of a media object that should be used as the music on holdstring(0..2048)false
music_on_hold.options.[]`string(‘preserve-position’‘random-start’)`false
music_on_hold.optionsOptions for playing music on hold`array(string(‘preserve-position’‘random-start’))`false
music_on_holdThe music on hold parameters used if not a property of the device ownerobject(){}false
mwi_unsolicited_updatesWhen true enables unsolicited mwi notificationsboolean()truefalse
nameA friendly name for the devicestring(1..128)truesupported
outbound_flagsList of flags (features) this device requires when making outbound calls`array(string())object()`false
owner_idThe ID of the user object that ‘owns’ the devicestring(32)false
presence_aliasesPresence Aliases#/definitions/presence_aliasesfalse
presence_idStatic presence ID (used instead of SIP username)string()falsesupported
provision.check_sync_eventValue to use in Event header for device reload/rebootstring()false
provision.check_sync_rebootValue to append to ‘check-sync’ event if phone should reboot after reloading settingsstring()reboot=truefalse
provision.check_sync_reloadValue to append to ‘check-sync’ event if phone should not reboot after reloading settingsstring()reboot=falsefalse
provision.combo_keys./^[0-9]+$/Device provisioner Combo/Feature Key#/definitions/devices.combo_keyfalse
provision.combo_keysobject()false
provision.endpoint_brandBrand of the phonestring()false
provision.endpoint_familyFamily name of the phonestring()false
provision.endpoint_modelModel name of the phone`string()integer()`false
provision.feature_keys./^[0-9]+$/Device provisioner Combo/Feature Key#/definitions/devices.combo_keyfalse
provision.feature_keysobject()false
provision.idProvisioner Template IDstring()false
provisionProvision dataobject()false
register_overwrite_notifyWhen true enables overwrite notificationsboolean()falsefalse
ringtones.externalThe alert info SIP header added when the call is from internal sourcesstring(0..256)false
ringtones.internalThe alert info SIP header added when the call is from external sourcesstring(0..256)false
ringtonesRingtone Parametersobject(){}false
sip.custom_sip_headers.inCustom SIP Headers to be applied to calls inbound to Kazoo from the endpoint#/definitions/custom_sip_headersfalse
sip.custom_sip_headers.outCustom SIP Headers to be applied to calls outbound from Kazoo to the endpoint#/definitions/custom_sip_headersfalse
sip.custom_sip_headers.^[a-zA-z0-9_\-]+$The SIP header to add`string()boolean()integer()`
sip.custom_sip_headersA property list of SIP headersobject()false
sip.custom_sip_interfaceIf the bridge string should target a different SIP interfacestring()false
sip.expire_secondsThe time, in seconds, sent to the provisioner for the registration period that the device should be configured with.integer()300falsesupported
sip.forwardForward IP to usestring()false
sip.ignore_completed_elsewhereWhen set to false the phone should not consider ring group calls answered elsewhere as missedboolean()false
sip.invite_formatThe SIP request URI invite format`string(‘username’‘npan’‘1npan’‘e164’
sip.ipIP address for this devicestring()falsesupported
sip.methodMethod of authentication`string(‘password’‘ip’‘authorization’)`password
sip.numberThe number used if the invite format is 1npan, npan, or e164 (if not set the dialed number is used)string()false
sip.passwordSIP authentication passwordstring(5..32)falsesupported
sip.proxyProxy IP address to usestring()false
sip.realmThe realm this device should use, overriding the account realm. Should rarely be necessary.string(4..253)false
sip.routeThe SIP URL used if the invite format is ‘route’string()falsesupported
sip.static_inviteSIP To userstring()false
sip.static_routeSends all inbound calls to this string (instead of dialed number or username)string()false
sip.transportSIP Transport to usestring()false
sip.usernameSIP authentication usernamestring(2..32)falsesupported
sipSIP Parametersobject(){}false
suppress_unregister_notificationsWhen true disables deregister notificationsboolean()falsefalse
timezoneDevice’s timezone#/definitions/timezonefalsesupported

addresses

Account, user or device addresses

KeyDescriptionTypeDefaultRequiredSupport Level
emergency.additional_informationAdditional location information. Example: Room 543string()false
emergency.callback_cid_number10-digit DID used as caller ID to PSAP, overrides CIDstring(10)false
emergency.countryThe country is identified by the two-letter ISO 3166 code. Example: USstring()true
emergency.countyCounty, parish, gun (JP), district (IN). Example: King’s Countystring()false
emergency.delivery_methodHow the emergency call is routed by the destination handler (not applicable to all providers)`string(‘direct’‘three_way’‘security_desk’)`
emergency.floorFloor. Example: 4integer()false
emergency.house_numberHouse number, numeric part only. Example: 123integer()true
emergency.house_number_suffixHouse number suffix. Example: A, 1/2string()false
emergency.latitudeThe geo-position of a location, north or south of the equator, using WGS84 formattingstring(0..11)false
emergency.localityCity, township, shi (JP). Example: New Yorkstring()true
emergency.location_identifierUnited States unique 10-digit number known as an E911 location identifier (ELIN)integer()false
emergency.longitudeThe geo-position of a location, east or west of the prime meridian, using WGS84 formattingstring(0..11)false
emergency.nameName (residence, business or office occupant). Example: Joe’s Barbershopstring()true
emergency.postal_codePostal code. Example: 10027-0401string()true
emergency.regionNational subdivisions (state, region, province, prefecture). Example: New Yorkstring()true
emergency.streetPrimary road or street. Example: Broadwaystring()true
emergency.street_directionLeading street direction. Example: N, Wstring()false
emergency.street_suffixTrailing street suffix. Example: SWstring()false
emergency.street_typeStreet type. Example: Avenue, Platz, Streetstring()false
emergencyEmergency addressobject()false

call_failover

The device call failover parameters, to replace the device with an extension/phone number when device is offline.

KeyDescriptionTypeDefaultRequiredSupport Level
direct_calls_onlyDetermines if the calls that are not directly sent to the device should be forwardedboolean()falsefalsesupported
enabledDetermines if the call failover should be used when device is offlineboolean()falsefalse
ignore_early_mediaThe option to determine if early media from the call forwarded number should ignoredboolean()truefalse
keep_caller_idDetermines if the caller id is kept when the call is forwarded, if not the devices caller id is usedboolean()truefalsesupported
numberThe number to forward calls tostring(0..35)falsesupported
require_keypressDetermines if the callee is prompted to press 1 to accept the callboolean()truefalse

call_forward

Call Forward

KeyDescriptionTypeDefaultRequiredSupport Level
busyCall Forward Propertiesobject()false
direct_calls_onlyboolean()falsefalse
enabledboolean()falsetrue
ignore_early_mediaboolean()truefalse
keep_caller_idboolean()truefalse
no_answerCall Forward Propertiesobject()false
numberstring(0..35)false
require_keypressboolean()truefalse
selective.direct_calls_onlyboolean()falsefalse
selective.enabledboolean()falsefalse
selective.ignore_early_mediaboolean()truefalse
selective.keep_caller_idboolean()truefalse
selective.numberstring(0..35)false
selective.require_keypressboolean()truefalse
selective.rules.[].direct_calls_onlyboolean()falsefalse
selective.rules.[].enabledboolean()falsefalse
selective.rules.[].ignore_early_mediaboolean()truefalse
selective.rules.[].keep_caller_idboolean()truefalse
selective.rules.[].match_list_idstring()false
selective.rules.[].numberstring(0..35)false
selective.rules.[].require_keypressboolean()truefalse
selective.rulesMatch list rules to check for call forwardingarray(object())false
selectiveConditionally check match lists to determine if call forwarding should be usedobject()false
substituteDetermines if the call forwarding replaces the deviceboolean()truefalse
unconditionalCall Forward Propertiesobject()false

call_forward_type

Call Forward Properties

KeyDescriptionTypeDefaultRequiredSupport Level
direct_calls_onlyboolean()falsefalse
enabledboolean()falsetrue
ignore_early_mediaboolean()truefalse
keep_caller_idboolean()truefalse
numberstring(0..35)false
require_keypressboolean()truefalse

call_limits

Schema for call limits

KeyDescriptionTypeDefaultRequiredSupport Level
max_concurrentMaximum number of concurrent calls allowed per endpointinteger()false

call_recording

endpoint recording settings

KeyDescriptionTypeDefaultRequiredSupport Level
anysettings for any calls to/from the endpoint#/definitions/call_recording.sourcefalse
inboundsettings for inbound calls to the endpoint#/definitions/call_recording.sourcefalse
outboundsettings for outbound calls from the endpoint#/definitions/call_recording.sourcefalse

call_recording.parameters

KeyDescriptionTypeDefaultRequiredSupport Level
enabledis recording enabledboolean()false
formatWhat format to store the recording on disk`string(‘mp3’‘wav’)`false
record_min_secThe minimum length, in seconds, the recording must be to be considered successful. Otherwise it is deletedinteger()false
record_on_answerRecording should start on answerboolean()false
record_on_bridgeRecording should start on bridgeboolean()false
record_sample_rateWhat sampling rate to use on the recordinginteger()false
should_announce_when_recordingWhether or not a prompt should be played (after bridge) when the call is being recordedboolean()false
should_record_feature_callsToggles whether to start a recording for calls to feature codesboolean()truefalse
time_limitTime limit, in seconds, for the recordinginteger(5..10800)false
urlThe URL to use when sending the recording for storagestring(6..)false

call_recording.source

KeyDescriptionTypeDefaultRequiredSupport Level
anysettings for calls from any network#/definitions/call_recording.parametersfalse
offnetsettings for calls from offnet networks#/definitions/call_recording.parametersfalse
onnetsettings for calls from onnet networks#/definitions/call_recording.parametersfalse

call_waiting

Parameters for server-side call waiting

KeyDescriptionTypeDefaultRequiredSupport Level
enabledDetermines if server side call waiting is enabled/disabledboolean()false

caller_id

Defines caller ID settings based on the type of call being made

KeyDescriptionTypeDefaultRequiredSupport Level
asserted.nameThe asserted identity name for the object typestring(0..35)false
asserted.numberThe asserted identity number for the object typestring(0..35)false
asserted.realmThe asserted identity realm for the object typestring()false
assertedUsed to convey the proven identity of the originator of a request within a trusted network.object()false
emergency.nameThe caller id name for the object typestring(0..35)false
emergency.numberThe caller id number for the object typestring(0..35)false
emergencyThe caller ID used when a resource is flagged as ‘emergency’object()false
external.nameThe caller id name for the object typestring(0..35)false
external.numberThe caller id number for the object typestring(0..35)false
externalThe default caller ID used when dialing external numbersobject()false
internal.nameThe caller id name for the object typestring(0..35)false
internal.numberThe caller id number for the object typestring(0..35)false
internalThe default caller ID used when dialing internal extensionsobject()false

caller_id_options

Caller ID options for endpoints

KeyDescriptionTypeDefaultRequiredSupport Level
format./.+/.prefixPrefix to add to captured group of regexstring()false
format./.+/.regexRegexp to match normalized CID and use first capture groupstring()false
format./.+/.suffixPrefix to add to captured group of regexstring()false
format./.+/Format to use for the CID classificationobject()false
format.all.prefixPrefix to add to captured group of regexstring()false
format.all.regexRegexp to match normalized CID and use first capture groupstring()false
format.all.suffixPrefix to add to captured group of regexstring()false
format.allFormat to use for all CID formatting needs (vs per-classifier)object()false
formatObject for CID formatters based on number classifiersobject()false
ignore_completed_elsewhereSuppress the completed elsewhere causeboolean()false
outbound_privacyDetermines what appears as caller id for offnet outbound calls. Values: full - hides name and number; name - hides only name; number - hides only number; none - hides nothing`string(‘full’‘name’‘number’‘none’)`
privacy_methodMethod to use for anonymizing CID`string(‘sip’‘none’‘kazoo’)`
show_rateWhether to show the rateboolean()false
typeCaller ID on endpoint to choose`string(‘internal’‘external’‘emergency’)`

codecs.audio

A list of audio codecs the endpoint supports

KeyDescriptionTypeDefaultRequiredSupport Level

codecs.video

A list of video codecs the endpoint supports

KeyDescriptionTypeDefaultRequiredSupport Level

custom_sip_headers

Custom SIP headers applied to an INVITE

KeyDescriptionTypeDefaultRequiredSupport Level
^[a-zA-z0-9_\-]+$The SIP header to add`string()boolean()integer()`

devices.combo_key

Device provisioner Combo/Feature Key

KeyDescriptionTypeDefaultRequiredSupport Level

dialplans

Permit local dialing by converting the dialed number to a routable form

KeyDescriptionTypeDefaultRequiredSupport Level
system.[]string()false
systemList of system dial plansarray(string())false

endpoint.media

Schema for endpoint media options

KeyDescriptionTypeDefaultRequiredSupport Level
audio.codecsA list of audio codecs the endpoint supports#/definitions/codecs.audiofalse
audioThe audio media parametersobject(){}false
bypass_mediaDefault bypass media mode (The string type is deprecated, please use this as a boolean)`boolean()string(‘auto’‘false’‘true’)`
encryption.enforce_securityIs Encryption Enabled?boolean()falsefalse
encryption.methods.[]`string(‘zrtp’‘srtp’)`false
encryption.methodsSupported Encryption Types`array(string(‘zrtp’‘srtp’))`[]false
encryptionEncryption Parametersobject(){}false
fax_optionIs T.38 Supported?boolean()false
ignore_early_mediaThe option to determine if early media from the endpoint should always be ignoredboolean()false
progress_timeoutThe progress timeout to apply to the endpoint (seconds)integer()false
video.codecsA list of video codecs the endpoint supports#/definitions/codecs.videofalse
videoThe video media parametersobject(){}false
webrtcIf true, forces a WebRTC compatible SDP on the INVITEboolean()false

formatters

Schema for request formatters

KeyDescriptionTypeDefaultRequiredSupport Level
^[[:alnum:]_]+$Key to match in the route request JSON`array(#/definitions/formatters.format_options)#/definitions/formatters.format_options`false

formatters.format_options

Schema for formatter options

KeyDescriptionTypeDefaultRequiredSupport Level
directionOnly apply the formatter on the relevant request direction`string(‘inbound’‘outbound’‘both’)`
match_invite_formatApplicable on fields with SIP URIs. Will format the username portion to match the invite format of the outbound request.boolean()false
prefixPrepends value against the result of a successful regex matchstring()false
regexMatches against the value, with optional capture groupstring()false
stripIf set to true, the field will be stripped from the payloadboolean()false
suffixAppends value against the result of a successful regex matchstring()false
valueReplaces the current value with the static value definedstring()false

metaflow

A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to

KeyDescriptionTypeDefaultRequiredSupport Level
children./.+/A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to#/definitions/metaflowfalse
childrenChildren metaflowsobject()false
dataThe data/arguments of the metaflow moduleobject(){}false
moduleThe name of the metaflow module to execute at this nodestring(1..64)true

metaflows

Actions applied to a call outside of the normal callflow, initiated by the caller(s)

KeyDescriptionTypeDefaultRequiredSupport Level
binding_digitWhat DTMF will trigger the collection and analysis of the subsequent DTMF sequence`string(‘1’‘2’‘3’‘4’
digit_timeoutHow long to wait between DTMF presses before processing the collected sequence (milliseconds)integer(0..)false
listen_onWhich leg(s) of the call to listen for DTMF`string(‘both’‘self’‘peer’)`
numbers./^[0-9]+$/A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to#/definitions/metaflowfalse
numbersA list of static numbers with their flowsobject()false
patterns./.+/A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to#/definitions/metaflowfalse
patternsA list of patterns with their flowsobject()false

presence_aliases

Endpoint Presence Aliases

KeyDescriptionTypeDefaultRequiredSupport Level

timezone

The default timezone

KeyDescriptionTypeDefaultRequiredSupport Level

Call forwarding

Legacy format

Currently the call_forward object allows you to define call forwarding or failover but not both. If call_forward.enabled is true it will take precedence and settings will be used only for call forwarding. If call_forward.enabled is false and call_forward.failover is true, failover settings will be used.

5.2 and beyond

In 5.2, call forwarding is being retooled to allow more dynamic decision-making for when to use the forwarding settings, one example being only allow a list of caller IDs to be sent through to the call-forwarding settings if the device fails to be rung.

As such, the call_forward object (if it exists) will be transformed into a set of sub-objects representing the new call forwarding options.

KAZOO will automatically “fix” the legacy format to the new format when processing calls; saving of the device doc with “call_forward” in legacy mode will result in schema errors.

Mapping legacy settings to the new format

It is a straight-forward process to move to the new format.

For system admins, sup crossbar_maintenance migrate_call_forward {ACCOUNT_ID} will migrate individual accounts. Normal sup kapps_maintenance migrate will also walk the account databases and migrate necessary docs.

For API clients, move the legacy call forwarding settings under the unconditional key:

Legacy JSON:

{
  "call_forward": {
    "enabled": "{ENABLED}",
    "number": "{CFWD_DID}"
  }
}

Converts to:

{
  "call_forward": {
    "unconditional": {
      "enabled": "{ENABLED}",
      "number": "{CFWD_DID}"
    }
  }
}

Example call_forward settings

As noted above, to always forward the device/user to a PSTN number:

{
  "call_forward": {
    "unconditional": {
      "enabled": true,
      "number": "{PSTN_NUMBER}"
    }
  }
}

For forwarding only when the device/user doesn’t answer, replace unconditional with no_answer. For when a device/user is “busy”, use busy. The settings under those keys are identical.

Selective call forwarding

Selective call forwarding allows the device/user’s call forwarding settings to only apply in certain cases. For instance, you may want calls from your family to route to your cell phone instead of your SIP devices.

To do so, the selective settings for call forwarding include a list of rules that map to matchlists where you can configure the logic around when to call forward.

For example, a simple match list based on the caller ID number could be created thusly:

curl -X PUT \
    -X "X-Auth-Token: {AUTH_TOKEN}" \
    -d '{"data":{"name":"My Call Forwarding Rules","rules":[{"name":"Match CID","regex":"41588679\\d{2}","target":"caller_id_number","type":"regex"}]}} \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/match_lists

The match list JSON:

{
  "name": "My Call Forwarding Rules",
  "rules": [
    {
      "name": "Match CID",
      "regex": "41588679\\d{2}",
      "target": "caller_id_number",
      "type": "regex"
    }
  ]
}

Capture the match list ID from the response, then create the call_forward settings:

{
  "call_forward": {
    "enabled": true,
    "selective": {
      "enabled": true,
      "number": "+14158867900",
      "rules": [
        {
          "enabled": true,
          "match_list_id": "{MATCH_LIST_ID}"
        }
      ]
    }
  }
}

PUT/POST/PATCH that to the device/user and only calls with caller ID matching 41588679 plus any two digits will be forwarded to the number configured.

Fetch the device summary

Lists all devices in an 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": [
        {
            "id": "4ee2d01d474a92ca299bb311efd23cef",
            "name": "Device1 Admin",
            "enabled": true,
            "flags": [],
            "features": [],
            "owner_id": "96f99542f33c180790d1836192300c27",
            "device_type": "sip_device",
            "mac_address": "001122334455",
            "username": "user_meme"
        }
    ],
    "page_size": 1,
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

New in Kazoo 5: List devices with their statuses

Using Kazoo 5+, If query string ?with_status=true is set result will also includes the device registration statuses (see Fetch registration statuses of all devices):

curl -v -X GET \
    -X "X-Auth-Token: {AUTH_TOKEN} \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices?with_status=true
{
    "auth_token": "{AUTH_TOKEN}",
    "data": [
        {
            "id": "4ee2d01d474a92ca299bb311efd23cef",
            "name": "Device1 Admin",
            "enabled": true,
            "flags": [],
            "features": [],
            "owner_id": "96f99542f33c180790d1836192300c27",
            "device_type": "sip_device",
            "mac_address": "001122334455",
            "username": "user_meme",
            "registrable": true,
            "registered": true
        }
    ],
    "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_unsolicited_updates": true,
        "name": "New Device",
        "register_overwrite_notify": false,
        "ringtones": {},
        "sip": {
            "invite_format": "username",
            "method": "password",
            "registration_expiration": 300
        },
        "suppress_unregister_notifications": false
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Remove a device

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

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_unsolicited_updates": true,
        "name": "New Device",
        "register_overwrite_notify": false,
        "ringtones": {},
        "sip": {
            "invite_format": "username",
            "method": "password",
            "registration_expiration": 300
        },
        "suppress_unregister_notifications": false
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Fetch a device

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

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_unsolicited_updates": true,
        "name": "New Device",
        "register_overwrite_notify": false,
        "ringtones": {},
        "sip": {
            "invite_format": "username",
            "method": "password",
            "registration_expiration": 300
        },
        "suppress_unregister_notifications": false
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Change a device doc

Including "sync":true in the “data” will attempt to reboot the phone. See the sync section below.

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

curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -H "Content-Type: application/json" \
    -d '{"data":{
        "name": "new device",
        "call_restriction": {},
        "caller_id": {},
        "contact_list": {},
        "dial_plan": {},
        "enabled": true,
        "exclude_from_queues": false,
        "media": {
            "audio": {"codecs": ["PCMU"]},
            "encryption": {"enforce_security": false, "methods": []},
            "video": {"codecs": []}
        },
        "music_on_hold": {},
        "mwi_unsolicited_updates": true,
        "register_overwrite_notify": false,
        "ringtones": {},
        "sip": {
            "invite_format": "username",
            "method": "password",
            "registration_expiration": 300
        },
        "suppress_unregister_notifications": false,
        "id": "4f3330e78e664bb57f8fb23fbaac2429"
        }}' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}
{
    "auth_token": "{AUTH_TOKEN}",
    "data": {
        "call_restriction": {},
        "caller_id": {},
        "contact_list": {},
        "dial_plan": {},
        "enabled": true,
        "exclude_from_queues": false,
        "id": "{DEVICE_ID}",
        "media": {
            "audio": {
                "codecs": [
                    "PCMU"
                ]
            },
            "encryption": {
                "enforce_security": false,
                "methods": []
            },
            "video": {
                "codecs": []
            }
        },
        "music_on_hold": {},
        "mwi_unsolicited_updates": true,
        "name": "new device",
        "register_overwrite_notify": false,
        "ringtones": {},
        "sip": {
            "invite_format": "username",
            "method": "password",
            "registration_expiration": 300
        },
        "suppress_unregister_notifications": false
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Patch a device

PATCH /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}

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_unsolicited_updates": true,
        "name": "new device",
        "presence_id":"dis_my_device",
        "register_overwrite_notify": false,
        "ringtones": {},
        "sip": {
            "invite_format": "username",
            "method": "password",
            "registration_expiration": 300
        },
        "suppress_unregister_notifications": false
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Send a SIP NOTIFY to a device

Kazoo will generate the NOTIFY packet if the device is registered.

PUT body options:

KeyDescriptionTypeDefaultRequiredSupport Level
data.body.content_typeThe Content-Type of the data in the NOTIFY content bodystring()true
data.body.dataThe NOTIFY content bodystring()true
data.bodyParameters of content body of SIP NOTIFYobject()false
data.eventEvent header value for SIP NOTIFYstring()true
dataAction-specific parametersobject()true

PUT /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}

curl -v -X POST \
    -H "X-Auth-Token: {AUTH_TOKEN}" \
    -H "Content-Type: application/json" \
    -d '{"action": "notify",
         "data":{
           "data": {
             "event": "event"
             ,"body":{
               "content_type":"application/xml"
               ,"data":"NOTIFY body content"
             }
           }
         }
        }' \
    http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}

An example for a Yealink might look like (thanks to forum user https://forums.2600hz.com/forums/topic/12045-sip-notify/#comment-62381 for the suggestion):

{
    "action": "notify"
    ,"data": {
        "data": {
            "event": "Yealink-xml",
            "body": {
                "data": "<YealinkIPPhoneTextScreen destroyOnExit=\"true\" Beep=\"true\" Timeout=\"0\" LockIn=\"false\"><Title wrap=\"true\">Title</Title><Text>Hello!</Text></YealinkIPPhoneTextScreen>",
                "content_type": "application/xml"
            }
        }
    }
}

Fetch registration statuses of all devices

This will fetch the current registrations of any devices.

New in Kazoo 5:

This will list all devices including non-registered devices. Some device types will never be expected to be registered. This list of device types are stored in System Config always_registered_device_types in crossbar.devices.

New field registrable is added to show if the device is registrable or not.

You can also use /v2/accounts/{ACCOUNT_ID}/devices?with_status=true if you need more info about the devices.

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_1}",
            "registrable": true,
            "registered": true
        },
        {
            "device_id": "{DEVICE_ID_2}",
            "registrable": false
        }
    ],
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}

Push payload to device

See pushes.md for information about this action.

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. Kazoo 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"
}

Reboot or not after syncing

If your device can support it, you can toggle whether to reboot the phone after it resyncs its configuration.

On the device document, set provision.check_sync_reboot to the suffix to add to the check-sync event when syncing the phone and rebooting.

On the device document, set provision.check_sync_reload to the suffix to add to the check-sync event when syncing the phone when not rebooting.

And of course you can override the check-sync prefix with provision.check_sync_event.

Rebooting example

The device settings:

{"provision":{
   "check_sync_reboot":"reboot=true"
 }
}

API to force the reboot: POST /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync?reboot=true

Will generate Event: check-sync;reboot=true in the SIP NOTIFY.

Reloading example

The device settings:

{"provision":{
   "check_sync_reload":"reboot=false"
 }
}

API to force the reboot: POST /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync?reboot=false

Will generate Event: check-sync;reboot=false in the SIP NOTIFY.

Check Sync Event

Should the device respond to a different value for the purposes of syncing, it can be overridden in the provision.check_sync_event.

There is also a system_config in crossbar.devices, check_sync_event, that can be set for defaults.

Quickcalls

See the quickcall docs for how to perform this action.

Adding Ringtones

You can setup internal and external ringtones by adding this:

{
    "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_unsolicited_updates": true,
        "name": "authn_by_ip",
        "register_overwrite_notify": false,
        "ringtones": {},
        "sip": {
            "invite_format": "e164",
            "ip": "{IP_ADDRESS}",
            "method": "ip",
            "registration_expiration": 300
        },
        "suppress_unregister_notifications": false
    },
    "request_id": "{REQUEST_ID}",
    "revision": "{REVISION}",
    "status": "success"
}