[{"data":1,"prerenderedAt":177},["ShallowReactive",2],{"blog-blueprints/twilio-integration":3},{"id":4,"title":5,"body":6,"category":157,"date":158,"dateModified":158,"description":159,"draft":160,"extension":161,"faq":162,"featured":160,"headerVariant":163,"image":162,"keywords":162,"meta":164,"navigation":165,"ogDescription":166,"ogTitle":162,"path":167,"readTime":168,"schemaOrg":169,"schemaType":170,"seo":171,"sitemap":172,"stem":173,"tags":174,"twitterCard":175,"__hash__":176},"blog/blog/blueprints/twilio-integration.md","Twilio Integration Security Guide",{"type":7,"value":8,"toc":146},"minimark",[9,20,24,30,35,50,54,63,67,76,85,89,94,97,100,103,106,109,120,134],[10,11,12],"blueprint-summary",{},[13,14,15,19],"p",{},[16,17,18],"strong",{},"To secure Twilio integration,"," you need to: (1) validate webhook signatures using validateRequest() on all incoming Twilio webhooks, (2) implement rate limiting by phone number AND IP to prevent SMS pumping fraud, (3) store credentials (Account SID, Auth Token) in environment variables only, (4) configure geographic permissions in Twilio console to block high-risk regions, and (5) use HTTPS for all webhook URLs. This blueprint prevents costly abuse of your SMS/voice infrastructure.",[21,22],"blueprint-meta",{"time":23},"1-2 hours",[25,26,27],"tldr",{},[13,28,29],{},"Twilio webhooks must be validated to prevent spoofing. Use validateRequest() for all incoming webhooks, implement rate limiting to prevent SMS pumping fraud, keep credentials server-side only, and use geographic permissions to limit abuse.",[31,32,34],"h2",{"id":33},"webhook-validation-twilio","Webhook Validation Twilio",[36,37,39],"code-block",{"label":38},"app/api/twilio/sms/route.ts",[40,41,46],"pre",{"className":42,"code":44,"language":45},[43],"language-text","import twilio from 'twilio'\n\nconst authToken = process.env.TWILIO_AUTH_TOKEN!\n\nexport async function POST(req: Request) {\n  const url = req.url\n  const signature = req.headers.get('x-twilio-signature')!\n\n  const formData = await req.formData()\n  const params: Record\u003Cstring, string> = {}\n  formData.forEach((value, key) => {\n    params[key] = value.toString()\n  })\n\n  // Validate the request came from Twilio\n  const isValid = twilio.validateRequest(authToken, signature, url, params)\n\n  if (!isValid) {\n    console.error('Invalid Twilio webhook signature')\n    return new Response('Forbidden', { status: 403 })\n  }\n\n  // Process the verified webhook\n  const from = params.From\n  const body = params.Body\n\n  console.log(`SMS from ${from}: ${body}`)\n\n  // Return TwiML response\n  const twiml = new twilio.twiml.MessagingResponse()\n  twiml.message('Thanks for your message!')\n\n  return new Response(twiml.toString(), {\n    headers: { 'Content-Type': 'text/xml' },\n  })\n}\n","text",[47,48,44],"code",{"__ignoreMap":49},"",[31,51,53],{"id":52},"sending-sms-securely","Sending SMS Securely",[36,55,57],{"label":56},"lib/twilio.ts",[40,58,61],{"className":59,"code":60,"language":45},[43],"import twilio from 'twilio'\n\nconst client = twilio(\n  process.env.TWILIO_ACCOUNT_SID!,\n  process.env.TWILIO_AUTH_TOKEN!\n)\n\nexport async function sendVerificationCode(\n  phoneNumber: string,\n  code: string\n) {\n  // Rate limit before sending\n  const recentAttempts = await getRecentAttempts(phoneNumber)\n  if (recentAttempts > 3) {\n    throw new Error('Too many verification attempts')\n  }\n\n  await client.messages.create({\n    body: `Your verification code is: ${code}`,\n    from: process.env.TWILIO_PHONE_NUMBER!,\n    to: phoneNumber,\n  })\n\n  await recordAttempt(phoneNumber)\n}\n",[47,62,60],{"__ignoreMap":49},[31,64,66],{"id":65},"sms-pumping-prevention","SMS Pumping Prevention",[36,68,70],{"label":69},"lib/sms-protection.ts",[40,71,74],{"className":72,"code":73,"language":45},[43],"import { Ratelimit } from '@upstash/ratelimit'\nimport { Redis } from '@upstash/redis'\n\nconst ratelimit = new Ratelimit({\n  redis: Redis.fromEnv(),\n  limiter: Ratelimit.slidingWindow(3, '1 h'),  // 3 per hour\n  analytics: true,\n})\n\nexport async function canSendSms(phoneNumber: string, ip: string) {\n  // Rate limit by phone number\n  const phoneLimit = await ratelimit.limit(`sms:phone:${phoneNumber}`)\n  if (!phoneLimit.success) return false\n\n  // Rate limit by IP\n  const ipLimit = await ratelimit.limit(`sms:ip:${ip}`)\n  if (!ipLimit.success) return false\n\n  // Block high-risk country codes (configure based on your needs)\n  const blockedPrefixes = ['+882', '+883']  // Satellite phones\n  if (blockedPrefixes.some(p => phoneNumber.startsWith(p))) {\n    return false\n  }\n\n  return true\n}\n",[47,75,73],{"__ignoreMap":49},[77,78,79],"warning-box",{},[13,80,81,84],{},[16,82,83],{},"SMS pumping is expensive."," Attackers can trigger thousands of SMS messages to premium-rate numbers. Always rate limit by phone number AND IP, and configure geographic permissions in your Twilio console.",[31,86,88],{"id":87},"security-checklist","Security Checklist",[90,91,93],"h4",{"id":92},"pre-launch-checklist","Pre-Launch Checklist",[13,95,96],{},"Webhook signatures validated",[13,98,99],{},"Credentials stored in environment variables",[13,101,102],{},"Rate limiting implemented",[13,104,105],{},"Geographic permissions configured",[13,107,108],{},"Webhook URL uses HTTPS",[110,111,112,117],"stack-comparison",{},[113,114,116],"h3",{"id":115},"related-integration-stacks","Related Integration Stacks",[13,118,119],{},"SendGrid Email Integration\nStripe Webhook Patterns\nEdge Rate Limiting",[121,122,123,129],"related-articles",{},[124,125],"related-card",{"description":126,"href":127,"title":128},"Email security","/blog/blueprints/sendgrid-integration","SendGrid Integration",[124,130],{"description":131,"href":132,"title":133},"Deep dive","/blog/best-practices/api-design","API Security Guide",[135,136,139,143],"cta-box",{"href":137,"label":138},"/","Start Free Scan",[31,140,142],{"id":141},"check-your-twilio-integration","Check Your Twilio Integration",[13,144,145],{},"Scan for webhook and credential issues.",{"title":49,"searchDepth":147,"depth":147,"links":148},2,[149,150,151,152,156],{"id":33,"depth":147,"text":34},{"id":52,"depth":147,"text":53},{"id":65,"depth":147,"text":66},{"id":87,"depth":147,"text":88,"children":153},[154],{"id":115,"depth":155,"text":116},3,{"id":141,"depth":147,"text":142},"blueprints","2026-02-12","Security guide for Twilio SMS and voice integration. Validate webhook signatures, protect API credentials, prevent SMS pumping, and secure your Twilio implementation.",false,"md",null,"purple",{},true,"Secure Twilio SMS and voice integration patterns.","/blog/blueprints/twilio-integration","10 min read","[object Object]","Article",{"title":5,"description":159},{"loc":167},"blog/blueprints/twilio-integration",[],"summary_large_image","DCbf3naxkDbI3zWJH_cOxiw7sjz8d7URuL9kW29kUSM",1775843932024]