Skip to main content
Version: 2.8

CCE CVP Script to create Voice Call records

To get the full value of Salesforce Service Cloud Voice, the call flow in Cisco CCE must be modified to create the Voice Call record in Service Cloud Voice as soon as the call arrives in the Contact Center.

An optional Omni-Flow can be executed, for routing decisions and automation in Salesforce.

For details about the used APIs, see Service Cloud Voice API Wrapper

Pre-requisites

In order to use the Service Cloud Voice API Wrapper, a Salesforce Connected App for IVR integration must be configured.

Cisco CCE and CVP sample Scripts

Download

Download the latest Cisco CCE and CVP sample scripts

High-level call flow:

  1. CCE Script: Define a unique call ID as the Vendor Call Key and store value in the Peripheral Variable as configured in the Contact Center (parameter Call Variable for the Vendor Call Key)
  2. CCE Script: Run CVP application (CVP Script / Call Studio Application): SCV_Create_Voice_Call
    1. Initialize
    2. Get Access Token
    3. Create Voice Call Record
    4. Execute Omni-Flow (optional)
  3. CCE Script: Assign voice call record ID, returned by the CVP Script, to the Peripheral Variable as configured in the Contact Center (parameter Call Variable for the Voice Call Record Id)
  4. CCE Script: Queue call
  5. CCE Script: Run IVR script: SCV_Queue to play prompt and queue music
    1. Play prompt "Please wait"
    2. Play queue music
    3. Trigger "hangup" event. If the caller hangs-up while in queue, execute CVP script SCV_Clear_Routing
      1. Initialize
      2. Get Access Token
      3. Clear Routing
      4. Update Voice Call Record

Create Voice Call record and Execute Omni-Flow

CCE Script

CCE Script: Create Voice Call record

  1. Define a unique call ID as the Vendor Call Key and write into Peripheral Variable to be sent to the agent
  2. Define CVP application to be executed
  3. Add the Vendor Call Key as parameter
  4. Execute CVP application
  5. Write return value "Voice Call record ID" into Peripheral Variable to be sent to the agent
  6. Write return value "Queue" into Peripheral Variable to be used for call routing
  7. Write return value "Agent" into Peripheral Variable to be used for call routing
  8. Write return value "Start Time" into Peripheral Variable to be used for call queuing

CCE Script Custom Function for Vendor Call Key

Every call handled in Service Cloud Voice creates a Voice Call record in Salesforce and requires a unique ID called Vendor Call Key. For Voice Call records created in CVP, the Vendor Call Key must be defined in the CCE Script and then passed along with the call to the Agent using a CCE Peripheral Variable.

To simplify CCE scripting, we recommend the definition of a CCE Script Custom Function:

Function Name: userVendorCallKey

Parameters: 0

Function definition: concatenate(Call.RouterCallDay,"-",Call.RouterCallKey,"-",Call.RouterCallKeySequenceNumber)

Use CCE script Set node to store the Vendor Call Key in a Peripheral Variable (for example in Call.PeripheralVariable6)

ValueStored in (example)Description
userVendorCallKey()Call.PeripheralVariable6"Vendor Call Key" into Peripheral Variable used in the CVP script to create the Voice Call Record and to be sent to the agent

Note: To reduce the number of Peripheral Variables, required for Service Cloud Voice, it is possible store the Voice Call record ID and the Vendor Call Key in one Peripheral Variable. See Combine Voice Call record ID and Vendor Call Key in one Peripheral Variable for more details

Input Parameters for the CVP application

Variable nameValueDescription
Call.user.microapp.ToExtVXML[0]"application=SCV_Create_Voice_Call"VXML application name
Call.user.microapp.ToExtVXML[1]concatenate("icmCallKey=",Call.PeripheralVariable6)Vendor Call Key - use Peripheral Variable as defined in pervious step
Call.user.microapp.ToExtVXML[x]"<parameter name>=<parameter value>"optional parameters

Return values from CVP application

