Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Models Tools & Services
Solutions
Organisations Developers Internet Service Providers Managed Service Providers AI-in-a-Box
Resources
Support Documentation Blog Downloads
Company
About Research Careers Investment Opportunities Contact
Log in

Dialplans

A dialplan is a list of rules. Each rule has a match (when does it apply?) and an action (what does it do?). The dialplan engine evaluates rules in priority order — lowest number first — and stops at the first match. Rules with no match are skipped; if no rule matches, the call hangs up with end_reason=no_rule_matched.

Match types#

Six match types, all stored as typed JSON in match_params. The admin UI's visual builder writes them for you; the wire shape is here for completeness.

always#

Always matches. Useful as a fallback at the bottom of the rule list (priority 999) so calls don't fall through to a 404.

json
1
{"match_type": "always", "match_params": {}}

did#

Matches when the call arrived on a specific DID.

json
1
{"match_type": "did", "match_params": {"did_id": "did_abc123"}}

Use when one dialplan serves multiple DIDs and you want different behaviour per number. A more common pattern is one dialplan per DID — wire the Did row directly to the dialplan and use other match types inside.

extension#

Matches when the call is being routed to a specific extension. This is for sub-dialplans called from other dialplans (a v1.1 feature), not the typical inbound flow.

json
1
{"match_type": "extension", "match_params": {"extension_id": "ext_abc123"}}

caller_prefix#

Matches when the caller's E.164 starts with a given prefix. Useful for country-based routing.

json
1
{"match_type": "caller_prefix", "match_params": {"prefix": "+31"}}

The prefix must be a valid E.164 starting with + and 1-15 digits.

time_window#

Matches when the call arrives within a day-of-week + time-of-day window. Useful for business-hours routing.

json
1
2
3
4
5
6
7
8
9
{
  "match_type": "time_window",
  "match_params": {
    "days": [0, 1, 2, 3, 4],
    "start_time": "09:00",
    "end_time": "17:00",
    "timezone": "Europe/Amsterdam"
  }
}

Days are 0-6 with Monday = 0. Times are 24-hour HH:MM. Timezone is an IANA name (or UTC). The visual builder normalises this — duplicate days are removed, sort order is enforced, and the time range is sanity-checked.

End time before start time means "this is an overnight window" (e.g. 22:00-06:00 → night-shift routing).

Action types#

Six actions. Each writes to action_params.

ring_extension#

The most common action — ring an extension. Type and ringing semantics come from the extension itself.

json
1
2
3
4
{
  "action_type": "ring_extension",
  "action_params": {"extension_id": "ext_abc123"}
}

If the extension's type is wave, the call rings the user's softphone. If bot, ScaiBot's voice worker joins the room. If voicemail, the call goes straight to voicemail. If external or sip_endpoint, the call is forwarded.

ring_bot#

Skip the extension layer and ring a bot directly. Useful when you want a "press 0 to talk to a bot" rule without a placeholder extension row.

json
1
2
3
4
{
  "action_type": "ring_bot",
  "action_params": {"bot_id": "bot_abc123"}
}

voicemail#

Record the caller into a voicemail box. extension_id is optional — when set, the voicemail is associated with that extension (and the extension owner sees it in /my/dial); when unset, it lands in the tenant's default box.

json
1
2
3
4
{
  "action_type": "voicemail",
  "action_params": {"extension_id": "ext_abc123"}
}

If the tenant opted into voicemail transcripts (Settings page), the recorder runs ScaiEcho after the call ends and stores the transcript + summary on the row.

forward#

Forward the call to an external E.164 or SIP URI via SIP REFER. The caller is removed from the original room once the carrier accepts the REFER.

json
1
2
3
4
{
  "action_type": "forward",
  "action_params": {"to": "+31201234567"}
}

hangup#

Terminate the call. Useful as a final rule when you want a blocklist:

json
1
2
3
4
5
6
7
{
  "priority": 1,
  "match_type": "caller_prefix",
  "match_params": {"prefix": "+44900"},
  "action_type": "hangup",
  "action_params": {}
}

play_message#

Play a TTS message then hang up. Useful for after-hours announcements.

json
1
2
3
4
5
6
7
{
  "action_type": "play_message",
  "action_params": {
    "text": "Our offices are closed. Please call back during business hours.",
    "voice_id": "vc_abc123"
  }
}

The voice_id is a ScaiSpeak voice your tenant has access to.

Priority and ordering#

Lower priority numbers fire first. The builder defaults new rules to 100; if you want a rule to act as a fallback, set it to 999. We recommend leaving room (100, 200, 300...) so you can insert rules later without renumbering.

Rules with the same priority are evaluated in created-at order, but you shouldn't rely on that — set distinct priorities.

A real-world example#

A small office wants:

  1. Calls during business hours ring the reception desk (ext 100).
  2. Calls during business hours that go unanswered after 25s ring the support bot.
  3. Calls outside business hours go to voicemail.
  4. Calls from a known spam prefix get dropped.
scdoc
1
2
3
4
priority 10  | caller_prefix +44900       | hangup
priority 100 | time_window Mon-Fri 9-17   | ring_extension ext_reception
priority 200 | time_window Mon-Fri 9-17   | ring_bot bot_support_assistant
priority 999 | always                     | voicemail

Rule 100 fires for in-hours calls. The "ring then bot" failover comes from setting ring_timeout_s = 25 on the reception extension and timeout_action = ring_bot with timeout_forward_to = bot_support_assistant. The dialplan stays simple; the failover lives on the extension.

What dialplans don't do#

  • No call queues. v1 calls ring one extension; if a queue with multiple agents is what you want, route to a bot that bridges to a queue product.
  • No "press 1 to..." menus. IVR menus are a v1.1 feature. The current play_message action is one-way.
  • No simultaneous ring across extensions. A rule can ring exactly one extension or one bot. The "ring my desk and my mobile" pattern lives in forwarding rules on the extension, not the dialplan.
Updated 2026-06-23 01:06:32 View source (.md) rev 1