Skip to main content

tenant.yaml reference

One file per tenant, in <tenants_dir>/<name>/tenant.yaml. Paths inside it resolve against the tenant directory.

name: acme
description: Acme Industries
domains: [acme.pbx.example.com]
dids: {...}
caller_id: {...}
accounts: [...]
ring_groups: {...}
inbound_routes: [...]
outbound_routes: [...]
moh: {...}
timezone: Europe/Amsterdam
inter_tenant: [globex]
extensions_dir: extensions

Top level

KeyTypeDefaultPurpose
namestringdirectory nameThe tenant identifier.
descriptionstringFree text, shown in the editor.
domainslistSIP domains this tenant's phones register with. Must be unique across tenants.
didsobjectNumbers this tenant owns on the shared trunks.
caller_idobjectOverrides the trunk's caller ID on outgoing calls.
accountslistSIP credentials.
ring_groupsmapNamed groups of targets.
inbound_routeslistDID → destination inside this tenant.
outbound_routeslistTried before the global routes. Same shape as the global ones.
mohobjectMusic-on-hold classes, layered over the global ones.
timezonestringglobal timezoneIANA timezone for this tenant's time conditions.
inter_tenantlistTenants this one may dial. Only effective with global allow_inter_tenant.
extensions_dirstringextensionsDirectory of dialplan files.

dids

dids:
numbers: ["+31201234567", "+31201234568"]
patterns: ['^\+312012345\d{2}$']
KeyTypeNotes
numberslistExact claims. Checked before patterns.
patternslistGo regular expressions. Not anchored implicitly.

A number claimed by two tenants is a validation error.

caller_id

caller_id:
number: "+31201234567"
name: Acme
KeyTypeNotes
numberstringPresented on outgoing calls, ahead of the trunk's.
namestringDisplay name.

accounts[]

accounts:
- username: alice
password: "..."
extension: "100"
display_name: Alice
KeyTypeRequiredNotes
usernamestringyesSIP username, unique within the tenant.
passwordstringyesDigest password, stored in plain text.
extensionstringyesExtension this account belongs to. Several accounts may share one.
display_namestringnoCaller name on internal calls.

ring_groups

ring_groups:
support:
strategy: simultaneous
targets: ["100", "101", "external:0612345678"]
timeout: 30s
KeyTypeRequiredNotes
strategystringyessimultaneous or sequential.
targetslistyesAt least one target reference.
timeoutdurationnoTotal ring time for simultaneous; per-target time for sequential. Defaults to 30s.

inbound_routes[]

inbound_routes:
- did: "+31201234567"
destination: {type: extension, target: "200"}
KeyTypeRequiredNotes
didstringyesThe number as it arrives, or * for a catch-all inside the tenant.
destination.typestringyesextension or ring_group.
destination.targetstringyesExtension number, or ring group name. Must exist.

outbound_routes[]

Identical in shape to the global outbound routes, and tried before them.

moh

moh:
default: ../../sounds/moh/acme.wav
classes:
jazz: ../../sounds/moh/acme-jazz.wav

Layered over the global map key by key: a class defined in both resolves to the tenant's file.

Target references

Wherever a target is accepted — ring group targets, follow-me stage targets, a dial step's endpoint — these three forms are valid:

FormMeaning
"101"An account extension of this tenant.
external:0612345678A number placed through the outbound routes.
tenant:globex/900Another tenant's extension, when inter-tenant calling is allowed on both switches.

Validation

  • ring_groups: invalid strategy; no targets; a target that is not a valid reference.
  • inbound_routes: a destination type that is not extension or ring_group; an unknown extension or ring group.
  • outbound_routes: a pattern that does not compile; an unknown trunk.
  • Target references: an extension that is not an account extension of the tenant; an empty external: target; a tenant: reference without allow_inter_tenant, without the tenant in inter_tenant, naming an unknown tenant, or naming an extension that tenant has no account for.
  • Across tenants: duplicate domains and duplicate DIDs.