Return Variable nameStored in (example)Description
Call.user.microapp.FromExtVXML[0]Call.PeripheralVariable7"Voice Call record ID" into Peripheral Variable to be sent to the agent
Call.user.microapp.FromExtVXML[1]Call.PeripheralVariable8"Queue" returned from Execute Omni-Flow, can be used for routing
Call.user.microapp.FromExtVXML[2]Call.PeripheralVariable9"Agent" returned from Execute Omni-Flow, can be used for routing
Call.user.microapp.FromExtVXML[3]Call.PeripheralVariable10"Start Time", used for call queuing

CVP script: SCV_Create_Voice_Call

  1. Initialize: Set Connection Data
  2. Get Access Token
  3. Create Voice Call Record
  4. Execute Omni-Flow (optional)
  5. Exit Flow and return data to CCE script

Input Parameters from CCE script

Variable nameDescription
{Data.Session.icmCallKey}Unique call ID
{Data.Session.<parameter name>}Optional custom data for Voice Call creation

Initialize: Set Connection Data

CVP script: Set Connection Data

Settings
Setting nameVariable valueDescription
startTimeisoStartTime">new Date().toISOString()Call start date and time
Data
NameValueExampleCreate when
sfClientIdConnected App "Consumer Key"Before
sfClientSecretConnected App "Consumer Secret"Before
sfCallCenterDevNameContact Center Developer NameCnxScvContactCenterBefore
sfCertDevNameAPI Name of Certificate (as configured in Contact Center)cnxscvBefore
sfAuthorizeEndpointUrlhttps://<your-domain-name>.my.salesforce.com/services/oauth2/tokenBefore
sfFlowNameSalesforce Omni-Flow API NameCisco_Routing_FlowBefore
sfFallbackQueueIdSalesforce API name or record ID of fallback queueFallback_QueueBefore

Get Access Token

CVP script: Get Access Token

1. REST request: Get Access Token
Settings
Setting nameVariable valueDescription
Endpoint URL{Data.Element.Set Connection Data.sfAuthorizeEndpointUrl}
HTTP MethodPOST
Parameters'grant_type':'client_credentials',
'client_secret':'{Data.Element.Set Connection Data.sfClientSecret}',
'client_id':'{Data.Element.Set Connection Data.sfClientId}'
Headers'Content-Type':'application/x-www-form-urlencoded'
BodyEmpty, no body content
Data
NameValueCreate whenDescription
status_code{Data.Element.Get Access Token.status_code}AfterREST request return value
response_body{Data.Element.Get Access Token.response_body}AfterREST request return value
2. Condition: Create Token result

Verify if the REST request was successful

Decision Editor
ExpressionActionExit State
If element data from "Get Access Token" and variable name "status_code" equals (string) the string "200"then returnsuccessful
3. Set Value: Store Token data
Settings
Setting nameVariable valueDescription
sfAccessTokenimportPackage(com.audium.server.cvpUtil);
var val = {Data.Element.Get Access Token.response_body};
var obj = JSON.parse(val);
obj.access_token;
write access token into a variable for future use
sfInstanceURLobj.instance_urlwrite instance URL into a variable for future use

Create Voice Call record

This step is required for every call. After the Voice Call record is created, the Voice Call record ID must be passed with the call to the agent in a Peripheral Variable. Configure the used Peripheral Variable in the Contact Center configuration in Service Cloud Voice.

CVP script: Create Voice Call record

1. Set Value: Prepare request body to create voice call record
Settings
Setting nameVariable valueDescription
createVoiceCallBodyPrepare the request body for the REST request to create the voice call record. For details see below.

When creating the Voice Call record, you can also update custom fields on the Voice Call record with call data. Below are two examples of the request body, one with all the required fields but without updating custom fields, and one with custom fields.

Without updating custom fields on Voice Call record:

attributes = '';

body = '{"callCenterDevName": "' + {Data.Element.Set Connection Data.sfCallCenterDevName} + '"';
body += ',"certDevName": "' + {Data.Element.Set Connection Data.sfCertDevName} + '"';
body += ',"vendorCallKey": "' + {Data.Session.icmCallKey} + '"';
body += ',"to": "' + {CallData.DNIS} + '"';
body += ',"from": "' + {CallData.ANI} + '"';
body += ',"initiationMethod": "Inbound"';
body += ',"startTime": "' + {LocalVar.isoStartTime} + '"';
body += ',"participants": [{"participantKey": "' + {CallData.ANI} + '","type" : "END_USER"}]';
body += attributes;
body += '}';
body;

