Multi-Tenant & White-Label
SIP.IO is multi-tenant from the ground up, with first-class support for resellers and white-label operators. This page explains the account hierarchy and how tenancy flows through the system.
The account hierarchy
Section titled “The account hierarchy”An account is a tenant. Accounts form a tree via parent_id:
- A platform-direct account has
parent_id = NULL. - A reseller account (
is_reseller = 1) can own child accounts, brand them, and bill them.
Platform├── Account: Acme Corp (platform-direct)└── Account: VoiceReseller Inc. (is_reseller = 1) ├── Account: Bistro Group (white-labeled under VoiceReseller) └── Account: City ClinicEvery tenant row in the data model carries an explicit, indexed account_id, so tenancy is never implicit: it’s a column you can see, index, and enforce.
Per-account branding & defaults
Section titled “Per-account branding & defaults”Each account carries its own branding and defaults, which children inherit unless overridden:
| Field | Purpose |
|---|---|
brand_name, brand_domain | White-label brand and the portal/API host for a reseller. |
timezone | Default timezone for the account (used by schedules unless a schedule overrides it). |
language | Default prompt language (one of the 16 supported languages). |
voice_gender | Default narrator gender for system prompts (male / female). |
default_cid_number | Default outbound caller-ID number. |
did_default_dest_kind / did_default_dest_id | Where unrouted DIDs land. |
A reseller serves its own customers under its own SIP domains (sip_domain) and brand domain, so end customers never see the platform.
SIP domains & realms
Section titled “SIP domains & realms”An account can answer on several SIP domains: its own plus white-label vanity domains. The domain is the realm used for digest authentication, so 1002@acmeA and 1002@acmeB are distinct identities even with the same extension number. Registration lookups are domain-scoped (use_domain), keeping tenants cleanly separated at the registrar.
How tenancy is enforced
Section titled “How tenancy is enforced”Tenancy isn’t just a data convention: it’s enforced at each decision point:
/authresolves the device by(auth_username, realm)and returns the owningaccount_id; the SIP signaling layer binds that account context to the registration./routescopes every lookup byaccount_id: DIDs, extensions, outbound routes, transforms, and caller-ID rules are all matched within the tenant.- stateful edge objects are per-account. The
PresenceDOandBalanceDOare addressed byaccount_id, so one tenant’s presence, ACD, CAC counters, and wallet are physically isolated in their own object.
Concurrency & spend per tenant
Section titled “Concurrency & spend per tenant”Each account has its own concurrency ceilings (max_in, max_out, max_dialer) and its own CAC counters in its PresenceDO. Spend is governed by a separate retail wallet (BalanceDO) plus the wholesale carrier’s authoritative balance, so one tenant can’t consume another’s capacity or budget.
Reseller billing
Section titled “Reseller billing”The account tree carries the billing relationship: a child account’s usage rolls up to its reseller parent. Wholesale termination and balance are handled by the carrier integration per subaccount, while the platform tracks the retail relationship.
Practical guidance
Section titled “Practical guidance”- Put each end customer in its own
account; give resellersis_reseller = 1and their ownbrand_domain. - Set the account’s
timezone,language, andvoice_genderonce, and schedules and prompts inherit them. - Use per-account
max_*ceilings as the first line of capacity isolation; layer rate rules on top for finer control.