as of version 4.0.0

Yap is an application to find meetings or someone to talk to over the phone (helpline) leveraging a BMLT root server.

The purposes of yap are :


This will require that you have an SSL certificate installed on your webserver to transit a secure connection. This is required by Twilio.

  1. Create a new virtual application or add the yap code to an existing folder. You can always find the latest stable version here (be sure download the yap-x-x-x.zip file and not the source code): https://github.com/bmlt-enabled/yap/releases/latest. You can also try out or help test the latest bleeding edge features by installing one of the unreleased versions. The newest version would always be the highest numbered build.
  2. You will need to set up a new blank MySQL database. Be sure to set up backups on your database as well. Your hosting provider may cover this more. Take note of the configuration host, database name, username and password.
  3. Once the application is configured visit the url where the application was installed. This will redirect you to an installer page. Fill out all the settings and when you are done copy and paste the result into a file called config.php on your server. If done correctly the database will automatically initialize and redirect you to the admin login page.
    • You will need to enter your twilio_account_sid and twilio_auth_token. You can find this on your account dashboard. You can also use a different Twilio account using the admin portal under “Service Bodies”. Keep in mind that if a key or keys are set at any parent above, all child service bodies will inherit that key. In order to use a key, just specify override_service_body_id in your webhook with the applicable id.
    • Be sure to get a Google Maps API key (for google_api_key) Make sure you have “Google Maps Geocoding API” and “Google Maps Time Zone API” enabled on your credentials. This key must be separate from your BMLT key with no server restrictions, this is safe because yap never passes the key client side. Your key however, should have an IP-based restriction if possible. You can get your server IP from your hosting provider. You can login into your Google API console here: https://console.cloud.google.com/apis/. This article may be useful  https://bmlt.app/google-api-key/
  4. You will need to set up a Twilio account, and do the following. Purchase a phone number (typically you would buy one for your locale, tollfree is pretty much unnecessary these days). Configure that number to point to a Webhook. It would be something like https://example.com/index.php. You can also configure SMS Gateway and Call Detail Records from this section well.  Demo phone numbers have proven to have many limitations, so funding your account and buying a number will be the only known reliable path forward.
  5. Make a call to your number and try it out. If there is a problem the debugger in the Twilio console will let you know why. Most likely you did not setup your config.php file correctly.
  6. There are many ways to customize the config.php and also to set overrides. See the rest of this documentation and the page on Configuration Precedence.

Call Detail Records

Point all your phone numbers Call Status Changes Callback Webhook in Twilio to your instance to status.php. You can use either HTTP GET or POST.

Voice Recognition Options

It’s possible to set the expected spoken language, for recognition by setting the following variable in config.php to the culture variant. The default is en-US, which is US English. Use the this chart to find the code of your preference https://www.twilio.com/docs/api/twiml/gather#languagetags.
					static $gather_language = "en-US"; 


You can also set some expected words or hints, to help the voice recognition engine along. Use the setting by separating words with commas. You can use phrases as well.

Each hint may not be more than 100 characters (including spaces). You can use up to 500 hints.

					static $gather_hints = "";

Voice recognition for input gathering is turned on by default, to turn it off you can do the following. When you make this change, the prompts will say “press or say” and now respond to saying the digit response as well as pressing the digit on a phone.

					static $speech_gathering = false; 


Configuration Precedence

It’s possible to override most of the settings in several different ways. There is a sequence of precedence as follows. You can always validate the setting by going to the settings in the admin portal.
  1. Querystring parameters that match the name. For example if you wanted to override the title for one page you’d do the following: index.php?title=something+here
  2. Session overrides. This means the entire call will use this setting. index.php?override_title=something+here. Twilio will respect this setting for entire during of the call.
  3. Service body overrides from the Admin UI. These have a cascading hierarchy of precedence based off the service body above it in the hierarchy tree from your root server. Either the override_service_body_id (which will affect call routing) or override_service_body_config_id will pull these settings into the session for use.
  4. Config.php. Any setting is controllable from within config.php.
  5. Factory defaults. You can review them on your /admin/settings.php page.
