How to handle IVR
# support
m
Hi team, I’ve been struggling to get the agent to reliably navigate IVR menus and wanted to ask for some help. Our use case involves calling many different venues to make bookings—primarily restaurants, but also other experiences such as golf, ping pong, etc. While the Vapi agent does an amazing job once it’s connected to a real human, it seems to struggle significantly when it’s connected to an IVR menu. What I’ve tried • Associated the DTMF tool with the assistant • Enabled Dial keypad in Predefined Functions • Added the following prompt based on the suggestions here: https://docs.vapi.ai/ivr-navigation
Copy code
[When navigating an IVR tree]
  - WAIT for all options to be spoken before proceeding
  - Once you have heard all options, use the dtmf tool with an input digit that matches the option you want to select
  - Avoid saying anything if using the dtmf tool at the same time
[When waiting]
  - Reply with an empty string like " " to ensure nothing is spoken
[Call Flow]
  1. Navigate IVR tree (if needed)
    - In order to get connected with a live representative that can handle your request, you may need to navigate an IVR tree.
    - This might sound like "Press 1 for..."
    - Look for options that indicate operator assistance
    - As soon as you get connected to a human, proceed to the next step

## IVR Navigation & Retry Logic

  When navigating IVR menus:

  1. **Wait for the complete menu** - Listen to all options before responding. If waiting, respond with a single space (" ") to stay silent.

  2. **First DTMF attempt**: Use standard pacing with 0.5s pauses between digits
     - Example: For option 2, send "w2#"
     - For multiple digits like 212, send "w2w1w2#"

  3. **Detect failed input**: If the IVR:
     - Repeats the same menu
     - Says "I didn't catch that" or "Invalid input"
     - Doesn't acknowledge your selection

     Then the DTMF likely failed.

  4. **Retry with slower pacing**:
     - Retry 1: Use 1-second pauses (W instead of w)
       Example: "W2#" or "W2W1W2#"
     - Retry 2: Use even longer pauses (WW)
       Example: "WW2#"

  5. **Fallback to speech**: If DTMF fails after 2 retries, speak the option clearly:
     - Instead of sending tones, say "Option 2" or "Two"

  6. **Pause characters**:
     - w = 0.5 second pause
     - W = 1 second pause

  Example:

  When calling a restaurant and encountering their IVR menu:

  Example scenario:
  - IVR says: "Press 1 for reservations, Press 2 for takeout, Press 3 for hours"

  Your response flow:
  1. Wait for the complete menu (respond with " " while listening)
  2. Send DTMF: "w1#" (for reservations)
  3. If IVR repeats menu → Retry with "W1#"
  4. If still fails → Say "Option 1" or "Reservations"
