Twilio Phone Numbers: Provisioning, Configuration, and Management
In this tutorial, you will learn about Twilio Phone Numbers: Provisioning, Configuration, and Management. We cover key concepts, practical examples, and best practices to help you master this topic.
Twilio phone numbers are virtual telephone numbers that can send and receive SMS and voice calls, with configurable Webhooks for inbound communication and support for geographic number pools.
What You'll Learn
How to search and purchase Twilio phone numbers, configure SMS and voice webhooks, release unused numbers, port existing numbers from other carriers, manage number pools, and set geographic permissions.
Why It Matters
Phone numbers are the foundation of Twilio communications. Choosing the right numbers, configuring them correctly, and managing costs directly impacts deliverability, user experience, and monthly spend.
Real-World Use
DodaTech needs numbers in the US, UK, and India for customer support. They search for numbers with specific area codes, configure SMS and voice webhooks per number, and set up a pool for automatic failover.
flowchart LR
A["Search\nAvailable Numbers"] --> B["Filter by\nArea Code / Country"]
B --> C["Purchase\nNumber"]
C --> D["Configure\nSMS Webhook"]
C --> E["Configure\nVoice Webhook"]
D --> F["Inbound SMS\nReady"]
E --> G["Inbound Voice\nReady"]
F --> H["Production\nUse"]
G --> H
style A fill:#f22f46,color:#fff
style B fill:#dbeafe,stroke:#2563eb
style H fill:#bbf7d0,stroke:#16a34a
Searching and Purchasing Numbers
import os
from twilio.rest import Client
client = Client(
os.environ["TWILIO_ACCOUNT_SID"],
os.environ["TWILIO_AUTH_TOKEN"]
)
# Search local numbers
def search_numbers(country="US", area_code=None, limit=5):
params = {"country": country, "limit": limit}
if area_code:
params["area_code"] = area_code
available = client.available_phone_numbers(country).local.list(**params)
print(f"Found {len(available)} numbers:")
for num in available:
print(f" {num.phone_number} ({num.locality}, {num.region})")
return available
numbers = search_numbers("US", area_code=415)
# Expected output:
# Found 3 numbers:
# +14155551234 (San Francisco, CA)
# +14155555678 (San Francisco, CA)
# +14155559012 (San Francisco, CA)
# Purchase a number
def purchase_number(phone_number, friendly_name=None):
params = {
"phone_number": phone_number,
"sms_url": "https://example.com/sms",
"voice_url": "https://example.com/voice"
}
if friendly_name:
params["friendly_name"] = friendly_name
purchased = client.incoming_phone_numbers.create(**params)
print(f"Purchased: {purchased.phone_number}")
print(f"SID: {purchased.sid}")
print(f"SMS URL: {purchased.sms_url}")
print(f"Monthly cost: ${purchased.bundle_sid or 'Standard'}")
return purchased
# number = purchase_number("+14155551234", "DodaTech Support US")
# Expected output:
# Purchased: +14155551234
# SID: PNxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# SMS URL: https://example.com/sms
# Monthly cost: Standard
Configuring Number Capabilities
# Update number capabilities after purchase
def configure_number(number_sid, sms_url, voice_url, friendly_name=None):
params = {
"sms_url": sms_url,
"sms_method": "POST",
"voice_url": voice_url,
"voice_method": "POST"
}
if friendly_name:
params["friendly_name"] = friendly_name
updated = client.incoming_phone_numbers(number_sid).update(**params)
print(f"Updated: {updated.phone_number}")
print(f" SMS: {updated.sms_url}")
print(f" Voice: {updated.voice_url}")
return updated
# configure_number("PNxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
# "https://example.com/sms",
# "https://example.com/voice",
# "DodaTech Support Hotline")
# Expected output:
# Updated: +14155551234
# SMS: https://example.com/sms
# Voice: https://example.com/voice
# List all owned numbers
def list_owned_numbers():
numbers = client.incoming_phone_numbers.list()
print(f"Total numbers: {len(numbers)}")
for num in numbers:
print(f" {num.phone_number} | {num.friendly_name}")
print(f" SMS: {num.sms_url or 'Not configured'}")
print(f" Voice: {num.voice_url or 'Not configured'}")
print()
# list_owned_numbers()
Releasing Numbers
def release_number(number_sid):
"""Release a phone number (stops billing)."""
deleted = client.incoming_phone_numbers(number_sid).delete()
if deleted:
print(f"Released number SID: {number_sid}")
print("Monthly billing stopped.")
else:
print("Failed to release number.")
return deleted
# release_number("PNxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
# Expected output:
# Released number SID: PNxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# Monthly billing stopped.
# Find numbers not used in 30+ days
def find_unused_numbers(days_unused=30):
from datetime import datetime, timedelta
cutoff = datetime.utcnow() - timedelta(days=days_unused)
numbers = client.incoming_phone_numbers.list()
unused = []
for num in numbers:
# Check if number was ever used
calls = client.calls.list(to=num.phone_number, limit=1)
messages = client.messages.list(to=num.phone_number, limit=1)
if not calls and not messages:
unused.append(num)
print(f"Unused: {num.phone_number}")
return unused
Porting Numbers
# Port an existing number from another carrier
def initiate_port(phone_number, carrier_info):
"""
carrier_info = {
"carrier_name": "Verizon Wireless",
"account_number": "VZW123456",
"account_pin": "1234",
"billing_telephone": "+14155551234",
"address": {
"street": "123 Main St",
"city": "San Francisco",
"state": "CA",
"postal_code": "94105"
}
}
"""
porting = client.porting.ports.create(
phone_number=phone_number,
**carrier_info
)
print(f"Port request: {porting.sid}")
print(f"Status: {porting.status}")
print("Porting takes 5-10 business days.")
return porting
# Expected output:
# Port request: POxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# Status: pending
# Porting takes 5-10 business days.
Common Mistakes
1. Buying Numbers Without Checking Capabilities
Some numbers support SMS only, voice only, or both. Check the capabilities field before purchasing. Use voice, sms, and mms booleans to confirm.
2. Forgetting to Release Unused Numbers
Each number costs $1-2/month. A dozen unused numbers cost $144-288/year. Regularly audit and release unused numbers. Set up automated cleanup scripts.
3. Not Configuring Webhooks at Purchase Time
Numbers purchased without webhooks will silently drop inbound messages and calls. Always set sms_url and voice_url during purchase or immediately after.
4. Porting Without Verifying Eligibility
Not all numbers can be ported. Verify portability using the Twilio Lookup API before initiating the port. Number pool, VoIP, and some toll-free numbers cannot be ported.
5. Using the Wrong Number for Geographic Routing
Sending SMS from a UK number to US customers may appear as international spam. Use numbers local to your recipients for higher deliverability and lower costs.
Practice Questions
- How do you search for available phone numbers in a specific area code?
- What happens if you configure a number without SMS and voice webhooks?
- How do you release a phone number to stop billing?
- What is number porting and how long does it take?
Answers:
- Call
client.available_phone_numbers('US').local.list(area_code=415)to search. Filter by capabilities, SMS, voice, and MMS as needed. - Inbound SMS and calls are silently dropped. The caller may hear silence or the message disappears. Always configure webhooks immediately after purchase.
- Call
client.incoming_phone_numbers(sid).delete()to release. Billing stops immediately. The number returns to the available pool after a short period. - Porting moves an existing number from another carrier to Twilio. It takes 5-10 business days. During porting, service continues on the old carrier until the port completes.
Challenge: Build a number management system: search and purchase 3 numbers in different area codes (415, 212, 312), configure each with unique SMS/voice webhooks, create a number audit that flags unused numbers, implement a port request for an existing number, and generate a monthly cost report.
FAQ
Mini Project
Build a number lifecycle management system: search and purchase 2 numbers with different capabilities, configure SMS and voice webhooks, write an audit script that identifies unused numbers, simulate a number port request, implement a monthly cost tracking report, and set geographic purchase restrictions.
What's Next
Messaging Service — scale SMS sending with pools and failover.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro