Call Routing via APIs

Introduction

Suppose you have a Sales representative that's been engaged in conversations with a prospect for the past month for a giant deal. Wouldn't it be great if when the prospect calls back on the company mainline, the call goes directly to the representative instead of sending them through an IVR? Along with showing the prospect that they're being given extra attention, it would also help the sales continue conversations with ease.

Dialpad's Routing APIs allow you to do just that! With these APIs, you can have total control over where each inbound call is routed, whether it's though our standard routing mechanisms in a Department or Call Centre, or whether it's sent through directly to a User. This document describes the basics of call routers, the steps needed to setup these call routers and the expected responses.

How Call Routing Works

The above diagram illustrates the working of a call router. Once a router is setup, call information is published to a specified URL. The third party then uses that data to generate routing information for that call. The call is then routed to the appropriate user or department or call centre. In the above example, the call was routed to a user. However, the system is flexible to route calls to a department or call centre depending on the call.

Creating the Call Router

To create a call router, invoke the POST callrouters method.

FieldTypeRequired?Description
namestringtrueSpecify a name for the call router
routing_urlstring (URL)trueThe URL that should be consulted to route calls
secretstringfalseA JWT secret to be used
office_idstringtrueThe office to which the call router belongs
default_target_idstringtrueThe fallback target to be used in case of client server unavailability
default_target_typestringtrueThe type associated with the default_target_id (i.e. office, department, callcenter, or user)
enabledbooleanfalseSet to true as default. If set as false, the call router will act as pass through to the office mainline

Note: For Geo Routers please refer to this Help Center article. Geo Routers are not accessible via API.

e.g.

import requests

url = "https://dialpad.com/api/v2/callrouters"

payload = '''{
  "default_target_id": "123456",
  "default_target_type": "callcenter",
  "name": "Hello Router",
  "office_id": "223456",
  "routing_url": "https://yourroutingservice.com/routecall",
}'''

headers = {
  'accept': "application/json",
  'content-type': "application/json"
}

response = requests.request("POST", url, data=payload, headers=headers)

Upon successful creation of the call router, the following response is sent

{
  “id”: “generated id”,
  “name”: “name”,
  “routing_url”: “routing_url”,
  “office_id”: “office_id”,
  “default_target_id”: “12341234”,
  “default_target_type”: “callcenter”,
  “enabled”: true,
  “phone_numbers”: [“e164 number”, ...],
  “signature”: {
    “type”: “jwt”,
    “algo”: “HS256”,
    “secret”: “secret”
  }
}

To set a phone number for the call router, invoke the POST callrouters/id/assign_number method. This number should be provided to your customers. Please ensure the office has available Additional Number licenses for phone numbers to be assigned.
e.g.

import requests

url = "https://dialpad.com/api/v2/callrouters/323456/assign_number"

headers = {
  'accept': "application/json",
  'content-type': "application/json"
}

response = requests.request("POST", url, headers=headers)

Providing Routing Information to the Call Router

Once a call comes into the number assigned to the call router, a JWT will be POST-ed to the routing_url . The JSON content of the JWT will be of the form:

{
  “date_started”: <ms_since_epoch>,
  “call_id”: <call_id>,
  “external_number”: “<e164 number>”,
  “internal_number”: “<e164 number>”,
  “contact_id”: <contact_id>,
  “contact_type”: <contact_type>,
}

The external_number will contain the number of the caller.

Allowed Actions

Based on the information provided to the URL, you can instruct the call router to take one of four actions. By default the action is assumed to be the route action, so to trigger a different action you must specify the desired action in the action field of the response payload.

FieldTypeRequired?
actionOne of: "route", "forward", "ask", "end"false

Route Action

The route action will route the call to the specified target. Use the route to transfer the call to a Dialpad target.

FieldTypeRequired?Description
target_idintegertrueThe ID of the Dialpad target that should receive the call
target_typestringtrueThe type associated with the target_id (i.e. office, department, callcenter, or user)

Forward Action

The forward action connects the call to a number that is not in Dialpad.

FieldTypeRequired?Description
forward_tostringtrueThe number to forward to in E.164 format as a string ie. "+14155552671"

Ask Action

