Invoking VXML Connector from applications
Applications use the VXML <subdialog> to connect to Mix dialog models through VoiceXML Connector. You can make this call anywhere in a client application. To run a Mix dialog model with minimal code, write a stub application containing a <subdialog>.
Note: A client application is a complete application designed and implemented on your IVR platform. A stub is a minimal client application that invokes a Mix dialog model. The client application and stub are sometimes called VXML drivers because both are VoiceXML documents.
Example <subdialog> in a client application
This example specifies the VoiceXML Connector location, starts execution of a Mix dialog model, and passes variables known to the dialog:
<!-- The VoiceXML Connector URL must be accessible from the Voice Browser -->
<subdialog name="mixapp" src="https://connector-server:8080/vxml-connector/start" method="post" namelist="dialogModelRef mixClientId mixSecret language userChannelId platformSessionId reportingVariables systemId sessionId channel grammarBaseUrl backendBaseUrl modelBaseUrl audioBaseUrl">
This example passes to the Mix dialog model but does not show how your client application sets those variables. Nor does the example show how to handle the return. See the example stub application for elaboration.
The <subdialog> can use HTTP or HTTPS (recommended).
Example stub application
VoiceXML Connector provides a sample stub application in the StubApp folder of the download package.
This stub application uses scripts to get session data and perform telephony transfers from the IVR platform. You must substitute appropriate scripts for the the APIs and syntax of your specific platform.
Recommended. Declare the language of the dialog provided via the Dialog service. Doing this avoid problems when your local default (the client) is different than the dialog itself. (In the example below, replace en-US with the appropriate language code.)
Header
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml" xml:lang="en-US">
<catch event="error cancel exit telephone connection">
<goto next="#exitError"/>
</catch>
(The <vxml> element terminates at the bottom of the example.)
Defining variables
<var name="sessionId" expr="''"/> <!-- The sessionID is used in all exchanges with VoiceXML Connector -->
<var name="xferData" expr="''"/>
<var name="xferType" expr="''"/>
<var name="transferReturnCode" expr="'-1'"/>
<var name="sessionVariables" expr="''"/>
<var name="event" expr="''"/>
<form id="dialog">
<var name="dialogModelRef" expr="'urn:nuance-mix:tag:model/APP_NAME/mix.dialog'"/>
<!-- Could also be url in form http://artifact-server:8080/model-DIALOG.zip -->
<var name="mixClientId" expr="'appID:NMDPTRIAL_example'"/>
<var name="mixSecret" expr="'secretFromMixDashboard'"/>
<var name="library" expr="'default'"/>
<var name="language" expr="'en-US'"/>
<var name="version" expr="''"/>
<var name="userChannelId" expr="''"/> <!-- For storing the ANI -->
<var name="platformSessionId" expr="''"/>
<var name="systemId" expr="''"/> <!-- For storing the DNIS -->
<var name="channel" expr="'default'"/>
<var name="reportingVariables" expr="''"/>
<var name="sessionTimeout" expr="3600"/>
<var name="grammarBaseUrl" expr="'http://grammar-server:8080/app_name'"/> <!-- Speech Suite uses this -->
<var name="modelBaseUrl" expr="'http://model-server:8080/app_name'"/> <!-- Speech Suite uses this -->
<var name="backendBaseUrl" expr="'http://backend-server:8080/app_name/'"/> <!-- VoiceXML Connector uses this -->
<var name="audioBaseUrl" expr="'http://audio-server:8080/app_name'"/> <!-- Voice Browser uses this -->
Populating variables
The stub gets session values at runtime from the IVR platform and the voice browser (using syntax and variables supported by your specific platform and browser).
<!-- Example to retrieve ANI (userChannelId), DNIS (systemId), and sessionId from a Nuance Voice Platform (NVP) session -->
<script>
function getSIPPort(sipstr) {
var offset;
offset=sipstr.indexOf("@");
if(offset>4){
return sipstr.substring(4,offset);
}else{
return sipstr;
}
}
if(userChannelId==''){
userChannelId = getSIPPort(session.connection.remote.uri+'');
}
if(systemId==''){
systemId = getSIPPort(session.connection.local.uri+'');
}
platformSessionId = session.connection.sessionid;
sessionId = session.connection.sessionid;
// reportingVariables = '{"<extraReportingKey>":"<extraReportingValue>"}';
</script>
Using <subdialog> to send the start request and call the Mix dialog model
The <subdialog> is the standard VoiceXML mechanism. The connector-server is hostname where the Connector is running, and 8080 is the port where the Connector is listening. (If you deploy a load balancer such as Envoy, substitute the hostname and port.) For parameter details, see Starting sessions.
<!-- The VoiceXML Connector URL must be accessible from the Voice Browser -->
<subdialog name="mixapp" src="https://connector-server:8080/vxml-connector/start" method="post" namelist="dialogModelRef mixClientId mixSecret language userChannelId platformSessionId reportingVariables systemId sessionId channel grammarBaseUrl backendBaseUrl modelBaseUrl audioBaseUrl">
<!-- Handle common vxml events -->
<catch event="error cancel exit telephone connection">
<goto next="#exitError"/>
</catch>
<!-- Handle the return codes -->
<filled>
<assign name="xferData" expr="mixapp.sessionVariables.transferDestination"/>
<assign name="xferType" expr="mixapp.sessionVariables.transferType"/>
<if cond="mixapp.returnCode == 'SUCCESS'">
<goto next="#exit"/>
<elseif cond="mixapp.returnCode == 'CALLER_HUNG_UP'"/>
<goto next="#exit"/>
<elseif cond="mixapp.returnCode == 'TRANSFER'"/>
<if cond="xferType == 'blind'">
<!-- Get transfer number from the dialog-->
<assign name="xferData" expr="mixapp.sessionVariables.transferDestination"/>
<goto next="#Transfer"/>
<elseif cond="xferType == 'bridge'"/>
<assign name="xferData" expr="mixapp.sessionVariables.transferDestination"/>
<goto next="#TransferBridge"/>
<elseif cond="xferType == 'consultation'"/>
<assign name="xferData" expr="mixapp.sessionVariables.transferDestination"/>
<goto next="#TransferConsultation"/>
<elseif cond="xferType == 'conditional'"/>
<assign name="xferData" expr="mixapp.sessionVariables.transferDestination"/>
<goto next="#TransferConditional"/>
<else/>
<assign name="xferData" expr="mixapp.sessionVariables.transferDestination"/>
<goto next="#Transfer"/>
</if>
<else/>
<!-- Handle FAILURE codes -->
<goto next="#exitError"/>
</if>
</filled>
</subdialog>
</form>
Handling the call returned from Mix
When the Mix dialog model returns to the client, the stub finishes the call. The customer's call might still be connected or it might have transferred or disconnected during the Mix dialog.
<form id="Transfer">
<transfer type="blind" connecttimeout="10s" destexpr="'tel:'+xferData" name="telTransfer"/>
<block>
<assign name="transferReturnCode" expr="'0'"/>
<goto next="#completeTransfer"/>
</block>
<catch event="telephone.disconnect.hangup">
<assign name="event" expr="_event"/>
<goto next="#completeTransfer"/>
</catch>
<catch event="connection.disconnect.hangup">
<assign name="event" expr="_event"/>
<goto next="#completeTransfer"/>
</catch>
<catch>
<script>
sessionVariables = '{"failureReason":"' + _event + '"}';
</script>
<goto next="#completeTransfer"/>
</catch>
</form>
<form id="TransferBridge">
<transfer type="bridge" connecttimeout="10s" destexpr="'tel:'+xferData" name="telTransfer"/>
<block>
<assign name="transferReturnCode" expr="'0'"/>
<goto next="#completeTransfer"/>
</block>
<catch event="telephone.disconnect.hangup">
<assign name="event" expr="_event"/>
<goto next="#completeTransfer"/>
</catch>
<catch event="connection.disconnect.hangup">
<assign name="event" expr="_event"/>
<goto next="#completeTransfer"/>
</catch>
<catch>
<script>
sessionVariables = '{"failureReason":"' + _event + '"}';
</script>
<goto next="#completeTransfer"/>
</catch>
</form>
<form id="TransferConsultation">
<transfer type="consultation" connecttimeout="10s" destexpr="'tel:'+xferData" name="telTransfer"/>
<block>
<assign name="transferReturnCode" expr="'0'"/>
<goto next="#completeTransfer"/>
</block>
<catch event="telephone.disconnect.hangup">
<assign name="event" expr="_event"/>
<goto next="#completeTransfer"/>
</catch>
<catch event="connection.disconnect.hangup">
<assign name="event" expr="_event"/>
<goto next="#completeTransfer"/>
</catch>
<catch>
<script>
sessionVariables = '{"failureReason":"' + _event + '"}';
</script>
<goto next="#completeTransfer"/>
</catch>
</form>
<form id="TransferConditional">
<transfer type="conditional" connecttimeout="10s" destexpr="'tel:'+xferData" name="telTransfer"/>
<block>
<assign name="transferReturnCode" expr="'0'"/>
<goto next="#completeTransfer"/>
</block>
<catch event="telephone.disconnect.hangup">
<assign name="event" expr="_event"/>
<goto next="#completeTransfer"/>
</catch>
<catch event="connection.disconnect.hangup">
<assign name="event" expr="_event"/>
<goto next="#completeTransfer"/>
</catch>
<catch>
<script>
sessionVariables = '{"failureReason":"' + _event + '"}';
</script>
<goto next="#completeTransfer"/>
</catch>
</form>
Cleaning up after a transfer
The client tells the Mix dialog model how the call ended. This allows the dialog to perform cleanup activities.
<form id="completeTransfer">
<var name="returnCode" expr="transferReturnCode"/>
<!-- vxml-connector URL needs to be accessible from Voice Browser -->
<subdialog name="mixtransfer" src="http://<vxml-connector IP:PORT>/vxml-connector/completeTransfer" method="post" namelist="sessionId returnCode sessionVariables event">
<catch event="error cancel exit telephone connection">
<goto next="#exitError"/>
</catch>
<filled>
<assign name="xferData" expr="mixtransfer.sessionVariables.transferDestination"/>
<assign name="xferType" expr="mixtransfer.sessionVariables.transferType"/>
<if cond="mixtransfer.returnCode == 'SUCCESS'">
<goto next="#exit"/>
<elseif cond="mixtransfer.returnCode == 'CALLER_HUNG_UP'"/>
<goto next="#exit"/>
<elseif cond="mixtransfer.returnCode == 'TRANSFER'"/>
<if cond="xferType == 'blind'">
<assign name="xferData" expr="xferData"/>
<goto next="#Transfer"/>
<elseif cond="xferType == 'bridge'"/>
<assign name="xferData" expr="xferData"/>
<goto next="#TransferBridge"/>
<elseif cond="xferType == 'consultation'"/>
<assign name="xferData" expr="xferData"/>
<goto next="#TransferConsultation"/>
<elseif cond="xferType == 'conditional'"/>
<assign name="xferData" expr="xferData"/>
<goto next="#TransferConditional"/>
<else/>
<assign name="xferData" expr="xferData"/>
<goto next="#Transfer"/>
</if>
<else/>
<goto next="#exitError"/>
</if>
</filled>
</subdialog>
</form>
Ending the session
The stub application ends the IVR session.
<!-- Exiting with an error -->
<form id="exitError">
<block>
<prompt bargein="false">
I'm sorry, a system error seems to have occurred. Please hang up and try again.
</prompt>
<exit/>
</block>
</form>
<!-- Normal exit -->
<form id="exit">
<block>
<exit/>
</block>
</form>
</vxml>
(The initial <vxml> element appears in the form's header.)
Example return from the dialog
This example shows a return from the Mix dialog model to the client application:
{
returnCode="TRANSFER"
event=""
eventMessage=""
sessionId="0a168013_00005ddc_609996a7_02f1_0002"
sessionVariables={"authAttempt":1.0}
sessionVariablesJson="{"authAttempt":1.0}"
}