Eedesy
Book Demo
HomeProductsContact
AI Voice Agent
  • Introduction
  • Quick Start
  • Architecture
  • Core Concepts
  • Configuration
  • Creating an Agent
  • Using Templates
  • System Prompt Configuration
  • Language Selection
  • Settings Reference
  • Overview
  • Upload Files (PDF, DOCX)
  • Web Crawling (URLs & Sitemaps)
  • Document Processing
  • RAG Integration
  • Troubleshooting
  • Creating a Campaign
  • CSV Upload & Variables
  • Scheduling & Retry Logic
  • Campaign Analytics
  • Contact Management
  • Uploading Contacts
  • Managing Contacts
  • Call History Enrichment
  • Trial Numbers
  • Purchasing Numbers
  • BYOP Setup
  • Exotel Setup
  • Telephony Providers Guide
  • Credits System
  • Provider Costs Breakdown
  • Usage Analytics
  • Credit Packs
  • Overview
  • Finding Your Workspace ID
  • Common Issues
  • Audio Quality
  • Latency Optimization
  • Error Codes
  • Overview
  • Twilio
  • Exotel
  • Plivo
  • Telnyx
  • WhatsApp
  • WebRTC Browser
  • Overview
  • Deepgram
  • Google Chirp
  • Azure Speech
  • ElevenLabs Scribe
  • AssemblyAI
  • OpenAI Whisper
  • Overview
  • Cartesia
  • ElevenLabs
  • Google TTS
  • Azure Neural
  • OpenAI TTS
  • Deepgram Aura
  • Sarvam Bulbul
  • HeyPixa Luna
  • Overview
  • OpenAI GPT-4o
  • Gemini 2.0/2.5 Flash
  • Gemini Live (Native Audio)
  • OpenAI Realtime
  • Anthropic Claude
  • Azure OpenAI
  • Overview
  • VAD (Voice Activity Detection)
  • Interruption Handling
  • Turn Detection
  • Audio Processing
  • Function Calling
  • Call Transfer
  • DTMF Handling
  • Call Recording
  • Exporting Recordings
  • Transcripts
  • Webhooks
  • Variables & Templates
  • Multi-Language Support
  • Hindi
  • Tamil
  • Assamese
  • Other Indian Languages
  • Latency Optimization
  • Scaling & Performance
  • Error Handling
  • Monitoring & Logging
  • Security Best Practices
  • Trigger Call via API
  • REST API
  • WebSocket Protocol
  • Webhooks
  • Webhook Subscriptions
  • SDKs
  • Overview
  • Financial Services
  • E-commerce
  • Logistics
  • Hyperlocal
  • Healthcare
  • Education
  • Overview
  • Customer Support
  • Sales & Lead Conversion
  • Marketing Campaigns
  • Debt Collection
  • Overview
  • Customer Support Bot
  • Order Status IVR
  • Appointment Booking
  • Lead Qualification
  • Outbound Sales
  • Recruitment Screening
  • Overview
  • Migrate from Vapi
  • Migrate from Retell AI
  • Migrate from Traditional IVR

Related Products

  • AI Voice Agent
  • AI Voice Assistant
  • Try Free
