Skip to main content

Twilio Phone Number Provider

🎯 Overview​

The Number API Provider (Providers/number-api.js) handles phone number operations including searching available numbers, purchasing (provisioning), updating configuration, and releasing numbers.

Source: external/Integrations/Twilio/Providers/number-api.js

Key Capabilities:

  • Search available phone numbers by country/area code
  • Purchase phone numbers (local, toll-free, mobile)
  • Configure SMS/Voice URLs and capabilities
  • Update phone number settings
  • Release (delete) phone numbers
  • Regulatory compliance support (bundle SID, address SID)
  • Get phone number pricing by country
  • List available countries

🔌 Provider Functions​

getList()​

Search for available phone numbers in a specific country and area code.

Signature:

exports.getList = async(
SID,
authToken,
countryCode,
areaCode,
(capabilities = {}),
(type = 'local'),
);

Parameters:

ParameterTypeRequiredDefaultDescription
SIDString✅-Twilio Account SID
authTokenString✅-Twilio Auth Token
countryCodeString✅-ISO 3166-1 alpha-2 country code (US, GB, CA, etc.)
areaCodeString❌-Area code for local/mobile numbers (e.g., '212', '415')
capabilitiesObject❌{}Required capabilities (sms, voice, mms, fax)
typeString❌'local'Number type: 'local', 'mobile', 'toll_free'

Returns:

Promise<
Array<{
friendlyName: string; // "+1 (212) 555-1234"
phoneNumber: string; // "+12125551234" (E.164 format)
lata: string; // Local Access and Transport Area
locality: string; // City name
rateCenter: string; // Rate center location
latitude: string;
longitude: string;
region: string; // State/province code
postalCode: string;
isoCountry: string; // Country code
addressRequirements: string; // "none", "any", "local", "foreign"
beta: boolean;
capabilities: {
voice: boolean;
SMS: boolean;
MMS: boolean;
fax: boolean;
};
}>
>;

Business Logic:

  1. Create Twilio Client

  2. Verify Country Availability

    • Fetches country resource to check supported number types
    • Returns empty array if requested type not available
  3. Search by Number Type

    • Local: Area code optional, returns local numbers
    • Mobile: Mobile numbers (area code optional)
    • Toll-Free: 800, 888, 877, etc. numbers (no area code)
  4. Return Available Numbers

    • Maximum 100 results per request

Example Usage:

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

// Search local numbers in New York (area code 212)
const numbers = await numberProvider.getList(
process.env.TWILIO_ACCOUNT_SID,
process.env.TWILIO_AUTH_TOKEN,
'US',
'212',
{},
'local',
);

console.log('Found numbers:', numbers.length);
numbers.forEach(num => {
console.log(`${num.friendlyName} - ${num.locality}, ${num.region}`);
console.log(`Capabilities: SMS=${num.capabilities.SMS}, Voice=${num.capabilities.voice}`);
});

// Output:
// +1 (212) 555-1234 - New York, NY
// Capabilities: SMS=true, Voice=true
// +1 (212) 555-5678 - New York, NY
// Capabilities: SMS=true, Voice=true

Search Toll-Free Numbers:

// Search toll-free numbers (no area code needed)
const tollFreeNumbers = await numberProvider.getList(
accountSID,
authToken,
'US',
null, // No area code for toll-free
{},
'toll_free',
);

console.log('Toll-free:', tollFreeNumbers[0].phoneNumber);
// Output: +18005551234

Search Mobile Numbers:

// Search mobile numbers in Los Angeles (area code 310)
const mobileNumbers = await numberProvider.getList(
accountSID,
authToken,
'US',
'310',
{},
'mobile',
);

console.log('Mobile:', mobileNumbers[0].phoneNumber);

Data Flow:

sequenceDiagram
participant API as DashClicks API
participant Provider as Number Provider
participant Twilio as Twilio SDK

API->>Provider: getList(countryCode, areaCode, type)
Provider->>Twilio: availablePhoneNumbers(country).fetch()
Twilio-->>Provider: Country resource

alt Number type available
Provider->>Twilio: .local.list() / .mobile.list() / .tollFree.list()
Note over Provider,Twilio: limit: 100, areaCode (if provided)
Twilio-->>Provider: Available numbers array
Provider-->>API: Return numbers
else Type not available
Provider-->>API: Return empty array []
end

style Provider fill:#e3f2fd
style Twilio fill:#fff4e6

addProvisionNumber()​

Purchase (provision) a phone number from Twilio.

Signature:

exports.addProvisionNumber = async(SID, authToken, dataToAdd);

Parameters:

