Step types
There are twelve step types. Every step shares three keys:
| Key | Meaning |
|---|---|
id | A label used in logs and in the editor. Defaults to the step type. |
type | Required. One of the twelve below. |
when | A time condition gating the step. |
| Type | Covered here | Also see |
|---|---|---|
play dial moh hangup goto | in full | |
ivr | the step | IVR menus |
queue | the step | Call queues |
voicemail voicemail_check | the step | Voicemail |
dnd forward record | the step | Feature codes |
play
Answers the call if it is not answered yet, then plays a WAV file to completion.
- id: greeting
type: play
file: ../sounds/welcome.wav
| Field | Required | Notes |
|---|---|---|
file | yes | Path to an 8 kHz mono 16-bit PCM WAV, relative to the tenant directory. |
Files are validated and cached in memory at startup, so a bad file fails fast instead of mid-call. See Audio files.
Playback always continues to the next step.
dial
Rings a destination and bridges the first leg that answers.
- id: follow-me
type: dial
timeout: 30s
moh: default
target:
kind: followme
stages:
- targets: ["101"]
timeout: 15s
- targets: ["100", "external:0612345678"]
timeout: 25s
| Field | Required | Default | Notes |
|---|---|---|---|
target | yes | — | What to ring. See the kinds below. |
timeout | no | 30s | How long to ring. For followme, the fallback for stages without their own. |
moh | no | ringback | Music-on-hold class the caller hears instead of ringback. |
If nobody answers, execution continues with the next step. If somebody answers, the legs are bridged and the plan ends there.
target.kind: endpoint
One extension of this tenant, or a tenant: reference.
target:
kind: endpoint
endpoint: "101"
Every device registered to that extension rings in parallel; first answer wins.
The value must be an account extension of the tenant, external:<number>,
or tenant:<name>/<extension> when
inter-tenant calling is enabled.
target.kind: ring_group
A named group, defined by a RingGroup document of the same tenant.
target:
kind: ring_group
group: support
See Ring groups and follow-me.
target.kind: followme
Sequential stages; each stage rings all of its targets in parallel.
target:
kind: followme
stages:
- targets: ["101"]
timeout: 15s
- targets: ["100", "external:0612345678"]
timeout: 25s
At least one stage is required, and each stage needs at least one target. A
stage without a timeout falls back to the step's timeout, then to 30s.
target.kind: external
A number placed through the outbound routes.
target:
kind: external
number: "+31612345678"
Target references
Anywhere a list of targets is accepted — endpoint, ring group targets,
follow-me stage targets — these three forms are valid:
| Form | Meaning |
|---|---|
"101" | An account extension of this tenant. |
external:0612345678 | A number routed through the outbound routes. |
tenant:globex/900 | An extension of another tenant, if allowed. |
A reference that resolves to nothing at call time — an extension with no registered device, for instance — is skipped rather than failing the step. If every target in a stage resolves to nothing, that stage rings nobody and the next one starts.
moh
Plays a music-on-hold class in a loop until the caller hangs up.
- id: hold
type: moh
moh: jazz
| Field | Required | Default | Notes |
|---|---|---|---|
moh | no | default | Class name, resolved in the tenant then globally. |
Because it only returns when the call ends, moh is effectively a terminal
step; anything after it is unreachable.
hangup
Ends the call.
- id: done
type: hangup
No fields. A plan that runs off its last step hangs the caller up anyway, so
hangup is for ending a plan early — and for making the intent obvious at
the bottom of a file.
- id: block-weekends
type: hangup
when:
days: [sat, sun]
goto
Hands the call to another dialplan of the same tenant. It does not come back.
- id: to-main
type: goto
extension: "700"
| Field | Required | Notes |
|---|---|---|
extension | yes | A dialplan extension of this tenant. Checked at startup. |
Jumps are checked when the PBX starts: a plan that points at itself, or a ring of plans pointing at each other, refuses to load rather than spinning on the first call that reaches it.
tenant acme: dialplan loop 700 → 800 → 700
A call may enter at most 20 plans in total, which bounds what a caller can reach through menu choices.
ivr
Plays one of the tenant's menus and follows the key the caller pressed.
- id: menu
type: ivr
menu: main
| Field | Required | Notes |
|---|---|---|
menu | yes | The metadata.name of an IVRMenu of this tenant. Checked at startup. |
A caller who makes no valid choice falls through to the next step. Full behaviour, and the three destination types that do not work, are on IVR menus.
queue
Parks the caller in one of the tenant's queues.
- id: wait
type: queue
queue: support
timeout: 3m
moh: jazz
| Field | Required | Default | Notes |
|---|---|---|---|
queue | yes | — | A key of the tenant's queues. Checked at startup. |
timeout | no | the queue's maxWait | Bounds this plan's wait. Can only shorten the queue's own limit. |
moh | no | the queue's moh | Music class for this plan. |
Nobody answering before the wait runs out continues to the next step. See Call queues.
voicemail
Plays a greeting, plays a beep, and records a message. Then hangs up.
- id: box
type: voicemail
| Field | Required | Default | Notes |
|---|---|---|---|
mailbox | no | this plan's own extension | A key of the tenant's mailboxes. Checked at startup. |
greeting | no | the mailbox's greeting, then the shipped prompts | A WAV to play instead. |
voicemail_check
Asks for a PIN and plays a mailbox back.
- id: check
type: voicemail_check
| Field | Required | Default | Notes |
|---|---|---|---|
mailbox | no | the authenticated caller's own box | Naming one lets a trunk call reach it. |
With no mailbox the step refuses a call that did not authenticate — a call from
a trunk proved nothing about who placed it. See Voicemail.
record
Arms or disarms recording for this call.
- id: rec
type: record
action: start
confirm: ../sounds/recording-on.wav
| Field | Required | Values |
|---|---|---|
action | yes | start, stop, toggle |
confirm | no | A WAV played after the change. |
It arms rather than opens: the file is created when the call is bridged, so
put the step in front of the dial it applies to.
dnd
Sets do-not-disturb for the endpoint that placed the call.
- id: dnd
type: dnd
action: on
confirm: ../sounds/dnd-on.wav
| Field | Required | Values |
|---|---|---|
action | yes | on, off, toggle |
confirm | no | A WAV played once the change has been made. |
forward
Sets or clears call forwarding for the endpoint that placed the call.
- id: set
type: forward
action: set
mode: always
collect: true
prompt: ../sounds/enter-number.wav
confirm: ../sounds/forward-set.wav
| Field | Required | Values |
|---|---|---|
action | yes | set, clear |
mode | yes | always, noanswer — busy is refused at startup |
collect | for set | true. There is nowhere else the destination could come from. |
prompt | no | Asks for the destination. |
confirm | no | Played once the change has been made. |
Both dnd and forward refuse a call that is not from an authenticated
endpoint, and only ever change the state of the caller, never of the number
that was dialled. See Feature codes.
Music on hold classes
moh on a dial step and the moh step both take a class name:
kind: System
spec:
moh:
default: ../sounds/moh/default.wav
classes:
jazz: ../sounds/moh/jazz.wav
---
kind: Tenant
metadata: { name: acme }
spec:
domains: [acme.pbx.example.com]
moh:
classes:
jazz: ../sounds/moh/acme-jazz.wav # overrides the global jazz
The class default resolves to the tenant's moh.default, then the global one.
Validation refuses a class no tenant and no global definition provides — and
refuses default when neither level defines it.