Skip to main content

Twilio Integration

🎯 Overview

The Twilio integration enables DashClicks to provide SMS messaging, voice calling, and phone number management capabilities through Twilio's communications platform. It supports bulk SMS sending, call handling, phone number provisioning, regulatory compliance, and A2P (Application-to-Person) messaging registration.

Provider: Twilio (https://www.twilio.com)
API Version: Twilio REST API
Integration Type: REST API with SDK (twilio-node) + WebSocket for real-time events

📁 Directory Structure

Documentation Structure:

twilio/
├── 📄 index.md - Twilio integration overview and setup
├── 📄 sms.md - SMS messaging (bulk sending, status tracking)
├── 📄 calls.md - Voice calls (making, managing, retrieving)
├── 📄 numbers.md - Phone number management (purchase, configuration)
├── 📄 subaccounts.md - Subaccount management for multi-tenancy
├── 📄 account.md - Account information and balance
├── 📄 regulatory-compliance.md - Regulatory bundles and compliance
├── 📄 a2p.md - A2P brand and campaign registration
├── 📄 addresses.md - Address validation and management
└── 📄 pricing.md - Pricing information for SMS/voice

Source Code Location:

  • Base Path: external/Integrations/Twilio/
  • Providers: Providers/ (9 provider files with business logic)
  • Controllers: Controllers/
  • Routes: Routes/
  • Models: Models/ (Twilio-specific models)
  • Utilities: Utils/
  • Validations: Validations/

🗄️ MongoDB Collections

📚 Detailed Schema: See Database Collections Documentation

twilio-number

  • Purpose: Store purchased Twilio phone numbers and configuration
  • Model: external/Integrations/Twilio/Models/twilio-number.js
  • Primary Use: Track phone numbers, SMS URLs, and associations
  • Key Fields:
    • phoneNumber - E.164 formatted phone number
    • sid - Twilio phone number SID
    • smsUrl - Webhook URL for incoming SMS
    • accountSid - Twilio account/subaccount SID
    • friendlyName - Display name

Twilio-Specific Collections

  • twilio-calls - Call records and metadata
  • twilio-messages - SMS message history
  • twilio-subaccounts - Subaccount management
  • twilio-regulatory-bundles - Compliance bundle tracking
  • twilio-a2p-campaigns - A2P campaign registrations

🔐 Authentication & Configuration

Authentication Method: HTTP Basic Auth (Account SID + Auth Token)

Required Environment Variables:

VariableDescriptionRequired
TWILIO_ACCOUNT_SIDMaster Twilio account SID
TWILIO_AUTH_TOKENMaster Twilio auth token
TWILIO_SMS_URLWebhook URL for incoming SMS
TWILIO_VOICE_URLWebhook URL for incoming calls

Authentication Pattern:

const Twilio = require('twilio');

// Using account-specific credentials (multi-tenant)
const client = Twilio(accountSID, authToken);

// Master account (development)
const client = Twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);

Multi-Tenant Pattern:

All Twilio Provider functions accept accountSID and authToken as parameters, enabling multi-tenant architecture where each DashClicks client can have their own Twilio subaccount.

🏗️ Architecture Overview

Key Responsibilities:

  • SMS Messaging: Bulk SMS sending, delivery tracking, status callbacks
  • Voice Calls: Outbound calls, call management, call logs
  • Phone Numbers: Purchase, configure, release phone numbers
  • Subaccounts: Create and manage Twilio subaccounts for clients
  • Regulatory Compliance: Manage regulatory bundles for compliance
  • A2P Messaging: Brand and campaign registration for 10DLC
  • Address Management: Validate and store addresses for compliance
  • Pricing: Retrieve SMS and voice pricing by country

API Communication Pattern:

  • REST API via Twilio SDK (twilio-node)
  • WebSocket for real-time events (socket.js provider)
  • Webhook callbacks for async events (SMS delivery, call status)
  • Account SID + Auth Token authentication

Multi-Tenant Architecture:

graph TB
A[DashClicks Client 1] -->|Subaccount 1| B[Twilio Subaccount 1]
C[DashClicks Client 2] -->|Subaccount 2| D[Twilio Subaccount 2]
E[DashClicks Client 3] -->|Subaccount 3| F[Twilio Subaccount 3]
B --> G[Twilio Master Account]
D --> G
F --> G
G -->|Messages/Calls| H[Carriers/Recipients]

Rate Limiting:

  • Twilio enforces API rate limits (varies by account tier)
  • SMS sending: Typically 1-10 messages per second
  • No explicit rate limiting in code - relies on Twilio's limits
  • Recommendation: Implement queuing for bulk SMS

🔗 Features & Capabilities

Core Features

🔄 Integration Data Flow

SMS Sending Flow

sequenceDiagram
participant DC as DashClicks API
participant SMSProvider as SMS Provider
participant TwilioClient as Twilio SDK
participant TwilioAPI as Twilio API
participant Recipient

DC->>SMSProvider: sendSms(accountSID, authToken, recipients, from, message)
SMSProvider->>SMSProvider: Create Twilio client

loop For each recipient
SMSProvider->>TwilioClient: messages.create()
TwilioClient->>TwilioAPI: POST /Messages
TwilioAPI->>Recipient: Deliver SMS
TwilioAPI-->>TwilioClient: Message SID + status
TwilioClient-->>SMSProvider: SMS sent
end

SMSProvider->>SMSProvider: Collect results
SMSProvider-->>DC: Return valid/invalid numbers

TwilioAPI->>DC: Status callback (async)
Note over DC: delivered/failed/undelivered

style SMSProvider fill:#e3f2fd
style TwilioAPI fill:#fff4e6

Phone Number Purchase Flow

