Inbound routing
Inbound routing answers two questions in order: which tenant owns this call, and which destination inside that tenant.
Which tenant
Matched in this order, first match wins:
- a global
inbound_overridesentry; - the owning tenant of the trunk, if the trunk names one;
- a tenant's exact DID claim (
dids.numbers); - a tenant's DID pattern (
dids.patterns); - a global catch-all override (
did: "*").
If nothing matches, the call is rejected.
dids:
numbers: ["+31201234567"]
patterns: ['^\+312012345\d{2}$']
A number claimed by two tenants is a validation error, so the ordering between steps 3 and 4 only matters when an exact number falls inside another tenant's pattern — the exact claim wins.
Which destination
Once the tenant is known, its own inbound_routes decide where the call goes:
inbound_routes:
- did: "+31201234567"
destination:
type: extension
target: "200"
- did: "+31201234568"
destination:
type: ring_group
target: sales
| Field | Values |
|---|---|
did | The number as it arrives, or * for a catch-all inside the tenant. |
destination.type | extension or ring_group |
destination.target | The extension number, or the ring group name. |
Routes are matched in order. A tenant with a single number usually needs one
route; a tenant with a block usually adds a * catch-all at the end so an
unmapped number still lands somewhere:
inbound_routes:
- did: "+31201234567"
destination: {type: extension, target: "200"}
- did: "*"
destination: {type: extension, target: "999"} # everything else
Global overrides
inbound_overrides in lyno.yaml win over everything a tenant claims. This is
how a number is redirected without touching the tenant that owns it:
inbound_overrides:
# hand acme's number to globex's extension 900
- did: "+31201234567"
tenant: globex
destination: {type: extension, target: "900"}
# only reassign the tenant; globex's own inbound routes then decide
- did: "+31201234599"
tenant: globex
# catch-all for numbers no tenant claims
- did: "*"
tenant: acme
destination: {type: extension, target: "999"}
| Field | Required | Meaning |
|---|---|---|
did | yes | The number, or * as a global catch-all. |
tenant | yes | The tenant that will handle the call. |
destination | no | Pins the destination. Without it, the tenant's own inbound routes run. |
An override is the right tool for temporary redirects — porting a number, covering an outage, moving a customer — because it is one entry in one file and leaves both tenants' configuration intact.
Worked example
Two tenants, one shared carrier:
trunks:
- name: carrier
host: sip.provider.example
inbound_overrides:
- did: "+31201234567"
tenant: globex
destination: {type: extension, target: "900"}
name: acme
domains: [acme.pbx.example.com]
dids:
numbers: ["+31201234567", "+31201234568"]
inbound_routes:
- did: "*"
destination: {type: extension, target: "200"}
A call to +31201234568 reaches acme extension 200 through the catch-all. A
call to +31201234567 — which acme also claims — is taken by the override and
lands on globex extension 900 instead. Nothing in acme's file changed.