You can completely override any config.php file setting as well with additional precedence.
  1. Create a new file called config_something.php. Add whichever settings you want to override. You do not need every setting, only those you want to override.
  2. Use the last part after the underscore in your webhook as, for example: https://your-yap-server/index.php?override_config=something.

State Province Lookup

It may be that your instance needs to search multiple states. By default searches will be biased towards the local number state (unless it’s tollfree). To enable province lookup set the $province_lookup, variable to true in the config.php file.
					static $province_lookup = true; 


You can also specify a predetermined list of provinces / states. If you use this setting, then a speech gathering will be replaced with a numbered menu of states. Currently it would support up to 9 states in the list. To enable this do the following for example (the order in the list and position is the number that will be said to be pressed in the menu):

					static $province_lookup = true;
static $province_lookup_list = ["North Carolina", "South Carolina"]; 


Province Bias

Tollfree is independent of any state/province bias. To enable a specific bias, add static $toll_free_province_bias to your config.php, and set to the two letter state or province bias. This example: will bias to Texas.
					$toll_free_province_bias = "TX" 


To enable a toll number bias (meaning to override the location of the number itself), add $toll_province_bias to your config.php, and set to the two letter state or province bias.

Location Lookup Bias

By default location lookups are biased toward the US. You can create a series of refinements by using the $location_lookup_bias in config.php. For example say you wanted to lookup Bayonne. By default Bayonne, New Jersey would be interpreted. If you were intended for France you would set your config as the following:
					static $location_lookup_bias = "country:France";

A full listing of available bias options are available here: https://developers.google.com/maps/documentation/geocoding/intro#ComponentFiltering. You can use as few or as many as you want, by separating each set with pipe “|” character.

Custom Geocoding

You can override the geocoding response by pre-populating exact address and postal code lookups with a Latitude and Longitude.  If specifying this at the server level use the following syntax for example:
					static $custom_coding = [['location' => "Pasco County, FL", 'latitude' => "0.00", 'longitude' => "0.00"]]

If you are using the Config option in the Admin UI to override by service body, use JSON formatting instead as seen below.

					[{"location": "Pasco County, FL", "latitude": "0.00", "longitude": "0.00"}]

Postal Code Lengths

By default a 5 digit postal code will be asked for. To override this set the following, for instance a 4 digit postal code:
					static $postal_code_length = 4;


There may be times when a root server is down, it’s possible to redirect a call to another if this happens. In your config.php, specify the following.
					static $helpline_fallback = "1919555555"; 

Voice Greeting

It’s possible to record a custom voice prompt and have it play back instead of the traditional voice engine. Set the following: *Keep in mind that this will override the main menu as well, so you should record the relevant prompts (i.e. press 1 to find someone to talk too… press 2 to find a meeting)
					static $en_US_greeting = "https://example.com/your-recorded-greeting.mp3"

You can also set a custom greeting for voicemail.

					static $en_US_voicemail_greeting = "https://example.com/your-recorded-greeting.mp3" 

These settings are overridable from within each service body call handling.

Language Options

There is a concept of language resource files. You will notice them in the lang/ folder. Please open a ticket if you would like to contribute to translating to another language. You can also override any of the language prompts in the config.php file. For example, say you wanted to still use English, but change the “city or county” prompt to say, “city or suburb”. You would do the following in config.php:
					static $override_city_or_county = "city or suburb"; 

You can see the full listing in the lang/en-US.php which always has the full latest listing of the voice prompts.

You can also change the spoken language accent. There is a wide variety. See the Twilio documentation for more details: https://www.twilio.com/docs/voice/twiml/say#attributes-language. There are also some additional voices available here as well https://www.twilio.com/docs/voice/twiml/say/text-speech#voices.

An example would be using an Australian English Accent. Set your config.php to:

					static $voice = "alice";
static $language = "en-AU"; 

Language Call Routing

You can also create a language selection menu upon dialing in. It will only be available for those that there are resource files for in lang/ folder. If you have some translations, please send them, so they can be merged in. Add a new setting called, specifying the language codes for each language you want included. The order will indicate the order in which it will be played back:
					static $language_selections = "en-US,pig-latin";