AI Voice Agent
  • Introduction
  • Quick Start
  • Architecture
  • Core Concepts
  • Configuration
  • Creating an Agent
  • Using Templates
  • System Prompt Configuration
  • Language Selection
  • Settings Reference
  • Overview
  • Upload Files (PDF, DOCX)
  • Web Crawling (URLs & Sitemaps)
  • Document Processing
  • RAG Integration
  • Troubleshooting
  • Creating a Campaign
  • CSV Upload & Variables
  • Scheduling & Retry Logic
  • Campaign Analytics
  • Contact Management
  • Uploading Contacts
  • Managing Contacts
  • Call History Enrichment
  • Trial Numbers
  • Purchasing Numbers
  • BYOP Setup
  • Exotel Setup
  • Telephony Providers Guide
  • Credits System
  • Provider Costs Breakdown
  • Usage Analytics
  • Credit Packs
  • Overview
  • Finding Your Workspace ID
  • Common Issues
  • Audio Quality
  • Latency Optimization
  • Error Codes
  • Overview
  • Twilio
  • Exotel
  • Plivo
  • Telnyx
  • WhatsApp
  • WebRTC Browser
  • Overview
  • Deepgram
  • Google Chirp
  • Azure Speech
  • ElevenLabs Scribe
  • AssemblyAI
  • OpenAI Whisper
  • Overview
  • Cartesia
  • ElevenLabs
  • Google TTS
  • Azure Neural
  • OpenAI TTS
  • Deepgram Aura
  • Sarvam Bulbul
  • HeyPixa Luna
  • Overview
  • OpenAI GPT-4o
  • Gemini 2.0/2.5 Flash
  • Gemini Live (Native Audio)
  • OpenAI Realtime
  • Anthropic Claude
  • Azure OpenAI
  • Overview
  • VAD (Voice Activity Detection)
  • Interruption Handling
  • Turn Detection
  • Audio Processing
  • Function Calling
  • Call Transfer
  • DTMF Handling
  • Call Recording
  • Exporting Recordings
  • Transcripts
  • Webhooks
  • Variables & Templates
  • Multi-Language Support
  • Hindi
  • Tamil
  • Assamese
  • Other Indian Languages
  • Latency Optimization
  • Scaling & Performance
  • Error Handling
  • Monitoring & Logging
  • Security Best Practices
  • Trigger Call via API
  • REST API
  • WebSocket Protocol
  • Webhooks
  • Webhook Subscriptions
  • SDKs
  • Overview
  • Financial Services
  • E-commerce
  • Logistics
  • Hyperlocal
  • Healthcare
  • Education
  • Overview
  • Customer Support
  • Sales & Lead Conversion
  • Marketing Campaigns
  • Debt Collection
  • Overview
  • Customer Support Bot
  • Order Status IVR
  • Appointment Booking
  • Lead Qualification
  • Outbound Sales
  • Recruitment Screening
  • Overview
  • Migrate from Vapi
  • Migrate from Retell AI
  • Migrate from Traditional IVR
  1. Docs
  2. AI Voice Agent
  3. Features
  4. DTMF Handling

DTMF Handling

Handle touch-tone input (DTMF) for menu navigation, PIN entry, and phone number collection.

DTMF Handling

DTMF (Dual-Tone Multi-Frequency) allows users to interact using their phone keypad, essential for secure input and menu navigation.

What is DTMF?

Phone Keypad:
┌─────┬─────┬─────┐
│  1  │  2  │  3  │
│     │ ABC │ DEF │
├─────┼─────┼─────┤
│  4  │  5  │  6  │
│ GHI │ JKL │ MNO │
├─────┼─────┼─────┤
│  7  │  8  │  9  │
│PQRS │ TUV │WXYZ │
├─────┼─────┼─────┤
│  *  │  0  │  #  │
│     │     │     │
└─────┴─────┴─────┘

Each key generates a unique tone pair
that can be detected and processed.

Configuration

Enable DTMF

{
  "agent": {
    "name": "IVR Agent",
    "dtmf": {
      "enabled": true,
      "interDigitTimeout": 3000,
      "maxDigits": 20,
      "terminators": ["#"]
    }
  }
}

Configuration Options

Option Type Default Description
enabled bool true Enable DTMF detection
interDigitTimeout int 3000 Max ms between digits
maxDigits int 20 Maximum digits to collect
terminators array ["#"] Keys that end input
minDigits int 1 Minimum digits required

Implementation

DTMF Handler

type DTMFHandler struct {
    buffer     strings.Builder
    lastDigit  time.Time
    timeout    time.Duration
    maxDigits  int
    minDigits  int
    terminators []string
    callback   func(digits string)
}

func (h *DTMFHandler) OnDigit(digit string) {
    h.lastDigit = time.Now()
    h.buffer.WriteString(digit)

    // Check for terminator
    for _, term := range h.terminators {
        if digit == term {
            h.complete()
            return
        }
    }

    // Check max digits
    if h.buffer.Len() >= h.maxDigits {
        h.complete()
        return
    }

    // Start/reset timeout timer
    h.startTimeout()
}

func (h *DTMFHandler) startTimeout() {
    go func() {
        time.Sleep(h.timeout)
        if time.Since(h.lastDigit) >= h.timeout {
            if h.buffer.Len() >= h.minDigits {
                h.complete()
            }
        }
    }()
}

