Skip to content

Tenants

Explain what a tenant is in Get2Dial and how tenant isolation is enforced.

A tenant is an isolated customer account, modeled in the tenants table (id UUID, unique domain, status, JSONB settings/limits/features). It owns its users, campaigns, routing, data and a dedicated edge. The shared control plane serves all tenants but scopes every request to exactly one, derived from the caller’s JWT tid claim.

Two reserved identities exist:

  • Platform tenant 00000000-0000-0000-0000-000000000000 (is_platform=true, domain platform.get2dial.local) — where platform_admin users live.
  • Dev tenant a0000000-0000-0000-0000-000000000001 (dev.get2dial.local) — seeded for development; the all-zero platform id can never collide with the a0000000-… app-tenant range.

Tenant identity belongs on the customer edge, not the shared control plane:

Terminal window
# On the edge call engine (single-tenant):
TENANT_ID=<the customer edge tenant UUID>
# On the shared control API: NO TENANT_ID — scoped per request from the JWT.

Tenants are created by the bootstrap flow or POST /api/v1/platform/tenants. Platform admins can set per-tenant limits (resource quotas) and features (boolean entitlements, deny-by-default — e.g. self_service_carriers).

A CDR written by the edge carries g2d_tenant_id (from a SIP header, falling back to the node’s NODE_TENANT_ID). If a bridged leg arrives without it, the call engine’s TENANT_ID is the fallback — which is why that value must be the real customer tenant, never a shared default.

  • Pinning a tenant on the shared control plane causes data to land under the wrong tenant. Don’t.
  • Isolation is defense-in-depth: JWT scoping, Postgres RLS (app.tenant_id), per-tenant Redis ACLs and NATS subject permissions.
  • Each edge serves exactly one tenant.