Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/signalwire/freeswitch/llms.txt

Use this file to discover all available pages before exploring further.

The FreeSWITCH XML dialplan is the primary mechanism for deciding what happens to a call after it arrives. It evaluates an ordered list of extensions in the active context, tests each extension’s conditions against the channel’s current state (caller ID, destination number, time of day, channel variables, and more), and then executes a list of applications when a match is found. The dialplan is deliberately simple — a pure data-driven ruleset expressed in XML — which makes it both easy to audit and straightforward to generate programmatically.

Dialplan Structure

The XML dialplan follows a strict four-level hierarchy: contexts contain extensions, extensions contain conditions, and conditions contain actions (and optionally anti-actions).
context
└── extension  [name, continue]
    └── condition  [field, expression, break]
        ├── action      (executed when condition matches)
        └── anti-action (executed when condition does NOT match)
Each element builds on the previous:
  • A context is an isolated routing table. Only callers placed into that context will evaluate its extensions.
  • An extension is a named rule block. Extensions are evaluated top-to-bottom within the context.
  • A condition tests a channel field against a regular expression. An extension can have multiple conditions; by default all must match before actions execute.
  • Actions are dialplan application calls executed in order when all conditions are satisfied.

Contexts

FreeSWITCH ships with two default contexts, both defined in conf/vanilla/dialplan/:
The default context handles calls from authenticated users — SIP phones that have registered with valid credentials, or calls transferred here from the public context. It is the context most extensions and features are placed in.
<!-- conf/vanilla/dialplan/default.xml -->
<context name="default">
  <!-- extensions go here -->
</context>
Contexts are completely isolated from each other. An extension in default cannot be matched by a caller in public unless the caller is explicitly transferred across contexts using the transfer application.

Conditions

A condition tests the value of a field — a channel variable or caller-profile attribute — against a regular expression using PCRE. Named capture groups ($1, $2, …) populated by the regex are available to actions within the same condition. Common field values:
FieldDescription
destination_numberThe dialed number (after normalization)
caller_id_numberThe calling party’s number
caller_id_nameThe calling party’s name
network_addrSource IP address of the call
${variable_name}Any channel variable (wrapped in ${})
wdayDay of the week (1=Sunday … 7=Saturday)
hourHour of the day (0–23)
mdayDay of the month (1–31)
monMonth (1–12)
The vanilla default dialplan shows time-based conditions in action:
<!-- conf/vanilla/dialplan/default.xml — time-of-day and holiday routing -->
<extension name="tod_example" continue="true">
  <condition wday="2-6" hour="9-18">
    <action application="set" data="open=true"/>
  </condition>
</extension>

<extension name="holiday_example" continue="true">
  <condition mday="25" mon="12">
    <!-- Christmas -->
    <action application="set" data="open=false"/>
  </condition>
  <condition wday="5-6" mweek="4" mon="11">
    <!-- Thanksgiving (4th Thursday in November) -->
    <action application="set" data="open=false"/>
  </condition>
</extension>
The break attribute on a <condition> controls evaluation flow when the condition fails:
break valueMeaning
on-false (default)Stop evaluating this extension if the condition fails
on-trueStop evaluating this extension if the condition succeeds
alwaysStop evaluating this extension regardless of outcome
neverAlways continue evaluating subsequent conditions

Actions and Anti-Actions

When all conditions in an extension match, each <action> tag is executed in document order. Each action specifies an application (a loaded function from a module like mod_dptools) and optional data passed to it.
<extension name="global-intercept">
  <condition field="destination_number" expression="^886$">
    <action application="answer"/>
    <action application="intercept" data="${hash(select/${domain_name}-last_dial_ext/global)}"/>
    <action application="sleep" data="2000"/>
  </condition>
</extension>
Anti-actions execute when the condition evaluates to false. They are declared with the <anti-action> tag and placed inside the same <condition> block as actions. A common use is to set a default value when a time-of-day condition does not match:
<extension name="check-hours" continue="true">
  <condition hour="9-17">
    <action application="set" data="business_hours=true"/>
    <anti-action application="set" data="business_hours=false"/>
  </condition>
</extension>

Channel Variables

Channel variables are key-value pairs stored on each call leg. They communicate state between dialplan steps and between modules. The set application writes a variable; the ${variable} syntax reads it back anywhere in the dialplan.
<!-- Set a variable -->
<action application="set" data="my_var=hello"/>

<!-- Read it back in a condition -->
<condition field="${my_var}" expression="^hello$">
  <action application="playback" data="hello-world.wav"/>
</condition>

<!-- Pass it to an application -->
<action application="bridge" data="sofia/gateway/mytrunk/${destination_number}"/>
Variables set with set survive for the duration of the call leg. The export application propagates a variable to the B-leg when a bridge is created. Use unset to remove a variable.
<action application="set" data="record_session=true"/>

Redial and Hash Examples

The vanilla dialplan shows real-world usage of channel variable substitution with the built-in hash API:
<!-- conf/vanilla/dialplan/default.xml — redial last dialed number -->
<extension name="redial">
  <condition field="destination_number" expression="^(redial|870)$">
    <action application="transfer" data="${hash(select/${domain_name}-last_dial/${caller_id_number})}"/>
  </condition>
</extension>

Inline Dialplan

For one-shot originate commands from the API or ESL, FreeSWITCH supports an inline dialplan that lets you specify a comma-separated list of app:data pairs directly in the originate string — no XML required. Prefix the extension list with & or use the dp: scheme.
# Originate a call and execute two apps inline
originate sofia/gateway/mytrunk/15551234567 &echo

# Inline dialplan with multiple apps separated by commas
originate sofia/gateway/mytrunk/15551234567 'answer,playback:hello-world.wav,hangup' inline
This is useful for automated tests, quick call generation, and scripting scenarios where writing a full XML dialplan entry would be unnecessary overhead.
Add continue="true" to an extension to keep evaluating subsequent extensions in the context even after a match. This is how time-of-day and holiday blocks work in the vanilla dialplan — they set variables and then continue so the actual routing extension below them can also fire.

Build docs developers (and LLMs) love