Use this file to discover all available pages before exploring further.
The FreeSWITCH XML dialplan is a pattern-matching engine that routes calls by evaluating a series of extensions top-to-bottom within a named context. Each extension contains one or more conditions that test channel variables (the dialed number, caller ID, time of day, etc.) against PCRE regular expressions. When all conditions in an extension match, the associated actions are executed. The dialplan lives in the dialplan/ subdirectory and is loaded into the dialplan section of the main configuration.
A context is a named group of extensions. Every inbound call is placed into exactly one context based on the SIP profile it arrived on and — after authentication — the user_context variable set in the user’s directory entry. Contexts provide isolation: a caller in the public context cannot reach extensions in the default context unless explicitly transferred there.
<include> <context name="default"> <!-- extensions go here --> </context></include>
The vanilla configuration ships with two contexts:
Context
File
Purpose
default
dialplan/default.xml
Authenticated callers — registered phones and transferred calls
public
dialplan/public.xml
Unauthenticated inbound calls arriving on port 5080
The SIP profile sets the initial context for all calls arriving on that profile (<param name="context" value="public"/>). Once a user authenticates via SIP registration, the user_context variable from the directory (value="default") is applied, routing subsequent calls to the correct context.
An extension is an ordered rule set inside a context. Extensions are evaluated top to bottom; the first extension whose conditions all match is executed. The name attribute is a human-readable label that appears in logs and traces.
A condition tests a channel variable against a regular expression. When the test passes, the <action> elements inside the condition run. When it fails, <anti-action> elements run instead (if any are defined).
Multiple conditions within a single extension are evaluated with AND logic — all conditions must pass for the actions to execute. The break attribute controls short-circuit behaviour:
break value
Behaviour
on-false (default)
Stop evaluating remaining conditions once one fails
on-true
Stop evaluating remaining conditions once one passes
always
Stop regardless of the result
never
Always evaluate all conditions in this extension
Capture groups from the regular expression are available as $1, $2, etc. in action data strings:
<condition field="destination_number" expression="^(10[01][0-9])$"> <!-- $1 contains the matched extension number --> <action application="bridge" data="user/$1@${domain_name}"/></condition>
Actions and anti-actions are dialplan applications invoked when a condition matches or fails, respectively. They use the application attribute to name the app and data for its argument string.
<condition field="destination_number" expression="^1800$"> <!-- Runs when condition is TRUE --> <action application="answer"/> <action application="playback" data="ivr/ivr-welcome.wav"/> <!-- Runs when condition is FALSE --> <anti-action application="set" data="toll_allow=local"/></condition>
Actions are executed in document order. A single extension can have many sequenced actions that build up call state before the final bridging or transfer step.
The field attribute can reference any channel variable using ${variable_name} syntax, or use one of several built-in field names that resolve without braces.
Conditions can test temporal fields instead of channel variables to build business-hours routing, holiday schedules, and night modes. These fields do not need a field attribute — they are named directly.
Attribute
Range
Description
year
4-digit year
e.g., 2025
mon
1–12
Month number (January = 1)
mday
1–31
Day of month
wday
1–7
Day of week (Sunday = 1, Monday = 2, … Saturday = 7)
week
1–52
Week of year
mweek
1–6
Week of month
hour
0–23
Hour in 24-hour format
minute
0–59
Minute within the hour
minute-of-day
1–1440
Minutes since midnight (e.g., 540 = 9:00 AM)
The values support hyphen-delimited ranges. The following examples come directly from the vanilla default.xml:
<!-- Business hours: Monday–Friday (wday 2–6), 9 AM–6 PM --><extension name="tod_example" continue="true"> <condition wday="2-6" hour="9-18"> <action application="set" data="open=true"/> </condition></extension><!-- New Year's Day: January 1st --><extension name="holiday_example" continue="true"> <condition mday="1" mon="1"> <action application="set" data="open=false"/> </condition> <!-- Martin Luther King Day: 3rd Monday in January --> <condition wday="2" mweek="3" mon="1"> <action application="set" data="open=false"/> </condition> <!-- Memorial Day: last Monday in May (only Monday between 25th–31st) --> <condition wday="2" mon="5" mday="25-31"> <action application="set" data="open=false"/> </condition> <!-- Independence Day: July 4th --> <condition mday="4" mon="7"> <action application="set" data="open=false"/> </condition> <!-- Thanksgiving: 4th Thursday in November --> <condition wday="5-6" mweek="4" mon="11"> <action application="set" data="open=false"/> </condition> <!-- Christmas: December 25th --> <condition mday="25" mon="12"> <action application="set" data="open=false"/> </condition></extension>
Using minute-of-day is convenient for ranges that span midnight or need finer granularity than whole hours:
<!-- 9:00 AM to 6:00 PM every day (540 = 9*60, 1080 = 18*60) --><condition minute-of-day="540-1080"> <action application="set" data="open=true"/></condition>
The two most fundamental routing operations in the dialplan are bridging and transferring.
bridge
Connect the current call leg to another endpoint. The caller and the remote party are joined in a media session.
<!-- Bridge to a registered user --><action application="bridge" data="user/1000@${domain_name}"/><!-- Bridge through the external profile to a SIP URI --><action application="bridge" data="sofia/external/+15551234567@sip.carrier.com"/><!-- Bridge to a gateway --><action application="bridge" data="sofia/gateway/my-carrier/15551234567"/>
transfer
Move the call to a different extension or context. The current dialplan execution ends and a new lookup begins.
<!-- Transfer to extension 2000 in the default context --><action application="transfer" data="2000 XML default"/><!-- Transfer inbound DID to an internal extension --><action application="transfer" data="1000 XML default"/>
The following is a simplified but complete example showing the structural patterns used in the vanilla configuration: an always-running time-of-day check, loop prevention, public-to-default transfer for known extensions, and a full local extension handler with voicemail fallback.
<?xml version="1.0" encoding="utf-8"?><include> <context name="default"> <!-- Prevent SIP routing loops --> <extension name="unloop"> <condition field="${unroll_loops}" expression="^true$"/> <condition field="${sip_looped_call}" expression="^true$"> <action application="deflect" data="${destination_number}"/> </condition> </extension> <!-- Business hours flag — continue="true" means evaluation keeps going --> <extension name="tod_example" continue="true"> <condition wday="2-6" hour="9-18"> <action application="set" data="open=true"/> </condition> </extension> <!-- Route calls to extensions 1000–1019 --> <!-- Dial the extension for 30 seconds; if unanswered or busy, continue_on_fail=true lets execution fall through to voicemail. --> <extension name="Local_Extension"> <condition field="destination_number" expression="^(10[01][0-9])$"> <action application="export" data="dialed_extension=$1"/> <action application="set" data="ringback=${us-ring}"/> <action application="set" data="transfer_ringback=$${hold_music}"/> <action application="set" data="call_timeout=30"/> <action application="set" data="hangup_after_bridge=true"/> <action application="set" data="continue_on_fail=true"/> <!-- Attempt the call --> <action application="bridge" data="user/${dialed_extension}@${domain_name}"/> <!-- If bridge failed, send to voicemail --> <action application="answer"/> <action application="sleep" data="1000"/> <action application="bridge" data="loopback/app=voicemail:default ${domain_name} ${dialed_extension}"/> </condition> </extension> </context></include>
FreeSWITCH uses PCRE (Perl-Compatible Regular Expressions) for all condition matching — not ERE or basic regex. Key differences to watch for:
Use \d for digits, \s for whitespace (PCRE extensions)
Quantifiers like +, ?, {n,m} work as expected
Anchors ^ and $ are strongly recommended — without them, expression="1000" matches 21000, 10001, etc.
Backslashes must be XML-escaped: \* becomes \\* in XML attributes, and \. becomes \\.
Named capture groups (?P<name>...) are supported and accessible as ${name} in action data
Always test regex patterns with fs_cli -x "regex 15551234567 ^1(\d{10})$ $1" before deploying.