In some scenarios, the ideal routing behaviour may be more complex than just dynamically forwarding a call. It may be desirable to ask the caller to choose between several options and make additional routing decision based on their response. It may also be desirable to play an audio clip to the caller and end the call (e.g. "Our office is currently closed. Please call back between 9 to 5 on a weekday"). This can be achieved using the ask action.

An ask action will ask the caller a specified question via a synthesized text-to-speech audio clip. The caller will be allowed to enter a response via their number pad. After an ask action is completed, your routing endpoint will receive an additional request to allow it to take an additional action based on the caller's response. That information will be included in the post-ask routing request in the form of a string containing the keys that the caller pressed. The hint_name you provide will be the field in which the caller's response will appear in the post-ask routing request.

FieldTypeRequired?Description
messagestring or arraytrueThe message that should be played to the caller via text-to-speech
*see additional considerations section
hint_namestringtrueThe field name in which to insert the caller's response in the subsequent routing request (more details below)
finish_on_keystringfalseThe key the caller should press to signal that they are finished inputting digits (by default, the input will conclude when the caller has pressed the number of digits specified in num_digits)
num_digitsintegerfalseThe number of digits that the caller should enter
Allowed values: any positive integer (defaults to 99)
valid_digitsstringfalseA string containing all keypad values that the caller can include in their response (defaults to "0123456789*#")
(the default is the full set of possible digits)
retriesintegerfalseThe number of times the audio prompt should be repeated to the caller if they don't press any buttons on their keypad
Allowed values: any positive integer (defaults to 10)
timeoutintegerfalseThe number of seconds to wait for the caller to press a button before repeating the prompt
Allowed values: any positive integer (defaults to 5)
timeout_actionstringfalseThe action to be taken if the caller does not provide any input after the max number of retries set. Set to disconnect by default.
* see additional options
localestringfalseThe locale code to specify the region specific voice used for the text-to-speech audio (defaults to US English)
* see additional notes for currently supported locales

Using ask actions increases the potential complexity of your routing logic, especially if the routing flow contains multiple ask actions. A new request will be hitting the same routing endpoint for every step of the routing flow, which can be logistically challenging. Making good use of the hint_name field can significantly simplify the logistical challenge. If you use a distinct hint_name for each ask action in your routing flow, then you will be able to distinguish between the post-ask requests without needing any information other than the request itself. Choosing human-readable names can also improve debugging by making it easier to read and comprehend a series of routing requests.

For very complex flows, it may even be helpful to break up the routing process into several parts, and handle each part with a different router. For example, one call router could serve as a single entry point for all the calls within a country, and could redirect the calls to region-specific call routers based on the area code of the caller. Since each router can specify its own routing URL, this strategy can be used to turn a single hard-to-understand routing endpoint into several easier-to-understand routing endpoints.

The caller's response to ask actions will only be included in the routing request immediately after that action, rather than being carrying forward into every subsequent routing request for that call. By default, if the message repeats retries times without any response from the caller, the call will simply end, and there will be no subsequent routing request. You can alter this behaviour using the timeout_action field.

Timeout action options

The timeout_action field is an optional field that allows you to customize the call router's behaviour following the timeout event of the final retry. For example, if retries is set to 2 and timeout is set to 5, the timeout action will be executed 5 seconds after the second prompt if the caller fails to respond.

Timeout optionDescription
"disconnect"Ends the call. (Default)
"default_target"Transfers the call to the call router's default target as set by default_target_id at call router creation. The target can be changed with Call Router -- Update.
"custom"Fetches new instructions from the routing_url.

The custom option provides the most flexibility in terms of routing. The call router sends another payload to the specified routing url for ad hoc processing to calculate the best route for this call. In addition to the initial call information, this payload will include the hint name set by the previous ask action with an empty value and 2 custom headers: DP-CALL-ROUTER-ASK-REATTEMPT-COUNT and DP-CALL-ROUTER-ASK-REATTEMPT-LIMIT.

HeaderDescription
DP-CALL-ROUTER-ASK-REATTEMPT-COUNTIndicates the number of times the caller has been prompted with an ask.
DP-CALL-ROUTER-ASK-REATTEMPT-LIMITThe number of times you may reattempt to retrieve a response with an ask for the same hint_name. Limit is 3.
{
  "date_started": <ms_since_epoch>,
  "call_id": <call_id>,
  "external_number": "<e164 number>",
  "internal_number": "<e164 number>",
  "contact_id": <contact_id>,
  "contact_type": <contact_type>,
  "<hint_name>": ""
}