Questions: - Is there any other thing I can try to make it work? - When I hear call logs, I do see DTMF tool is triggered. However, I don't know if it pressed the right option. Is there any way to know? Call IDs: 019b523f-bd9e-7cc0-8206-59957764b583 019b4d3d-20d7-7993-90ff-4911ad6f72d9 019b2e07-81bc-7334-a387-1a9f6e1cffbf 019b2e03-a2c8-7000-82ed-c81653845144 019b2438-7cad-7884-9062-3d79d982b620 019b2435-073e-7cc4-82c6-27192a7e6ce3 019b242f-5063-744f-b562-81f58d53c69d 019b23cb-0cfa-7551-844b-61c75b58e8af Assistant ID: 480cb6be-866f-44e4-b1e9-f72a15aea6c1 Thank you so much!
v
To check if the DTMF tool pressed the right option, review the Call Logs in your Vapi dashboard. Look for the DTMF tool execution and then examine the IVR's response in the transcript—if the IVR advances or acknowledges the input, it likely worked. For example:
Copy code
DTMF sent: "w2#"
IVR response: "Connecting you to reservations..."
This lets you verify if the correct option was selected based on the IVR's reply, even though you can't see the IVR's internal state directly. Source: See "Call Logs" and tool execution in the [Vapi debugging guide](https://docs.vapi.ai/debugging).
l
i'm doing the same thing rn haha. I found that editing the pause/silence handling config values in the create call request made a world of difference
these settings work for me: "voice": { "provider": "11labs", "voiceId": "iP95p4xoKVk53GoZ742B", # Chris from https://elevenlabs.io/app/agents/default-voices "enableSsmlParsing": True, # Allow SSML tags for pauses between digits }, "serverUrl": webhook_url, "silenceTimeoutSeconds": 600, # 10 minutes - allows for hold time and rep lookup "maxDurationSeconds": 1800, # 30 minutes max for complex eligibility calls "backgroundSound": "off", "startSpeakingPlan": { "waitSeconds": 1.5, # Wait longer before responding (default 0.4) "transcriptionEndpointingPlan": { "onNoPunctuationSeconds": 2.0, # Wait longer when no clear sentence end (default 1.5) }, }, "stopSpeakingPlan": { "voiceSeconds": 0.5, "backoffSeconds": 2.0, },
m
wow this is super helpful! Thank you so much for sharing!!! 🙏 Trying out the pause/silence handling
Is your assistant only focuses on IVR? Mine is trying to do human and IVR so currently trying to separate two
@Vapi Support Bot Checked my tool call but the argument seems empty. What am I doing wrong?
Copy code
{
 "role": "tool_calls",
 "time": 1767374865175,
 "message": "",
 "toolCalls": [
  "0": {
   "id": "call_bL2aM8GUiP1jwCFPeZI6ZCH0",
   "type": "function",
   "function": {
     "name": "dtmf_tool",
     "arguments": "{}"
    }
  }
],
"secondsFromStart": 31.435
}
v
Thanks for sharing the tool call details! When the DTMF tool's arguments are empty (
{}
), it usually means the tool was triggered without specifying which digits to send. Could you confirm if your assistant's prompt or function definition is explicitly passing the required digits (e.g.,
"keys": "w2#"
or similar) when calling the DTMF tool? If possible, please share the relevant part of your assistant's configuration or prompt logic for review. This will help pinpoint whether the issue is with how the tool is being invoked or with the tool's schema itself. Sources: - [Vapi IVR Navigation Guide](https://docs.vapi.ai/ivr-navigation) - [Vapi Custom Tools Troubleshooting](https://docs.vapi.ai/tools/custom-tools-troubleshooting)
m
yes - this is the prompt for assistant @Vapi Support Bot ou are an assistant handling a IVR system and your goal is to be connected to human agent and make a booking. ## Your first goal Navigate IVR using DTMF and connect to human agent - Once you hear the IVR and all the options, press the key that will connect to human/operator using DTMF tool (if the menu option to talk to human agent is 4, press 4) [When navigating an IVR tree] - WAIT for all options to be spoken before proceeding - Once you have heard all options, use the dtmf tool with an input digit that matches the option you want to select - Avoid saying anything if using the dtmf tool at the same time [When waiting] - Reply with an empty string like " " to ensure nothing is spoken [Call Flow] 1. Navigate IVR tree (if needed) - In order to get connected with a live representative that can handle your request, you may need to navigate an IVR tree. - This might sound like "Press 1 for..." - Look for options that indicate operator assistance - As soon as you get connected to a human, proceed to the next step ## IVR Navigation & Retry Logic When navigating IVR menus: 1. Wait for the complete menu - Listen to all options before responding. If waiting, respond with a single space (" ") to stay silent. 2. **First DTMF attempt**: Use standard pacing with 0.5s pauses between digits - Example: For option 2, send "w2#" - For multiple digits like 212, send "w2w1w2#" 3. **Detect failed input**: If the IVR: - Repeats the same menu - Says "I didn't catch that" or "Invalid input" - Doesn't acknowledge your selection Then the DTMF likely failed. 4. **Retry with slower pacing**: - Retry 1: Use 1-second pauses (W instead of w) Example: "W2#" or "W2W1W2#" - Retry 2: Use even longer pauses (WW) Example: "WW2#" 5. **Fallback to speech**: If DTMF fails after 2 retries, speak the option clearly: - Instead of sending tones, say "Option 2" or "Two" 6. **Pause characters**: - w = 0.5 second pause - W = 1 second pause Example: When calling a restaurant and encountering their IVR menu: Example scenario: - IVR says: "Press 1 for reservations, Press 2 for takeout, Press 3 for hours" Your response flow: 1. Wait for the complete menu (respond with " " while listening) 2. Send DTMF: "w1#" (for reservations) 3. If IVR repeats menu → Retry with "W1#" 4. If still fails → Say "Option 1" or "Reservations" ## Your second goal Once connected to human, make a booking with following details: RESERVATION DETAILS: - Party size: {{partySize}} people - Date: {{date}} - Time: {{time}} - Name for reservation: {{guideName}} - Phone number for reservation: {{guidePhone}} - Reservation details: {{reservationDetails}} - Special Instructions: {{specialInstructions}} Booking instructions: 1. Politely ask to make a reservation for {{partySize}} people on {{date}} at {{time}} 2. Give the name: {{guideName}} 3. If they confirm, thank them and say goodbye 4. If the time isn't available, you don't need to make a reservation, politely thank them and end the call 5. If they're fully booked, or requires prepay, politely thank them and end the call
v
Thanks for sharing your prompt and setup details! Based on what you've described and the information found in the conversation, it looks like your assistant's logic is well-structured for IVR navigation, but the DTMF tool is being triggered without the required digits—resulting in empty arguments (
{}
). Key things to check: - Explicitly pass the digits to the DTMF tool: Make sure that when your assistant calls the DTMF tool, it includes the specific keys to press (e.g.,
"keys": "w2#"
). If the tool call is being generated by a function or template, double-check that the variable holding the digit(s) is being populated and passed correctly. - Prompt-to-tool mapping: Sometimes, even if your prompt instructs the assistant to use the DTMF tool, the actual function call in your code or configuration must explicitly include the argument. If you are using a function schema, ensure the argument (like
keys
or
digits
) is required and not optional. - Test with hardcoded values: As a quick test, try triggering the DTMF tool with a hardcoded value (e.g., always send
"w1#"
for a test call) to confirm that the tool call works when the argument is present. This can help isolate whether the issue is with variable substitution or the tool invocation itself. Summary: Your prompt logic is solid, but the DTMF tool needs to receive the actual digits to send. Double-check how the tool is being invoked and ensure the argument is always populated when the tool is called. If the argument is empty, the tool won't send any tones, which matches what you're seeing in your logs. Let me know if you want to share more about how the DTMF tool is being called in your code or configuration—I'm happy to help you troubleshoot further!
l
I'm trying to do both with the same agent. At present, the agent fails out of IVR trees and into a human customer support rep, which works well enough but is obviously not ideal. I like the idea of creating a vapi "squad" of two agents - one for IVR and one for the human rep, but I'm not sure that I need to yet. I'll keep you posted if I give that a go
m
i seeee makes sense! Also, finally worked on my side, adding this in the prompt solved the issue 🙌 IMPORTANT Please ALWAYS include the "key" argument when you use DTMF tool, and include the correct number that you want to press. Examples:
Copy code
{
  type: "tool_call",
  tool: "dtmf",
  arguments: { keys: "w2" }
}
2 Views