Example with updating the custom fields on a Voice Call record:

attributes = ',"callAttributes": "{';

attributes += '\\"Service__c\\": \\"' + {Data.Session.selectedService} + '\\"';
attributes += ',\\"Language__c\\": \\"' + {Data.Session.selectedLanguage} + '\\"';
attributes += ',\\"Customer_ID__c\\": \\"' + {Data.Session.customerId} + '\\"';

attributes += '}"';

body = '{"callCenterDevName": "' + {Data.Element.Set Connection Data.sfCallCenterDevName} + '"';
body += ',"certDevName": "' + {Data.Element.Set Connection Data.sfCertDevName} + '"';
body += ',"vendorCallKey": "' + {Data.Session.icmCallKey} + '"';
body += ',"to": "' + {CallData.DNIS} + '"';
body += ',"from": "' + {CallData.ANI} + '"';
body += ',"initiationMethod": "Inbound"';
body += ',"startTime": "' + {LocalVar.isoStartTime} + '"';
body += ',"participants": [{"participantKey": "' + {CallData.ANI} + '","type" : "END_USER"}]';
body += attributes;
body += '}';
body;

Variable nameVariable value
sfCallCenterDevNameContact Center Developer Name
sfCertDevNameAPI Name of Certificate (as configured in Contact Center)
icmCallKeyUnique call ID
DNISCalled Number (= DNIS)
ANICalling Number (= ANI)
isoStartTimeCall start time, created in the initialization step

Example using custom fields on Voice Call object:

Custom field on Voice Call objectVariable nameVariable value
Service__cselectedService<depends on use case>
Language__cselectedLanguage<depends on use case>
Customer_ID__ccustomerId<depends on use case>
2. REST request: Create Voice Call record
Settings
Setting nameVariable valueDescription
Endpoint URL{LocalVar.sfInstanceURL}/services/apexrest/cnxscv/voice/v1/createVoiceCall
HTTP MethodPOST
ParametersEmpty, no parameters
Headers'Authorization':'Bearer {LocalVar.sfAccessToken}','Content-Type':'application/json'
Body{LocalVar.createVoiceCallBody}
Data
NameValueCreate whenDescription
status_code{Data.Element.Create Voice Call Record.status_code}AfterREST request return value
response_body{Data.Element.Create Voice Call Record.response_body}AfterREST request return value
3. Condition: Create Voice Call Record Result

Verify if the REST request was successful

Decision Editor
ExpressionActionExit State
If element data from "Create Voice Call Record" and variable name "status_code" equals (string) the string "200"then returnsuccessful
4. Set Value: Read Voice Call record ID
Settings
Setting nameVariable valueDescription
sfVoiceCallRecordIdimportPackage(com.audium.server.cvpUtil);
var val = {Data.Element.Create Voice Call Record.response_body};
var obj = JSON.parse(val);
obj.data.voiceCallId;
write Voice Call record ID into a variable for future use

Execute Omni-Flow (optional step)

Use Execute Omni-Flow when you want to

  • run automated tasks, for example search for or create records, and link the records with the Voice Call record
  • search for records and do screen-pop
  • synchronize Salesforce and Cisco queues
  • let Service Cloud Voice make the routing decision

This request always returns the "queue" or "agent" to where the call must be routed.

info

After executing this request, make sure you send Clear Routing if the caller hangs-up before being answered by an agent. See Queue Call

CVP script: Execute Omni-Flow

1. Set Value: Prepare request body to execute omni flow
Settings
Setting nameVariable valueDescription
executeFlowBodyprepare the request body for the REST request to execute the Omni-Flow. For details see below.

Apart from the required fields, you can pass additional data as input variables to the Omni-Flow. Below are two examples of the request body. First without additional flow parameters, required fields only, the second with two input variables.

Example with Omni-Flow parameters:

parameters = '';

body = '{"callCenterDevName": "' + {Data.Element.Set Connection Data.sfCallCenterDevName} + '"';
body += ',"certDevName": "' + {Data.Element.Set Connection Data.sfCertDevName} + '"';
body += ',"voiceCallId": "' + {LocalVar.sfVoiceCallRecordId} + '"';
body += ',"dialedNumber": "' + {CallData.DNIS} + '"';
body += ',"flowDevName": "' + {Data.Element.Set Connection Data.sfFlowName} + '"';
body += ',"fallbackQueue": "' + {Data.Element.Set Connection Data.sfFallbackQueueId} + '"';
body += parameters;
body += '}';
body;

