Send SMS During Calls Application Migration from TwiML to FlexML

If you have read the Migrating from Twilio to CarrierX Quick Start, you could see that TwiML and FlexML are not too much different. Both offer a special syntax to provide instructions, and all you need is to change the representation of these instructions in your code.

But when it comes to a real-case migration from Twilio to CarrierX, users might meet some difficulties.

Let’s see such a migration in details and learn how to solve the issues that arise so that your migrated application worked with CarrierX flawlessly.

Getting Application Source Code

We take the Send SMS During Calls application from Twilio as an example. This sample application sends a text message to the caller and then responds with a voice message. You can download the application source code at GitHub.

Once you download the application, you can see that it has the following structure:

[tests]
.dockerignore
.env.example
.gitignore
.mergify.yml
CODE_OF_CONDUCT.md
CONTRIBUTING.md
Dockerfile
LICENSE
Makefile
README.md
calls.py
docker-compose.yml
requirements.txt
settings.py

Actually, the only file we need to modify here is calls.py. All the routes used to send requests and responses for our application are here.

Modifying Routes

The calls.py file contains a single route—answer—that the application uses to greet its users and send a text message.

Let’s take a look at the route and see what, where, and how should be modified.

I. answer Route

We modify the answer route like this:

  1. The answer route uses the VoiceResponse() class to build the TwiML response to the call. In FlexML we do not need it, so we can remove this line.

  2. The next code portion to change is the way the application gets the data from the call. Twilio sends the call data in the form of an immutable MultiDict. In CarrierX, it is pure JSON, which you can receive and parse using the common Flask request module. Refer to the code below to see how we replace the definition of the caller and twilio_number variables. We additionally rename the twilio_number variable to carrierx_number to reflect our migration.

  3. We use the send_sms() function as a part of the application response to the caller, so we create a new sms_response variable and assign it to this function. Refer to the section below for more information on how we edit the send_sms() function.

  4. Before returning the response, TwiML needs to form the final response code using resp.say. In FlexML, we do this inside the return statement, so we remove this line.

  5. Finally, we return the resulting response to the call with the return statement using the FlexML Say verb. We also include the sms_response variable, we created earlier, into the response.

TwiML Python Code

@app.route("/answer", methods=['GET', 'POST'])
def answer():
    resp = VoiceResponse()

    caller = request.values.get('From')
    twilio_number = request.values.get('To')
    send_sms(caller, twilio_number)

    resp.say("Thanks for calling! We just sent you a text with a clue.",
             voice='alice')

    return str(resp)

Corresponding FlexML Python Syntax

@app.route("/answer", methods=['GET', 'POST'])
def answer():
    data = request.get_json()
    caller = data.get('From','')
    carrierx_number = data.get('To','')
    sms_response = send_sms(caller, carrierx_number)

    return f'''
        <Response>
            {sms_response}
            <Say voice="woman">Thanks for calling! We just sent you a text with a clue.</Say>
        </Response>'''

II. send_sms() Function

We change the send_sms() function the following way:

  1. In FlexML, we do not need any additional actions to send a text message in response to the incoming call. So we simply replace the Twilio logic with the FlexML Sms syntax that sends messages for us using the To and From phone numbers, and return it to the answer route.

TwiML Python Code

def send_sms(to_number, from_number):
    client = Client(ACCOUNT_SID, AUTH_TOKEN)

    try:
        client.messages.create(
            body="There's always money in the banana stand.",
            from_=from_number,
            to=to_number
        )
    except TwilioRestException as exception:
        if exception.code == 21614:
            print("Uh oh, looks like this caller can't receive SMS messages.")

Corresponding FlexML Python Syntax

def send_sms(to_number, from_number):
    return f'<Sms from="{from_number}" to="{to_number}">There\'s always money in the banana stand.</Sms>'

Finishing Migration

Now that we modified the routes and functions, we can safely remove the Twilio libraries import declaration from the beginning of the calls.py file, as well as the import of the ACCOUNT_SID and AUTH_TOKEN system variables:

from twilio.twiml.voice_response import VoiceResponse
from twilio.rest import Client
from twilio.base.exceptions import TwilioRestException

from settings import ACCOUNT_SID, AUTH_TOKEN
from flask import Flask, request

app = Flask(__name__)

@app.route("/answer", methods=['GET', 'POST'])
def answer():
    data = request.get_json()
    caller = data.get('From','')
    carrierx_number = data.get('To','')
    sms_response = send_sms(caller, carrierx_number)

    return f'''
        <Response>
            {sms_response}
            <Say voice="woman">Thanks for calling! We just sent you a text with a clue.</Say>
        </Response>'''

def send_sms(to_number, from_number):
    return f'<Sms from="{from_number}" to="{to_number}">There\'s always money in the banana stand.</Sms>'

if __name__ == "__main__":
    app.run(debug=True, host='0.0.0.0')

You can also remove the importing of Twilio modules from the requirements.txt file.

Follow the instructions from the application GitHub page to run the application. Then associate the application with the CarrierX phone number, and call that number to check how the application works.

Further Reading

You have successfully migrated the Send SMS During Calls application from TwiML to FlexML!

Refer to the following pages to learn more about FlexML verbs and how to use them, and about ways to set up a FlexML endpoint:

Use our Migrating from Twilio to CarrierX Quick Start to learn more about other difficulties you can meet while migrating from Twilio to CarrierX and the ways to solve these issues.

Read other instructions on real-case migrations from Twilio to CarrierX here:

Refer to our other quick starts for instructions on how to work with CarrierX: