Skip to content

Namespace Profiles

A namespace profile is a named bundle of configuration a parent namespace offers to its children: these translation contexts, these line profiles, these voicemail policies, plus a set of granted aliases. The parent attaches a profile to a child through the child’s namespace linkage, and the selected entries are merged into the child’s configuration automatically.

This is the reseller/carrier workflow in practice: author your standard service classes and routing once, in the parent, and every customer namespace receives them — while each child remains free to add its own configuration on top, or override what it received.

namespace-profiles:
standard-tenant:
inherit-translation-contexts: [shared-routing, to-pstn]
inherit-line-profiles: [residential, business]
inherit-screening-contexts: [no-intl, no-toll]
inherit-voicemail-contexts: [default-vm]
inherit-special-number-profiles: [default]
granted-aliases:
pstn: self

A profile does nothing by itself. It takes effect only when a linkage’s inheritance: block names it for a specific child (or for every child, via the child shorthand entry) — see Namespace Linkages for the grant side.

Each inherit-* field is a list of entry names from the corresponding section of the parent’s configuration:

Profile field Parent section selected from
inherit-translation-contexts translations:
inherit-screening-contexts screening-contexts:
inherit-line-profiles line-profiles:
inherit-trunk-profiles trunk-profiles:
inherit-voicemail-contexts voicemail-contexts:
inherit-caller-id-contexts caller-id-contexts:
inherit-special-number-profiles special-number-profiles:
inherit-feature-code-maps feature-codes:
inherit-namespace-profiles namespace-profiles: (yes — profiles themselves)

Every name in an inherit-* list must exist in your configuration; a dangling name is rejected when you store the version.

Note what is not on the list: lines, devices, trunks, ring groups, voicemail boxes, routes, recordings, linkages, the stirshaken policy, and the configuration: map are never inheritable. Only reusable, template-like sections travel; a child’s concrete subscribers, interconnects, and policies are always its own.

granted-aliases is a map of friendly name → target namespace that every child using this profile receives (it appears in the child’s effective configuration as received-aliases:). The special value self resolves to the granting parent’s own namespace ID:

granted-aliases:
pstn: self # "pstn" = me, the parent
conference: 019078a2-1a49-7bbb-8888-3f0c9d1e2f55 # a concrete nsid

An alias is what lets a child write resource-type: pstn or resource-type: namespace / resource-id: conference in its translation rules without knowing any namespace IDs. No alias is built in — pstn only exists in a child because a parent granted it.

The per-child linkage grant can also carry granted-aliases; those overlay the profile’s set (the linkage wins on a name collision), letting you give one child a different pstn target than the rest.

An alias value may take three forms, each resolved to a concrete namespace ID when the child’s configuration is compiled:

  • self — the granting parent itself;
  • a namespace UUID — used literally;
  • the name of an alias you yourself received — re-granting by name. pstn: pstn hands your own pstn target down, so an alias chains through a multi-level tree without any namespace knowing the concrete ID at the top.

Any other value is rejected when you store the version, so a typo’d grant can never materialize as an unresolvable alias in a child. (A grant naming a namespace that has since been deleted still fails at call time, with the route’s failure treatment.)

When a child namespace stores a configuration version, the system compiles the child’s effective configuration — the document that actually runs — in a fixed sequence:

  1. Resolve the grant. The parent’s linkage for this child is found (an entry keyed by the child’s nsid wins; otherwise the child shorthand entry applies). Its inheritance.profile names the namespace profile to use. No linkage or no profile means nothing is selected — but see pass-through below.
  2. Select from the parent. Two sets are drawn from the parent’s running effective configuration:
    • Profile-selected entries — every name listed in the profile’s inherit-* fields.
    • Pass-through entries — everything the parent itself inherited (entries present in the parent’s effective configuration but not authored by the parent). These flow down automatically, to every child, whether or not a profile selects them.
  3. Overlay the child. The child’s authored document is laid on top of the selected set. Where a name collides, the child’s definition replaces the inherited one in its entirety — a translation context, a line profile, a voicemail context is swapped as a whole unit, never merged rule-by-rule or field-by-field.
  4. Materialize aliases. The profile’s granted-aliases (overlaid by the linkage grant’s) are resolved — self becomes the parent’s nsid, and a re-granted alias name is resolved through the parent’s own received-aliases: — and written to the child’s received-aliases:.
  5. Validate the result. The merged document is validated as a whole, and stored as the version’s effective configuration.

Three consequences of this model deserve emphasis:

The merged document is validated in the child’s context. An inherited translation context whose rules target a named resource (a specific line, ring group, trunk, or route) will fail the child’s validation unless the child happens to define that name — the parent’s resources do not exist in the child. Shared contexts must therefore be self-contained, using only targets that resolve anywhere:

  • resource-type: pstn / namespace with a granted alias,
  • resource-id: "!dialedNum" dynamic targets,
  • treatment, hangup, and application targets,
  • translation-context targets pointing at other inherited contexts.
# In the parent — safe to inherit: nothing here names a parent-local resource.
translations:
shared-routing:
"100":
match:
- ast-pattern: "_1XXX"
target:
resource-type: line
resource-id: "!dialedNum" # resolves against the CHILD's lines
not-found-treatment: vacant-code
"300":
match:
- ast-pattern: "_NXXNXXXXXX"
- ast-pattern: "_1NXXNXXXXXX"
modify:
operations:
- must-normalize: e164
target:
resource-type: pstn # resolves via the granted alias
failure-treatment: temporary-failure
"900":
match:
- always: true
target:
resource-type: treatment
resource-id: cannot-complete-as-dialed

The same rule applies to references between inherited entries: a line profile that names a screening context, or a voicemail context that names a default-greeting recording, needs its referent inherited alongside it (or defined by the child). Bundle dependent entries together in the profile.

The parent (a carrier) defines the standards and one profile:

# ---- parent namespace ----
line-profiles:
business:
inbound-translation-context: shared-routing
calling-features: [voicemail, cfa, cfb, cfna, dnd]
screening-contexts:
no-intl:
"100":
match:
- match-on-call-details:
match-on: call-type
match:
- exact: "international"
permit: false
"200":
match:
- always: true
permit: true
translations:
shared-routing:
# ... as above ...
namespace-profiles:
standard-tenant:
inherit-translation-contexts: [shared-routing]
inherit-line-profiles: [business]
inherit-screening-contexts: [no-intl]
granted-aliases:
pstn: self
ns-linkages:
child:
allow-inbound: true
inbound-transfer-context: from-tenants
inheritance:
profile: standard-tenant

A child under this parent can then be almost empty:

# ---- child namespace (authored) ----
configuration:
sip-realm: "tenant1.example.net"
edge-proxy: "198.51.100.10"
devices:
alice-desk: "1001"
lines:
"1001":
line-profile: business # inherited — not defined in this document
devices: [alice-desk]

The child’s effective configuration contains shared-routing, business, no-intl, and received-aliases: {pstn: <parent nsid>} alongside its own line — and line 1001 dials out through the parent because shared-routing targets the granted pstn alias.

If the child later wants different business-hours routing, it defines its own translations: shared-routing: — its version replaces the inherited one for that child only, and every other tenant keeps the standard.

Fetch a version’s effective configuration (rather than your authored document) to see the post-merge result: inherited entries appear in their sections, and received-aliases: shows your granted aliases resolved to concrete namespace IDs:

Terminal window
vsscli config get running --effective
# or over the API:
curl -s "$VSS/v1/ns/$NSID/config/running?view=effective" \
-H "Authorization: Bearer $TOKEN"

When routing behaves as if a rule you never wrote is firing, the effective view — together with the route-forensics log, which names the context and rule that matched — is the place to look. (Read-only: edit and push your authored document, never the effective one — see Managing Configuration Versions.)