Complete Phone Number Validation: International Formats and Standards

Master international phone number validation with comprehensive coverage of global formats, standards, and validation techniques.

Complete Phone Number Validation: International Formats and Standards
August 10, 2025
18 min read
Phone Validation

Complete Phone Number Validation: International Formats and Standards


Phone Validation Process

Phone Validation Process


Phone number validation is essential for global applications, requiring deep understanding of international formats, regional variations, and carrier-specific requirements. Proper validation ensures reliable communication while respecting local conventions.


International Phone Standards


Phone number validation relies on established international standards and regional implementations.


E.164 Standard Format


The E.164 standard defines the international public telecommunication numbering plan:

  • Maximum 15 digits including country code
  • No spaces, hyphens, or other formatting
  • Always begins with country code
  • Example: +1234567890123

ITU-T Recommendations


Country Code Assignment

  • ITU-T E.164 assigns country codes
  • 1-3 digit country codes
  • Geographic and non-geographic codes
  • Special service codes

Number Plan Structure

  • Country code + National destination code + Subscriber number
  • Variable length based on country
  • Reserved ranges for special services
  • Mobile vs. fixed-line distinctions

Regional Numbering Plans


North American Numbering Plan (NANP)

  • Countries: US, Canada, Caribbean nations
  • Format: +1 NXX NXX XXXX
  • Area codes and exchange codes
  • Overlay and split planning

European Numbering Plans

  • Variable country code lengths (2-3 digits)
  • Different national number formats
  • Mobile number prefixes vary by country
  • International dialing conventions

International Phone Formats

International Phone Formats


Advanced Validation Techniques


Modern phone validation requires sophisticated techniques beyond basic format checking.


Carrier Intelligence


Mobile Network Code (MNC) Analysis

  • Identify specific mobile carriers
  • Determine network capabilities
  • Assess number portability status
  • Validate against carrier databases

Number Type Classification

  • Mobile vs. fixed-line identification
  • VoIP and virtual number detection
  • Premium rate number identification
  • Toll-free number recognition

// Advanced phone number validation with libphonenumber
import { PhoneNumberUtil, PhoneNumberType, PhoneNumberFormat } from 'google-libphonenumber'

interface PhoneValidationResult {
  isValid: boolean
  isMobile: boolean
  isFixedLine: boolean
  countryCode: string
  nationalNumber: string
  formattedNumber: string
  type: string
  carrier?: string
  errors: string[]
  warnings: string[]
}

class PhoneValidator {
  private phoneUtil: PhoneNumberUtil

  constructor() {
    this.phoneUtil = PhoneNumberUtil.getInstance()
  }

  async validatePhoneNumber(phoneNumber: string, defaultRegion?: string): Promise<PhoneValidationResult> {
    const result: PhoneValidationResult = {
      isValid: false,
      isMobile: false,
      isFixedLine: false,
      countryCode: '',
      nationalNumber: '',
      formattedNumber: '',
      type: '',
      errors: [],
      warnings: []
    }

    try {
      // Parse the phone number
      const number = this.phoneUtil.parseAndKeepRawInput(phoneNumber, defaultRegion || 'US')

      // Check if the number is valid
      if (!this.phoneUtil.isValidNumber(number)) {
        result.errors.push('Invalid phone number format')
        return result
      }

      result.isValid = true

      // Get country code
      result.countryCode = this.phoneUtil.getRegionCodeForNumber(number)

      // Get national number
      result.nationalNumber = this.phoneUtil.getNationalSignificantNumber(number)

      // Format the number in E.164
      result.formattedNumber = this.phoneUtil.format(number, PhoneNumberFormat.E164)

      // Determine number type
      const numberType = this.phoneUtil.getNumberType(number)
      result.type = this.getNumberTypeString(numberType)

      // Check if mobile or fixed line
      result.isMobile = numberType === PhoneNumberType.MOBILE
      result.isFixedLine = numberType === PhoneNumberType.FIXED_LINE

      // Get carrier information if available
      try {
        const carrier = await this.getCarrierInfo(number)
        result.carrier = carrier
      } catch (error) {
        result.warnings.push('Carrier information unavailable')
      }

      // Validate against regional constraints
      const regionValidation = this.validateRegionalConstraints(number, result.countryCode)
      if (!regionValidation.isValid) {
        result.warnings.push(...regionValidation.warnings)
      }

    } catch (error) {
      result.errors.push(`Phone validation failed: ${error.message}`)
    }

    return result
  }

  private getNumberTypeString(type: PhoneNumberType): string {
    switch (type) {
      case PhoneNumberType.MOBILE: return 'mobile'
      case PhoneNumberType.FIXED_LINE: return 'fixed_line'
      case PhoneNumberType.TOLL_FREE: return 'toll_free'
      case PhoneNumberType.PREMIUM_RATE: return 'premium_rate'
      case PhoneNumberType.VOIP: return 'voip'
      case PhoneNumberType.UAN: return 'uan'
      case PhoneNumberType.PAGER: return 'pager'
      case PhoneNumberType.VOICEMAIL: return 'voicemail'
      default: return 'unknown'
    }
  }

  private async getCarrierInfo(number: any): Promise<string | undefined> {
    // In production, integrate with carrier lookup APIs
    // For demo purposes, return mock data
    return 'Verizon Wireless'
  }

  private validateRegionalConstraints(number: any, countryCode: string): {
    isValid: boolean
    warnings: string[]
  } {
    const warnings: string[] = []

    // Example: US numbers should have 10 digits after country code
    if (countryCode === 'US') {
      const nationalNumber = this.phoneUtil.getNationalSignificantNumber(number)
      if (nationalNumber.length !== 10) {
        warnings.push('US phone numbers should have 10 digits')
      }
    }

    // Example: Indian mobile numbers should start with 6,7,8,9
    if (countryCode === 'IN') {
      const nationalNumber = this.phoneUtil.getNationalSignificantNumber(number)
      if (nationalNumber.length === 10) {
        const firstDigit = nationalNumber[0]
        if (!['6', '7', '8', '9'].includes(firstDigit)) {
          warnings.push('Indian mobile numbers should start with 6, 7, 8, or 9')
        }
      }
    }

    return { isValid: warnings.length === 0, warnings }
  }
}

// Usage example
const validator = new PhoneValidator()
const result = await validator.validatePhoneNumber('+1 (555) 123-4567')
console.log(result)
/*
{
  isValid: true,
  isMobile: true,
  isFixedLine: false,
  countryCode: 'US',
  nationalNumber: '5551234567',
  formattedNumber: '+15551234567',
  type: 'mobile',
  carrier: 'Verizon Wireless',
  errors: [],
  warnings: []
}
*/

Real-Time Validation


HLR (Home Location Register) Lookups

  • Query carrier databases directly
  • Verify number assignment status
  • Check roaming and availability
  • Assess delivery capabilities

// HLR lookup service for real-time validation
interface HLRResult {
  isActive: boolean
  isRoaming: boolean
  isPorted: boolean
  carrier: string
  country: string
  mccmnc: string // Mobile Country Code + Mobile Network Code
  originalCarrier?: string
  error?: string
}

class HLRValidator {
  private hlrApiKey: string

  constructor(apiKey: string) {
    this.hlrApiKey = apiKey
  }

  async lookupPhoneNumber(phoneNumber: string): Promise<HLRResult> {
    try {
      // Normalize phone number to E.164
      const normalizedNumber = this.normalizeToE164(phoneNumber)

      // Call HLR API (example with mock response)
      const hlrResponse = await this.callHLRAPI(normalizedNumber)

      return {
        isActive: hlrResponse.status === 'active',
        isRoaming: hlrResponse.roaming || false,
        isPorted: hlrResponse.ported || false,
        carrier: hlrResponse.current_carrier,
        country: hlrResponse.country,
        mccmnc: hlrResponse.mccmnc,
        originalCarrier: hlrResponse.original_carrier
      }
    } catch (error) {
      return {
        isActive: false,
        isRoaming: false,
        isPorted: false,
        carrier: '',
        country: '',
        mccmnc: '',
        error: error.message
      }
    }
  }

  private normalizeToE164(phoneNumber: string): string {
    // Remove all non-digit characters except +
    const cleaned = phoneNumber.replace(/[^d+]/g, '')

    // If it doesn't start with +, assume it's a national number
    if (!cleaned.startsWith('+')) {
      // Add default country code (US in this example)
      return '+1' + cleaned
    }

    return cleaned
  }

  private async callHLRAPI(phoneNumber: string): Promise<any> {
    // In production, make actual API call to HLR provider
    // Example response structure
    return {
      status: 'active',
      roaming: false,
      ported: false,
      current_carrier: 'Verizon Wireless',
      original_carrier: 'Verizon Wireless',
      country: 'US',
      mccmnc: '310004'
    }
  }
}

// Usage in validation pipeline
async function comprehensivePhoneValidation(phoneNumber: string): Promise<{
  isValid: boolean
  basicValidation: PhoneValidationResult
  hlrValidation?: HLRResult
  riskScore: number
}> {
  const validator = new PhoneValidator()
  const hlrValidator = new HLRValidator(process.env.HLR_API_KEY!)

  // Basic validation
  const basicValidation = await validator.validatePhoneNumber(phoneNumber)

  if (!basicValidation.isValid) {
    return {
      isValid: false,
      basicValidation,
      riskScore: 100 // High risk for invalid numbers
    }
  }

  // HLR validation for mobile numbers
  let hlrValidation: HLRResult | undefined
  if (basicValidation.isMobile) {
    hlrValidation = await hlrValidator.lookupPhoneNumber(basicValidation.formattedNumber)
  }

  // Calculate risk score
  let riskScore = 0

  // Invalid HLR status increases risk
  if (hlrValidation && !hlrValidation.isActive) {
    riskScore += 50
  }

  // Roaming might indicate higher risk
  if (hlrValidation?.isRoaming) {
    riskScore += 20
  }

  // Ported numbers might be legitimate but warrant attention
  if (hlrValidation?.isPorted) {
    riskScore += 10
  }

  return {
    isValid: basicValidation.isValid && (!hlrValidation || hlrValidation.isActive),
    basicValidation,
    hlrValidation,
    riskScore: Math.min(100, riskScore)
  }
}

// Example usage
const result = await comprehensivePhoneValidation('+1 555-123-4567')
console.log('Validation result:', result)

Geographic Validation


Location Consistency

  • Cross-reference with IP geolocation
  • Validate against user-provided location
  • Check for impossible geographic combinations
  • Assess travel patterns and timing

Time Zone Analysis

  • Validate against expected time zones
  • Check for consistent usage patterns
  • Assess communication timing
  • Identify potential fraud indicators

// Geographic validation with phone number location intelligence
interface GeoValidationResult {
  isConsistent: boolean
  phoneLocation: {
    country: string
    region: string
    city?: string
    timezone: string
    coordinates?: { lat: number; lon: number }
  }
  ipLocation?: {
    country: string
    region: string
    city?: string
  }
  riskFactors: string[]
  confidence: number // 0-100
}

class PhoneGeoValidator {
  async validateGeographicConsistency(phoneNumber: string, userIP?: string): Promise<GeoValidationResult> {
    const result: GeoValidationResult = {
      isConsistent: true,
      phoneLocation: {
        country: '',
        region: '',
        timezone: ''
      },
      riskFactors: [],
      confidence: 100
    }

    try {
      // Get phone number location
      const phoneLocation = await this.getPhoneLocation(phoneNumber)
      result.phoneLocation = phoneLocation

      // If IP is provided, cross-reference with IP location
      if (userIP) {
        const ipLocation = await this.getIPLocation(userIP)
        result.ipLocation = ipLocation

        // Check for geographic consistency
        const consistency = this.checkGeographicConsistency(phoneLocation, ipLocation)
        result.isConsistent = consistency.isConsistent
        result.riskFactors = consistency.riskFactors
        result.confidence = consistency.confidence
      }

      // Check time zone consistency
      const timezoneValidation = await this.validateTimeZone(phoneLocation.timezone)
      if (!timezoneValidation.isValid) {
        result.riskFactors.push('Inconsistent timezone usage')
        result.confidence -= 20
      }

    } catch (error) {
      result.riskFactors.push('Geographic validation failed')
      result.confidence = 0
    }

    return result
  }

  private async getPhoneLocation(phoneNumber: string): Promise<GeoValidationResult['phoneLocation']> {
    // Extract country code from phone number
    const countryCode = this.extractCountryCode(phoneNumber)

    // In production, use carrier data and location APIs
    const locationData: Record<string, any> = {
      '1': { country: 'US', region: 'North America', timezone: 'America/New_York' },
      '44': { country: 'GB', region: 'Europe', timezone: 'Europe/London' },
      '86': { country: 'CN', region: 'Asia', timezone: 'Asia/Shanghai' },
      '91': { country: 'IN', region: 'Asia', timezone: 'Asia/Kolkata' }
    }

    return locationData[countryCode] || {
      country: 'Unknown',
      region: 'Unknown',
      timezone: 'UTC'
    }
  }

  private async getIPLocation(ip: string): Promise<GeoValidationResult['ipLocation']> {
    // In production, use IP geolocation service
    return {
      country: 'US',
      region: 'California',
      city: 'San Francisco'
    }
  }

  private extractCountryCode(phoneNumber: string): string {
    // Extract country code from international format
    const cleaned = phoneNumber.replace(/[^d+]/g, '')
    if (cleaned.startsWith('+')) {
      // Find the country code (1-4 digits after +)
      const match = cleaned.match(/+(d{1,4})/)
      return match ? match[1] : ''
    }
    return ''
  }

  private checkGeographicConsistency(
    phoneLocation: GeoValidationResult['phoneLocation'],
    ipLocation: GeoValidationResult['ipLocation']
  ): { isConsistent: boolean; riskFactors: string[]; confidence: number } {
    const riskFactors: string[] = []
    let confidence = 100

    // Same country check
    if (phoneLocation.country !== ipLocation.country) {
      riskFactors.push('Phone and IP locations in different countries')
      confidence -= 40
    }

    // Same region check (if available)
    if (phoneLocation.region && ipLocation.region &&
        phoneLocation.region !== ipLocation.region) {
      riskFactors.push('Phone and IP locations in different regions')
      confidence -= 20
    }

    return {
      isConsistent: riskFactors.length === 0,
      riskFactors,
      confidence: Math.max(0, confidence)
    }
  }

  private async validateTimeZone(timezone: string): Promise<{ isValid: boolean; reason?: string }> {
    // Check if current time makes sense for the timezone
    const now = new Date()
    const userTimezone = Intl.DateTimeFormat('en-US', {
      timeZone: timezone,
      timeZoneName: 'short'
    }).formatToParts(now)

    // Basic validation - in production, check for reasonable usage patterns
    return { isValid: true }
  }
}

// Usage example
const geoValidator = new PhoneGeoValidator()
const geoResult = await geoValidator.validateGeographicConsistency(
  '+1 555-123-4567',
  '192.168.1.1'
)
console.log('Geographic validation:', geoResult)
/*
{
  isConsistent: true,
  phoneLocation: { country: 'US', region: 'North America', timezone: 'America/New_York' },
  ipLocation: { country: 'US', region: 'California', city: 'San Francisco' },
  riskFactors: [],
  confidence: 100
}
*/

SMS Delivery Testing

  • Test message delivery capability
  • Verify number reachability
  • Assess delivery timing
  • Monitor delivery status

// SMS delivery testing service
interface SMSTestResult {
  canReceiveSMS: boolean
  deliveryTime: number // milliseconds
  carrier: string
  error?: string
  suggestions?: string[]
}

class SMSTester {
  private smsApiKey: string

  constructor(apiKey: string) {
    this.smsApiKey = apiKey
  }

  async testSMSDelivery(phoneNumber: string): Promise<SMSTestResult> {
    const startTime = Date.now()

    try {
      // Send test SMS (ping)
      const pingResult = await this.sendTestSMS(phoneNumber)

      // Wait for delivery confirmation (typically 5-30 seconds)
      await this.waitForDeliveryConfirmation(phoneNumber)

      const deliveryTime = Date.now() - startTime

      return {
        canReceiveSMS: pingResult.delivered,
        deliveryTime,
        carrier: pingResult.carrier,
        suggestions: pingResult.suggestions
      }
    } catch (error) {
      return {
        canReceiveSMS: false,
        deliveryTime: Date.now() - startTime,
        carrier: '',
        error: error.message
      }
    }
  }