func (h *DTMFHandler) complete() {
    digits := h.buffer.String()
    // Remove terminator if present
    digits = strings.TrimSuffix(digits, "#")
    digits = strings.TrimSuffix(digits, "*")

    h.buffer.Reset()
    h.callback(digits)
}

Integration with Pipeline

func (p *Pipeline) handleDTMF(digit string) {
    // Pause STT during DTMF collection
    if p.collectingDTMF {
        p.dtmfHandler.OnDigit(digit)
        return
    }

    // Single digit actions
    switch digit {
    case "0":
        p.transferToOperator()
    case "*":
        p.repeatLastMessage()
    default:
        // Treat as start of DTMF sequence
        p.startDTMFCollection(digit)
    }
}

Common Use Cases

Menu Navigation

systemPrompt := `You are an IVR assistant.

When presenting options, always say:
"Press 1 for [option], Press 2 for [option]..."

Available menus:
- Main: 1=Orders, 2=Support, 3=Billing, 0=Operator
- Orders: 1=Status, 2=Returns, 3=New Order
- Support: 1=Technical, 2=Account, 3=Other`

func (p *Pipeline) handleMenuDTMF(digit string) {
    menu := p.currentMenu

    switch menu {
    case "main":
        switch digit {
        case "1":
            p.setMenu("orders")
            p.tts.Speak("Orders menu. Press 1 for order status...")
        case "2":
            p.setMenu("support")
            p.tts.Speak("Support menu. Press 1 for technical support...")
        case "0":
            p.transferToOperator()
        }
    case "orders":
        // Handle orders submenu
    }
}

PIN/Password Entry

func (p *Pipeline) collectPIN() string {
    p.tts.Speak("Please enter your 4-digit PIN, followed by the pound key.")

    // Pause recording for security
    p.recorder.Pause()
    defer p.recorder.Resume()

    // Mute STT to avoid PIN in transcript
    p.stt.Mute()
    defer p.stt.Unmute()

    // Collect DTMF
    p.dtmfHandler.Configure(DTMFConfig{
        MinDigits:   4,
        MaxDigits:   4,
        Terminators: []string{"#"},
        Timeout:     10 * time.Second,
    })

    pin := <-p.dtmfHandler.Result()

    return pin
}

Phone Number Collection

func (p *Pipeline) collectPhoneNumber() string {
    p.tts.Speak("Please enter your 10-digit phone number, followed by the pound key.")

    p.dtmfHandler.Configure(DTMFConfig{
        MinDigits:   10,
        MaxDigits:   11, // Allow country code
        Terminators: []string{"#"},
        Timeout:     15 * time.Second,
    })

    phone := <-p.dtmfHandler.Result()

    // Validate
    if len(phone) < 10 {
        p.tts.Speak("I didn't get a complete phone number. Let's try again.")
        return p.collectPhoneNumber()
    }

    // Format and confirm
    formatted := formatPhoneNumber(phone)
    p.tts.Speak(fmt.Sprintf("I have %s. Is that correct? Press 1 for yes, 2 for no.",
        speakPhoneNumber(formatted)))

    confirmation := <-p.dtmfHandler.Result()
    if confirmation == "1" {
        return formatted
    }

    return p.collectPhoneNumber()
}

func speakPhoneNumber(phone string) string {
    // "4 1 5. 5 5 5. 1 2 3 4"
    var parts []string
    for i, digit := range phone {
        if i == 3 || i == 6 {
            parts = append(parts, ".")
        }
        parts = append(parts, string(digit))
    }
    return strings.Join(parts, " ")
}

Credit Card Entry (PCI Compliant)

func (p *Pipeline) collectCardNumber() string {
    p.tts.Speak("For security, please enter your 16-digit card number using your keypad, followed by pound.")

    // Disable recording and transcription
    p.recorder.Pause()
    p.stt.Mute()

    p.dtmfHandler.Configure(DTMFConfig{
        MinDigits:   15, // Some cards have 15 digits
        MaxDigits:   16,
        Terminators: []string{"#"},
        Timeout:     30 * time.Second,
        MaskInput:   true, // Don't log digits
    })

    cardNumber := <-p.dtmfHandler.Result()

    // Re-enable
    p.recorder.Resume()
    p.stt.Unmute()

    // Validate using Luhn algorithm
    if !isValidCardNumber(cardNumber) {
        p.tts.Speak("That doesn't appear to be a valid card number. Let's try again.")
        return p.collectCardNumber()
    }

    // Confirm last 4 digits only
    last4 := cardNumber[len(cardNumber)-4:]
    p.tts.Speak(fmt.Sprintf("Card ending in %s. Is that correct? Press 1 for yes, 2 for no.",
        speakDigits(last4)))

    if <-p.dtmfHandler.Result() == "1" {
        return cardNumber
    }

    return p.collectCardNumber()
}

func isValidCardNumber(number string) bool {
    // Luhn algorithm
    sum := 0
    alternate := false

    for i := len(number) - 1; i >= 0; i-- {
        n := int(number[i] - '0')
        if alternate {
            n *= 2
            if n > 9 {
                n -= 9
            }
        }
        sum += n
        alternate = !alternate
    }

    return sum%10 == 0
}

Provider Integration

Twilio

func (h *TwilioHandler) handleMediaMessage(msg TwilioMediaMessage) {
    if msg.Event == "dtmf" {
        digit := msg.Dtmf.Digit
        h.pipeline.HandleDTMF(digit)
    }
}

Plivo

func (h *PlivoHandler) handleControlMessage(msg PlivoControlMessage) {
    if msg.Event == "dtmf" {
        digit := msg.Digit
        h.pipeline.HandleDTMF(digit)
    }
}

Exotel

func (h *ExotelHandler) handleDTMF(digit string) {
    h.pipeline.HandleDTMF(digit)
}

LLM Integration

Let the LLM handle DTMF naturally:

systemPrompt := `You are a voice assistant with DTMF capability.

When you need numeric input (phone numbers, PINs, account numbers),
ask the user to enter it on their keypad.

Example:
User: "I want to check my account balance"
You: "I can help with that. Please enter your 6-digit account number on your keypad, followed by the pound key."

After receiving DTMF input, you'll get a message like:
[DTMF Input: 123456]

Then continue the conversation naturally.`

func (p *Pipeline) handleDTMFComplete(digits string) {
    // Inject as system message
    p.context.AddMessage(Message{
        Role:    "system",
        Content: fmt.Sprintf("[DTMF Input: %s]", digits),
    })

    // Continue LLM conversation
    p.processWithLLM()
}

Error Handling

func (h *DTMFHandler) handleTimeout() {
    if h.buffer.Len() == 0 {
        h.callback("timeout:no_input")
    } else if h.buffer.Len() < h.minDigits {
        h.callback("timeout:incomplete:" + h.buffer.String())
    } else {
        h.complete()
    }
}

func (p *Pipeline) handleDTMFResult(result string) {
    if strings.HasPrefix(result, "timeout:") {
        if result == "timeout:no_input" {
            p.tts.Speak("I didn't receive any input. Let me repeat that.")
            p.repeatLastPrompt()
        } else {
            p.tts.Speak("I didn't get enough digits. Please try again.")
            p.retryDTMFCollection()
        }
        return
    }

    // Valid input
    p.processDTMFInput(result)
}

Best Practices

1. Clear Instructions

// Good
"Please enter your 10-digit phone number, followed by the pound sign."

// Bad
"Enter your phone number."

2. Confirmation for Important Data

func confirmInput(input, inputType string) bool {
    message := fmt.Sprintf("You entered %s. Press 1 to confirm, or 2 to re-enter.",
        formatForSpeech(input, inputType))
    tts.Speak(message)

    confirmation := waitForDTMF(1)
    return confirmation == "1"
}

3. Timeout Handling

func (p *Pipeline) collectWithRetry(prompt string, config DTMFConfig) (string, error) {
    maxRetries := 3

    for attempt := 0; attempt < maxRetries; attempt++ {
        p.tts.Speak(prompt)
        result := p.collectDTMF(config)

        if !strings.HasPrefix(result, "timeout:") {
            return result, nil
        }

        if attempt < maxRetries-1 {
            p.tts.Speak("I didn't catch that. Let me try again.")
        }
    }

    return "", fmt.Errorf("DTMF collection failed after %d attempts", maxRetries)
}

Next Steps

  • Recording - Pause during sensitive DTMF
  • Call Transfer - Transfer on "0"
  • Security - PCI compliance