If you want to route calls to volunteers by language, see the section on Language in Specialized Routing.

This example will make option 1, English and option 2, pig latin.

Mixing languages and voices

Voices can be configured for every language option. For example for Spanish:

					es_US_voice = "Polly.Penelope"; 

Custom Extensions

It’s possible to make custom extensions with the use of a few settings.
  1. Add an option to your $digit_map_search_type that points to SearchType::CUSTOM_EXTENSIONS.
  2. Add mappings in $custom_extensions for each extension you want to add. For example if you wanted redirect extension “365” to a specific phone number you would do the below:
					static $custom_extensions = [365 => '555-555-1212']; 
  1. Add an option for the mp3 or wav file prmpt that will play back all the choices in the custom extensions menu $en_US_custom_extensions_greeting (be sure to specify recordings for each language that you offer).

To test, call in dial the digit map choice and you should hear the audio file prompt playback. Enter the extension number followed by the pound sign (it might be good to inform the end-user in your prompt to press pound after they dial the appropriate extension).

Also to note is that the main menu greeting will not inform the user about the custom extensions option, so you may also want to set $en_US_greeting to include that information.


If you want to completely block a specific number you can use the setting as follows (comma-separated). Sometimes it’s best to look at the Caller querystring value in your logs or the Twilio console to see the exact number being passed.
					static $blocklist = "";


User authentication has primarily been sourced by a BMLT. You can create users outside the BMLT and use Yap’s internal user authentication. To create an admin user run the following MySQL script. Be sure to set a strong password and fill it in the variable before running this on your MySQL instance.
					SET @realname = '';
SET @username = '';
SET @password = '';
INSERT INTO users (name, username, password, permissions, is_admin) VALUES (@realname, @username, SHA2(@password, 256), 0, 1);

Meeting Search Radius

Change the default meeting search radius, this can be in miles or a negative number which would set the radius at the first n results. You can change this in your config.php with the following:
					static $meeting_search_radius = 30; 

This would set the radius to a maximum of 30 miles.

					static $meeting_search_radius = -50; 

This would set the radius at the first 50 results and is the default.

More information on how the BMLT uses search radius is here: https://bmlt.app/how-auto-radius-works/

Results Counts Maximums

The default number of meeting results is 5. You can change this in your config.php with the following:
					static $result_count_max = 10; 

This would set to a maximum of ten (10) results.

Grace Period

This is so that yap still returns results for meetings that have already started. By default a 15 minute grace period will be applied. This can be adjusted by setting $grace_minutes in your config.php.
					static $grace_minutes = 10; 

Ignoring Certain Formats

In some cases you might want to ignore a specific format. Add the following setting with the formats you want to exclude. Separate each with a comma.
					static $ignore_formats = "ASM"; 

Post Call Options

Making SMS results for voice calls optional

The default of the system is to send an SMS after each voice meeting result. As an option to you audience you can add the following parameter to your config.php file.
					static $sms_ask = true; 

By setting this, a prompt will be played at the end of the results, asking if they would like the results texted to them. If they do not respond the call will automatically hang up in 10 seconds.

Infinite Searches

You can provide an option to allow someone to search again. Just set:

					static $infinite_searching = true; 

Suppress Voice Results

In order to prevent voice results from being returned for meeting searches set the following setting:

					static $suppress_voice_results = true; 

SMS Gateway

In order to use SMS to get a list of meetings you will configure Messaging to point to Webhook sms-gateway.php. Then you can send a zip code, county or city to your phone number and get back a response.

SMS Options

SMS Summary Page

You can configure the SMS results as a summary page link using croutonjs. Set your configuration to have
					static $sms_summary_page = true; 

Adding Map Links

Some older handsets are not capable of rendering maps links. If you want to enable this feature add the following to your config.php file.

					static $include_map_link = true; 


Adding Location Text

This feature enables you to include the name of the meeting location in search results, by default it is disabled. If you want to enable this feature add the following to your config.php file.

					static $include_location_text = true; 


Adding Distance Details

This feature allow you to include the distance from the search criteria in an SMS response. You can specify either mi or km.

					static $include_distance_details = 'mi'; 

Combining to a single SMS versus individual ones


					static $sms_combine = true; 

Custom Query

In some cases you may want use a custom BMLT query. For example, if you have a small service body you may want to ignore the day of the week concept that is the default behavior in searches. You can do this with the setting custom_query. This setting also supports the use of some magic variables. For example say you want to always use the service body id for making queries, you could create the settings as follows:
					static $custom_query="&services[]={SETTING_SERVICE_BODY_ID}" 


Because there is a setting called service_body_id already and assuming you had overridden it, meeting searches will now send a query to the BMLT and return accordingly.

You could have also hardcoded it if you wanted. Like any other variable, you can set this on the querystring as a session wide override.

In some cases you may need to combine this with the result_count_max to increase the limit of how many results are returned. You may also need to use sms_ask, as many results could be returned.

There are a couple of other stock magic variables.

  1. {DAY} – will use the day of today / tomorrow.
  2. {LATITUDE} – the latitude of the lookup.
  3. {LONGITUDE} – the longitude of the lookup.

If you do not have {LATITUDE} or {LONGITUDE} in your custom query, it will automatically skip the location gathering aspects of the meeting search menus and go directly to returning results.

Sorting Results

By default the results will be sorted starting with today and then moving on to the next result. If latitude and longitude are not used in the meeting query, the first meeting latitude and longitude will be the assumed timezone. If you wanted to hardcode the sorting to start with another day you could use say for Wednesday use static
					static $meeting_result_sort = 4; 

Or you can keep a more natural flow by setting it to 1 which would sort Sunday to Saturday.

Disabling Postal Code Gathering

To disable postal code lookups set your config as follows:
					static $disable_postal_code_gather = true; 

Mobile Check

You can configure the SMS results to check if the device is mobile and not a landline or voip before sending. If not a mobile device SMS will not be sent. Set your configuration to have
					static $mobile_check = true; 

Including Unpublished

If running root server 2.15.1 or greater you can include unpublished meetings.
					static $include_unpublished = true; 

Temporary Closures / Showing Meeting Format Details

If a meeting is marked with the TC format then it will be excluded from results. If it marked as a Virtual Meetings as well then it will be returned by with no physical address details.

If you want the text from the format description to be returned add TC to include_format_details. Example:

					static $include_format_details = ['TC', 'VM', 'HY']; 

You can include any format here.  For example if you wanted to show whether a meeting is Open or Closed you could do that by including the format code in this setting.

If you want to change the description of some of the specific formats you can change the format description for that specific language in your root server.

Virtual Meetings

If a meeting is marked as VM or HY with a format then you should be able to automatically have the virtual_meeting_link and phone_meeting_number returned in the SMS. If you want the links (for some reason), to be said in voice responses, you can enable this with say_links set to true. If you want the text from the format description to be returned add VM or HY to include_format_details. Example:
					static $include_format_details = ['TC', 'VM', 'HY']; 

If you want to change the description of some of the specific formats you can change the format description for that specific language in your root server.

Helpline Search Radius

Change the default helpline search radius, this is in miles. You can change this in your config.php with the following:
					static $helpline_search_radius = 30; 

This would set the radius to a maximum of 30 miles and is the default.

Helpline Call Routing

The helpline router utilizes a BMLT server (2.9.0 or later), that has helpline numbers properly configured in the “Service Body Administration” section. A prompt will ask for a piece of location information in turn it will look up latitude and longitude and then send that information to the BMLT root server you have configured. You can also tie this into an existing extension based system, say for example Grasshopper. If you want to dial an extension just add something like 555-555-5555|wwww700 for example after the helpline field on the BMLT Service Body Administration. In this case it’s instructing to dial 555-555-5555 and wait 4 seconds and then dial 700.

Music On Hold

Music on hold will play when doing volunteer routing which is configurable from within the service body call handling. You can specify one or more URLs to an MP3 file or Shoutcast stream. Separate them by commas. You can also create your own custom MOH as a PSA to be played during the wait period for a volunteer to accept the call. Example: https://bmltserver.org/audio/PSA_60sec.mp3 There are also some free alternatives. They are licensed by Creative Commons. They are playlists themselves so they may not be combined with any other URLs. Music on Hold loops indefinitely.

