SIP IVR Routing
Interactive Voice Response (IVR) is an effective and efficient way to route inbound phone calls to LiveSwitch through the SIP Connector. As IVR constraints and characteristics vary, LiveSwitch supports the following routing options:
Routing Models
Number Routing
Number routing forwards calls from your IVR to phone numbers from a SIP trunk that are mapped to an Application ID or a Channel ID in your SIP Connector configuration. Number routing is useful for environments where direct call-in is configured and you want to migrate to an IVR call-in model.
The IVR must support connecting calls to external phone numbers:
<Connect number="18883796686" />
This is the typical call flow:
- IVR answers the call and then prompts for user input.
- IVR connects the call to one of the SIP trunk phone numbers based on user input.
- SIP trunk routes call to your SIP Connector.
- SIP Connector routes call to the Application ID or Channel ID mapped to the phone number.
Note
This routing model typically results in double-billing: the IVR in/out rate and the SIP trunk in/out rate.
Extension Routing
Extension routing skips the SIP trunk and routes the call directly from the IVR to extensions mapped to an Application ID or a Channel ID in your SIP Connector configuration. Extension routing has two key advantages over number routing:
- You don't have to purchase phone numbers from a SIP trunk.
- You only pay the IVR in/out rate. You aren't double-billed.
You must expose the SIP Connector through the firewall for unsolicited inbound SIP messages.
Note
Always configure your firewall rules to restrict inbound traffic to your SIP server port (typically 5060) and the known IP ranges of your IVR provider.
The IVR must support connecting calls to external SIP endpoints.
Pseudo-code IVR control block:
<Connect sip="sip:my-extension@my-sip-connector.xyz" />
This is the typical call flow:
- IVR answers the call and then prompts for user input.
- IVR connects the call to one of your SIP Connector extensions based on user input.
- SIP Connector routes call to the Application ID or Channel ID mapped to the extension.
Header Routing
Header routing allows the IVR to manage all the routing details instead of relying on mappings in your SIP Connector configuration. The consolidation of routing details into one place makes it easier to maintain and implement change control.
Like exension routing, the SIP Connector must be exposed through the firewall for unsolicited inbound SIP messages.
Note
Always configure your firewall rules to restrict inbound traffic to your SIP server port (typically 5060) and the known IP ranges of your IVR provider.
The IVR must support connecting calls to external SIP endpoints, but it must also support adding custom headers to the outbound INVITE message. The call is routed to the Application ID or Channel ID indicated in the lsa
and lsc
headers.
Pseudo-code IVR control block:
<Connect sip="sip:my-ivr@my-sip-connector.xyz">
<Headers>
<lsa>my-application-id</lsa>
<lsc>my-channel-id</lsc>
</Headers>
</Connect>
Note
The Application ID and Channel ID must be URI-encoded, like encodeURIComponent
.
This is the typical call flow:
- IVR answers the call and then prompts for user input.
- IVR connects the call to one of your SIP Connector extensions based on user input and then adds Application ID or Channel ID headers.
- SIP Connector routes call to the Application ID or Channel ID in the headers.
Advanced Options
Explicit User IDs
Some IVRs replace the caller number with the IVR number when connecting the inbound call to the SIP Connector. If this happens, your LiveSwitch application shows a user ID that reflects the IVR number instead of the caller number.
If you are using extension or header routing, you can resolve this problem by explicitly setting the user ID.
For Extension Routing
Append lsu=
and the caller number to the query part of the SIP URI to sign the request.
Pseudo-code IVR control block:
<Connect sip="sip:my-extension@my-sip-connector.xyz?lsu=16041235789" />
Note
The user ID must be URI-encoded, such as encodeURIComponent
.
For Header Routing
Add lsu
header with the caller number to set the user ID.
Pseudo-code IVR control block:
<Connect sip="sip:my-ivr@my-sip-connector.xyz">
<Headers>
<lsa>my-application-id</lsa>
<lsc>my-channel-id</lsc>
<lsu>16041235789</lsu>
</Headers>
</Connect>
Note
The user ID must be URI-encoded, such as encodeURIComponent
.
Request Signatures
Signing outbound requests is strongly recommended for the additional security it provides.
If you are using extension or header routing, signing means adding an expiry
and signature
using one of the following algorithms and encodings:
Algorithms
hm128
: HMAC-MD5 (128 bits)hs160
: HMAC-SHA-1 (160 bits)hs256
: HMAC-SHA256 (256 bits)
Encodings
b64
: Base64. Valid characters areA-Za-z0-9+/=
, for space-restricted use cases.hex
: Hexadecimal. Valid characters area-f0-9
, for charset-restricted use cases.
Note
For Base64, you may trim the padding (=
) off the end to save space.
The expiry
is a Unix timestamp measured in seconds since epoch. If the SIP Connector rejects inbound calls with an expiry in the past, ensure that your server synchronizes its system clock with a reliable timestamp server.
To generate a signature:
- Create a message to be signed by joining these values together in the following order using a newline (
\n
) separator:- Application ID
- Channel ID
- User ID
- Expiry
- Sign the message with an algorithm of your choice and the
Signature Secret
from your SIP Connector configuration. - Convert the binary signature into text using the encoding of your choice.
- Concatenate the encoding ID, algorithm ID, and encoded signature.
Psuedo-code signature snippet:
const CryptoJS = require("crypto-js");
var hmac = (algorithmId, input, secret) => {
switch (algorithmId) {
case 'hm128': return CryptoJS.HmacMD5(input, secret);
case 'hs160': return CryptoJS.HmacSHA1(input, secret);
case 'hs256': return CryptoJS.HmacSHA256(input, secret);
}
throw new Error('Unrecognized algorithm.');
};
var encode = (encodingId, input) => {
switch (encodingId) {
case 'b64': return CryptoJS.enc.Base64.stringify(input).replace(/=+$/,'');
case 'hex': return CryptoJS.enc.Hex.stringify(input);
}
throw new Error('Unrecognized encoding.');
};
var getSignature = (applicationId, channelId, userId, signatureSecret, algorithmId, encodingId) => {
var expiry = Math.floor(Date.now() / 1000) + 300; // 5-minute expiry
var input = [applicationId || '', channelId || '', userId || '', expiry].join('\n');
var output = encode(encodingId, hmac(algorithmId, input, signatureSecret));
return encodingId + algorithmId + output;
};
For Extension Routing
Append lse=
, the expiry, lss=
, and the signature to the query part of the SIP URI to sign the request.
Pseudo-code IVR control block:
<Connect sip="sip:my-extension@my-sip-connector.xyz?lse=1224486000&lss=b64hm128llIah1XxLtd9qeuEpWhApg" />
Note
The signature must be URI-encoded, such as encodeURIComponent
.
For Header Routing
Add lse
header with the expiry and lss
header with the signature to sign the request.
Pseudo-code IVR control block:
<Connect sip="sip:my-ivr@my-sip-connector.xyz">
<Headers>
<lsa>my-application-id</lsa>
<lsc>my-channel-id</lsc>
<lsu>16041235789</lsu>
<lse>1224486000</lse>
<lss>b64hm128llIah1XxLtd9qeuEpWhApg</lss>
</Headers>
</Connect>
Note
The signature must be URI-encoded, such as encodeURIComponent
.
Syntax Reference
For Extension Routing
The following parameter names are defined:
lsa=<application-id>
lsc=<channel-id>
lsu=<user-id>
lse=<expiry>
lss=<encoding-id><algorithm-id><signature>
You can add multiple fields to the query part of the SIP URI.
For Header Routing
The following header names may be used:
LSA: <application-id>
LSC: <channel-id>
LSU: <user-id>
LSE: <expiry>
LSS: <encoding-id><algorithm-id><signature>
The SIP Connector ignores prefixes and casing in header names to maximize interoperability with third-party IVRs that may append arbitrary prefixes or restrict the use of certain characters.
For example, the following header names are considered identical:
lsa
LSA
X-lsa
FM-LSA
FM-X-LSA
Definitions
application-id = encodeURIComponent(*CHAR)
channel-id = encodeURIComponent(*CHAR)
user-id = encodeURIComponent(*CHAR)
expiry = *DIGIT ; Unix timestamp (seconds since epoch)
encoding-id = "b64" / ; Base64
"hex" ; Hex
algorithm-id = "hm128" / ; HMAC-MD5
"hs160" / ; HMAC-SHA1
"hs256" ; HMAC-SHA256
signature = encoding-id + algorithm-id + encodeURIComponent(*CHAR)