Twilio Receive SMS — Handling Incoming Text Messages with Webhooks
In this tutorial, you will learn about Twilio Receive SMS. We cover key concepts, practical examples, and best practices to help you master this topic.
Twilio receives incoming SMS messages by sending an HTTP POST Webhook to your application when someone sends a text to your Twilio number, allowing you to Process messages and respond programmatically.
What You'll Learn
- How to configure your Twilio number for incoming SMS
- How to process incoming SMS Webhooks
- How to respond to SMS with TwiML
Why It Matters
Receiving SMS enables two-way communication: customer support via text, order confirmations via reply, and interactive SMS applications. Twilio's webhook model lets you handle incoming messages with a simple HTTP endpoint.
Real-World Use
DodaTech's support number receives SMS from customers. When a customer texts "STATUS" to the support number, the webhook processes the message, looks up their latest order status, and replies with tracking information — all without human intervention.
Webhook Setup
from flask import Flask, request, Response
from twilio.twiml.messaging_response import MessagingResponse
app = Flask(__name__)
@app.route('/twilio/sms-inbound', methods=['POST'])
def handle_incoming_sms():
# Extract message details
from_number = request.form.get('From')
to_number = request.form.get('To')
body = request.form.get('Body', '').strip()
message_sid = request.form.get('MessageSid')
print(f"Received SMS from {from_number}: {body}")
# Log the incoming message
database.log_incoming_message(
sid=message_sid,
from_number=from_number,
to_number=to_number,
body=body
)
# Create a response
response = MessagingResponse()
response.message(f"Thanks for your message! We received: '{body[:50]}...'")
return Response(str(response), mimetype='text/xml')
Interactive SMS Handler
@app.route('/twilio/sms-interactive', methods=['POST'])
def handle_interactive_sms():
from_number = request.form.get('From')
body = request.form.get('Body', '').strip().upper()
response = MessagingResponse()
if body == 'HELP':
response.message(
"Available commands:\n"
"STATUS - Check your order status\n"
"BALANCE - Check account balance\n"
"SUPPORT - Talk to a human\n"
"STOP - Unsubscribe"
)
elif body == 'STATUS':
orders = database.get_recent_orders(from_number)
if orders:
msg = "Your orders:\n"
for order in orders[:3]:
msg += f"#{order['id']}: {order['status']}\n"
response.message(msg)
else:
response.message("No recent orders found.")
elif body.startswith('SUPPORT'):
database.create_support_ticket(from_number, body)
response.message(
"A support agent will contact you shortly. "
"Your ticket ID: TKT-" + str(int(time.time()))
)
elif body == 'STOP':
database.update_sms_preference(from_number, opted_out=True)
response.message("You've been unsubscribed. Reply START to resubscribe.")
else:
response.message(
"I didn't understand that. Reply HELP for available commands."
)
return Response(str(response), mimetype='text/xml')
Processing Incoming Messages
def parse_sms_command(body, from_number):
"""Parse incoming SMS and determine the action to take"""
body = body.strip().upper()
if body == 'STOP' or body == 'STOPALL' or body == 'UNSUBSCRIBE' or body == 'CANCEL':
return {'action': 'opt_out', 'message': 'You have been unsubscribed.'}
elif body == 'START' or body == 'YES':
return {'action': 'opt_in', 'message': 'You have been resubscribed.'}
elif body == 'HELP' or body == 'INFO':
return {
'action': 'help',
'message': 'Commands: HELP, STATUS, BALANCE, SUPPORT, STOP'
}
elif body.startswith('Y') or body.startswith('YES'):
return {'action': 'confirm', 'message': 'Confirmed!'}
elif body.startswith('N') or body == 'NO':
return {'action': 'decline', 'message': 'Action cancelled.'}
else:
return {'action': 'unknown', 'message': 'Reply HELP for options.'}
Common Mistakes
1. Not Returning TwiML Properly
The webhook must return a text/xml response with valid TwiML. Returning JSON or HTML causes Twilio to retry and potentially mark the message as failed.
2. Forgetting to Acknowledge Opt-Out Keywords
Twilio requires handling of standard opt-out keywords (STOP, STOPALL, UNSUBSCRIBE, CANCEL). Not handling them violates carrier regulations.
3. Slow Webhook Responses
Twilio expects a response within 15 seconds. If your processing takes longer, return an empty 200 response immediately and process asynchronously.
4. Not Validating Twilio Requests
Anyone could send requests to your webhook URL. Validate the Twilio signature to ensure requests actually come from Twilio.
5. Hardcoding the Messaging Service SID
If you use a Messaging Service, messages may come from different numbers. Handle the To parameter dynamically.
Practice Questions
- What HTTP method does Twilio use for incoming SMS webhooks?
- What response format does Twilio expect?
- What standard opt-out keywords must be handled?
- What is the timeout for webhook responses?
- How do you validate that a webhook came from Twilio?
Answers
- POST. 2. TwiML (text/xml). 3. STOP, STOPALL, UNSUBSCRIBE, CANCEL. 4. 15 seconds. 5. Validate the X-Twilio-Signature header using your auth token.
Challenge
Build an interactive SMS chatbot that: handles HELP, STATUS, STOP, and START commands, looks up user data from a database, responds with personalized information, handles opt-out/opt-in according to regulations, and logs all conversations.
FAQ
Mini Project
Build a two-way SMS customer support system: incoming SMS webhook that categorizes messages (support, order status, general inquiry), automated responses for common queries, ticket creation for complex issues, and forwarding to human agents when automated handling fails.
What's Next
- Learn about Twilio Messaging Service for scaling SMS
- Explore Twilio Verify for phone verification
- Continue to Twilio WhatsApp API for business messaging
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro