Creating An IVR Attendant

Whatever method you use to obtain the various prompts and messages that you'll use in your IVR menus, you should lay out a picture of the IVR Attendant menu tree and identify all of the sounds that you'll use at each step of the way. This will help you in obtaining the needed sounds and building the actual dialplan that implements the IVR Attendant. Here is an example of a simple IVR Attendant that we use:

     Daytime (09:00-18:59)
     --> play: thank-you-for-calling
               if-you-know-dial-any-time
               P1-for-dir-or-stay-on
         wait for dialed digits
        --> 0 --> ring the operator
            1 --> goto IVR Directory
            invalid --> play: not-valid-extension
                        retry
            timeout --> play: transfer-to-operator
                        ring the operator
            6XX --> ring the extension
     Nights/Weekend (19:00-08:59)
     --> play: thank-you-for-calling
               at-present-closed
               if-you-know-dial-any-time
               party-no-answer-voicemail
               if-dont-know-P1-for-dir
         wait for dialed digits
        --> 1 --> goto IVR Directory
            invalid --> play: not-valid-extension
                        retry
            timeout --> play: hasta-la-vista
                        hang up
            6XX --> ring the extension
     Vacation (July 4)
     --> play: thank-you-for-calling
               at-present-vacation
               if-you-know-dial-any-time
               party-no-answer-voicemail
               if-dont-know-P1-for-dir
         wait for dialed digits
        --> 1 --> goto IVR Directory
            invalid --> play: not-valid-extension
                        retry
            timeout --> play: hasta-la-vista
                        hang up
            6XX --> ring the extension
     Mental Health Hotline
     --> play: mental-health-hotline
         wait for dialed digits
        --> 1 --> goto IVR Directory
            invalid --> play: not-valid-extension
                        retry
            timeout --> play: hasta-la-vista
                        hang up
            6XX --> ring the extension
     IVR Directory
     --> play: dir-dial-three-letters
         wait for dialed digits
        --> invalid --> play: dir-dont-recognize-name
                        retry
            timeout --> play: goodbye
                        hang up
            2XX --> play: transfer-to-norm-cole
                    ring extension 601
            9XX --> play: transfer-to-ed-wilson
                    ring extension 600

The messages, shown in the menus above, have the following texts:

     at-present-closed -           At present, we are closed.
     at-present-vacation -         At present, we are taking some time off and
                                   are closed for vacation.
     dir-dial-three-letters -      Please dial the first three letters of your
                                   party's last name.
     dir-dont-recognize-name -     I'm sorry.  I don't recognize that person's
                                   name.  Please try again.
     goodbye -                     Goodbye.
     hasta-la-vista -              Hasta la vista, baby.
     if-you-know-dial-any-time -   If you know the extension of the party you
                                   wish to reach, you may dial it at any time.
     if-dont-know-P1-for-dir -     If you don't know your party's extension,
                                   press 1 for directory assistance
     mental-health-hotline -       Hello and welcome to The Mental Health
                                   Hotline.  If you are obsessive/compulsive,
                                   press 1 repeatedly.  If you are co-dependant,
                                   ask someone to press 2 for you.  If you have
                                   multiple personalities, press 3, 4, 5 and 6.
                                   If you are paranoid, we know what you are and
                                   what you want, stay on the line and we'll
                                   trace your call.  If you are delusional,
                                   press 7 and your call will be transferred to
                                   The Mother Ship.  If you are schizophrenic,
                                   listen carefully and a small voice will tell
                                   which number to press.  If you are depressive,
                                   it doesn't matter which number you press,
                                   no-one will answer you.  If you are dyslexic,
                                   press 69, 69, 69, 69.  If you have a nervous
                                   disorder, please fidget with the hash key
                                   until the beep.  After the beep, please wait
                                   for the beep.  If you have a short-term memory
                                   loss, please try your call again later, and if
                                   you have low self-esteem, hang up, all our
                                   operators are too busy to talk.
     not-valid-extension -         I'm sorry.  That is not a valid extension.
                                   Please try again.
     P1-for-dir-or-stay-on -       Press 1 for directory assistance or stay on
                                   the line for the operator.
     party-no-answer-voicemail -   If your party does not answer, you will be
                                   able to leave a voicemail message.
     thank-you-for-calling -       Thank-you for calling.
     transfer-to-ed-wilson -       Transferring to Ed Wilson at extension 600.
     transfer-to-norm-cole -       Transferring to Norm Cole at extension 601.
     transfer-to-operator -        Transferring to the operator.

