Paul's Internet Landfill/ 2015/ Routing an IVR in FusionPBX

Routing an IVR in FusionPBX

I'm not going to lie. I found the process of getting an external number to route to an interactive voice response (aka IVR, aka "auto attendant") menu was really really frustrating. It is supposed to be the simplest thing in FusionPBX, but I banged my head against it for tens of hours.

The version of FusionPBX is still 3.7.1 running on Debian Wheezy.

Here is what I have learned the hard way.

IVRs and IVR Menus

FreeSWITCH has the concept of an "IVR" and a concept of an "IVR Menu". These are not the same thing. An IVR is a program. It can do anything, but most commonly it contains the logic about how to read telephone button presses, transfer extensions, and so on.

An "IVR Menu" is a special kind of configuration file that contains settings to use for a particular organization: what prompts should play, what should happen when users press numbers, and so on. It does NOT contain logic about how to actually process button presses.

FreeSWITCH comes with an IVR called the "demo IVR", which is associated with extension 5000. It is written as a series of XML commands. For FusionPBX, ignore this file. FusionPBX does not use it, and you should probably not try to create your own IVR (in XML or Javascript or anything else). Instead, FusionPBX comes with its own IVR program written in Lua (on my system, this is in /usr/local/freeswitch/scripts/ivr_menu.lua (aka scripts/ivr_menu.lua).

The next lesson is that you never call the ivr command directly in FusionPBX. In FreeSWITCH you need to make a dialplan entry that calls an IVR. FusionPBX handles this for you (in a confusing way).

FusionPBX has some GUI to help you make IVR menus. Since FusionPBX 3.3, the project went off the rails and implemented the IVR menu functionality completely differently from standard FreeSWITCH. In standard FreeSWITCH, you add XML files to the conf/ivr_menus folder to indicate which IVR menus exist, and use a command called ivr in your incoming routes to call this IVR. This does not apply in FusionPBX. Instead, IVR menus are stored in the FusionPBX database, and the ivr_menu.lua script queries the database dynamically, as documented here: https://code.google.com/p/fusionpbx/issues/detail?id=474&can=1&q=ivr_menu .

If you try to make a dialplan that uses the ivr command you will end up with errors like the following in the FreeSWITCH logs:

sofia/external/5195551234@64.4.6.100 ivr(aa_test01_ivr) 
6deabebc-ac2b-11e4-869d-5b1cf34b86ba 2015-02-04 00:05:26.759537 [ERR] mod_dptools.c:1959 Unable to find menu

and you will tear your hair out trying to make stupid FusionPBX find the menu.

Creating a Working IVR

I found getting an IVR to work with an inbound route to be tricky and frustrating, but I am dumber than you (and apparently everybody else who uses FusionPBX). Here are the steps that worked for me:

This should be enough to get you going.

If you look at the dialplan after creating it you will see that the Number is blank, but that there are the following settings:

The transfer is the hard part, because the IVR menu XML file is created in the default context, and the dialplan is created in the public context. Connecting the two took me a long time to figure out.

XML Files

Here are the XML files that get created as a result:

In conf/dialplan/default/333_v_<ivr_menu_name>.xml is the IVR menu entry, where <ivr_menu_name> is the name you assigned to the IVR menu. Mine looks something like this:

<extension name="aa_test01_ivr" >
   <condition field="destination_number" expression="^998$" >
       <action application="answer" />
       <action application="sleep" data="1000" />
       <action application="set" data="hangup_after_bridge=true" />
       <action application="set" data="ringback=${hold_music}" />
       <action application="set" data="transfer_ringback=${hold_music}" />
       <action application="set" data="ivr_menu_uuid=5lkgh1f4-b979-4754-b656-2448b72805ac" />
   <action application="lua" data="ivr_menu.lua" />
   </condition>
</extension>

You can see that FusionPBX does not use the ivr command at all, but rather calls a custom IVR program manually. The "998" is the extension I gave this IVR menu entry.

<extension name="aa_test02_dialplan" >
   <condition field="context" expression="public" />
   <condition field="destination_number" expression="5195551234" >
       <action application="set" data="call_direction=inbound"/>
       <action application="set" data="domain_uuid=5567619e-af21-4a14-9f78-857da972104b"/>
       <action application="set" data="domain_name=nb-freeswitch"/>
       <action application="set" data="domain=nb-freeswitch"/>
       <action application="transfer" data="998 XML default" />
   </condition>
</extension>

"5195551234" was the incoming DID I was matching against. You can see the magical "transfer" line at the end of the dialplan.

This stuff is supposed to be easy, but it's hard for me! I hope that by writing this out somebody else can benefit from my suffering.