  private async sendTestSMS(phoneNumber: string): Promise<any> {
    // In production, integrate with SMS testing service
    // Mock response for demo
    return {
      delivered: true,
      carrier: 'Verizon Wireless',
      messageId: 'msg_12345'
    }
  }

  private async waitForDeliveryConfirmation(phoneNumber: string): Promise<void> {
    // In production, set up webhook or polling for delivery status
    // For demo, simulate delay
    await new Promise(resolve => setTimeout(resolve, 1000))
  }

  async batchTestSMS(numbers: string[]): Promise<SMSTestResult[]> {
    const results: SMSTestResult[] = []

    // Process in batches to avoid rate limits
    const batchSize = 10
    for (let i = 0; i < numbers.length; i += batchSize) {
      const batch = numbers.slice(i, i + batchSize)

      const batchResults = await Promise.allSettled(
        batch.map(number => this.testSMSDelivery(number))
      )

      // Extract successful results
      batchResults.forEach((result, index) => {
        if (result.status === 'fulfilled') {
          results.push(result.value)
        } else {
          results.push({
            canReceiveSMS: false,
            deliveryTime: 0,
            carrier: '',
            error: result.reason?.message || 'Test failed'
          })
        }
      })

      // Small delay between batches
      if (i + batchSize < numbers.length) {
        await new Promise(resolve => setTimeout(resolve, 1000))
      }
    }

    return results
  }
}

// Integration with validation pipeline
async function validatePhoneWithSMS(phoneNumber: string): Promise<{
  isValid: boolean
  smsTest?: SMSTestResult
  overallRisk: number
}> {
  const smsTester = new SMSTester(process.env.SMS_TEST_API_KEY!)

  try {
    // First do basic validation
    const basicValidation = await comprehensivePhoneValidation(phoneNumber)

    if (!basicValidation.isValid) {
      return {
        isValid: false,
        overallRisk: 100
      }
    }

    // If it's a mobile number, test SMS capability
    if (basicValidation.basicValidation.isMobile) {
      const smsTest = await smsTester.testSMSDelivery(phoneNumber)

      // Calculate overall risk
      let smsRisk = 0
      if (!smsTest.canReceiveSMS) {
        smsRisk += 60
      }
      if (smsTest.deliveryTime > 10000) { // > 10 seconds
        smsRisk += 20
      }

      return {
        isValid: basicValidation.isValid && smsTest.canReceiveSMS,
        smsTest,
        overallRisk: Math.min(100, basicValidation.riskScore + smsRisk)
      }
    }

    return {
      isValid: basicValidation.isValid,
      overallRisk: basicValidation.riskScore
    }

  } catch (error) {
    return {
      isValid: false,
      overallRisk: 100
    }
  }
}

// Usage example
const smsValidation = await validatePhoneWithSMS('+1 555-123-4567')
console.log('SMS validation result:', smsValidation)

Phone Validation Techniques

Phone Validation Techniques


Regional Considerations


Different regions have unique phone number characteristics and validation requirements.


Asia-Pacific Region


China (+86)

  • 11-digit mobile numbers
  • Carrier-specific prefixes
  • Government regulations on validation
  • WeChat integration considerations

India (+91)

  • 10-digit mobile numbers after country code
  • Multiple carrier networks
  • Number portability complexities
  • Regional language considerations

Japan (+81)

  • Complex numbering plan structure
  • Mobile number prefixes 070, 080, 090
  • Carrier-specific services
  • Cultural communication preferences

European Union


GDPR Compliance

  • Privacy requirements for validation
  • Consent mechanisms for processing
  • Data retention limitations
  • Cross-border data transfer rules

Country-Specific Formats

  • Germany: Variable length numbers
  • France: Geographic area codes
  • UK: Complex numbering plan
  • Italy: Mobile prefix variations

Americas


United States (+1)

  • NANP format consistency
  • Area code overlays and splits
  • Carrier number portability
  • Do Not Call registry compliance

Brazil (+55)

  • Mobile numbers with 9th digit
  • Geographic area codes
  • Carrier competition effects
  • Regulatory compliance requirements

