Skip to main content

Tenants

A tenant file describes one customer. The minimum is a domain; everything else has a global fallback or a default.

configs/tenants/acme/tenant.yaml
name: acme
description: Acme Industries
domains:
- acme.pbx.example.com
- voice.acme.example

dids:
numbers: ["+31201234567", "+31201234568"]
patterns: ['^\+312012345\d{2}$']

caller_id:
number: "+31201234567"
name: Acme

timezone: Europe/Amsterdam

moh:
classes:
jazz: ../../sounds/moh/jazz.wav

inter_tenant: [globex]
extensions_dir: extensions

Domains

domains: [acme.pbx.example.com]

The SIP domains this tenant's phones register with. They select the tenant for any endpoint request and become the digest realm for that tenant's authentication.

  • Domains must be unique across tenants; validation refuses a duplicate.
  • A tenant may have several domains, which is useful during a migration.
  • Phones must use the domain as their SIP domain and the PBX address as their outbound proxy.

DIDs

dids:
numbers: ["+31201234567"]
patterns: ['^\+312012345\d{2}$']

The numbers this tenant owns on the shared trunks. numbers are exact claims, patterns are Go regular expressions matched against the called number.

Exact claims are checked before patterns, and a number claimed by two tenants is a validation error. A global inbound_overrides entry beats both — see Inbound routing.

Anchor your patterns

^ and $ are not implied. '^\+312012345\d{2}$' claims a block of one hundred numbers; '\+312012345' would match any number containing that string.

Caller ID

caller_id:
number: "+31201234567"
name: Acme

Presented on outgoing calls, overriding the trunk's own caller ID. That is what lets several tenants share one carrier account and still each present their own number.

The resolution order is: the tenant's caller_id, then the trunk's caller_id, then nothing.

Timezone

timezone: Europe/Amsterdam

Used by this tenant's time conditions, overriding the global timezone. An individual condition can override it again with its own timezone: key. Names come from the IANA database.

Music on hold

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

The tenant's classes are layered on top of the global ones, key by key: a class name defined in both resolves to the tenant's file. A dial or moh step then refers to a class by name.

Paths resolve against the tenant directory.

Other keys

KeyPurpose
nameThe tenant's identifier. Defaults to the directory name.
descriptionFree text, shown in the editor.
accountsSIP accounts — see Accounts and extensions.
ring_groupsNamed groups — see Ring groups and follow-me.
inbound_routesDID → destination inside this tenant.
outbound_routesTried before the global routes.
inter_tenantTenants this one may dial directly.
extensions_dirWhere the dialplan files live. Defaults to extensions.

The full key-by-key listing is in the tenant configuration reference.