What i'm trying to accomplish:
On an incoming call, I display a small box in the frontend that contains caller info along with a button to pickup the call, and a button to send to voicemail. When the agent clicks the button for voicemail, I want to simply forward the incoming call to voicemail.
The issue:
As long as the call is unanswered and still ringing, I cannot redirect it by updating the call the usual way, it has to be answered to allow updating. If I make the button either ignore or reject the call, I have no specific callback status to track, ignore has no status at all, reject just returns "completed" which is no help to me at all.
What I have tried:
// Called by Ajax on button click, variable $callSid contains the call SID
$client->calls($callSid)->update([
"method" => "POST",
"url" => "https://URL_TO_TWIML"
]);
// TWIML returned by URL_TO_TWIML
$response = new VoiceResponse();
$response->say('Agent is unable to take your call, please leave a message');
$response->record(['timeout' => 10]);
$response->hangup();
return $response;
I have tried to find a usable status on callback for ignore / reject as mentioned previously without success. I've searched far and wide for an answer to this without success.
Maybe i'm looking at it the wrong way, i'm still fairly new to Twilio. Any help would be appreciated.
Related
I am developing a simple application in C# which
Trigger a call using Twilio
receiver to press * after receiving the call and finish the call after pressing *
Provide the status completed if user pressed * otherwise provide different status.
I was able to make a call but not able to receive the user input Or status, I tried finishOnKey() but that didn't work, and it always provides status as completed. I didn't get much help from Twilio code sample, can someone redirect to correct article or provide the code to accomplish above.
Twilio developer evangelist here.
Once a call is answered successfully, it doesn't matter how the call is finished, the final status it reaches will be "completed". You can see more about Twilio call statuses in this documentation. You can see that the final call statuses could be:
completed: call was answered successfully and then finished
no-answer: Twilio dialled the number but there was no answer before the timeout
busy: Twilio dialled the number but received a busy signal
cancelled: The number was dialled, but the call was then cancelled using the API before answering
failed: the carrier couldn't connect the call
If you are using <Gather> to take the user input, you should ensure you have set the action attribute to a URL in your application. That URL will receive a new webhook request when the user presses a digit. For example:
<Response>
<Gather action="/gather_results" digits="1">
<Say>... your content goes here ...</Say>
</Gather>
</Response>
With the above TwiML a user would only have to press 1 key before the call is moved to the next stage and the webhook '/gather_results'.
The request to the /gather_results endpoint would include a body with a Digits parameter. If the user pressed "*" then the body of the request would include Digits=*, if the user pressed "1" then it would include Digits=1. You could then choose to do whatever you like with those results, including hanging up the call or recording the submitted digits.
Let me know if this helps at all.
I'd like the following functionality with Twilio/Node: either
my server receives incoming call and the call rings on our custom client; at some point during the call (ideally can work before answering or after answering) or if no one answers on the client, the call is transferred to a webhook on a different server (my CRM provider) so the CRM can deal with it. OR
same as above, but the incoming call posts the incoming call request to both my server & my CRM webhook for the incoming call; I think this might not be possible though, not sure
I'm able to receive a Twilio call on my server without problem, and able to receive Twilio calls in my CRM without problem. However, when I tried to forward a call to the CRM after first receiving it on my custom server/client, it seems to always disconnect abrubtly. Pls help!
The code I'm using to update the call is below. The url works normally if sending the call directly to the CRM webhook. The CallSid is from my custom client from the incoming call
client.calls(req.body.CallSid)
.update({method: 'POST', url: 'https://crm.crmprovider.com/ctiapi/xml/cticall/twilio?authtoken=abc'})
Appreciate any help!
Think I figured out the proper way to do this. Should be using an "action" with "dial" and then checking "DialCallStatus" in the action endpoint and dealing with various statuses as appropriate. Sample code:
// On server, receive call. This is the url Twilio is
// set to post webhook to when call comes in
app.post('/incomingCall', (req, res) => {
const twiml = new VoiceResponse();
// Dial client first; after, call /callAction
// I believe this will call /callAction if call is unanswered for 10 seconds or after a completed call or if there's no client open
const dial = twiml.dial({timeout:10, action: '/callAction'});
const client = 'whateverClientName'
dial.client(client)
res.type('text/xml')
res.send(twiml.toString())
})
app.post('/callAction',(req,res)=>{
const twiml = new VoiceResponse();
// Can set below if for other things like if call not completed, answered, or cancelled
// In this example we say if call's not completed, route call to 3rd party site's webhook to further deal with the ongoing call
if(req.body.DialCallStatus!=='completed'){
twiml.redirect({method: 'POST'},'https://thirdpartywebhook.com/abc')}
else {twiml.hangup()}
res.type('text/xml')
res.send(twiml.toString())
})
I didn't find Twilio docs super straightforward on this so hopefully this helps someone in the future!
I have two available Twilio <client> to receive inbound calls on my website (after caller enters a code) using JS Quickstart and Twilio client PHP library, these calls are recorded and registered on my database.
I've noticed when one <client> hangs up an open inbound call , this call goes to the website of the other <client> I have have 2 registers on my database instead of one.
This is an example:
<?php
//...
//Validating connection status
//$estd is the connection status I get via AJAX
if($estd=="open"){
$call = $twilio->calls($callsid)->update(array("status" => "completed"));
$calla = $twilio->calls($callsid)->fetch();
$parentCall = $calla->parentCallSid; //parent call
$calld = $twilio->calls($parentCall)->update(array("status" => "completed"));
} else if($estd=="pending"){
$call = $twilio->calls($callsid)->update(array("status" => "completed"));
$calla = $twilio->calls($callsid)->fetch();
$parentCall = $calla->parentCallSid; //parent call
$calld = $twilio->calls($parentCall)->update(array("twiml" => '<Response><Dial timeout="20" record="record-from-answer" recordingStatusCallback="https://mywebsite.com/record.php" recordingStatusCallbackEvent="in-progress completed absent"><Client><Identity>the_other_client</Identity><Parameter name="numdoc" value="user_code"/></Client></Dial></Response>'));
}
?>
How can I fix it?
I'd like your help.
I believe this could be occurring because a single incoming voice call will trigger both of your $estd if statements.
According to Twilio documentation (https://www.twilio.com/docs/voice/client/javascript/connection#status), an incoming call will first have the status pending, and then the status open. If your statuscallbackURL is set for when the status changes, you may be calling your record-keeping code more than once. Depending on how you have your SQL you may be inserting new records each time.
The way to prevent the double record is to save the resource SID for the call in your database and insert on duplicate key or update to prevent creating new records.
Alternatively, if the code snippet you are displaying is from record.php, when you make your outbound call using Twiml, you use a callbackURL to call record.php -- at which time you may be creating a new record in your database (as this call will have it's own unique SID). If you want to attach it to the current record, then you will need to create a different callbackURL for those outbound dials made from this script.
(But it is difficult from the details you have provided to know what code is being called when).
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.
I have some working code for call screening with NodeJS, which I modified from the official twilio example.
https://www.twilio.com/docs/howto/callscreening
https://github.com/coolaj86/bizilio/blob/master/routes/twilio/voice/index.js#L246
Snippit:
response += ""
+ '<Response><Gather action="/twilio/voice/connect' + search + '" finishOnKey="any digit" numDigits="1">'
+ '<Say>Press any key to accept this call</Say>'
+ '</Gather>'
// TODO instead of hanging up, redirect to voicemail?
// otherwise it's left to the fallback url to pickup the voicemail and that takes a while
+ '<Hangup/>'
+ '</Response>'
;
If the screening completes successfully, I get a callback to /twilio/voice/connect?foo=bar.
If the screening is unsuccessful I also want a callback to /twilio/voice/miss?foo=bar.
Is the most appropriate way to do this to do a <Redirect> instead of <Hangup/> and then do the <Hangup/> in the redirect? Or should I had a statusCallback somewhere in the original dial and reference the call id?
In thinking about the possibilities to write out the question here, I've probably already discovered a working solution (and I'll go try it), but I'd still like to hear a best practice approach.
As you suggest, you should replace the <Hangup> with a <Redirect>/twilio/voice/miss?foo=bar</Redirect>. After the timeout expires (by default 5 seconds, but configurable via the timeout attribute of the Gather verb), if no input has been received it will go to the next instruction.
From the Twilio Docs for <Gather>:
If no input is received before timeout, falls through to the next verb in the TwiML document.
In the URL that you redirect to you can record that no input was gathered and return any TwiML you like to continue processing the call or return an empty <Response></Response> (or Hangup) to end the call.
StatusCallback is only used at the completion of the call and cannot execute further TwiML instructions.