Skip to main content

The subaccount organization model

Orbit has two levels of grouping that are easy to conflate: the tenant, which is the hard data boundary, and the organization tree inside a tenant, which is the soft, business boundary resellers use to model their own customers. This page defines that tree — parent organization, subaccounts, and the resources each one owns — so you can decide, per customer, whether to open a subaccount or a separate tenant, and so you can predict who sees what once the tree exists. For the mechanics of creating and operating subaccounts, see White-label subaccounts and Subaccounts API. For the hard boundary underneath, see Tenant isolation. This page is the model those guides operate on.

Section 1 — Parent org, subaccount, resource: the hierarchy

A subaccount is a full organization — a row in the shared public.organizations catalog with its own id, plan, API keys, users, and branding — created with a parent pointer to the reseller’s organization. Organizations with no parent are parent orgs; organizations with one are subaccounts. Nesting stops there: a subaccount cannot parent another subaccount.
Two properties make the tree meaningful:
  • The API key resolves one organization. Every key is issued against exactly one org — parent or subaccount. The auth layer resolves the key to that org on every request and derives the tenant from the org’s tenant_id; nothing in the request can override it. A caller is strictly one node of the tree at a time.
  • The subaccount is a scope inside a tenant, not a tenant. The entire parent family — the parent org and all its subaccounts — resolves to one tenant schema. Sibling subaccounts share tenant_<tenant_id>; only owners outside the family get a different schema. What separates siblings inside that shared schema is org ownership: every row carries an owning-org column and every read or write is gated against it (worked example in Tenant isolation, Section 3).
So the scope chain on any request is: API key → organization → tenant schema → row-level ownership gate. The key picks the org, the org picks the schema, ownership picks the rows.

Section 2 — Connection modes: which connection a subaccount’s channel resolves to

Per channel (SMS, Voice, Email, WhatsApp, and the LLM/voice-AI providers), a parent decides which connection its subaccounts’ traffic runs on. Three modes exist, and they compose per channel: The mechanics — the one-active-connection-per-type registry, masked credentials, the 403 when a subaccount tries to manage provider config, and fail-safe fallback — live in Per-channel connection mode: BYO vs platform default. One rule from that guide belongs in the model: BYO is parent-scoped and family-wide. A subaccount reading the reseller slice gets an empty provider list and a “managed by your parent” view; the parent is the single point of configuration.

Section 3 — Per-resource attribution: the reason a reseller can bill per subaccount

Every billable resource a subaccount creates is attributed to that subaccount’s organization id from the moment it exists. Attribution is not a report computed after the fact — it is the ownership column on each row, and usage aggregates roll up along it. That attribution is what makes the reseller statement vendible: usage rolls up per day × per meter per subaccount at wholesale cost, the parent’s margin markup applies over it, and an invoice to the end-customer is an export away. The concept beneath pricing — how a send resolves a rate — is on Pricing & rate resolution.

Section 4 — Cross-subaccount visibility: who can see what

Visibility follows the ownership gate, with one asymmetry: the parent sees the tree; a subaccount sees only itself.
  • The parent org reads and writes across its family: list all subaccounts, read each one’s usage, transfer credits, set pricing, manage branding, reassign owned numbers, and operate any subaccount directly. The parent’s vantage is the whole tree in Section 1.
  • A subaccount sees its own org only. Its key resolves to itself; a request for a sibling’s resource hits the ownership gate and fails. It reads the parent’s provider configuration as an empty list and its overview surfaces show a “managed by your parent” state where the parent owns the decision.
  • A subaccount’s own admin is admin of that one org — the {id} in a subaccount-management path is accepted only when it is the caller’s own organization. An end-customer with a subaccount key can never climb the tree upward or sideways.
The practical consequence: cross-sibling consolidation (a tree-wide usage rollup, a numbers move, a pricing sweep) is always a parent operation. If your end-customers need a consolidated view of each other, they are not subaccounts of one parent — they are separate tenants or separate orgs under their own parents.

Section 5 — Structuring audiences: campaigns, contacts, and shared assets

Two attributes split here — ownership is per-org; some assets can still be shared downward.
  • Contacts are subaccount-scoped. Audience data an end-customer uploads or syncs belongs to their subaccount and is gated to it. A subaccount builds its campaign audiences from its own contacts; a sibling’s list is unreachable.
  • Campaigns are per-subaccount artifacts. A campaign is created, targeted, and reported within one org. Dedicated senders on a campaign belong to the org that owns the campaign.
  • Shared assets flow downward, not sideways. Rate cards are the model example: the parent authors a pricing card once in its library and assigns it to any subaccount — the child resolves rates against the assigned card as a pointer, never a copy. Provider connections (Section 2) inherit the same way. Branding offers both shapes: inherit the parent’s branding wholesale, or override per subaccount.
The rule to remember: shared assets are authored at the parent, referenced by the child; audience and send artifacts are authored at the child, invisible to siblings. Design downstream tooling — bi-directional sync jobs, billing exports, support tooling — against that shape and you never have to special-case subaccounts.

Section 6 — What the subaccount model is NOT

Three comparisons settle most “should this be a subaccount?” debates:
  • Not tenant isolation. Subaccounts share one tenant schema; the isolation between siblings is the org-ownership gate the application enforces, not a database boundary. The SOC 2-visible guarantee Orbit makes — one schema per tenant, server-side tenant resolution — applies across families, never within one. The full argument is on Tenant isolation.
  • Not an RBAC role. Admin-of-subaccount is not a permission a user’s role grants; it is a property of which organization the credential resolves to. Roles inside an org (admin, member) still exist and still govern what a user of that org can do — but no role widens a caller beyond their own org.
  • Not a tenant shortcut. A subaccount is one API call cheaper than a new tenant, but it is also inside the parent’s tenant: same schema, family-wide BYO inheritance, parent-visible usage. Choose a separate tenant when the customer needs a hard data boundary from the reseller; choose a subaccount when the relationship is genuinely reseller-to-end-customer and consolidated operation is the point.

Cross-references