Build a Twilio SMS Notification System in Your SaaS (2025 Guide)
Twilio powers SMS, voice, and WhatsApp notifications in thousands of SaaS products. But integrating it properly — with webhooks, error handling, and rate limiting — takes more than copy-pasting their quickstart. Here is everything you need to know.
1. Why Twilio for SaaS (Not Just Transactional Email)
Email open rates hover around 20%. SMS open rates are 98%. If your SaaS sends important alerts — billing failures, security notifications, appointment reminders, or status updates — SMS is the channel that actually gets read.
Twilio gives you:
- Programmable SMS and MMS (global reach, 180+ countries)
- WhatsApp Business API
- Verify API for OTP and two-factor authentication
- Conversations API for in-app messaging
2. Architecture: Where Twilio Lives in Your Stack
Never call the Twilio API directly from the frontend. Always route through your backend. Here is the correct flow:
- User triggers event (payment fails, appointment booked, order shipped)
- Your server queues a notification job (using BullMQ or similar)
- Worker dequeues and calls
client.messages.create() - Twilio delivers the message and posts delivery status to your webhook
- Your webhook handler updates the notification record in your database
This pattern decouples notification delivery from your request/response cycle and gives you reliable retry logic.
3. Set Up Twilio in a Next.js + Supabase SaaS
Install the SDK: npm install twilio. Store credentials as environment variables — never commit them to Git.
Create a utility function:
import twilio from 'twilio';
const client = twilio(
process.env.TWILIO_ACCOUNT_SID,
process.env.TWILIO_AUTH_TOKEN
);
export async function sendSms(to: string, body: string) {
return client.messages.create({
to,
from: process.env.TWILIO_PHONE_NUMBER,
body,
});
}
Call this from a server action or API route, never from a React component.
4. Handling Webhooks for Delivery Status
Twilio POSTs delivery status (delivered, failed, undelivered) to a URL you configure. Set this up in your Twilio console under "Messaging > Phone Numbers > Configure".
Your webhook endpoint should:
- Validate the Twilio signature (
twilio.validateRequest()) - Update the notification record in your database
- Return a 200 with an empty TwiML response
- Handle retries idempotently (Twilio retries on non-200 responses)
5. Phone Number Provisioning for Multi-Tenant SaaS
If each of your customers needs their own Twilio number (common in white-label SMS tools), use Twilio SubAccounts and the Incoming Phone Numbers API to provision numbers programmatically. Charge customers per number per month as a line item in your Stripe subscription.
6. Rate Limiting and Cost Control
SMS costs money. Build rate limiting at three levels:
- Per-user: max N messages per hour per recipient
- Per-tenant: soft and hard caps per billing period
- Global: circuit breakers on your Twilio spend using spend caps in the Twilio console
Always let users opt out. Handle STOP replies automatically — Twilio does this at the platform level for US numbers, but you should also record opt-outs in your database.
7. OTP and Phone Verification with Twilio Verify
Do not build your own OTP system. Use Twilio Verify — it handles code generation, expiry, rate limiting, and delivery automatically.
// Send OTP
await client.verify.v2.services(VERIFY_SERVICE_SID)
.verifications.create({ to: phoneNumber, channel: 'sms' });
// Check OTP
const check = await client.verify.v2.services(VERIFY_SERVICE_SID)
.verificationChecks.create({ to: phoneNumber, code: userCode });
if (check.status === 'approved') {
// Mark phone as verified in your database
}
8. Common Mistakes That Sink Twilio Projects
- Hardcoding credentials in application code
- Not validating webhook signatures (spoofing risk)
- Ignoring opt-out management (legal risk in the US and EU)
- Calling the API synchronously in the request path (latency risk)
- Not testing with Twilio's Magic Numbers before going live
If you need a developer who has integrated Twilio into production SaaS products, I am available on Fiverr and ship projects in 2–4 weeks.
Share this article