sequenceDiagram
participant DC as DashClicks API
participant NumberProvider as Number Provider
participant TwilioAPI as Twilio API
participant DB as MongoDB

DC->>NumberProvider: purchaseNumber(accountSID, phoneNumber)
NumberProvider->>TwilioAPI: POST /IncomingPhoneNumbers
Note over NumberProvider,TwilioAPI: Body: phoneNumber, smsUrl, voiceUrl
TwilioAPI-->>NumberProvider: Number purchased (SID)

NumberProvider->>DB: Save to twilio-number
Note over DB: phoneNumber, sid, smsUrl, accountSid

NumberProvider-->>DC: Return number details

style NumberProvider fill:#e3f2fd
style TwilioAPI fill:#fff4e6

🔗 Submodules

🚨 Error Handling

Common Error Scenarios:

  1. Invalid Phone Number Format

    • Error: "The 'To' number is not a valid phone number"
    • Cause: Phone number not in E.164 format
    • Solution: Validate and format as +[country code][number]
  2. Insufficient Balance

    • Error: "Insufficient balance"
    • Cause: Twilio account out of credits
    • Solution: Add funds to Twilio account
  3. Invalid Credentials

    • Status: 401 Unauthorized
    • Cause: Invalid Account SID or Auth Token
    • Solution: Verify credentials
  4. Rate Limit Exceeded

    • Status: 429 Too Many Requests
    • Cause: Exceeded API rate limits
    • Solution: Implement backoff and retry logic
  5. Unverified Phone Number

    • Error: "The number is unverified"
    • Cause: Trial account trying to send to unverified number
    • Solution: Verify number or upgrade account

📊 Monitoring & Logging

  • SMS Status Callbacks: Webhook for delivery status
  • Call Status Callbacks: Webhook for call progress
  • Error Logging: Errors returned in Provider responses
  • No Centralized Logging: Each Provider handles errors independently

⚠️ Important Integration Notes

  1. Multi-Tenant: All providers accept accountSID/authToken for subaccount isolation
  2. E.164 Format: Phone numbers must be in E.164 format +[country][number]
  3. Async Callbacks: SMS/call status updates arrive via webhooks
  4. Rate Limits: Twilio enforces rate limits per account tier
  5. Trial Accounts: Limited to verified phone numbers
  6. A2P Registration: Required for high-volume SMS to US numbers
  7. Regulatory Compliance: Some countries require regulatory bundles
  8. Webhook Security: Validate Twilio signature on incoming webhooks
  9. Error Handling: Providers return Promise.resolve/reject patterns
  10. SDK Usage: Uses official twilio-node SDK for API calls

🔧 Quick Start Examples

Send SMS

const smsProvider = require('./Providers/sms-api');

// Send SMS to multiple recipients
const result = await smsProvider.sendSms(
accountSID,
authToken,
['+12125551234', '+12125555678'],
'+12125550100', // From number
'Hello from DashClicks!',
'https://app.dashclicks.com/webhooks/sms-status', // Status callback
);

console.log('Valid numbers:', result.validNumberArr);
console.log('Invalid numbers:', result.invalidNumberArr);
console.log('Sent messages:', result.sentSmsDetails);

Purchase Phone Number

const numberProvider = require('./Providers/number-api');

// Purchase a specific number
const number = await numberProvider.purchaseNumber(
accountSID,
authToken,
'+12125551234',
'https://app.dashclicks.com/webhooks/sms',
'https://app.dashclicks.com/webhooks/voice',
);

console.log('Purchased:', number.phoneNumber);
console.log('SID:', number.sid);

Create Subaccount

const subaccountProvider = require('./Providers/subaccount-api');

// Create subaccount for client
const subaccount = await subaccountProvider.createSubAccount(
masterAccountSID,
masterAuthToken,
'Client Name',
);

console.log('Subaccount SID:', subaccount.sid);
console.log('Auth Token:', subaccount.authToken);

💡 Provider Pattern

All Twilio providers follow a consistent pattern:

// Provider function signature
exports.functionName = async (accountSID, authToken, ...params) => {
try {
// 1. Create Twilio client
const client = Twilio(accountSID, authToken);

// 2. Call Twilio API
const result = await client.resource.method(params);

// 3. Return success
return Promise.resolve(result);
} catch (error) {
// 4. Return error
return Promise.reject(error);
}
};

Benefits:

  • Consistent: All providers use same pattern
  • Multi-Tenant: Each call uses specific account credentials
  • Error Handling: Standardized Promise-based error handling
  • Testable: Easy to mock Twilio SDK

🎯 Use Cases

SMS Marketing Campaigns

// Send bulk SMS campaign
const recipients = await Customer.find({ optedIn: true }).select('phone');
const phoneNumbers = recipients.map(c => c.phone);

const result = await smsProvider.sendSms(
accountSID,
authToken,
phoneNumbers,
twilioNumber,
'Special offer: 50% off this week!',
);

Call Tracking

// Track incoming calls
const calls = await callProvider.getCalls(accountSID, authToken, {
startTime: '2024-01-01',
endTime: '2024-01-31',
});

const callVolume = calls.length;
const totalDuration = calls.reduce((sum, call) => sum + parseInt(call.duration), 0);

Phone Number Provisioning

// Find and purchase local number
const available = await numberProvider.searchAvailableNumbers(accountSID, authToken, 'US', {
areaCode: '212',
limit: 10,
});

const number = await numberProvider.purchaseNumber(
accountSID,
authToken,
available[0].phoneNumber,
smsUrl,
voiceUrl,
);
💬

Documentation Assistant

Ask me anything about the docs

Hi! I'm your documentation assistant. Ask me anything about the docs!

I can help you with:
- Code examples
- Configuration details
- Troubleshooting
- Best practices

Try asking: How do I configure the API?
09:31 AM