Skip to main content

Dialplan overview

Every extension is its own file under the tenant's extensions/ directory. An extension is an ordered list of steps that runs top to bottom.

configs/tenants/acme/extensions/200.yaml
extension: "200"
name: "Support follow-me"
steps:
- id: greeting
type: play
file: ../../../sounds/welcome.wav
when:
days: [mon, tue, wed, thu, fri]
hours: "09:00-17:30"

- id: follow-me
type: dial
moh: default
target:
kind: followme
stages:
- targets: ["101"]
timeout: 15s
- targets: ["100", "external:0612345678"]
timeout: 25s

- id: nobody-home
type: play
file: ../../../sounds/closed.wav

- id: done
type: hangup
KeyRequiredMeaning
extensionyesThe number this plan answers for.
namenoLabel shown in the editor and in logs.
stepsyesOrdered steps.

The execution rules

These five rules explain every dialplan you will ever write:

  1. Steps run top to bottom.
  2. A step whose time condition does not match is skipped, and execution continues with the next one.
  3. A dial that nobody answers continues to the next step. This is the whole reason "greet, then follow-me, then announce we are closed" works.
  4. A dial that is answered bridges the legs and ends the plan.
  5. A failing step does not kill the plan. The error is logged and execution continues, so a missing sound file still lets the follow-me behind it run.

Execution also stops when a hangup step runs, or when the caller hangs up.

Time is sampled once

The clock is read once, when the plan starts. Every time condition in that run is evaluated against the same instant, so a call that begins at 17:29:59 does not change behaviour halfway through.

Step types

TypeFieldsBehaviour
playfileAnswers the call if needed and plays a WAV file.
dialtarget, timeout, mohRings a destination and bridges the first answer.
mohmohPlays music on hold until the caller hangs up.
hangupEnds the call.

Every step also accepts an optional id (used in logs) and an optional when time condition. Full details in Step types.

Common shapes

A simple extension

extension: "100"
name: Alice
steps:
- id: ring
type: dial
timeout: 30s
target: {kind: endpoint, endpoint: "100"}

Office hours, with an out-of-hours announcement

extension: "200"
name: Reception
steps:
- id: open
type: dial
timeout: 25s
when:
days: [mon, tue, wed, thu, fri]
hours: "09:00-17:00"
target: {kind: ring_group, group: reception}

- id: closed
type: play
file: ../../../sounds/closed.wav

- id: done
type: hangup

Out of hours the dial is skipped and the announcement plays. During office hours the announcement is only reached when nobody picked up — the fall-through rule doing the work.

Park the caller on hold

extension: "700"
name: Parking
steps:
- id: hold
type: moh
moh: jazz

moh never returns while the call is up, so it is effectively terminal.

Where the numbers come from

An extension file is reached in three ways:

  • an inbound route whose destination is this extension;
  • a phone in the same tenant dialling the number;
  • another extension's dial step targeting it.

An extension does not need a matching account. Extension 200 above is an entry point with no phone behind it. Conversely, a dial target of kind endpoint must be an account extension — that is what validation checks.