A Phone Number Proxy 📱↔️👻↔️📱
Time to read: 7 minutes
What would you do if you could have a dedicated phone number for anything you wanted? This blog post will show you how to create a phone number that hides your private phone number and acts as an intermediary between your phone number and other phone numbers. The use cases are many:
- separate work and private numbers
- international numbers while traveling (without buying a local sim)
- an event hotline for Code of Conduct violations
- an alias number for a Tinder date, which you can delete if things go badly…
Let’s assume we need a number for an event Code of Conduct hotline because we would prefer not to give attendees our private number. In this post, we will build just such a phone number proxy using:
- a Twilio account – sign up for free
- a Twilio phone number with calling and texting capability
- Python 3.x
- the micro web framework Flask
- the Twilio Python helper library
- ngrok - sign up for free
Before we start, please ensure you have Python 3 and ngrok installed. To be able to use ngrok to build your dog or security cam, you have to also sign up for a free ngrok account. We will set up everything else as we go.
Environment and project setup
Install & configure virtualenv
We are going to use Virtualenv to set up a virtual environment for this project, in order to isolate the dependencies of this project from your other projects. Please create a file in your project directory named requirements.txt
, with the following as its contents:
These are the dependencies we would like to install in our virtual environment. Next we will install virtualenv
to create and activate your virtual environment. Once this is done we will install the dependencies from the dependencies file you created above into your virtual environment. Run the following commands in your command-line:
Run ngrok
In a different terminal window, let’s start ngrok
. Ngrok will allow you to expose your localhost at port 5000 to incoming requests. We will be using this to allow Twilio to communicate with our local python server. It is important that you do not close this terminal window, so please have two terminal windows open – one for python and the other for ngrok.
Once you type in the above your terminal window should look similar to this:
Acquire a Twilio Number
Next, use the Twilio Console to acquire a Twilio number with calling and texting capability. We’ll use this as our event hotline.
Pull it all together
Now that we have our Twilio phone number, let’s set up a config file with all the important details so that we can keep them separately managed. Create a file called config.py
with the following as its contents, replacing the placeholder phone numbers with your values:
Next, create a file called server.py
. We’ll be building this file up as we go along. (If you prefer to copy the entire file as one, you can find the complete file on GitHub.)
Let’s finish our setup by importing the libraries we’ll need and our configuration variables – please add these at the top of your file:
Receive and send texts using your Twilio number
With everything set up, we want to make sure that
- texts from an event attendee to our event hotline will reach our normal number
- we can reply to them
After all, we do want to talk to our attendee, despite not wanting to give them our private phone number. Did I say attendee? I meant attendees! We obviously want to talk to more than one of them. However, all messages routed through our proxy will show up on our phone as being from the proxy number. To not get confused about which attendee sent us what, we will have to come up with a way to know who each text is from.
Encode & decode messages from multiple senders
To know who sent a certain text, we will use a protocol-like formatting that allows us to see both, so Hello World!
becomes +447987654321: Hello World!
.
Add the following function to the end of your server.py
file:
We will use the above function to get an encoded message when someone messages us. When we send a message from our phone, we will have to send it formatted the same way, and our server will decode it before it gets sent to the actual recipient. Add this decoding function to server.py
:
Integrate with Twilio Programmable SMS
Now we can use the above helper functions to integrate with Twilio. The code below will create the Flask app and set up the first endpoint. The Flask app is initialized in the first line and started in the last line with app.run()
. In between, we add the /sms
endpoint.
Later in this section, we will configure our Twilio number to send a request to the /sms
endpoint upon receiving a text message. This request contains the message body and the number of the sender. In our endpoint code, we store both in variables. We use the sender number to determine whether the sender number is ours or an attendee’s and execute the respective clause in the if-else-statement.
If we are the sender, we expect the message body to be of the format +447987654321: Hello World!
. In this case we decode the message body and then call the send_message
. If the message comes from an attendee, it should be of the format Hello World!
. We encode the message and send it to our number using the send_message
function.
The send_message
function takes as input a message and the designated recipient’s number. After creating a MessagingResponse
object, we create the response with the given message and number by calling the message method on the object. Afterwards, we return the response object to finish the request.
Add the following lines to the bottom of your server.py
file:
If you have been following along and copying the code into your server.py
file, you can now save it. Run this code by typing python server.py
into your terminal (python3 server.py
if you are using python3). Once the code is running your server will be live at the forwarding URL ngrok displayed in your other terminal window.
Copy your server’s URL, and navigate to the dashboard page for your Twilio phone number (you can find this by navigating to the phone numbers overview and then selecting your Twilio number). You should see a form that looks like the one below. We need to paste the Ngrok URL with /sms
appended to the end into “Messaging” > “A Message Comes In” as a webhook. While you’re at it, you can work ahead and fill in “Voice & Fax” > “A Call Comes In” with the URL and /call
.
Twilio will now know to send an HTTP POST request to your webserver when your Twilio number gets a message which will hit the endpoint we created above. You’re now ready to text attendees through your proxy and receive replies. Try it by asking a friend to send a text message to the Twilio number! Alternatively, acquire another Twilio number and send a text message using this number.
When your friend or your friendly second Twilio number sends a text to your Twilio proxy number, your normal number should receive an encoded message. Reply in the encoded format and see whether your friend gets your reply as well. If you sent the number with another Twilio number, you can see received messages in the console by navigating to “Messages Log” for your second Twilio number.
Call and Receive Calls Using Your Twilio Number
Now that texting works, we’ve almost got a fully functional proxy number! The only thing left is to set up calling.
Forward calls with TwiML
Let’s start with forwarding calls made to our Twilio number. When a call is received by our Twilio number, Twilio will make a request to our server’s /call
endpoint (as we configured above). We have to create a response that instructs Twilio to forward the call to our private number when we receive that request.
TwiML is exactly such a response. TwiML is an XML encoded set of instructions that tell Twilio what to do when an incoming call (or SMS) is received.
In our case we want to redirect a received call to our personal number. The snippet below does this using the TwiML verb . We pass two arguments: the
number
to which we want to forward the call and caller_id
. Passing caller_id
as None
will allow us to see the original caller on our phone. When we are making a call, we will pass the TWILIO_NUMBER
as the caller_id
. Thus we can program it so that when an attendee is calling you can see their number, and when you call an attendee, they see your TWILIO_NUMBER
.
Copy the following function below your send_message
function but above the if-statement:
Make calls with Python
Next, we’ll add two endpoints to our server: /call
and /aliasing
.
/call: One endpoint to receive calls
A request to this endpoint will be made both when attendees call us as well as when we want to call attendees. Fortunately, when a request is received at this endpoint, the payload includes the number of the caller. The number of the caller will allow us to identify whether we are calling ourselves by checking whether the number is equal to our PRIVATE_NUMBER
. If it’s not our number it is probably an attendee. In that case let’s simply pass the call on to the PRIVATE_NUMBER
.
Add the following above the send_message
function:
If the number is our number we have some more work to do. The code below uses another TwiML verb, <Gather>, to deliver a warm welcome message asking us to dial the number of the person we wish to call, followed by the #-symbol. After we type in a number and press the #-symbol, the Gather implementation will perform the action that is specified when initializing the Gather object. In our case, it sends a request with the gathered data to the endpoint /aliasing
. We will create the /aliasing
endpoint in the next step.
Add the following else
statement to your /call
route:
/aliasing: One endpoint to send calls
Within the aliasing
endpoint, we will get the digits that we entered on the phone and perform a call to that number. In this case we will pass the TWILIO_NUMBER
as the caller_id
so that the person on the other end does not see our private number. Add the following right below the send_message
function we just added.
Test what we’ve built
Restart your server and that’s it! Dial your Twilio number from a friend’s phone and it should forward the call to your phone. Then try calling your Twilio number from your personal number, and you’ll be prompted to input a number you’d like to call. Input your friend’s number and you’ll see your Twilio number showing up on your friend’s screen.
You can see the complete project on GitHub. Go on and make as many numbers as you’d like! If you don’t need the number anymore or need to ghost, just delete the number from your Twilio account. If you’re interested in taking this project to the next level you could implement logic for a number that only redirects calls during work hours or even come up with semi-automated answers. To have this proxy number permanently running you will also want to move your project to a server instead of your local machine.
If you have any questions feel free to reach out at @naomi_pen or find me at naomi.codes.
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.