Twilio Target Worker Expression--blocking voice calls while on a text - twilio

I've read the documentation here: https://www.twilio.com/docs/taskrouter/multitasking#preventing-a-worker-from-receiving-chat-tasks-if-on-a-voice-task on how to block an agent from getting chats while they are on a voice call, but I want to do the reverse with a twist.
I successfully managed to stop workers from getting a voice call while they have an active chat going using "worker.channel.chat.assigned_tasks == 0" as the Expression. However, it also prevents a second chat, SMS, Facebook, or WhatsApp message coming in even though the worker's capacity is higher than 1.
Would love suggestions on what the expression should be so that the additional SMS or chats can come through up to the worker's capacity but not any voice calls when they have an active chat or SMS going.

The following filter should do the trick. The expression will only apply to voice tasks and the target routes to workers with no assigned chats.
{
"filter_friendly_name": "Do not assign Voice Tasks if assigned Chat",
"expression": "(task_channel_unique_name=='voice')",
"targets": [
{
"queue": <default queue sid>,
"expression": "worker.channel.chat.assigned_tasks == 0"
}
]
},

Related

Twilio voice callback

I'm having a tough time getting the Twilio Voice callback function to work properly, and would greatly appreciate any assistance in resolving this.
I have a working VOIP webapp using Python, twilio package and twilio voice SDK.
I need to get call status when a call is being made: answered, completed, ringing, in-progress and the likes.
is_record = fetch_recording_data_from_DB
handle_url = '/handle'
callback_url = '/events'
events = 'answered ringing initiated completed'
#incoming call
dial = Dial(timeout=15, record='record-from-ringing' if is_record else 'false', action=handle_url)
dial.client(
identity=contact_data['company_id'] or company_id,
status_callback_event = events,
status_callback = callback_url,
status_callback_method = 'POST'
)
return response.append(dial)
The handle_url is triggered after call ends or the 20s is exhausted with no answer to determine whether to make a call forwarding or play VM, this works fine. No error whatsoever, calls come in - I answer and talk for a while, if I don't, it goes to voicemail, records and hangs up. I see my recording, cost, duration and other data on the calls tab on Twilio console, under Monitor. All fine. I just can't get the status callback bit.
#status callback function
def stat_events():
return request.values, {'Content-Type': 'text/xml'}
.....
class StatEvents(Resource):
def post(self):
return stat_events()
Now, on the Twilio console, I can see the response and the other information (fromstate, sequencenumber,...) under Request Inspector (multiple times, as it should be) xdxxdxd.ngrok.io/events (POST, 200) regarding the call, but on my network tab (chrome) (when I make a call on the frontend) I check under the events network and see {} - empty
I tried console.log() on the events, nothing! so either I am not using this option well or there's something magical at play.
I need the status so I can save the call log to my DB (background task) when it's completed or no-answer.
data I want but it's only showing up on Twilio console and empty on network tab (apart from saving call log, I need this data to show the status on the front-end):
"Called": "+653xxxxxx",
"ParentCallSid": "CAd1ed07xxxxxxxxxxxxxxx",
"ToState": "",
"CallerCountry": "US",
"Direction": "outbound-dial",
"Timestamp": "Fri, 22 Jul 2022 08:58:56 +0000",
"CallbackSource": "call-progress-events",
"CallerState": "MI",
"ToZip": "",
"SequenceNumber": "0",
"CallSid": "CA3a39c6b1xxxxxxxxxxxxxx",
"To": "+653xxxxxxxx",
"CallerZip": "",
"ToCountry": "SG",
"CalledZip": "",
"ApiVersion": "2010-04-01",
"CalledCity": "",
"CallStatus": "initiated",
"From": "+194xxxxxxx",
"AccountSid": "ACb9f4fe8f52xxxxxxxxxxxxx",
"CalledCountry": "SG",
"CallerCity": "",
"ToCity": "",
"FromCountry": "US",
"Caller": "+1947xxxxxx",
"FromCity": "",
"CalledState": "",
"FromZip": "",
"FromState": "MI"
}```
```handle_url```'s function uses ```DialCallStatus``` in place of ```CallStatus```, as I read that this would be sent by Twilio request to the endpoint.
You describe that you are receiving requests to your /events webhook, but that you're not getting events in the browser.
When you register to receive events via a status_callback_url then those events are only sent as webhooks to your server.
However, if you have implemented the Twilio Voice SDK in JavaScript, then you can get call events by listening to events on the Twilio.Device object and on Twilio.Call objects. For example, the Twilio.Device will emit the incoming event when there is a new incoming call. And the Twilio.Call will emit accept events when an incoming call is accepted, and disconnect for when a call is over.
You can use these events to show call progress in your UI.
Events looks to be a list:
status_callback_event=['initiated', 'answered']

SQS Event Bridge Once Per Minute

We are looking at Event Bridge to give us a scheduled task added to our SQS once per minute.
We are looking at Event Bridge to make it happen. So far it properly puts messages into the queue, but we are trying to schedule it for once per minute and noticing that the queue only gets messages once per five minutes sometimes six minutes.
The metrics seem to state invocation is happening; however, the queue isn't receiving them in the time frame specified.
Considerations
SQS FIFO Queue - Deduplication
Constant JSON String
The "duh" of not seeing messages at prescribed interval is because of this in the AWS documentation:
The token used for deduplication of sent messages. If a message with a
particular message deduplication ID is sent successfully, any messages
sent with the same message deduplication ID are accepted successfully
but aren’t delivered during the 5-minute deduplication interval
Open to suggestions and will be looking for a workaround.
Update
I tried using Input Transformer to fix by adding the time as uniquely changing item in the queue message; however, still not getting below 5 minutes.
Variable Input
{"addedOn":"$.time"}
Message
{"AddedOn":<addedOn>}
The queue polling built into SQS just wasn't polling for my updated count of greater than 10 messages. Once I deleted out the old messages the timing was correct and it was updating 1/min.
The answer is if you are going to use a constant string it'll have to be for scheduled jobs that are greater than 5 minutes.
Adding info here despite redundancy from question for linked Google searches:
The token used for deduplication of sent messages. If a message with a particular message deduplication ID is sent successfully, any messages sent with the same message deduplication ID are accepted successfully but aren’t delivered during the 5-minute deduplication interval
Despite the messages being a unique event once per minute the Constant (JSON text) not being unique still saw it as a duplicate to remove.
To solve I switched to Input transformer
Example event and what you other fields you can add as variables:
{
"version": "0",
"id": "7bf73129-1428-4cd3-a780-95db273d1602",
"detail-type": "EC2 Instance State-change Notification",
"source": "aws.ec2",
"account": "123456789012",
"time": "2015-11-11T21:29:54Z",
"region": "us-east-1",
"resources": [
"arn:aws:ec2:us-east-1:123456789012:instance/i-abcd1111"
],
"detail": {
"instance-id": "i-0123456789",
"state": "RUNNING"
}
}
I needed a unique variable so time was an obvious choice.
Input for Input Transformer
Input Path:
{"addedOn":"$.time"}
Template:
{"AddedOn":<addedOn>}
Documentation
Also, found that moving over to not using FIFO queues is a potential solution if that's an easy option for future SQS developers as well.

Twilio Gather is recording too soon

The following code is used to build up TwiML to ask the caller which department they are looking for.
If the user is already talking when the gather.Say is being read to the caller, then whatever they are saying over the message is being included, as well as their actual answer to the question in the Action url.
The documentation states:
The following example shows a that specifies speech input
from the user. When this TwiML executes, the caller will hear the
prompt. Twilio will then collect speech input for up to 60
seconds.
However the speech input collection is happening whilst the say is executing.
How do i make sure that whatever is being said whilst the Say is executing is not included as part of the actual response to the question?
...
var call = GetCallData();
var gather = new Gather(
timeout: 4,
input: new List<Gather.InputEnum> { Gather.InputEnum.Speech },
method: HttpMethod.Post,
language: call.TwilioLanguage,
bargeIn: false
)
{
Action = new Uri("MyUrl/Answer/Department")
};
gather.Say("Please say the name of the department you wish to be connected to",
language: call.TwilioLanguage,
voice: call.TwilioVoice);
response.Append(gather);
response.Redirect(new Uri("MyUrl/Hangup"), HttpMethod.Post);
return TwiML(response);
If you do not nest the Say in the Gather, the caller must listen to the Say before the Gather collects input.
More details are here.
TwiML Gather
"By nesting Say or Play in your Gather, you can read some text or play music for your caller while waiting for their input. See "Nest other verbs" below for examples and more information."

Twilio REST API to Flex

Looking for a little guidance here. The docs don't really cover this use case, so can someone please let me know if 1) this is possible, and 2) how to accomplish it?
Sequence:
REST Api to create a task
|
That task ends up as an incoming SMS in Twilio Flex
|
A worker accepts/responds via the Flex console
|
that message is sent to the user via text (SMS)
I've been testing in postman, and got it to the point where I can create a task, and it shows up in Flex, but it comes in as a default task with no sms component.
The docs are pretty thin regarding what the task creation fields can be, let alone what their values need to be.
Attributes = { "type" : "web", "to": "2024105613", "from" : "+14086871234", "queue" : "Everyone", "task-reason" : "service_request", "body" : "joel test" }
Please let me know if the use case / sequence I'm attempting is possible, and if so, do you have any pointers on what I'm doing wrong?
Thanks in advance!
More info/clarification:
What I'm hoping to do is have the worker see the incoming help request/task (that was sent in via the REST API) in Flex, and then respond in flex to the user which shows up on the user's device as a text message.
Right now, I can get the task to show up in flex, and I see the phone number that it "came" from, but I struggling with how I can have the worker respond via sms from the Flex portal.

Twilio - Connecting an Enqueued call to an Agent

I'm trying to create a phone system where a caller gets enqueued, and ideally, the system will then call out to an agent, who would then pickup and then modify the call to bridge the top of the queue.
What I've accomplished thus far is the dialing loop, where a user calls in, and it dials agents in sequence, until someone picks up, or gives the user the option to leave a message or stay on the line while hearing it ring. And a simple enqueue with hold music.
I just can't seem to figure out how to combine these two systems.
The closest I've found is this post, and it's helpful, but it glosses over how to call out once the caller is enqueued.
Unfortunately, the only Twilio documentation I've found thus far tells me how to dial into the queue, which isn't what I want out of this system. I want this system to place a caller in a queue with hold music, while the system then dials agent numbers until an agent picks up.
Any and all help is much appreciated.
Thanks.
Edit:
Solution
index.php
This is the general IVR tree that the caller initially hits.
<Say>This hits your general IVR tree</Say>
<Say>As the last action, since the caller hasn't pressed anything and should be enqueued, redirect the caller to EnqueueCaller.php</Say>
<Redirect>./EnqueueCaller.php</Redirect>
Since PHP is a preprocessor, there's no real way to sleep or timeout the dialing of the call. The redirect in the IVR tree is necessary so the Agents aren't being dialed when the user is still in the IVR tree.
EnqueueCaller.php
This is where the Caller gets redirected once the IVR tree has finished and the user has chosen to wait for an agent. The call actually happens before the Enqueue, since PHP loads first before the TwiML xml is read (I think?). But since there's an inherent delay when calling, the caller will always be enqueued before an agent can pick up (I hope).
<Enqueue waitUrl="wait_file.xml">name_of_queue</Enqueue>
$call = $client->account->calls->create($from, $to, "http://example.com/DialQueueHandler.php", array( "StatusCallback" => "DialQueueEventHandler.php" );
DialQueueHandler.php
This simply bridges the agent and whoevers at the top of the queue.
<Say>Connecting to caller now.</Say>
<Dial><Queue>name_of_queue</Queue></Dial>
DialQueueEventHandler.php
This script houses the logic for what happens when the dialed agent state changes (answered, complete, initiated, ringing) from $_REQUEST['CallStatus']. In my case, I dialed a single agent from the enqueue script, and in this script, either continue dialing the next agents via setting of a flag.
switch($_REQUEST['CallStatus'] {
case 'answered':
case 'completed':
$next = false;
break;
default:
$next = true;
break;
}
if($next) { $call = $client->account->calls->create($from, $nextAgentNumber, "http://example.com/DialQueueHandler.php", array( "StatusCallback" => "DialQueueEventHandler.php?agentOffset=$num" ); } //same line from EnqueueCaller.php, and track where we are in agent array.
If the call is not answered or completed, then dial the next agent. Otherwise when the call is picked up by an agent, the DialQueueHandler.php file gets hit and the call becomes bridged.
Jeff, I'm Megan from Twilio.
You can utilize the workflowSid attribute of <Enqueue> to configure a Task which initiates the call flow to an available agent using TaskRouter. There is a TaskRouter quickstart in PHP and I think given where you've gotten so far, you could pick up on the third part.
Let me know if you find this to be helpful.

Resources