Mexico (+52)

  • Recent numbering plan changes
  • Mobile number format updates
  • Cross-border considerations
  • Carrier infrastructure variations

Regional Phone Considerations

Regional Phone Considerations


Implementation Guide


Building robust phone validation requires careful implementation and ongoing maintenance.


Validation Pipeline Architecture


Input Normalization

  • Remove formatting characters
  • Handle international prefixes
  • Standardize to E.164 format
  • Validate character sets

Multi-Stage Validation

1. Format and length validation

2. Country code verification

3. Number plan compliance

4. Carrier and type identification

5. Real-time reachability testing


Result Processing

  • Confidence scoring
  • Error categorization
  • Recommendation generation
  • Audit trail creation

Library and Tool Selection


Google libphonenumber

  • Comprehensive format validation
  • Regular updates for number plans
  • Multi-language support
  • Open source and well-maintained

Commercial APIs

  • Twilio Lookup API
  • Nexmo Number Insight
  • Telesign Phone ID
  • Custom carrier integrations

Performance Optimization


Caching Strategies

  • Cache validation results by number
  • Implement TTL based on number type
  • Use distributed caching for scale
  • Monitor cache hit rates

Batch Processing

  • Process multiple numbers simultaneously
  • Implement rate limiting for APIs
  • Use connection pooling
  • Provide progress tracking

Error Handling


Graceful Degradation

  • Fallback to basic format validation
  • Provide partial results when possible
  • Handle API timeouts appropriately
  • Maintain service availability

User Experience

  • Clear error messages
  • Formatting suggestions
  • Alternative input methods
  • Progressive validation feedback

Implementation Architecture

Implementation Architecture


Quality Assurance and Testing


Validation Accuracy Testing


Test Number Databases

  • Maintain test numbers for each country
  • Include edge cases and special formats
  • Regular updates for number plan changes
  • Automated testing suites

Carrier Integration Testing

  • Test with multiple carriers per country
  • Validate special number types
  • Check error handling scenarios
  • Monitor API response times

Performance Monitoring


Key Metrics

  • Validation accuracy rates
  • API response times
  • Error rates by country
  • User satisfaction scores

Continuous Improvement

  • Regular accuracy assessments
  • User feedback integration
  • Carrier relationship management
  • Technology stack updates


Privacy Requirements


Data Protection

  • Minimize data collection and retention
  • Implement appropriate security measures
  • Provide user control and transparency
  • Support data deletion requests

Consent Management

  • Clear consent for validation activities
  • Opt-out mechanisms where required
  • Age verification for minors
  • Cross-border data transfer compliance

Regulatory Compliance


Telecommunications Regulations

  • Respect local numbering authorities
  • Comply with carrier access rules
  • Follow spam and privacy laws
  • Maintain appropriate licenses

Industry Standards

  • Follow CTIA guidelines (US)
  • Comply with GSMA recommendations
  • Adhere to regional best practices
  • Participate in industry initiatives


Technology Evolution


5G Network Impact

  • Enhanced number portability
  • New service types and capabilities
  • Improved location accuracy
  • Advanced authentication methods

Rich Communication Services (RCS)

  • Enhanced messaging capabilities
  • Business messaging integration
  • Verification and authentication
  • Cross-platform compatibility

Regulatory Changes


Privacy Enhancement

  • Stricter consent requirements
  • Enhanced user control mechanisms
  • Cross-border data restrictions
  • Industry self-regulation initiatives

Number Portability Expansion

  • Easier carrier switching
  • Reduced validation complexity
  • Enhanced user mobility
  • Competitive market effects

Conclusion


Comprehensive phone number validation requires understanding international standards, regional variations, and carrier-specific requirements. Success depends on:


  • Standards compliance with E.164 and regional numbering plans
  • Multi-layered validation combining format, carrier, and reachability checks
  • Regional expertise understanding local requirements and conventions
  • Performance optimization for real-time validation needs
  • Continuous maintenance keeping up with numbering plan changes

Organizations implementing robust phone validation can achieve 95%+ accuracy while ensuring global compatibility and regulatory compliance.


Validate phone numbers globally with our comprehensive Phone Validation API, featuring real-time carrier intelligence and international format support.

Tags:phone-validationinternational-formatse164libphonenumber