Tomato Helpline Routing

In some cases you might want make use of aggregated helpline information. In order use the setting:
					static tomato_helpline_routing = true; 

When a call comes in first a lookup will occur in Tomato to determine which root server can handle that request. If the root server matches first helpline_bmlt_root_server if used, and then bmlt_root_server, it will use that for the subsequent routing requests. Otherwise it will use the helpline routing field for the remote root servers in the tomato response.

Using Hidden Service Bodies For Helpline Lookups

It is possible to create a service body with an unpublished group in order to create additional routing for service bodies that may not exist in a given root server. Once those service bodies have been populated and the unpublished meetings are added, you can make use of the helpline field to route calls. You will also need to add to the config.php three additional variables. This allows yap to authenticate to the root server and retrieve the unpublished meetings. This is required as a BMLT root server by design will not return unpublished meetings in the semantic interface.
					static $helpline_search_unpublished = true;
static $bmlt_username = "";
static $bmlt_password = ""; 

You will need to also ensure that PHP has write access to write to this folder, in order to store the authentication cookie from the BMLT root server.

NOTE: This will not work for the Tomato server, because there is no concept of authentication.

Using A Different BMLT server for routing

In order to specify a different BMLT root server for call routing but not for meeting list lookups, set the variable in config.php.

					static $helpline_bmlt_root_server = ""; 

Checking the Call Routing

There is a very simple way to check where a could would be routed to.
					curl https://example.com/yap/helpline-search.php?Digits=Turkey,NC 

When configuring the TwiML app instead of pointing to index.php point to input-method.php?Digits=2 in your webhook.

If you still want the title to display point your webhook to input-method.php?Digits=2&PlayTitle=1.

This could useful for wiring up to a Grasshopper extension. Typically you set this as Department Extension and have your prompt instruct to press a series of keypresses.

For example, if you set this up as extension 1, from within you employee extensions you would instruct the caller to press *1 (star one) for finding meetings.

Force Helpline Routing

You can force the helpline option to go directly to a specific service body by specifying the following on your webhook in Twilio.

The service body id would be found in your BMLT root server. It must exist in that root server instance to be routed correctly.

Volunteer Routing

Incompatible with Yap 1.x Volunteer Dialers, you will have reconfigure your setup.
  1. You will need to ensure that the following config.php parameters are set. They should be a service body admin that will be responsible for reading and writing data back to your BMLT. This will not work with the “Server Administrator” account.
					static $bmlt_username = "";
static $bmlt_password = ""; 

2. You will need to specify Twilio API parameters. You can find this on your account dashboard when you login into Twilio.

					static $twilio_account_sid = "";
static $twilio_auth_token = "";
  1. Head over to your admin login page. https://your-yap-instance/admin.

  2. Login with any credentials from your BMLT server.

  3. Go to the Service Bodies tab and click “Call Handling”. From there you should see a drop-down menu labeled “Helpline Routing” open it, make sure “Volunteers” is selected and save.

  4. Go to Volunteers, and you should see that service body in the dropdown, and select it.

  5. Click Add Volunteer. Fill out the Name field, and then click the “+” to expand out the rest of the details. You should be able to start populating the number and shift information. You will also have to click “Enable” in the bottom right. Once you are done, click “Save Volunteers”.

  6. You can also sort the sequence by dragging and dropping the volunteer cards.

  7. Go to Schedules to preview your changes. Select your service body from the dropdown, and it should render onto the calendar.

  8. You can now test to see if things are working.

    • Volunteer Routing Redirect: You do this by setting in the Service Body Call Handling the Volunteer Routing mechanism to “Volunteers Redirect” and specifying the respective Service Body Id in the “Volunteers Redirect Id” field.
    • Forced Caller Id: This setting changes the outgoing display caller id.
    • Call Timeout: This is the number of seconds before trying the next number for volunteer routing.

SMS Volunteer Routing

