Translation Contexts
Translation contexts are the core routing engine of the switch. Every call that enters your namespace — from a subscriber line, from a SIP trunk, or handed over from another namespace — is walked through a translation context, which decides three things:
- Match — does this rule apply to the call?
- Modify — how should the dialed number be rewritten?
- Target — where does the call go?
If you have worked with a class-4/5 switch before, a translation context is a digit-analysis table; if you come from a PBX background, it is a dialplan context.
Where translation contexts are used
Section titled “Where translation contexts are used”Contexts are named blocks under the top-level translations: key. They never
run on their own — something must point a call at them:
| Referenced from | Field | Applies to |
|---|---|---|
| Line profile | inbound-translation-context |
Every number a line dials |
| Trunk profile | inbound-translation-context |
Calls arriving on the trunk (DID delivery) |
| Trunk profile | outbound-translation-context |
Calls being sent out the trunk |
| Namespace linkage | inbound-transfer-context / outbound-transfer-context |
Calls crossing between namespaces |
| Special-number profile | translation-context |
Early-matched emergency/priority numbers (911) |
| Voicemail context | outbound-translation-context |
The message-callback (“return the call”) feature |
| Another translation | target: translation-context |
Chained contexts |
Anatomy of a context
Section titled “Anatomy of a context”A context is a map of priority keys (numeric strings) to translation
objects. Each object has an optional match, modify, and target block:
translations: from-lines: "100": match: - ast-pattern: "_1NXXNXXXXXX" modify: operations: - add-prefix: "+" target: resource-type: route resource-id: outbound-lcr "200": match: - always: true target: resource-type: treatment resource-id: cannot-complete-as-dialedUse spaced priorities ("100", "200", "300") so you can insert rules later
without renumbering. Keys must be integers in quotes; non-integer keys are
ignored.
How the walk works
Section titled “How the walk works”The rules are evaluated lowest priority first. For each rule:
- The
matchblock is evaluated against the current dialed number. Entries in the list are OR’d — any one matching makes the rule match. A rule with nomatchblock never matches (usealways: truefor a catch-all). - On a match, the
modifyoperations run in order, rewriting the number. - If the rule has a
target, the walk ends — the call goes to that destination. First matching rule with a target wins. - If the rule has no target (a rewrite-only rule), the walk continues
from the next rule, carrying the rewritten number forward. The walk
never restarts from the top, so a rewrite-only
alwaysrule cannot loop. - If no rule matches by the end of the chain, the caller receives the
reordertreatment.
Every walk is recorded in the route forensics log: each rule evaluated, whether it matched, every rewrite step with before/after values, and the final target. When a call routes somewhere unexpected, the forensic record shows you exactly which rule fired.
Match operations
Section titled “Match operations”Each entry in a match list is one operation. Top-level entries are OR’d;
use and to require several conditions together.
Literal string equality against the current number.
match: - exact: "911"Quote the value — YAML would otherwise read a bare number and can drop leading zeros.
ast-pattern
Section titled “ast-pattern”An Asterisk-style dialplan pattern. Patterns must start with _; without the
underscore the value is treated as a literal (same as exact).
| Symbol | Matches |
|---|---|
X |
any digit 0–9 |
Z |
any digit 1–9 |
N |
any digit 2–9 |
[125-8] |
one character from the set (ranges with -) |
. |
one or more remaining characters (must be last) |
! |
zero or more remaining characters (must be last) |
- |
ignored (readability separator) |
match: - ast-pattern: "_1NXXNXXXXXX" # 11-digit NANP - ast-pattern: "_011." # international with 011 prefixA regular expression (RE2 syntax). The expression matches anywhere in the
number unless you anchor it — almost always anchor with ^ and $:
match: - regex: "^\\+1415555\\d{4}$"A nested list of match operations that must all be true. This is how you combine a number pattern with a time window or a call-detail condition:
match: - and: - ast-pattern: "_NXXNXXXXXX" - time-of-day: days: [mon, tue, wed, thu, fri] start: "08:00" end: "17:59" timezone: America/Chicagoand lists can nest further and blocks, patterns, time-of-day, and
match-on-call-details entries.
time-of-day
Section titled “time-of-day”Matches on the wall-clock time the call is processed.
| Field | Form | Empty means |
|---|---|---|
days |
list of mon tue wed thu fri sat sun |
every day |
start |
"HH:MM" 24-hour |
from midnight |
end |
"HH:MM" 24-hour, inclusive |
through end of day |
timezone |
IANA name, e.g. America/New_York |
UTC |
match-on-call-details
Section titled “match-on-call-details”Matches on enriched telephony metadata about the calling, called, or routing number (OCN, LATA, state, rate center, jurisdiction) instead of the dialed digits. Covered in full on its own page: Call-Detail Enrichment.
match: - match-on-call-details: match-on: call-type match: - exact: "international"always / never
Section titled “always / never”always: true matches unconditionally — the standard catch-all / default
rule. never: true never matches — useful for temporarily disabling a rule
without deleting it.
Modify operations
Section titled “Modify operations”The modify block rewrites the dialed number. Operations run in listed order,
each seeing the previous operation’s output.
modify: failure-treatment: cannot-complete-as-dialed operations: - strip-prefix: "9" - must-normalize: e164Operation reference
Section titled “Operation reference”| Operation | Argument | Effect |
|---|---|---|
replace |
string | Replace the entire number with the argument |
normalize / must-normalize |
e164, nanp, or national |
Reformat the number (see below) |
strip-prefix / must-strip-prefix |
string | Remove the argument from the front if present |
strip-suffix / must-strip-suffix |
string | Remove the argument from the end if present |
add-prefix |
string | Prepend the argument |
add-suffix |
string | Append the argument |
isolate-digits |
"start:stop" |
Keep only digits, then keep the inclusive zero-based range |
regex-replace / must-regex-replace |
"pattern!replacement" |
Regex substitution (see below) |
Normalize modes. The number is parsed as a phone number (10-digit numbers are assumed to be North American):
e164— full international form:+13125551212nanp— bare 10-digit national number:3125551212. Fails for non-NANP (non-+1) numbers.national— the number’s national display format.
isolate-digits. First removes every non-digit character, then keeps the
inclusive, zero-based range start:stop. Either side may be empty:
"0:2" keeps the first three digits, "3:" drops the first three,
":" keeps all digits (i.e. just strips formatting).
regex-replace. The argument is split on the first ! into a regex
and a replacement; the replacement may use capture groups ($1, $2). If the
pattern does not match, the number is left unchanged (or, for the must-
variant, the rule fails):
# 011 + country code dialing → E.164- regex-replace: "^011(\\d+)$!+$1"Soft vs must- semantics
Section titled “Soft vs must- semantics”Every conditional operation comes in two flavors:
- Soft (
strip-prefix,normalize, …): if the operation cannot apply (prefix absent, number unparseable, regex didn’t match), it is skipped and the walk continues normally. must-(must-strip-prefix,must-normalize, …): if the operation cannot apply, the rule fails terminally — the caller immediately receives the block’sfailure-treatment(defaultreorder).
Targets
Section titled “Targets”The target block names the destination. resource-id may contain the token
!dialedNum, which is substituted with the dialed number after the modify
block has run — this is how one rule serves a whole number block.
target: resource-type: line resource-id: "!dialedNum" not-found-treatment: vacant-code failure-treatment: temporary-failureTarget types
Section titled “Target types”resource-type |
resource-id |
The call… |
|---|---|---|
line |
line name or !dialedNum |
rings the line’s devices (honoring the line’s features) |
ring-group |
ring-group name | runs the hunt group |
device |
device name | rings a single device directly, bypassing line features |
trunk |
trunk name | is sent out one specific SIP trunk |
route |
route name | is sent out a route block (trunk selection strategy and/or LCR) |
voicemail-box |
box name or !dialedNum |
goes straight to the mailbox to leave a message |
treatment |
treatment name | plays the treatment announcement/tone and releases (see below) |
recording |
recording name | plays the named recording |
namespace |
namespace ID or granted alias | is transferred into another namespace, subject to that namespace’s linkage policy |
pstn |
— | is transferred to the PSTN via your granted pstn alias |
hangup |
— | is released immediately with normal clearing |
translation-context |
context name or !dialedNum |
continues in another translation context |
application |
application name | is handed to an application (e.g. voicemail.access, voicemail.access-menu) |
Two per-target treatment overrides are available on every target:
not-found-treatment— played when the referenced resource doesn’t exist in the running configuration. Default:reorder.failure-treatment— played when the destination action fails (for example, the dial failed and no fallback answered). Default:reorder.
Chaining contexts
Section titled “Chaining contexts”A translation-context target jumps the walk into another context, carrying
the (rewritten) number with it. This is useful for factoring routing into
stages — e.g. an access-code stage, then a shared routing stage used by both
lines and inbound transfers.
Chains are limited to 8 hops, and the validator rejects configurations whose contexts form a loop.
Treatments
Section titled “Treatments”A treatment plays an announcement or tone to the caller and releases the call with a specific cause. Your PBX or upstream switch sees these as SIP final responses; they also appear in your call detail records as the Q.850 cause.
| Treatment | Meaning | Q.850 | SIP |
|---|---|---|---|
reorder |
congestion / routing failure (fast busy) | 34 | 503 |
busy |
called party busy | 17 | 486 |
disconnect |
normal clearing | 16 | — |
vacant-code |
number not in service | 1 | 404 |
unallocated-number |
number not assigned | 1 | 404 |
no-route |
no route to destination | 3 | 404 |
cannot-complete-as-dialed |
invalid number format | 28 | 484 |
temporary-failure |
transient network failure | 41 | 503 |
all-circuits-busy |
concurrent-call cap reached | 34 | 503 |
denied |
call rejected by policy | 21 | 403 |
toll-denied |
destination not permitted for this line (toll restriction) | 57 | 403 |
unauthorized-code |
unauthorized access/feature code | 21 | 403 |
caller-not-accepted |
caller rejected | 21 | 403 |
not-acceptable |
rejected by policy | 21 | 403 |
spam |
rejected as suspected spam | 21 | 403 |
Worked examples
Section titled “Worked examples”Hosted PBX (line-served customer)
Section titled “Hosted PBX (line-served customer)”Four-digit extension dialing, an operator, night service, and PSTN access — the context every line’s profile points at:
translations: from-lines: # Extension dialing: 1000-1999 → the matching line. "100": match: - ast-pattern: "_1XXX" target: resource-type: line resource-id: "!dialedNum" not-found-treatment: vacant-code
# Operator: business hours → front-desk ring group… "200": match: - and: - exact: "0" - time-of-day: days: [mon, tue, wed, thu, fri] start: "08:00" end: "17:59" timezone: America/New_York target: resource-type: ring-group resource-id: front-desk
# …after hours → general-delivery voicemail. "210": match: - exact: "0" target: resource-type: voicemail-box resource-id: "100"
# Rewrite-only: normalize any NANP form to E.164, then continue. "300": match: - ast-pattern: "_NXXNXXXXXX" - ast-pattern: "_1NXXNXXXXXX" modify: operations: - must-normalize: e164
# Off-net: everything E.164 goes to the PSTN. "400": match: - regex: "^\\+" target: resource-type: pstn failure-treatment: temporary-failure
# Catch-all. "900": match: - always: true target: resource-type: treatment resource-id: cannot-complete-as-dialedBecause forwards re-originate from the line, a line with call-forward-always set to a mobile number walks this same context — and succeeds, because rules 300/400 handle off-net numbers. Without them, forwarding would break.
DID delivery (trunk-served customer)
Section titled “DID delivery (trunk-served customer)”Inbound calls from a carrier arrive on a trunk; the trunk profile’s
inbound-translation-context delivers DIDs to lines:
translations: from-carrier: # Normalize the incoming DID to 10 digits. "100": match: - always: true modify: failure-treatment: cannot-complete-as-dialed operations: - must-normalize: nanp
# Main number → auto-attendant ring group. "200": match: - exact: "4155551000" target: resource-type: ring-group resource-id: main-line
# DID block 415-555-1001..1099 → matching lines. "300": match: - ast-pattern: "_41555510XX" target: resource-type: line resource-id: "!dialedNum" not-found-treatment: vacant-code
# Unknown DID: end here — NEVER route back out the trunk. "900": match: - always: true target: resource-type: treatment resource-id: unallocated-numberITSP / wholesale outbound
Section titled “ITSP / wholesale outbound”An outbound context that gates international calling, normalizes everything to E.164, and hands domestic traffic to an LCR-backed route:
translations: wholesale-out: # 011 international dialing → E.164, only if the account allows it. "100": match: - ast-pattern: "_011." modify: failure-treatment: cannot-complete-as-dialed operations: - must-regex-replace: "^011(\\d+)$!+$1" target: resource-type: route resource-id: international-carriers failure-treatment: no-route
# Domestic: normalize and send to the LCR route. "200": match: - ast-pattern: "_NXXNXXXXXX" - ast-pattern: "_1NXXNXXXXXX" modify: failure-treatment: cannot-complete-as-dialed operations: - must-normalize: e164 target: resource-type: route resource-id: domestic-lcr failure-treatment: all-circuits-busy
"900": match: - always: true target: resource-type: treatment resource-id: cannot-complete-as-dialedFor routing on jurisdiction, carrier of record, or ported-number data (for example, sending traffic for a specific OCN down a direct interconnect), see Call-Detail Enrichment.