Example with updating the custom fields on Voice Call record:

parameters = ',"flowInputParameters": {';

parameters += '"param1": "' + {Data.Session.param1} + '"';
parameters += ',"param2": "' + {Data.Session.param2} + '"';

parameters += '}';

body = '{"callCenterDevName": "' + {Data.Element.Set Connection Data.sfCallCenterDevName} + '"';
body += ',"certDevName": "' + {Data.Element.Set Connection Data.sfCertDevName} + '"';
body += ',"voiceCallId": "' + {LocalVar.sfVoiceCallRecordId} + '"';
body += ',"dialedNumber": "' + {CallData.DNIS} + '"';
body += ',"flowDevName": "' + {Data.Element.Set Connection Data.sfFlowName} + '"';
body += ',"fallbackQueue": "' + {Data.Element.Set Connection Data.sfFallbackQueueId} + '"';
body += parameters;
body += '}';
body;
Variable nameVariable value
sfCallCenterDevNameContact Center Developer Name
sfCertDevNameAPI Name of Certificate (as configured in Contact Center)
voiceCallIdID of the voice call record, created in the previous step
DNISCalled Number (= DNIS)
sfFlowNameDeveloper name of the Omni-Flow to execute
sfFallbackQueueIdQueue ID or Queue API name of the fallback queue

Example using custom fields on Voice Call object:

Omni-Flow parameter variable nameVariable nameVariable value
param1param1<depends on use case>
param2param2<depends on use case>
2. REST request: Execute Omni Flow
Settings
Setting nameVariable valueDescription
Endpoint URL{LocalVar.sfInstanceURL}/services/apexrest/cnxscv/voice/v1/executeOmniFlow
HTTP MethodPOST
ParametersEmpty, no parameters
Headers'Authorization':'Bearer {LocalVar.sfAccessToken}','Content-Type':'application/json'
Body{LocalVar.executeFlowBody}
Data
NameValueCreate whenDescription
status_code{Data.Element.Create Voice Call Record.status_code}AfterREST request return value
response_body{Data.Element.Create Voice Call Record.response_body}AfterREST request return value
3. Condition: Execute Omni Flow Result
Decision Editor
ExpressionActionExit State
If element data from "Execute Omni Flow" and variable name "status_code" equals (string) the string "200"then returnsuccessful
4. Set Value: Read Queue and Agent

Verify if the REST request was successful

Settings
Setting nameVariable valueDescription
sfAccessTokenimportPackage(com.audium.server.cvpUtil);
var val = {Data.Element.Execute Omni Flow.response_body};
var obj = JSON.parse(val);
obj.data.queue;
write queue name into a variable for future use
sfInstanceURLobj.data.agentwrite agent name into a variable for future use

Exit Flow and return data to CCE script

Return values to CCE script
Return Variable nameValueDescription
FromExtVXML0{LocalVar.sfVoiceCallRecordId}"Voice Call record ID" into Peripheral Variable to be sent to the agent
FromExtVXML1{LocalVar.sfQueue}"Queue" returned from Execute Omni-Flow, can be used for routing
FromExtVXML2{LocalVar.sfAgent}"Agent" returned from Execute Omni-Flow, can be used for routing
FromExtVXML3{LocalVar.isoStartTime}"Start Time", used for call queuing

Queue Call and handle abandoned calls

info

The following scripts for queue announcements and queue music is only needed if the "Execute Omni-Flow" feature was used.

This step is required to clean-up Service Cloud Voice if the caller hangs up the call before it is answered by an agent.

If "Execute Omni-Flow" is not used, you can use your preferred method to queue calls and play music announcements.

CCE Script

CCE Script: Queue Call

  1. Queue call: Route to Skill Group / Precision Queue
  2. Define CVP application to be executed
  3. Add the Voice Call Record ID (returned from the "SCV_Create_Voice_Call") as parameter
  4. Add the Start Time (returned from the "SCV_Create_Voice_Call") as a parameter
  5. Execute CVP application

