Patrick P Patrick P - 4 months ago 55
Node.js Question

Prompt agent for acceptance before dequeuing an incoming call

I've set up a basic workflow on Twilio/node.js, that will transfer an incoming call to agents' phones. Because the agents might have a voicemail setup on their phone/cell phone, I wanted to prompt them for acceptance through a "gather" instruction. If they press 1, then the call will be transferred ("dequeue" instruction). Otherwise, the reservation is to be rejected.

My problem is that I don't know how to order the instructions: if I gather before enqueuing, then gather doesn't seem to know yet "who to ask". But if enqueue before gathering, then the prompt message will be heard by the caller (incoming client) and it will be too late to reject the reservation...

Answer Source

Twilio developer evangelist here.

In this case you should not respond to the assignment callback with "dequeue". Instead, you should use the "call" instruction to initiate a call to the agent instead.

With the call instruction you include a URL that will be requested when the call connects to the agent. At this point you should read out your message and use <Gather> to ensure the agent is ready for the call. When the agent presses a button or the <Gather> times out, the action attribute of the <Gather> will be requested. Then, if you find the user did enter a digit, by checking the Digits parameter you can respond with TwiML to <Dial> the <Queue>. In order to dial the actual caller that the reservation refers to, you need to add the reservationSid attribute to the <Queue> element. You will receive the ReservationSid as a parameter in the task assignment webhook. When the call bridges it will accept the reservation.

If the <Gather> times out, then you should just reject the reservation and it will be passed to the next worker.

Let me know if that helps at all.

Edit

Example TwiML for this situation.

You first respond to the assignment callback with JSON, using a call instruction:

{
  "instruction": "call",
  "to": AGENT_PHONE_NUMBER,
  "from": YOUR_TWILIO_NUMBER,
  "url": "https://example.com/worker_call
}

Then when the worker answers their phone Twilio calls to the url we set above and we use it to ask them if they want to take the call.

# /worker_call
<Response>
  <Gather action="/gather_result?reservation_sid=${req.body.ReservationSid}&task_sid=${req.body.TaskSid}" numDigits="1">
    <Say voice="alice">You have an incoming call, dial any number to accept</Say>
  </Gather>
</Response>

Note, I have added the ReservationSid and TaskSid from the incoming request to the URL of the <Gather> action. Now, when the action URL is called we need to respond based on whether the call was accepted or not. I need to use some actual code for this rather than just TwiML, so I'll do it with Node. We need to be able to call the reservations resource in the REST API, so this comes with some setup:

const accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const authToken = 'your_auth_token';
const workspaceSid = 'WSXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const twilio = require('twilio')
const client = twilio(accountSid, authToken);

app.post('/gather_result', function(req, res) {
  const twiml = new twilio.twiml.VoiceResponse();
  if (req.body.Digits && req.body.Digits.length > 0) {
    // There was a positive result, call the Queue and connect the caller
    const dial = twiml.dial();
    dial.queue({queue: req.query.reservation_sid});
    res.send(twiml.toString());
  } else {
    // no response, reject the reservation.
    client.taskrouter.v1
      .workspaces(workspaceSid)
      .tasks(req.query.task_sid)
      .reservations(req.query.reservation_sid)
      .update({ reservationStatus: 'rejected' })
      .then(function() {
        // once the reservation is updated, then hangup the call.
        twiml.hangup();
        res.send(twiml.toString());
      });
  }
});