tl;dr this article details how to setup a basic call forwarding and voice messaging system through Twilio.

This involves some backend work, so this is a good entry point if you want to connect incoming Twilio calls to your backend and do not know where to start.

As it seems Coronavirus is suddenly making remote work a standard... but sometimes you hit a wall called "reality".

No, you can not manually set call fowarding on your landline. No, forwarding of voice message in an email is not feasible.

What you think should be a commodity isn't.

I am not a telecommunication expert, I am sure that the right hardware can solve the second problem. I have absolutely no clue about the first one... but this was frustrating.

Let's not flame or put the blame. Think forward: that is not a good thing for business.

We had set aside any deeper integration with Twilio for quite some time. It felt a bit too complex to enable a quick switch without consuming technical resources.

What Twilio offers

Basically Twilio enables easier integration with phone related things, voice or messages.

Twilio likely enables you to buy a phone number in your country. For us, in Luxembourg there was no option in the interface, but their support quickly solved the problem. It was an admin problem that was quickly solved.

Incoming calls and messages can be processed through programmatic ways.

Those ways are:

Mostly a markup language called TwiML

Twilio functions, which are stored in Twilio infrastructure and can be used without having your own server

Twilio Studio, a visual workflow editor which aims to cover basic use cases easily.

Maybe other things which I do not know as the interface contains a lot of confusing names for the outsider. And I am an outsider.

We are going to expand on Twilio Studio because if you want to do anything fast... that is where you should go.

Part 1: call forwarding

Here just paraphrase what is already in Twilio's documentation Forward Incoming calls with Twilio Studio.

Twilio Studio is accessible through the side bar on the left of your Twilio console. Or here https://www.twilio.com/console/studio/dashboard.

Click the + to create a new Flow and choose the Start from scratch option.

The interface is quite simple, the top part is useless, the left part is navigation towards other screens. If you except the flow you are building in the middle everything is happening in the right block.

From this block you can :

Add widgets

Configure the currently selected widget if any.

Basically you are almost done for the trivial case of call forwarding.

Add a Connect call widget Connect this block from the Incoming Call branch of the first block. Indicate the target phone number, without space, starting with + and your country code

Your workflow is done do not forget to click Save , and then Publish in the top bar.

Publishing makes your changes available to the phone number. Do not forget this button or you will feel stupid. Yes, I did! Yes, many times!

You can also bypass this publishing problem by enabling test users.

Last but not least, you need to associate this flow with your phone number.

Go back to your phone numbers https://www.twilio.com/console/phone-numbers/incoming Select the phone number you want to play with. Down in the Configure tab you will see a A call comes in input. Set it to Twilio Studio and the flow you just created.

Part 2: sending and receiving data

This is all nice and shiny but we are going to try to spice things up a bit.

Here we are just going to create a simple service to provide the target phone number to which the call should be forwarded.

This will show how to send information and receive information.

First select the initial Trigger, go in the right window in the Transitions and disconnect the current connection to the Connect Call .

Then add new widget Make HTTP request ,

Configure an HTTP parameter to forward the incoming phone number. The value of it is stored in a variable {{contact.channel.address}} .

Note: that the double curly brackets enable the access to some variables inside the flow.

Write a small script to receive this and give back a target phone number to whom the call should be forwarded.

<?php // Just to make it easier to access anything coming from the outside $request = array_merge ( $_REQUEST , $_GET , $_POST ); // This to make debugging easier `tail -f out.log` $handle = fopen ( 'out.log' , 'a' ); fwrite ( $handle , var_export ( $request , true )); fclose ( $handle ); $incomingPhoneNumber = $request [ 'incomingPhoneNumber' ] ?? '' ; $isLuxembourgishCaller = strpos ( $incomingPhoneNumber , '+352' ) === 0 ; // Let's dispatch the phone to our local number or our default one $targetPhoneNumber = $isLuxembourgishCaller ? '+352123456' : '+1234567890' ; header ( 'Content-Type: application/json' ); echo '{"targetPhoneNumber": $targetPhoneNumber}' ; die ;

Then you need to make this script available by using a remote server. Or using something to expose your local environment like ngrok.

Two lines for those who choose this last option :

php -S localhost:8010 & ngrok http 8010

The last command will give you an URL that you must set as the Request URL of your Make HTTP Request widget.

We are done with sending the request. Now let's connect the initial trigger incoming call to our Make HTTP request widget. Here note that mine is called using the default naming set by Twilio http_1 .

Connect this widget to the now orphan Connect call to widget.

Last step for this part: configure the connect call widget to Connect call to {{widgets.http_1.parsed.targetPhoneNumber}} .

Note: fields returned from your webservice are accessible in the parsed value of your Make HTTP request widget and that how you can reuse them.

Part 3: handling voice messages

By default your call connection has a timeout of 30 seconds. In that case, we want to let the user record a voice message.

We create a Split based on widget in our workflow for the Connected Call Ended transition. This component is just a way to make part of your flow conditional. Here we are defining the variable to test has being widgets.connect_call_1.DialCallStatus ; connect_call_1 being the name of the call connection widget.

Then we are going to define what happens when the value is no-answer . Click on New then Condition matches , and make it match when equals too no-answer and do not forget to save.

Then add a Record Voicemail widget to connect it after this branching. This widget requires no configuration for our little play time.

Note: there is a cool feature where messages can be automatically transcribed.

Then it is time to add another Make HTTP request component, connected to the Recording Complete transition. This time this component will be charged of sending your message to enable you to do whatever you want with this.

Here you can send it to the same service we previously wrote. Just do not forget this time to setup a request parameter, voiceMessageUrl , to {{widgets.record_voicemail_1.RecordingUrl}} .

Here, if you are using the little PHP script we wrote above, you should be able to tail -f out.log and see the URL of the voice recording. From there, sending an email should be pretty straightforward.

Reminder: do not forget to save and publish to test everything.

We will stop the technical how-to here. The final result should look like this:

Conclusion

We did skip any earlier Twilio integration because decent use without code was impossible. In our example there are to HTTP requests, the one to tell to which number a call should be forwarded was there as an illustration. The other one to actually provide some access to the voice messages is more of a must have.

My personal take would be that this kind of usage should be perceived as commodities and achievable without code. But that is an opinion nobody asked for and perhaps there is some underlying complexity I do not understand.

Twilio does not provide a Send an email widget. Yet this would strongly enhance Twilio Studio's potential for the masses — and the lazies.

To their defense Twilio can host your code in their Twilio functions. A good solution to not have a server, a not so good solution to centralize code and configuration if you already have a backend somewhere.

If you pursue anything like what I have presented here it would be a good thing to secure the calls to your server through a shared token, using the Set Variables widget could be a nice thing.