Previous
Call Transfer
Next
Call Recording

On this page

  • What is DTMF?
  • Configuration
  • Enable DTMF
  • Configuration Options
  • Implementation
  • DTMF Handler
  • Integration with Pipeline
  • Common Use Cases
  • Menu Navigation
  • PIN/Password Entry
  • Phone Number Collection
  • Credit Card Entry (PCI Compliant)
  • Provider Integration
  • Twilio
  • Plivo
  • Exotel
  • LLM Integration
  • Error Handling
  • Best Practices
  • 1. Clear Instructions
  • 2. Confirmation for Important Data
  • 3. Timeout Handling
  • Next Steps

Stay Updated

Get the latest updates on AI voice technology, product releases, and exclusive resources.

Get Started

Try our products for free
AI Voice Agent
Build voice AI for calls
WhatsApp AI Bot
Automate WhatsApp chats
Website Chatbot
AI chat for websites
Edesy CRM
Manage leads & customers
Book a DemoCall UsEmail Us
Eedesy

Your all-in-one platform for digital innovation. We build AI-powered solutions that transform how businesses operate.

[email protected]+91 95475 31359

Products

  • AI Voice Assistant
  • WhatsApp Voice AI
  • WhatsApp Bot Builder
  • AI Website Chatbot
  • AI-SDR
  • Number Masking
  • Shopify Apps
  • View All Products

Solutions

  • For E-commerce
  • For Healthcare
  • For Real Estate
  • For Restaurants
  • For Appointments
  • View All Use Cases

Services

  • AI Chatbot Development
  • Voice AI Development
  • Shopify Development
  • SaaS Development
  • WhatsApp API Integration
  • View All Services

Resources

  • Documentation
  • Voice Agent Docs
  • API Reference
  • Number Masking API Docs
  • Blog
  • Changelog
  • Book a Demo

Company

  • About Us
  • Contact
  • Careers
  • Privacy Policy
  • Terms of Service

Products

  • AI Voice Assistant
  • WhatsApp Voice AI
  • WhatsApp Bot Builder
  • AI Website Chatbot
  • AI-SDR
  • Number Masking
  • Shopify Apps
  • View All Products

Solutions

  • For E-commerce
  • For Healthcare
  • For Real Estate
  • For Restaurants
  • For Appointments
  • View All Use Cases

Services

  • AI Chatbot Development
  • Voice AI Development
  • Shopify Development
  • SaaS Development
  • WhatsApp API Integration
  • View All Services

Resources

  • Documentation
  • Voice Agent Docs
  • API Reference
  • Number Masking API Docs
  • Blog
  • Changelog
  • Book a Demo

Company

  • About Us
  • Contact
  • Careers
  • Privacy Policy
  • Terms of Service
  • AI Voice Assistant
  • WhatsApp Voice AI
  • WhatsApp Bot Builder
  • AI Website Chatbot
  • AI-SDR
  • Number Masking
  • Shopify Apps
  • View All Products
  • For E-commerce
  • For Healthcare
  • For Real Estate
  • For Restaurants
  • For Appointments
  • View All Use Cases
  • AI Chatbot Development
  • Voice AI Development
  • Shopify Development
  • SaaS Development
  • WhatsApp API Integration
  • View All Services
  • Documentation
  • Voice Agent Docs
  • API Reference
  • Number Masking API Docs
  • Blog
  • Changelog
  • Book a Demo
  • About Us
  • Contact
  • Careers
  • Privacy Policy
  • Terms of Service

Popular Free Tools

Compress PDFMerge PDFPDF to WordGST CalculatorEMI CalculatorSIP CalculatorJSON FormatterBase64 EncoderImage CompressorQR Code GeneratorVoice AI ROI CalculatorAmazon FBA CalculatorAI Email WriterVideo to GIFPrivacy Policy GeneratorCRM ROI CalculatorMeeting Cost Calculator
Categories:PDF ToolsDeveloper ToolsFinance CalculatorsImage ToolsVideo ToolsAI Writing ToolsAudio ToolsWhatsApp ToolsDocument GeneratorsVoice AI ToolsE-commerce ToolsView All Tools

© 2026 Edesy Technology Labs Pvt Ltd

SSL Secured
99.9% Uptime