Build communication features with Twilio: SMS messaging, voice calls, WhatsApp Business API, and user verification (2FA). Covers the full spectrum from simple notifications to complex IVR systems and multi-channel authentication. Critical focus on compliance, rate limits, and error handling. Use when: twilio, send SMS, text message, voice call, phone verification.
Add this skill
npx mdskills install sickn33/twilio-communicationsComprehensive guide with production-ready patterns for SMS, voice, and 2FA
1---2name: twilio-communications3description: "Build communication features with Twilio: SMS messaging, voice calls, WhatsApp Business API, and user verification (2FA). Covers the full spectrum from simple notifications to complex IVR systems and multi-channel authentication. Critical focus on compliance, rate limits, and error handling. Use when: twilio, send SMS, text message, voice call, phone verification."4source: vibeship-spawner-skills (Apache 2.0)5---67# Twilio Communications89## Patterns1011### SMS Sending Pattern1213Basic pattern for sending SMS messages with Twilio.14Handles the fundamentals: phone number formatting, message delivery,15and delivery status callbacks.1617Key considerations:18- Phone numbers must be in E.164 format (+1234567890)19- Default rate limit: 80 messages per second (MPS)20- Messages over 160 characters are split (and cost more)21- Carrier filtering can block messages (especially to US numbers)222324**When to use**: ['Sending notifications to users', 'Transactional messages (order confirmations, shipping)', 'Alerts and reminders']2526```python27from twilio.rest import Client28from twilio.base.exceptions import TwilioRestException29import os30import re3132class TwilioSMS:33 """34 SMS sending with proper error handling and validation.35 """3637 def __init__(self):38 self.client = Client(39 os.environ["TWILIO_ACCOUNT_SID"],40 os.environ["TWILIO_AUTH_TOKEN"]41 )42 self.from_number = os.environ["TWILIO_PHONE_NUMBER"]4344 def validate_e164(self, phone: str) -> bool:45 """Validate phone number is in E.164 format."""46 pattern = r'^\+[1-9]\d{1,14}$'47 return bool(re.match(pattern, phone))4849 def send_sms(50 self,51 to: str,52 body: str,53 status_callback: str = None54 ) -> dict:55 """56 Send an SMS message.5758 Args:59 to: Recipient phone number in E.164 format60 body: Message text (160 chars = 1 segment)61 status_callback: URL for delivery status webhooks6263 Returns:64 Message SID and status65 """66 # Validate phone number format67 if not self.validate_e164(to):68 return {69 "success": False,70 "error": "Phone number must be in E.164 format (+1234567890)"71 }7273 # Check message length (warn about segmentation)74 segment_count = (len(body) + 159) // 16075 if segment_count > 1:76 print(f"Warning: Message will be sent as {segment_count} segments")7778 try:79 message = self.client.messages.create(80 to=to,81 from_=self.from_number,82 body=body,83 status_callback=status_callback84 )8586 return {87 "success": True,88 "message_sid": message.sid,89 "status": message.status,90 "segments": segment_count91 }9293 except TwilioRestException as e:94 return self._handle_error(e)9596 def _handle_error(self, error: Twilio97```9899### Twilio Verify Pattern (2FA/OTP)100101Use Twilio Verify for phone number verification and 2FA.102Handles code generation, delivery, rate limiting, and fraud prevention.103104Key benefits over DIY OTP:105- Twilio manages code generation and expiration106- Built-in fraud prevention (saved customers $82M+ blocking 747M attempts)107- Handles rate limiting automatically108- Multi-channel: SMS, Voice, Email, Push, WhatsApp109110Google found SMS 2FA blocks "100% of automated bots, 96% of bulk111phishing attacks, and 76% of targeted attacks."112113114**When to use**: ['User phone number verification at signup', 'Two-factor authentication (2FA)', 'Password reset verification', 'High-value transaction confirmation']115116```python117from twilio.rest import Client118from twilio.base.exceptions import TwilioRestException119import os120from enum import Enum121from typing import Optional122123class VerifyChannel(Enum):124 SMS = "sms"125 CALL = "call"126 EMAIL = "email"127 WHATSAPP = "whatsapp"128129class TwilioVerify:130 """131 Phone verification with Twilio Verify.132 Never store OTP codes - Twilio handles it.133 """134135 def __init__(self, verify_service_sid: str = None):136 self.client = Client(137 os.environ["TWILIO_ACCOUNT_SID"],138 os.environ["TWILIO_AUTH_TOKEN"]139 )140 # Create a Verify Service in Twilio Console first141 self.service_sid = verify_service_sid or os.environ["TWILIO_VERIFY_SID"]142143 def send_verification(144 self,145 to: str,146 channel: VerifyChannel = VerifyChannel.SMS,147 locale: str = "en"148 ) -> dict:149 """150 Send verification code to phone/email.151152 Args:153 to: Phone number (E.164) or email154 channel: SMS, call, email, or whatsapp155 locale: Language code for message156157 Returns:158 Verification status159 """160 try:161 verification = self.client.verify \162 .v2 \163 .services(self.service_sid) \164 .verifications \165 .create(166 to=to,167 channel=channel.value,168 locale=locale169 )170171 return {172 "success": True,173 "status": verification.status, # "pending"174 "channel": channel.value,175 "valid": verification.valid176 }177178 except TwilioRestException as e:179 return self._handle_verify_error(e)180181 def check_verification(self, to: str, code: str) -> dict:182 """183 Check if verification code is correct.184185 Args:186 to: Phone number or email that received code187 code: The code entered by user188189 R190```191192### TwiML IVR Pattern193194Build Interactive Voice Response (IVR) systems using TwiML.195TwiML (Twilio Markup Language) is XML that tells Twilio what to do196when receiving calls.197198Core TwiML verbs:199- <Say>: Text-to-speech200- <Play>: Play audio file201- <Gather>: Collect keypad/speech input202- <Dial>: Connect to another number203- <Record>: Record caller's voice204- <Redirect>: Move to another TwiML endpoint205206Key insight: Twilio makes HTTP request to your webhook, you return207TwiML, Twilio executes it. Stateless, so use URL params or sessions.208209210**When to use**: ['Phone menu systems (press 1 for sales...)', 'Automated customer support', 'Appointment reminders with confirmation', 'Voicemail systems']211212```python213from flask import Flask, request, Response214from twilio.twiml.voice_response import VoiceResponse, Gather215from twilio.request_validator import RequestValidator216import os217218app = Flask(__name__)219220def validate_twilio_request(f):221 """Decorator to validate requests are from Twilio."""222 def wrapper(*args, **kwargs):223 validator = RequestValidator(os.environ["TWILIO_AUTH_TOKEN"])224225 # Get request details226 url = request.url227 params = request.form.to_dict()228 signature = request.headers.get("X-Twilio-Signature", "")229230 if not validator.validate(url, params, signature):231 return "Invalid request", 403232233 return f(*args, **kwargs)234 wrapper.__name__ = f.__name__235 return wrapper236237@app.route("/voice/incoming", methods=["POST"])238@validate_twilio_request239def incoming_call():240 """Handle incoming call with IVR menu."""241 response = VoiceResponse()242243 # Gather digits with timeout244 gather = Gather(245 num_digits=1,246 action="/voice/menu-selection",247 method="POST",248 timeout=5249 )250 gather.say(251 "Welcome to Acme Corp. "252 "Press 1 for sales. "253 "Press 2 for support. "254 "Press 3 to leave a message."255 )256 response.append(gather)257258 # If no input, repeat259 response.redirect("/voice/incoming")260261 return Response(str(response), mimetype="text/xml")262263@app.route("/voice/menu-selection", methods=["POST"])264@validate_twilio_request265def menu_selection():266 """Route based on menu selection."""267 response = VoiceResponse()268 digit = request.form.get("Digits", "")269270 if digit == "1":271 # Transfer to sales272 response.say("Connecting you to sales.")273 response.dial(os.environ["SALES_PHONE"])274275 elif digit == "2":276 # Transfer to support277 response.say("Connecting you to support.")278 response.dial(os.environ["SUPPORT_PHONE"])279280 elif digit == "3":281 # Voicemail282 response.say("Please leave a message after283```284285## ⚠️ Sharp Edges286287| Issue | Severity | Solution |288|-------|----------|----------|289| Issue | high | ## Track opt-out status in your database |290| Issue | medium | ## Implement retry logic for transient failures |291| Issue | high | ## Register for A2P 10DLC (US requirement) |292| Issue | critical | ## ALWAYS validate the signature |293| Issue | high | ## Track session windows per user |294| Issue | critical | ## Never hardcode credentials |295| Issue | medium | ## Implement application-level rate limiting too |296
Full transparency — inspect the skill content before installing.