Input Parameters for the CVP application

Variable nameValueDescription
Call.user.microapp.ToExtVXML[0]"application=SCV_Queue"VXML application name
Call.user.microapp.ToExtVXML[1]"VoiceCallRecordId=Call.PeripheralVariable7"Voice Call Record ID, returned from the "SCV_Create_Voice_Call"
Call.user.microapp.ToExtVXML[2]"CallStartTime=Call.PeripheralVariable10"Start Time, returned from the "SCV_Create_Voice_Call"

Return values from the CVP application

No return values.

CVP script: SCV_Queue

  1. Play "Queue" announcement ("Please stay on the line...")
  2. Play queue music
  3. Register for hangup event
  4. Execute CVP script SCV_Clear_Routing

Input Parameters from CCE script

Variable nameDescription
{Data.Session.VoiceCallRecordId}Voice Call Record ID
{Data.Session.CallStartTime}Start Time

CVP Script: Queue Call

1. Play "Queue" announcement

Select the prompt of your choice.

2. Play queue music

Select the queue music of your choice.

3. Register for hangup event

If the caller hangs-up the call before it is answered by an agent, we have to update Service Cloud Voice and terminate the call.

  • If Execute Omni-Flow was used, send Clear Routing to delete the Pending Service Routing (PSR)
  • Send Update Voice Call, to update the start and end times on the Voice Call record and to change the status from New to Completed

Register for event when caller hangs-up call before being answered by the agent. Execute CVP script SCV_Clear_Routing

Hotevent: Hangup
General

Event: connection.disconnect.hangup

4. Execute CVP script SCV_Clear_Routing

Application Transfer: SCV_Clear_Routing
General

Destination: SCV_Clear_Routing

Session Data
  • VoiceCallRecordId
  • CallStartTime

CVP script: SCV_Clear_Routing

  1. Initialize: Set Connection Data
  2. Get Access Token
  3. Clear Routing
  4. Update Voice Call

Input Parameters from CVP script SCV_Queue

Variable nameDescription
{Data.Session.SCV_Queue_VoiceCallRecordId}Voice Call Record ID
{Data.Session.SCV_Queue_CallStartTime}Start Time

Initialize: Set Connection Data

CVP Script: Clear Routing Set Connection Data

Settings
Setting nameVariable valueDescription
isoEndTimeisoStartTime">new Date().toISOString()Call end date and time
VoiceCallRecordId{Data.Session.SCV_Queue_VoiceCallRecordId}extract Voice Call record ID from session data
CallStartTime{Data.Session.SCV_Queue_CallStartTime}Extract Call start date and time from session data
Data
NameValueExampleCreate when
sfClientIdConnected App "Consumer Key"Before
sfClientSecretConnected App "Consumer Secret"Before
sfCallCenterDevNameContact Center Developer NameCnxScvContactCenterBefore
sfCertDevNameAPI Name of Certificate (as configured in Contact Center)cnxscvBefore
sfAuthorizeEndpointUrlhttps://<your-domain-name>.my.salesforce.com/services/oauth2/tokenBefore

Get Access Token

CVP Script: Clear Routing Get Access Token

1. REST request: Get Access Token
Settings
Setting nameVariable valueDescription
Endpoint URL{Data.Element.Set Connection Data.sfAuthorizeEndpointUrl}
HTTP MethodPOST
Parameters'grant_type':'client_credentials',
'client_secret':'{Data.Element.Set Connection Data.sfClientSecret}',
'client_id':'{Data.Element.Set Connection Data.sfClientId}'
Headers'Content-Type':'application/json'
BodyEmpty, no body content
Data
NameValueCreate whenDescription
status_code{Data.Element.Get Access Token.status_code}AfterREST request return value
response_body{Data.Element.Get Access Token.response_body}AfterREST request return value
2. Condition: Create Token result

Verify if the REST request was successful

Decision Editor
ExpressionActionExit State
If element data from "Get Access Token" and variable name "status_code" equals (string) the string "200"then returnsuccessful
3. Set Value: Store Token data
Settings
Setting nameVariable valueDescription
sfAccessTokenimportPackage(com.audium.server.cvpUtil);
var val = {Data.Element.Get Access Token.response_body};
var obj = JSON.parse(val);
obj.access_token;
write access token into a variable for future use
sfInstanceURLobj.instance_urlwrite instance URL into a variable for future use

CVP Script: Clear Routing Set Connection Data

Clear Routing

CVP Script: Clear Routing Clear

1. REST request: Clear Routing
Settings
Setting nameVariable valueDescription
Endpoint URL{LocalVar.sfInstanceURL}/services/apexrest/cnxscv/voice/v1/clearRouting
HTTP MethodPOST
ParametersEmpty, no parameters
Headers'Authorization':'Bearer {LocalVar.sfAccessToken}','Content-Type':'application/json'
Body{"callCenterDevName": "{Data.Element.Set Connection Data.sfCallCenterDevName}","certDevName": "{Data.Element.Set Connection Data.sfCertDevName}","voiceCallId": "{LocalVar.VoiceCallRecordId}"}
Data
NameValueCreate whenDescription
status_code{Data.Element.Clear Routing.status_code}AfterREST request return value
response_body{Data.Element.Clear Routing.response_body}AfterREST request return value
2. Condition: Clear Routing Result

Verify if the REST request was successful

Decision Editor
ExpressionActionExit State
If element data from "Clear Routing" and variable name "status_code" equals (string) the string "200"then returnsuccessful

Update Voice Call

CVP Script: Clear Routing Update Voice Call

1. REST rquest: Update Voice Call
Settings
Setting nameVariable valueDescription
Endpoint URL{LocalVar.sfInstanceURL}/services/apexrest/cnxscv/voice/v1/updateVoiceCall
HTTP MethodPOST
ParametersEmpty, no parameters
Headers'Authorization':'Bearer {LocalVar.sfAccessToken}','Content-Type':'application/json'
Body{"callCenterDevName": "{Data.Element.Set Connection Data.sfCallCenterDevName}","certDevName": "{Data.Element.Set Connection Data.sfCertDevName}","voiceCallId": "{LocalVar.VoiceCallRecordId}","startTime": "{LocalVar.CallStartTime}","endTime": "{LocalVar.isoEndTime}"}
Data
NameValueCreate whenDescription
status_code{Data.Element.Update Voice Call.status_code}AfterREST request return value
response_body{Data.Element.Update Voice Call.response_body}AfterREST request return value
2. Condition: Update Voice Call Result

Verify if the REST request was successful

Decision Editor
ExpressionActionExit State
If element data from "Update Voice Call" and variable name "status_code" equals (string) the string "200"then returnsuccessful

Combine Voice Call record ID and Vendor Call Key in one Peripheral Variable (optional)

To reduce the number of Peripheral Variables, required for Service Cloud Voice, it is possible store the Voice Call record ID and the Vendor Call Key in one Peripheral Variable.

Format: <Voice Call record id>;<Vendor Call Key>

The Voice Call record ID and the Vendor Call Key are separated by a semicolon (;)

Example: 0LQ06000002KMII;154524-2801-0

Example 1: Separate Peripheral Variables for Voice Call record ID and Vendor Call Key

ParameterStored in (example)Example value
Call Variable for the Voice Call Record IDCall.PeripheralVariable70LQ06000002KMII
Call Variable for the Vendor Call KeyCall.PeripheralVariable6154524-2801-0

Example 2: Combined Peripheral Variable for Voice Call record ID and Vendor Call Key

ParameterStored in (example)Example value
Call Variable for the Voice Call Record IDCall.PeripheralVariable70LQ06000002KMII;154524-2801-0
Call Variable for the Vendor Call Keynot configured

Example 3: Separate Peripheral Variables for Voice Call record ID and Vendor Call Key, but Vendor Call Key empty

ParameterStored in (example)Example value
Call Variable for the Voice Call Record IDCall.PeripheralVariable70LQ06000002KMII;154524-2801-0
Call Variable for the Vendor Call KeyCall.PeripheralVariable6empty

If the Call Variable for the Vendor Call Key is configured but empty, the connectors checks if the Call Variable for the Voice Call Record ID contains both, the Voice Call record ID and the Vendor Call Key, separated by a semicolon (;). If this is the case, the Call Variable for the Voice Call Record ID is considered as a combined variable and this Vendor Call Key is used.