Skip to main content

Multi-environment subaccounts

Subaccounts are not only a reseller feature. A single organization can declare its own child organizations — one per environment (dev, staging, prod) or one per product line — and get per-subaccount wallets, spend caps, connection-scoped keys, and a spend-attribution structure that flat membership cannot express. Traffic and billing stay separated by design, without you maintaining three login environments. Every control in this guide is tenant-owned: nothing below changes how outbound traffic terminates. This guide covers the whole lifecycle — election, provisioning, funding, scope assignment, billing, and daily operations. Readers: platform engineers splitting one org into stages, or an org head splitting product lines.

1. The account after election

Provisioning follows the account operators you chose during signup. The creator of the organization becomes its owner; the people you invite into Settings → Team become the operators who administer subaccounts. Subaccount writes accept only owner or admin role tokens, so the election step of choosing operators lands here: subaccount management follows whoever you made an admin. See Team members, invitations, and roles if the operator list needs adjusting first — an environment subaccount inherits nothing about your member roster, and the parent’s admins are the people who can wire it.

2. Declare one subaccount per environment

One call per stage against the flat create endpoint. Reach for the plain POST /api/v1/subaccounts (or the one-shot POST /api/v1/subaccounts/provision) — both the reseller import flow and the channel connection modes pages build on the same pair:
Only name is required; plan, cap, and initial funding are optional. Repeat once per environment so naming stays unambiguous: payments-dev, payments-staging, or product-a / product-b for a product-line split. The response returns the child id (sub_...) you carry into every later step.

3. Deploy stages

A subaccount per stage gives each environment its own wallet, budget, and isolation boundary:
  • Per-subaccount wallet — credits transfer between the parent’s wallet and the child’s wallet with POST /api/v1/subaccounts/{id}/transfer-credits. Traffic on the child draws only from the child’s balance.
  • Budgetmonthly_spend_cap_cents on the child stops a stage from draining the parent wallet. Stage budgets are usually tighter than the production cap.
  • Plan and limits — seats and the rate limit follow the child, so a dev subaccount’s traffic ceiling does not compete with production callers.
The parent’s wallet is the feeder for every stage. When staging empties, another transfer tops it up; the parent’s remaining balance is unchanged until you move credits.

4. Reuse stages through scoped keys

Inheritance means the scoping rules your integration already knows apply per subaccount too. A key minted on the parent administers the tree; a key minted on the child reaches only that child — one leak can’t pivot across environments. The scope-per-integration guide walks through which scope family each surface needs; on a child you mint the same narrow pair (messages:write + messages:read, e.g.) and your staging worker uses its own scoped key just as a production one does.
Hand the returned key to the staging worker. A production worker gets a key minted on the production subaccount the same way — the pair never share credentials. Because the child-scope boundary sits at the key layer, you can rotate the stage key on a schedule without touching production.

5. Billing and attribution

A multi-environment tree gives you two attribution patterns at once; pick either or combine:
  • Payer/payee attribution — the parent’s org is the payer; each child is a payee. GET /api/v1/subaccounts/{id}/usage reads one child’s metered usage, and GET /api/v1/subaccounts/usage-rollup folds the whole tree, so the parent’s statement line-items per environment.
  • Chargeback per stage — finer tags still work: a metadata.cost_center on the send (see Cost-center chargeback) lets one environment split its own spend internally, e.g. stage_regression vs stage_ux, while the parent still sees one rollup line per child.
Membership structure stays relevant here: the parent’s admins are the members who read both surfaces — see Team management for who can reach the billing endpoints when the operator list changes.

6. Operate the lifecycle

Day-to-day operation is the parts you exercise once the tree exists:
  1. Subaccount-scoped vs tenant-scoped keys — a parent-scope key mints, funds, and retires children; a child-scope key does only the child’s messaging. Guard the integration by which scope the caller actually holds — a child key against POST /api/v1/subaccounts returns 403, the parent key against a child’s data returns 404 on reads the child scopes.
  2. Wallet isolation — a child cannot see the parent’s balance; the parent’s remaining-credit figure only moves when you transfer. Stage top-ups are explicit calls, never automatic drain.
  3. Organization-profile hygiene — when the parent’s profile changes (billing contact, organization name), the change lives on GET/PUT /api/v1/organization/profile; children inherit nothing by design, so environment display names and branding remain per-child even if you update the parent.
Worked example: a dev org runs a staged campaign against a stage child while production runs against the primary. POST /api/v1/campaigns on stage’s key sends the regression traffic; the same call with the production child’s key — which is the production workspace — handles live traffic. The parent’s rollup shows one usage line per stage, and the spend cap on stage means a runaway test campaign cannot drain production’s wallet.

See also