Skip to main content

Extension file reference

One file per extension, in <tenant dir>/<extensions_dir>/<number>.yaml. Paths inside resolve against the tenant directory.

extension: "200"
name: "Support follow-me"
steps: [...]
KeyTypeRequiredNotes
extensionstringyesThe number this plan answers for.
namestringnoLabel shown in the editor and in logs.
stepslistyesOrdered steps, run top to bottom.

steps[]

Common keys on every step:

KeyTypeRequiredNotes
idstringnoLabel used in logs. Defaults to the step type.
typestringyesplay, dial, moh or hangup.
whenobjectnoTime condition gating the step.

Type-specific keys:

TypeKeyRequiredDefaultNotes
playfileyes8 kHz mono 16-bit PCM WAV. Answers the call if needed.
dialtargetyesSee below.
dialtimeoutno30sRing time; for followme, the per-stage fallback.
dialmohnoringbackMusic-on-hold class heard instead of ringback.
mohmohnodefaultClass name. Runs until the caller hangs up.
hangupNo fields.

target

target:
kind: endpoint | ring_group | followme | external
kindKeyRequiredNotes
endpointendpointyesA target reference.
ring_groupgroupyesName of a ring group in this tenant.
externalnumberyesNumber placed through the outbound routes.
followmestagesyesAt least one stage.

stages[]

stages:
- targets: ["101"]
timeout: 15s
- targets: ["100", "external:0612345678"]
timeout: 25s
KeyTypeRequiredNotes
targetslistyesAt least one target reference. Rung in parallel.
timeoutdurationnoFalls back to the step's timeout, then 30s.

Stages run in order; the first answer wins and the rest are cancelled. A target that resolves to nothing at call time — an extension with no registered device — is skipped.

when

when:
days: [mon, tue, wed, thu, fri]
hours: "09:00-17:30"
dates: ["2026-12-25", "2026-12-30..2027-01-01"]
timezone: Europe/Amsterdam
not: false
KeyTypeFormatNotes
dayslistmon tue wed thu fri sat sunCase-insensitive.
hoursstring"HH:MM-HH:MM"Start inclusive, end exclusive. Wraps midnight when start > end.
dateslist"YYYY-MM-DD" or "YYYY-MM-DD..YYYY-MM-DD"Ranges are inclusive on both ends.
timezonestringIANA nameOverrides the tenant timezone for this condition.
notboolInverts the combined result.

All configured parts must match. An omitted part is not a constraint. See Time conditions for the evaluation details and the traps around not.

A complete example

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

Validation

Every step is built and every time condition compiled at startup, so runtime never encounters bad configuration. Rejected: an unknown step type; play without file; dial without target; an invalid target kind; an unknown ring group; an empty external number; followme with no stages, or a stage with no targets; a music-on-hold class no level defines; and any invalid day, hour range, date, date range or timezone in a when block.