This is enabled in the service body call handling through the drop down selecting “Volunteer and SMS”. There are two routing strategies, random or blast. Blast will send to all active volunteers at that moment in time. This is configured similarly to phone volunteer routing. You can add shifts as SMS or Phone & SMS. The SMS trigger keyword by default is “talk”, followed by the location information. You can override this by using the sms_helpline_keyword setting. You cannot use the word “help” or “stop” by itself as these are reserved keywords by Twilio. You could however, use a combination of words like “get help” or “need help”. As a safety measure, if no volunteers are specified with “SMS”, but it’s enabled on the service body call handling, it will send to the primary contact number.


This is configured through service body call handling, through your call strategy setting.

Voicemail Recordings

NEW in Yap 3.x Recordings are now available in the admin portal under “Service Bodies > Call Records” for each respective area.

Voicemail Notifications to SMS

NEW in Yap 3.x You can set up any volunteer to receive voicemail notifications. Within the volunteer setting, set the dropdown Responder to “Enabled”. If you specify a Primary Contact Number, it will SMS a link to the recording that person when a voicemail is left. You can also comma separate the values if you want it to go to more than one person.

Voicemail Notifications to Email

You can also optionally use email. You will have to enable this by adding an email address under the Primary Contact Email. You can optionally supply a list of comma separated emails for multiple recipients. You will also need to ensure that the following settings are in your config.php.
					static $smtp_host = '';             // the smtp server
static $smtp_username = '';         // the smtp username
static $smtp_password = '';         // the smtp password
static $smtp_secure = '';           // either ssl (port 486) or more securely tls (port 587)
static $smtp_from_address = '';     // the address where the email will be sent from
static $smtp_from_name = '';        // the label name on the from address 

If you need to, for some reason, to override the port here is another optional setting.

					static $smtp_alt_port = '';         // enter the integer for the respective to use 

If you do not receive an email, check your server logs. There should be some good information there. Also the upgrade advisor should give you some information about what might be missing as long as $smtp_host is set.

Specialized Routing

Gender Routing

Gender routing allows you to specify volunteers as Male or Female to enable callers to speak with volunteers of their gender selection.

This setting is configured from within each service body call handling.

If you want to add the option to allow callers to choose no preference for gender, add the following setting:

					static $gender_no_preference = true;


You can tag volunteers to zero or more languages (The default setting will be whatever the first option is in the language_selections setting.  This setting takes effect in the case that no language has been set on a volunteer). Be sure to set the list of languages you want your callers to be prompted, see Language Options for more information.

Service Body Direct Dial

If you set the config value extension_dial = true, you can override the default behavior of any phone number to ask for a service body ID. This will then route the call directly to that service body.

Volunteer Auto Answer

By using this feature it will automatically answer the call. This can have the side effect of going to someone’s voicemail however. To enable add to your config.php:
					static $volunteer_auto_answer = true; 

Logging Debugging

To enable advanced debugging set in your config.php
					static $debug = true; 

Playback for the Just For Today Meditation

This will add an option on the main menu to press 3 to playback the Just For Today meditation.
					static $jft_option = true; 


Make a new folder with the newer version and copy over the config.php. Once you feel comfortable you can delete the older folder and rename it. Be sure to run the upgrade-advisor.php

Upgrading from Yap 1.x to Yap 2.x

You will also need to follow item #3 & #4 under Setup, to add the Twilio credentials.

You can check that everything is functioning by going to the upgrade advisor


Upgrading from Yap 2.x to Yap 3.x

Follow the upgrading steps here first. You will also need to follow item #8 under Setup, to add the database configuration.

You can check that everything is functioning by going to the upgrade advisor


If you need to re-import your data from your root server you can run the following script. This will delete any changes you have made since you upgraded.

					TRUNCATE TABLE config;
DELETE FROM flags WHERE flag_name='root_server_data_migration'; 

Upgrading from Yap 3.x to Yap 4.x

There are no special upgrade steps to perform before making this upgrade.  


Fork this repo and send a pull request. For testing locally, run the yap server and then use ngrok. Grab the ngrok hostname that is generated and then use that in your Twilio settings. You get an instant proxy to your local services to step through and debug.


Yap has an API, and so there are other ways to pull out Yap information.