You may return ask instructions with the same hint_name and custom timeout action a max number of 3 times. Each time the set of instructions fails to receive a valid user response, DP-CALL-ROUTER-ASK-REATTEMPT-COUNT will increment. When DP-CALL-ROUTER-ASK-REATTEMPT-COUNT has incremented to 3, timeout_action will default to disconnect regardless of the option provided.

The following diagram illustrates an example where timeout_action is leveraged to send a different message for the same information. When the caller fails to respond in the allotted time for a second time, the call is routed to the call router's default target to speak with a representative.

Timeout Action Example

End Action

An end action will play a synthesized text-to-speech audio clip and then hang up the call.

FieldTypeRequired?Description
messagestring or arraytrueThe message that should be played to the caller via text-to-speech
*see additional considerations section
localestringfalseThe locale code to specify the region specific voice used for the text-to-speech audio (defaults to US English)
* see additional notes for currently supported locales

Deleting Call Routers

Call routers can be deleted by calling the DELETE callrouters/id method. Note that deletion takes effect immediately and would place the number assigned to the call router in reserve.

Error Handling

If the endpoint takes more than 5 seconds to respond or if there are more than 10 failures in an hour, then the call router will be automatically disabled, and an email will be sent to the office admin. In order to rejuvenate the call router, it must be re-enabled via the PATCH callrouters/id method. In this situation, the first step will be to investigate and correct the underlying issue in your routing endpoint.

Uniform Errors

In many cases the issue will have a consistent source, and the error may be completely resolved once the issue is addressed. In this situation, the call router can simply be re-enabled the call router by setting the enabled property to true via the PATCH endpoint.

Inconsistent Errors

In some situations (such as performance issues that occasionally result in request latency greater than 5-seconds), your routing endpoint may still have occasional routing errors after applying a fix. In this situation, it may be desirable to re-enable the router in addition to resetting the internal error count. To accomplish this, you can make a PATCH request that includes "reset_error_count": true, "enabled": true.

Additional Notes

Text-to-speech

For best results with text-to-speech fields (i.e. the message field), the value should either be a single short string, or an array of short strings. When the Dialpad backend receives an end or ask action, it needs to take the message, synthesize it into an audio file, and then play that audio file to the caller. Text-to-speech is a computationally expensive operation, and in this context it needs to happen as quickly as possible. By allowing the input to be a list of strings, we can process each string into an audio file independently. This means that playback can begin as soon as the first string has been processed, rather than blocking on processing the whole message.

There is also a caching mechanism that helps reduce the playback latency. If Dialpad has seen a particular string before, then it likely already has an audio file in the cache that it can retrieve immediately.

To leverage these mechanisms most effectively:

  • The message should be split into small pieces whenever possible
  • The first string in a list of messages is the most important, since playback cannot begin until that string is processed.
  • If the first string is always the same, Dialpad can make use of the audio file cache, so any dynamic strings should ideally come after an initial static string, where the processing time is much less likely to matter.

Supported locales

Dialpad currently supports the following language specific voices to synthesize text-to-speech. If an invalid string is passed to the locale field with the ask or end action, the message will be synthesized using English (US). We will be expanding our language support in the future with customer demand.

🚧

Locale is not translation

Specifying the locale ensures that the text-to-speech message is generated with the preferred regional accent. It will not translate the message into the indicated language. Please pass in the translated phrase as message along with the locale code.

Locale codeLanguage
deGerman
enEnglish (US)
en-auEnglish (Australia)
en-gbEnglish (British)
esSpanish (US)
frFrench
fr-caFrench (Canadian)
itItalian
jaJapanese
nlDutch
ptPortuguese (Brazilian)
ruRussian
zhChinese, Mandarin

Call routers can be assigned multiple numbers.

Using multiple numbers may be useful for assessing the efficacy of an ad campaign or providing separate numbers for support and sales. Your routing endpoint can use this information to make routing decisions, since the internal_number will indicate which number the caller dialled.

Call routers can be configured to send JWT payloads for additional security.

In order to verify that a routing request is genuine, you can set the secret property on the call router by using the POST or PATCH endpoints. If a call router is given a secret, then it will use that secret to send a signed JWT payload to your endpoint, rather than a raw JSON payload.