0
votes

Hoping someone can point me in the right direction. I'd like to be able to do this via Twilio Studio. If not, I can learn TwiML. That's about as far as my brain will stretch.

I've made a simple flow in Twilio Studio that enables the caller to record a voicemail. I would like to add an option for the current caller to be able to play the previous caller's recorded voicemail. I think I need to use a Say/Play widget for this. What do I need to use for the "URL of audio file" so that the previous recorded voicemail is played? I assume this URL will change every time that a caller leaves a voicemail, so it'll need to auto-update. Can I use "RecordingURL" somehow? Is there a solution using TwiML? Any help appreciated

Thanks!

1

1 Answers

0
votes

Without a way to keep state between the call, this is not possible. The best way would be to have some type of DB you can store the recording SID and reference it in a future flow. You can use a tool like Twilio Sync to do this or Airtable, but it does require code.

I can't think of a way to do this without involving some coding.

Alternate ways are to list the recording records and pull the most recent one off the list but not ideal since you don't know when the last recording occurred.

Another approach is to modify the webhook associated with your Twilio phone number for that Studio Flow to pass in the last Recording SID into your flow and you use that SID to dynamically construct the recording URL to playback, as shown in the JSON flow below (which you can import when creating a new Studio Flow).

Don't forget to set the recordingStatuscallback to the above Twilio Function which updates the phone number webhook to pass in the recording SID. You set your Recording Status Callback of your Record Voicemail Widget to point to your unique Function domain and function path (currently set to: https://magnolia-kitty-3234.twil.io/phUpdate).

Feel free to improve on the below and share.

Twilio Function Code

exports.handler = function(context, event, callback) {
    
    let client = context.getTwilioClient();
    
    const telephoneNumAccountSid = "PN..."; \\ set this to your Phone Number SID
    const accountSid = event.AccountSid; 
    const studioFlowSid = "FW..."; \\ set this to your Studio Flow SID
    const webhookUrl = `https://webhooks.twilio.com/v1/Accounts/${accountSid}/Flows/${studioFlowSid}`;
    const recordingSid = event.RecordingSid;

    client
        .incomingPhoneNumbers(telephoneNumAccountSid)
        .update({ voiceUrl: `${webhookUrl}?recording=${recordingSid}`, voiceFallbackUrl: `${webhookUrl}?recording=${recordingSid}` })
        .then (result => {
             console.log(result.voiceUrl);
             callback(null, "success");
         })
         .catch(err => {
             console.log(err);
             callback("error");
         });
}; 

Studio Flow JSON

{
  "description": "A New Flow",
  "states": [
    {
      "name": "Trigger",
      "type": "trigger",
      "transitions": [
        {
          "event": "incomingMessage"
        },
        {
          "next": "set_variables_1",
          "event": "incomingCall"
        },
        {
          "event": "incomingRequest"
        }
      ],
      "properties": {
        "offset": {
          "x": 0,
          "y": 0
        }
      }
    },
    {
      "name": "split_1",
      "type": "split-based-on",
      "transitions": [
        {
          "next": "say_play_2",
          "event": "noMatch"
        },
        {
          "next": "gather_1",
          "event": "match",
          "conditions": [
            {
              "friendly_name": "{{trigger.call.recording}}",
              "arguments": [
                "{{trigger.call.recording}}"
              ],
              "type": "is_not_blank",
              "value": "Is Not Blank"
            }
          ]
        }
      ],
      "properties": {
        "input": "{{trigger.call.recording}}",
        "offset": {
          "x": 110,
          "y": 350
        }
      }
    },
    {
      "name": "say_play_1",
      "type": "say-play",
      "transitions": [
        {
          "event": "audioComplete"
        }
      ],
      "properties": {
        "play": "https://api.twilio.com/2010-04-01/Accounts/{{flow.variables.accountSid}}/Recordings/{{flow.variables.recording}}.mp3",
        "offset": {
          "x": 450,
          "y": 1110
        },
        "loop": 1
      }
    },
    {
      "name": "set_variables_1",
      "type": "set-variables",
      "transitions": [
        {
          "next": "split_1",
          "event": "next"
        }
      ],
      "properties": {
        "variables": [
          {
            "value": "{{trigger.call.recording}}",
            "key": "recording"
          },
          {
            "value": "{{trigger.call.AccountSid}}",
            "key": "accountSid"
          }
        ],
        "offset": {
          "x": 60,
          "y": 170
        }
      }
    },
    {
      "name": "say_play_2",
      "type": "say-play",
      "transitions": [
        {
          "next": "record_voicemail_1",
          "event": "audioComplete"
        }
      ],
      "properties": {
        "voice": "Polly.Joanna-Neural",
        "offset": {
          "x": -120,
          "y": 650
        },
        "loop": 1,
        "say": "Please leave a message at the beep!",
        "language": "en-US"
      }
    },
    {
      "name": "record_voicemail_1",
      "type": "record-voicemail",
      "transitions": [
        {
          "event": "recordingComplete"
        },
        {
          "event": "noAudio"
        },
        {
          "event": "hangup"
        }
      ],
      "properties": {
        "transcribe": false,
        "offset": {
          "x": -120,
          "y": 860
        },
        "trim": "trim-silence",
        "play_beep": "true",
        "recording_status_callback_url": "https://magnolia-kitty-3234.twil.io/phUpdate",
        "timeout": 5,
        "max_length": 3600
      }
    },
    {
      "name": "gather_1",
      "type": "gather-input-on-call",
      "transitions": [
        {
          "next": "split_2",
          "event": "keypress"
        },
        {
          "event": "speech"
        },
        {
          "event": "timeout"
        }
      ],
      "properties": {
        "number_of_digits": 1,
        "speech_timeout": "auto",
        "offset": {
          "x": 300,
          "y": 650
        },
        "loop": 1,
        "finish_on_key": "#",
        "say": "There is a previous recording, press 1 if you want to listen to it or 2 if you want to leave a new voicemail.",
        "stop_gather": true,
        "gather_language": "en",
        "profanity_filter": "true",
        "timeout": 5
      }
    },
    {
      "name": "split_2",
      "type": "split-based-on",
      "transitions": [
        {
          "event": "noMatch"
        },
        {
          "next": "say_play_1",
          "event": "match",
          "conditions": [
            {
              "friendly_name": "If value equal_to 1",
              "arguments": [
                "{{widgets.gather_1.Digits}}"
              ],
              "type": "equal_to",
              "value": "1"
            }
          ]
        },
        {
          "next": "say_play_2",
          "event": "match",
          "conditions": [
            {
              "friendly_name": "If value equal_to 2",
              "arguments": [
                "{{widgets.gather_1.Digits}}"
              ],
              "type": "equal_to",
              "value": "2"
            }
          ]
        }
      ],
      "properties": {
        "input": "{{widgets.gather_1.Digits}}",
        "offset": {
          "x": 280,
          "y": 870
        }
      }
    }
  ],
  "initial_state": "Trigger",
  "flags": {
    "allow_concurrent_calls": true
  }
}

Alan