Search code examples
twiliotwilio-functions

Twilio Function - Whisper


I am attempting to modify the following code to perform a whisper and require the agent who answers to press 1. If they do not answer or do not press 1, the call will then go to voicemail. I need this to be in a function simply because I can't call a Twiml Bin from Studio. Any help would be greatly appreciated. The source of the script below is https://github.com/philnash/useful-twilio-functions/tree/master/hunt.

exports.handler = function(context, event, callback) {
  const numbers = context.PHONE_NUMBERS.split(',').map(number => number.trim());
  const response = new Twilio.twiml.VoiceResponse();
  if (event.DialCallStatus === 'complete') {
    // Call was answered and completed
    response.hangup();
  } else if (event.finished === 'true') {
    if (context.FINAL_URL) {
      response.redirect(context.FINAL_URL);
    } else {
      response.hangup();
    }
  } else {
    const numberToDial = event.nextNumber ? event.nextNumber : numbers[0];
    const currentNumberIndex = numbers.indexOf(numberToDial);
    let url;
    if (currentNumberIndex + 1 === numbers.length) {
      // No more numbers to call after this.
      url = '/hunt?finished=true';
    } else {
      const nextNumber = numbers[currentNumberIndex + 1];
      url = '/hunt?nextNumber=' + encodeURIComponent(nextNumber);
    }
    const dial = response.dial({ action: url });
    dial.number(numberToDial);
  }
  callback(null, response);
};

Solution

  • Twilio developer evangelist (and owner of that repo) here.

    To perform a whisper you need to add a url attribute to the <Number> that points to a URL that returns TwiML with the message you want to whisper.

    In the code above, this means you need to update the line:

    dial.number(numberToDial);
    

    to:

    dial.number({ url: 'https://example.com/whisper' }, numberToDial);
    

    Then, at that URL you need to return your message nested in a <Gather> so you can get the result from the answerer. The <Gather> will need an action attribute set to a URL where you will get the result. You could do this with just a TwiML Bin and the result should look a bit like this:

    <Response>
      <Gather action="ACTION_URL" numDigits="1">
       <Say>You are receiving a call, please dial 1 to accept or anything else to reject</Say>
      </Gather>
    </Response>
    

    Finally, your ACTION_URL needs to point at a function again, so that you can deal with the result. Something like this should work:

    function handler(context, event, callback) {
      const response = new Twilio.twiml.VoiceResponse();
      if (event.Digits === '1') {
        response.say('Connecting you now');
      } else {
        response.hangup();
      }
      callback(null, response);
    }
    

    This will do the whispering, but since this is part of the hunt from that function, you'll need to provide your FINAL_URL that would take the caller to voicemail after the hunt is over.

    Let me know if that helps at all.