The IVR Attendant's messages are actually stored in the local "ivr" subdirectory that we added under the Asterisk "sounds" directory (i.e. /var/lib/asterisk/sounds/ivr). This being the case, we must prefix the name of each message name with "ivr/", when we use it in the dial plan.

We prefer to build the IRV Attendant portion of the dial plan in a separate file, in the local directory, where it can be conveniently changed, if need be. This file can then be included in the exetensions.conf file and the "ivrmenutree" macro referenced in the appropriate place in the CO lines file.

/etc/asterisk/local/ivr-menutree.conf:

     ; local/ivr-menutree.conf - Local IVR menu tree.
     ;
     ; This module is contains a macro that defines the IVR menu tree used by the
     ; local CO lines.  Once this module is included in the CO lines file, the
     ; macro may be invoked to answer the phone and play the IVR menu.
     ;
     ; It also defines all of the sub-menus, including special sub-menus for
     ; off hours and holidays, as well as a sub-menu for doing a directory search
     ; by last name.
     ;
     ; Note that, before this module is included, you should define the global
     ; variable EXTPATTERN, which is used to define the pattern used to match
     ; extension numbers.  Typically, it is set to something like "6XX" or
     ; "5XXX".
     ;
     ;
     ; IVR attendant macro.  This starts up the IVR menu tree.  It checks the
     ; time and branches to the appropriate sub-menu for the date/time.  There
     ; is a special sub-menu for Dale.
     ;
     [macro-ivrmenutree]
     ; Answer the phone.
     exten => s,1,Answer()
     ; Dale always gets special treatment -- The Mental Health Hotline.
     exten => s,n,Gotoif($[${CALLERID(num)} = 1234567890]?ivrmental,s,1:)
     ; Check for the holidays first.  These override the regular hours.
     exten => s,n,GotoIfTime(*,*,4,jul?ivrholiday,s,1)
     ; If the office is closed, go to the closed greeting.
     exten => s,n,GotoIfTime(19:00-08:59,*,*,*?ivrclosed,s,1)
     ; Fall through to the regular, working hours greeting.
     exten => s,n,Goto(ivrworking,s,1)
     ;
     ; This is the regular, working hours menu.
     ;
     [ivrworking]
     exten => s,1,Background(ivr/thank-you-for-calling&\
                             ivr/if-you-know-dial-any-time&\
                             ivr/P1-for-dir-or-stay-on)
     exten => s,2,WaitExten(10)
     ; The user can press 0 for the operator.  This will make Dale happy.
     exten => 0,1,Goto(from-internal,0,1)
     ; The user can press 1 for the directory.
     exten => 1,1,Goto(ivrdirectory,s,1)
     ; If they don't press a valid key, give them an error.
     exten => i,1,Playback(ivr/not-valid-extension)
     exten => i,n,Goto(ivrworking,s,2)
     ; If the wait for a digit times out, transfer to the operator.
     exten => t,1,Playback(ivr/transfer-to-operator)
     exten => t,n,Goto(from-internal,0,1)
     ; Ring the extension that the user dialed (we do this by jumping to the
     ; from-internal context, as if one of the internal lines dialed an
     ; extension, so that we can use the same extension definitions found
     ; therein).
     exten => _${EXTPATTERN},1,Goto(from-internal,${EXTEN},1)
     ; We optionally enable the virtual extensions from outside lines, if the
     ; virtual outside switch is on.
     exten => _${VIRTPATTERN},1,Gotoif($[${EXISTS(${VIRTOUTSIDE})}]?\
                                       virtual-extensions,${EXTEN},1:)
     exten => _${VIRTPATTERN},n,Playback(sorry2)
     exten => _${VIRTPATTERN},n,Hangup()
     ; Define an extension that will get us into voicemail so that we can
     ; check it from outside.
     exten => ${EXTVMAIL},1,VoicemailMain()
     exten => ${EXTVMAIL},n,Hangup()
     ;
     ; This is the after hours menu.
     ;
     [ivrclosed]
     exten => s,1,Background(ivr/thank-you-for-calling&\
                             ivr/at-present-closed&\
                             ivr/if-you-know-dial-any-time&\
                             ivr/party-no-answer-voicemail&\
                             ivr/if-dont-know-P1-for-dir)
     exten => s,2,WaitExten(10)
     ; The user can press 1 for the directory
     exten => 1,1,Goto(ivrdirectory,s,1)
     ; If they don't press a valid key, give them an error.
     exten => i,1,Playback(ivr/not-valid-extension)
     exten => i,n,Goto(ivrclosed,s,2)
     ; If the wait for a digit times out, say goodbye and hang up.
     exten => t,1,Playback(ivr/hasta-la-vista)
     exten => t,n,Hangup()
     ; Ring the extension that the user dialed.
     exten => _${EXTPATTERN},1,Goto(from-internal,${EXTEN},1)
     ; We optionally enable the virtual extensions from outside lines, if the
     ; virtual outside switch is on.
     exten => _${VIRTPATTERN},1,Gotoif($[${EXISTS(${VIRTOUTSIDE})}]?\
                                       virtual-extensions,${EXTEN},1:)
     exten => _${VIRTPATTERN},n,Playback(sorry2)
     exten => _${VIRTPATTERN},n,Hangup()
     ; Define an extension that will get us into voicemail so that we can
     ; check it from outside.
     exten => ${EXTVMAIL},1,VoicemailMain()
     exten => ${EXTVMAIL},n,Hangup()
     ;
     ; This is the holiday menu.
     ;
     [ivrholiday]
     exten => s,1,Background(ivr/thank-you-for-calling&\
                             ivr/at-present-vacation&\
                             ivr/if-you-know-dial-any-time&\
                             ivr/party-no-answer-voicemail&\
                             ivr/if-dont-know-P1-for-dir)
     exten => s,2,WaitExten(10)
     ; The user can press 1 for the directory
     exten => 1,1,Goto(ivrdirectory,s,1)
     ; If they don't press a valid key, give them an error.
     exten => i,1,Playback(ivr/not-valid-extension)
     exten => i,n,Goto(ivrholiday,s,2)
     ; If the wait for a digit times out, say goodbye and hang up.
     exten => t,1,Playback(ivr/hasta-la-vista)
     exten => t,n,Hangup()
     ; Ring the extension that the user dialed.
     exten => _${EXTPATTERN},1,Goto(from-internal,${EXTEN},1)
     ; We optionally enable the virtual extensions from outside lines, if the
     ; virtual outside switch is on.
     exten => _${VIRTPATTERN},1,Gotoif($[${EXISTS(${VIRTOUTSIDE})}]?\
                                       virtual-extensions,${EXTEN},1:)
     exten => _${VIRTPATTERN},n,Playback(sorry2)
     exten => _${VIRTPATTERN},n,Hangup()
     ; Define an extension that will get us into voicemail so that we can
     ; check it from outside.
     exten => ${EXTVMAIL},1,VoicemailMain()
     exten => ${EXTVMAIL},n,Hangup()
     ;
     ; This is The Mental Health Hotline menu.
     ;
     [ivrmental]
     exten => s,1,Background(ivr/mental-health-hotline)
     exten => s,2,WaitExten(10)
     ; The user can press 0 for the operator.  This will make Dale happy.
     exten => 0,1,Goto(from-internal,0,1)
     ; The user can press 1 for the directory.
     exten => 1,1,Goto(ivrdirectory,s,1)
     ; If they don't press a valid key, give them an error.
     exten => i,1,Playback(ivr/not-valid-extension)
     exten => i,n,Goto(ivrmental,s,2)
     ; If the wait for a digit times out, say goodbye and hang up.
     exten => t,1,Playback(ivr/hasta-la-vista)
     exten => t,n,Hangup()
     ; Ring the extension that the user dialed (we do this by jumping to the
     ; from-internal context, as if one of the internal lines dialed an
     ; extension, so that we can use the same extension definitions found
     ; therein).
     exten => _${EXTPATTERN},1,Goto(from-internal,${EXTEN},1)
     exten => _${EXTPATTERN},n,Hangup()
     ;
     ; This is the IVR directory, where we look up the party's name and return
     ; their extension.  We'll ask the caller to enter the first three letters
     ; of the party's last name.
     ;
     [ivrdirectory]
     exten => s,1,Background(ivr/dir-dial-three-letters)
     exten => s,2,WaitExten(20)
     ; If they don't dial a valid name, give them an error.
     exten => i,1,Playback(ivr/dir-dont-recognize-name)
     exten => i,n,Goto(ivrdirectory,s,2)
     ; If the wait for a name times out, say goodbye and hang up.
     exten => t,1,Playback(ivr/goodbye)
     exten => t,n,Hangup()
     ; Here, we can use a pattern match to match the first three letters of
     ; the party's last name.  If the first one or two letters makes it unique,
     ; you can use the anymatch digit to blow away whatever else they type.
     ; Alternately, there's no need to listen for more digits, if you don't
     ; want to but it gives the impression we're a big-time organization.
     exten => _2XX,1,Playback(ivr/transfer-to-norm-cole)
     exten => _2XX,n,Goto(from-internal,601,1)
     exten => _9XX,1,Playback(ivr/transfer-to-ed-wilson)
     exten => _9XX,n,Goto(from-internal,600,1)