ParameterTypeRequiredDescription
SIDString✅Twilio Account SID
authTokenString✅Twilio Auth Token
dataToAddObject✅Phone number configuration

dataToAdd Object:

FieldTypeRequiredDescription
phoneNumberString✅Phone number to purchase (E.164 format)
friendlyNameString❌Display name for the number
smsUrlString❌Webhook URL for incoming SMS
voiceUrlString❌Webhook URL for incoming calls
smsMethodString❌HTTP method for SMS webhook (GET or POST, default POST)
voiceMethodString❌HTTP method for voice webhook (default POST)
bundleSidString❌Regulatory compliance bundle SID (required for some countries)
addressSidString❌Address SID for compliance (required for some numbers)
emergencyEnabledBoolean❌Enable E911 emergency services
emergencyAddressSidString❌E911 address SID

Returns:

Promise<{
sid: string; // Phone number SID (PN...)
accountSid: string;
friendlyName: string;
phoneNumber: string;
voiceUrl: string;
smsUrl: string;
voiceMethod: string;
smsMethod: string;
capabilities: {
voice: boolean;
SMS: boolean;
MMS: boolean;
fax: boolean;
};
addressRequirements: string;
beta: boolean;
dateCreated: Date;
dateUpdated: Date;
emergencyStatus: string; // "Active" if emergency enabled
emergencyAddressSid: string;
bundleSid: string;
identitySid: string;
origin: string; // "twilio" or "hosted"
status: string; // "in-use"
uri: string;
}>;

Business Logic:

  1. Create Twilio Client

  2. Prepare Provision Data

    • Copy dataToAdd object
    • Handle regulatory compliance (bundleSid, addressSid)
    • Remove internal parameters (countryCode)
  3. Purchase Number via Twilio

    • Calls client.incomingPhoneNumbers.create()
    • Twilio provisions number immediately
  4. Error Handling

    • Enhanced error messages for compliance failures
    • Code 21452: Bundle validation failed
    • Code 21453: Address validation failed

Example Usage:

// Purchase local number with SMS/Voice webhooks
const number = await numberProvider.addProvisionNumber(
process.env.TWILIO_ACCOUNT_SID,
process.env.TWILIO_AUTH_TOKEN,
{
phoneNumber: '+12125551234',
friendlyName: 'Customer Support Line',
smsUrl: 'https://app.dashclicks.com/webhooks/sms',
voiceUrl: 'https://app.dashclicks.com/webhooks/voice',
smsMethod: 'POST',
voiceMethod: 'POST',
},
);

console.log('Purchased:', number.phoneNumber);
console.log('SID:', number.sid); // PN1234567890abcdef
console.log('Status:', number.status); // in-use

Purchase with Regulatory Compliance (Required for some countries):

// Purchase number with regulatory bundle (required for US A2P)
const number = await numberProvider.addProvisionNumber(accountSID, authToken, {
phoneNumber: '+12125551234',
bundleSid: 'BU1234567890abcdef', // From regulatory-compliance provider
addressSid: 'AD1234567890abcdef', // From address provider
smsUrl: 'https://app.dashclicks.com/webhooks/sms',
voiceUrl: 'https://app.dashclicks.com/webhooks/voice',
});

Purchase with Emergency Services:

// Purchase with E911 enabled
const number = await numberProvider.addProvisionNumber(accountSID, authToken, {
phoneNumber: '+12125551234',
emergencyEnabled: true,
emergencyAddressSid: 'AD1234567890abcdef',
voiceUrl: 'https://app.dashclicks.com/webhooks/voice',
});

updateProvisionNumber()​

Update configuration of a purchased phone number.

Signature:

exports.updateProvisionNumber = async(accountSID, authToken, numberSID, dataToUpdate);

Parameters:

ParameterTypeRequiredDescription
accountSIDString✅Twilio Account SID
authTokenString✅Twilio Auth Token
numberSIDString✅Phone number SID (PN...)
dataToUpdateObject✅Fields to update

dataToUpdate Object (all optional):

FieldTypeDescription
friendlyNameStringUpdate display name
smsUrlStringUpdate SMS webhook URL
voiceUrlStringUpdate voice webhook URL
smsMethodStringUpdate SMS HTTP method
voiceMethodStringUpdate voice HTTP method
emergencyEnabledBooleanEnable/disable E911
emergencyAddressSidStringUpdate E911 address

Returns:

Promise<TwilioPhoneNumberInstance>;

Example Usage:

// Update SMS webhook URL
const updated = await numberProvider.updateProvisionNumber(
accountSID,
authToken,
'PN1234567890abcdef',
{
smsUrl: 'https://app.dashclicks.com/v2/webhooks/sms',
voiceUrl: 'https://app.dashclicks.com/v2/webhooks/voice',
},
);

