Instructions for Twilio's IVR Buila-a-thon Session! This guide provides instructions for creating a Dialogflow agent that allows callers to order life insurance over the phone and take payments via Twilio's Stripe integration.
Before you begin, ensure you have the following:
- Google Account: To access Dialogflow.
Note: The $300 credit can only be assigned to newly created accounts. Feel free to use a personal email address to sign up if your company email address is assigned to a Google Cloud account in production. We will remind everyone at the end of the event about the free trial limitations to avoid any surprise bills. To learn more, please check out these Google Cloud docs.
- Create a Dialogflow Agent (see below)
- Set up Twilio's Dialogflow connector.
- Twilio Account: For phone call integration.
- (Optional) Stripe Account: For payment processing.
Go to the Dialogflow Console and sign in with your Google account.
- Click on Create Agent.
- Enter an Agent Name (e.g., "Plant Bot").
- Select your default language and time zone.
- Click Create.
Intents are used to understand user queries and respond accordingly. In the Manage tab on the left had side, select Intents and create the intents listed below. Under training phrases you will add common user statements so Dialogflow can match it to the intent.
- Create an intent for making a new order (e.g., order.new).
- Create an intent for checking order status (e.g., order.track).
Define entities to capture specific data such as item type, order number, etc.
- Create an entity for handeling yes or no responses.
- Create an entity for possible order items (e.g., items).
- Create an intent for possible order items with the newly created entity. (e.g., order.new.item). Make sure to include the order items in the training phrases.
Under the Build tab, you will see a drag and drop GUI to build out the agent flow.
- On the left hand side, under
Pages
, create 3 new pages: "track", "new", and "confirm". - Click on
Start Page
and add aRoute
- Under the
Intent
section select the intent made for making a new order. At the bottom of the page underTransition
, seelctPage
and select the page title "new". - Create another Intent under
Route
and select the intent made for checking order status.There should now be 2 boxes connected to
Start Page
,new
andtrack
. - Select the
track
box which will be used to track an order status. ClickEdit Fulfillment
and findAgent says
. Add the response, "Ok, let's check on your order" and save your work. - Add a new paramater to the page. Give a display name of
order-id
and add an entity type@sys.number-sequence
and check the box that saysRequired
. Save your work. - Back on the track page, add a new route. Scroll down and find
Webhook settings
. Enable the webhook and in the drop down, select+ Create webhook
. The link to a webhook will be provided during the demo. However if you're working on this outside of the build-a-thon, the endpoint will look similar to this:
exports.handler = async function(context, event, callback) {
// fulfillment response creator
function fulfillmentCreator (txt, ...args){
let a = {
"fulfillment_response": {
"messages": [
{
"text": {
"text": [txt]
}
}
]
},
"sessionInfo":{
"parameters": {
}
}
}
if (args) {
for (let i = 0; i < args.length; i += 2) {
a.sessionInfo.parameters[args[i]] = args[i + 1];
}
}
return a;
}
const config = {
host: context.host,
port: context.port,
user: context.user,
database: context.databaseName,
};
const orderNumber = Number(event.sessionInfo.parameters["order-number"]);
try{
// connect
const db = await mysql.createConnection(config);
// Perform the query
const [rows] = await db.execute(`SELECT * FROM orders WHERE id="${orderNumber}"`);
await db.end(); // Close the connection
console.log(rows);
let order = rows[0]
const name = order.name;
const time = order.time;
let txt = `Your order for a ${name} will arrive in ${time} days.`
const jsonResp = fulfillmentCreator(txt);
return callback(null, jsonResp);
} catch (err){
console.log(err)
return callback(null, err);
}
};
After the webhook executes, the agent will respond with the generated response. NOTE: the
fulfillmentCreator
function is required.
-
Add a tag of "id" to the webhook.
-
After enabling and adding the webhook, scroll up to the
Condition
section and select the condition ruleMatch AT LEAST ONE rule
. Under Parameter, add$page.params.status
and under Value, add"FINAL"
. This will automatically move the agent to the next transition.OPTIONAL: You can add a transition page asking if there's anything other requests.
-
Select the box "new" which will be used for making a new order. Select
Edit Fulfillment
add the text, "Okay, let's start a new order" to the sectionAgent says
. -
Add a new parameter. Under
Agent responses
add the text "What would you like to order?". Scroll up to theEntity type
and select the entity created for handeling possible order items. Give the display name the value "item" and finally, check theRequired
box. Save your work.OPTIONAL: Under
Reprompt event handlers
for the eventNo-match default
, add a agenet response that says, "Sorry I didn't get that. What item would you like to order". -
Create a new route. Under
Agent says
add the text, "You have selected a $session.params.item-parameter-name, one moment please while we gather the information about your order". -
Next create a new webhook to handle the order. The link to a webhook will be provided during the demo. However if you're working on this outside of the build-a-thon, the endpoint will look similar to this:
exports.handler = async function(context, event, callback) {
function fulfillmentCreator (txt, ...args){
let a = {
"fulfillment_response": {
"messages": [
{
"text": {
"text": [txt]
}
}
]
},
"sessionInfo":{
"parameters": {
}
}
}
if (args) {
for (let i = 0; i < args.length; i += 2) {
a.sessionInfo.parameters[args[i]] = args[i + 1];
}
}
return a;
}
const config = {
host: context.host,
port: context.port,
user: context.user,
database: context.databaseName,
};
let orderName = `"${event.sessionInfo.parameters.item}"`;
let shippingTime = Math.floor(Math.random() * 365);
let price = 5;
const sql2 = `INSERT INTO orders (name, price, time) VALUES (${orderName}, ${price}, ${shippingTime})` //, customer ${phoneNumber}
try{
const db = await mysql.createConnection(config);
const [confirmation] = await db.execute(sql2);
await db.end(); // Close the connection
console.log(confirmation);
let txt = `Your order for a ${orderName} will arrive in ${shippingTime} days. Your confirmation number is ${confirmation.insertId}.`
const jsonResp = fulfillmentCreator(txt, "order-id", confirmation.insertId, price);
return callback(null, jsonResp);
} catch (err){
console.log(err)
return callback(null, err);
}
}
Add a tag of "order" to the webhook settings.
- Back in the Dialogflow console for the
new
page's route, add a new condition. Select the condition ruleMatch AT LEAST ONE rule
and add the parameter$page.params.status
with the value"FINAL"
. This will conclude the flow.OPTIONAL: You can add a transition page asking if there's anything other requests.
- Scroll down to
Transition
and select the "confirm" page that was created earlier. Save your work.There should now be a "confirm" box attached to the "new" box.
- Select the "confirm" box and edit the fulfillment. Under
Agent responses
, add the response, "Would you like to continue and place the order?". Save your work. - Create a new parameter, and select the entity type "yes-or-no" that was created earlier.
- Next two routes will be created to handle the yes or no response from the customer.
- In the first route, under
Condition rules
select the optionMatch AT LEAST ONE rule
and for the parameter, enter the value "$session.params." with a value of no. UnderAgent responses
add a value of "Not a problem! Transferring you back to the main menu", and underTransition
, selectStart Page
. - For the second route, underCondition rules
select the optionMatch AT LEAST ONE rule
and for the parameter, enter the value "$session.params." with a value of yes. UnderAgent responses
add a value of "Transferring you to payment", and underTransition
, selectEnd Session
.
If you haven't done so already, head over to the Integration section under the Manage tab. Under "One-click Telephony", connect Twilio. You must be signed in the the Twilio console to complete this action
Once there, add a friendly-name for your new flow. Once completed, a new Studio flow will be created for the agent.
Head over to the newly created Studio flow and complete the following steps:
- Under the
Incoming Call
flow, add aSay/Play
widget and add the text "Hello, this call will be recorded for quality assurance". - Connect the Say/Play widget to a
Call Recording
widget and turn on call recording. - Connect the recording widget to the
Connect Virtual Agent
widget. Under the parameter section, add an additional parameter calledcaller
with the value{{trigger.call.From}}
. This will allow Dialogflow to have access to the user's caller ID. - Under the Flow Control section, add a
Set Variable
widget to capture the price of the item that was purchased. Under the key, set a value of "price" and a value of{{widgets.<virtual-agent-widget-name>.VirtualAgentProviderData.sessionInfo.parameters.price}} || null
. - Add another variable with a key name of "item", and tha value of
{{widgets.<virtual-agent-widget-name>.VirtualAgentProviderData.sessionInfo.parameters.item}}
. - Add a
Split Based On
widget and check if there is a value for the price variable that was defined. - Connect the split widget to a
Capture Payments
widget and enter the optional Stripe pay connector information. This will be built in the next section.
Voice Intelligence is one of Twilio's newest features that transcribes voice calls and highlights actions and words mentioned in a call using AI. Voice Intelligence can also summerize and measure call satisfaction.
In the Twilio console, head over to the Voice Intelligence section and create a new service.
- Create and name a new service and select the settings necessary for your use case. For now, do not select PII redaction.
- In the newly created service, create 2 new operators. One called
plants
and one calledcompetitors
. - For the
plants
operator, create a new phrase set with the labelficus
. For the phrase match, selectExact match
and add the values:rubber fig
,fiddle-leaf
,fig
, andbanyan
. Create another phrase set titled,pothos
, then add the values:golden
,jade
, andmarble queen
with exact matching for each. - For the
competitors
operator, create a new phrase set with the labellarge corporation
. For the phrase match, selectExact match
and add the values:House Depot
,Windowmart
, andHighs
. - Add each of these newly created operators to the newly created service. Each operator has a "Try it out" feature where previously recorded conversations can be tested for the inclusion of each operator's phrases/words.
If you haven't done so already, create a Stripe account.
- Integrate the Stripe Pay Connector in the Twilio console. Under Voice > Manage > Pay Connectors, select Stripe Connector. Install and look over the terms and conditions and confirm if you agree with the t&c.
- Create a Twilio function to handle the payment results. Head to Functions and Assets > Services and create a new service with the name
process-payment
. Add a new endpoint namedprocess
. Next to the endpoint name, open the visibility to the public then add this code to your function:
exports.handler = function(context, event, callback) {
console.log("in Pay");
console.log(event);
console.log(event.Result);
let twiml = new Twilio.twiml.VoiceResponse();
switch (event.Result) {
case "success":
text = "Thank you for your payment";
break;
case "payment-connector-error":
text = "The Payment Gateway is reporting an error";
console.log(decodeURIComponent(event.PaymentError));
break;
default:
text = "The payment was not completed successfully";
}
twiml.say(text);
callback(null, twiml);
};
then save and deploy the function.
- Create a new TwiML Bin to handle the payment. The caller will hear prompts to enter their payment information. Add the following code and add the link from the twilio function that was just created to the
action
attribute:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Calling Twilio Pay</Say>
<Pay paymentConnector="Default" action=<link-to-twilio-payment-function> chargeAmount="{{Body}}"/>
</Response>
to learn more about the Pay verb and optional attributes, check out the Twilio documentation here.
-
Head back to the Studio Flow and enter the information from the newly created Stripe Connector.
- Select the acceptable card types
- Configure the postal and security code options
- Add the unique name of the payment gateway connector that was created
- For the carge amount, add the value {{flow.variables.price}}
- Select the currency to charge the payments
-
Connect the Success flow to a
Say/Play
widget that says, "Thank you for your payment of {{flow.variables.price}} for your {{flow.variables.item}} have a great day!" -
Connect the error messages to a
Gather Input on Call
widget that says, "Sorry, there was an error processing your order, would you like me to connect you to an agent?", and add any logic thereafter.