console.log('Updated:', updated.phoneNumber);
console.log('New SMS URL:', updated.smsUrl);

Update Friendly Name:

// Change display name
await numberProvider.updateProvisionNumber(accountSID, authToken, numberSID, {
friendlyName: 'Sales Line - East Coast',
});

deleteProvisionNumber()​

Release (delete) a purchased phone number.

Signature:

exports.deleteProvisionNumber = async(accountSID, authToken, numberSID);

Parameters:

ParameterTypeRequiredDescription
accountSIDString✅Twilio Account SID
authTokenString✅Twilio Auth Token
numberSIDString✅Phone number SID to delete

Returns:

Promise<true>;

Example Usage:

// Release phone number
const result = await numberProvider.deleteProvisionNumber(
accountSID,
authToken,
'PN1234567890abcdef',
);

console.log('Number released:', result); // true

⚠️ WARNING: This permanently releases the number back to Twilio's pool. It may be purchased by another customer immediately.


getPricing()​

Get phone number pricing for a specific country.

Signature:

exports.getPricing = async(SID, authToken, countryCode);

Parameters:

ParameterTypeRequiredDescription
SIDString✅Twilio Account SID
authTokenString✅Twilio Auth Token
countryCodeString✅ISO 3166-1 alpha-2 country code

Returns:

Promise<{
country: string;
isoCountry: string;
phoneNumberPrices: Array<{
type: string; // "local", "mobile", "toll free"
basePrice: string;
currentPrice: string;
}>;
priceUnit: string; // Currency code (USD, GBP, etc.)
url: string;
}>;

Example Usage:

// Get US phone number pricing
const pricing = await numberProvider.getPricing(accountSID, authToken, 'US');

console.log('Country:', pricing.country); // United States
console.log('Currency:', pricing.priceUnit); // USD

// Local number price
const localPrice = pricing.phoneNumberPrices.find(p => p.type === 'local');
console.log('Local number:', localPrice.currentPrice); // 1.00 (per month)

// Toll-free price
const tollFreePrice = pricing.phoneNumberPrices.find(p => p.type === 'toll free');
console.log('Toll-free:', tollFreePrice.currentPrice); // 2.00 (per month)

Pricing by Country:

// Get UK pricing
const ukPricing = await numberProvider.getPricing(accountSID, authToken, 'GB');
console.log('UK Local:', ukPricing.phoneNumberPrices[0].currentPrice); // GBP

// Get Canada pricing
const caPricing = await numberProvider.getPricing(accountSID, authToken, 'CA');
console.log('CA Local:', caPricing.phoneNumberPrices[0].currentPrice); // CAD

availableCountries()​

List all countries where Twilio offers phone numbers.

Signature:

exports.availableCountries = async(accountSID, authToken, limit);

Parameters:

ParameterTypeRequiredDescription
accountSIDString✅Twilio Account SID
authTokenString✅Twilio Auth Token
limitNumber❌Maximum countries to return

Returns:

Promise<
Array<{
country: string; // "United States"
countryCode: string; // "US"
uri: string;
beta: boolean;
subresourceUris: {
local: string; // URI if local numbers available
mobile: string; // URI if mobile numbers available
tollFree: string; // URI if toll-free available
};
}>
>;

Example Usage:

// Get all available countries
const countries = await numberProvider.availableCountries(accountSID, authToken, 100);

console.log('Countries:', countries.length);

countries.forEach(country => {
console.log(`${country.country} (${country.countryCode})`);
console.log(' Local:', !!country.subresourceUris.local);
console.log(' Mobile:', !!country.subresourceUris.mobile);
console.log(' Toll-Free:', !!country.subresourceUris.tollFree);
});

// Output:
// United States (US)
// Local: true
// Mobile: true
// Toll-Free: true
// United Kingdom (GB)
// Local: true
// Mobile: true
// Toll-Free: false

💡 Integration Examples​

Phone Number Purchase Flow​

async function purchasePhoneNumber(countryCode, areaCode) {
// 1. Search available numbers
const available = await numberProvider.getList(
process.env.TWILIO_ACCOUNT_SID,
process.env.TWILIO_AUTH_TOKEN,
countryCode,
areaCode,
{},
'local',
);

if (available.length === 0) {
throw new Error('No available numbers found');
}

// 2. Purchase first available
const number = await numberProvider.addProvisionNumber(
process.env.TWILIO_ACCOUNT_SID,
process.env.TWILIO_AUTH_TOKEN,
{
phoneNumber: available[0].phoneNumber,
friendlyName: `${countryCode} ${areaCode} Number`,
smsUrl: process.env.TWILIO_SMS_URL,
voiceUrl: process.env.TWILIO_VOICE_URL,
},
);

// 3. Store in database
await TwilioNumber.create({
sid: number.sid,
phoneNumber: number.phoneNumber,
friendlyName: number.friendlyName,
accountSid: number.accountSid,
smsUrl: number.smsUrl,
voiceUrl: number.voiceUrl,
capabilities: number.capabilities,
});

return number;
}

Number Search UI​

async function searchNumbers(filters) {
const { countryCode, areaCode, type, capabilities } = filters;

// Search numbers
const numbers = await numberProvider.getList(
accountSID,
authToken,
countryCode,
areaCode,
capabilities,
type,
);

// Format for UI
return numbers.map(num => ({
phoneNumber: num.phoneNumber,
friendlyName: num.friendlyName,
location: `${num.locality}, ${num.region}`,
capabilities: {
sms: num.capabilities.SMS,
voice: num.capabilities.voice,
mms: num.capabilities.MMS,
},
addressRequirements: num.addressRequirements,
}));
}

Update Number Configuration​

async function updateNumberWebhooks(numberSID, smsUrl, voiceUrl) {
const updated = await numberProvider.updateProvisionNumber(accountSID, authToken, numberSID, {
smsUrl,
voiceUrl,
});

// Update database
await TwilioNumber.updateOne({ sid: numberSID }, { smsUrl, voiceUrl });

return updated;
}

Release Unused Numbers​

async function releaseUnusedNumbers() {
// Find numbers not used in last 30 days
const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);

const unusedNumbers = await TwilioNumber.find({
lastUsed: { $lt: thirtyDaysAgo },
});

const released = [];

for (const number of unusedNumbers) {
try {
await numberProvider.deleteProvisionNumber(accountSID, authToken, number.sid);

await TwilioNumber.deleteOne({ _id: number._id });

released.push(number.phoneNumber);
} catch (error) {
console.error(`Failed to release ${number.phoneNumber}:`, error);
}
}

return released;
}

Cost Calculator​

async function calculateMonthlyCost(countryCode, localCount, tollFreeCount) {
// Get pricing
const pricing = await numberProvider.getPricing(accountSID, authToken, countryCode);

// Find prices
const localPrice = parseFloat(
pricing.phoneNumberPrices.find(p => p.type === 'local')?.currentPrice || 0,
);

const tollFreePrice = parseFloat(
pricing.phoneNumberPrices.find(p => p.type === 'toll free')?.currentPrice || 0,
);

// Calculate
const localCost = localPrice * localCount;
const tollFreeCost = tollFreePrice * tollFreeCount;
const totalCost = localCost + tollFreeCost;

return {
currency: pricing.priceUnit,
localCount,
localPrice,
localCost,
tollFreeCount,
tollFreePrice,
tollFreeCost,
totalCost,
};
}

// Usage
const cost = await calculateMonthlyCost('US', 10, 2);
console.log(`Monthly cost: $${cost.totalCost}`);
// Output: Monthly cost: $14.00 (10 local @ $1 + 2 toll-free @ $2)

🚨 Error Handling​

Common Errors​

1. Number Already Purchased

Error: 21452 - Phone number is already owned by another account
  • Cause: Number was purchased by another customer
  • Solution: Search for new available numbers

2. Regulatory Compliance Required

Error: 21452 - Regulatory bundle validation failed
  • Cause: Country requires regulatory bundle (e.g., US A2P)
  • Solution: Create regulatory bundle first, provide bundleSid

3. Address Validation Failed

Error: 21453 - Address validation failed for compliance
  • Cause: Invalid or missing address SID for compliance
  • Solution: Validate address via address provider first

4. Number Not Found

Error: PHONE_NUMBERS_NOT_FOUND - No available numbers found for this country
  • Cause: No numbers available for country/area code combination
  • Solution: Try different area code or country

5. Invalid Country Code

Error: 21401 - Invalid Country Code
  • Cause: Country code not in ISO 3166-1 alpha-2 format
  • Solution: Use 2-letter codes (US, GB, CA, not USA, UK, CAN)

⚡ Performance Considerations​

Search Optimization​

  • Limit: Twilio returns max 100 numbers per request
  • Caching: Consider caching available numbers for 5-10 minutes
  • Fallback: If specific area code unavailable, try nearby area codes

Purchase Flow​

  • Immediate: Number provisioning is synchronous (< 1 second)
  • Atomic: Either succeeds completely or fails (no partial success)
  • Verification: Always verify purchase success before storing in DB

External Resources:

💬

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