> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Subaccounts API

> Parent-org control plane: create child orgs, transfer credits, manage their API keys, branding, custom domains, pricing overrides, and MCCMNC routing.

# Subaccounts API

For platforms reselling Orbit to their own customers — agencies, MSPs, vertical SaaS. A **parent org** creates and operates **subaccount orgs**, each with its own API keys, isolated data, optional custom branding and domain, and per-subaccount pricing.

**Base path:** `/api/v1/subaccounts`

**Authentication:** Parent-org session JWT or API key with admin role.

## Lifecycle

| Method   | Path                                  | Purpose                                                                                                                        |
| -------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `POST`   | `/api/v1/subaccounts/`                | Create a subaccount                                                                                                            |
| `POST`   | `/api/v1/subaccounts/provision`       | Create a fully-configured subaccount — org, plan, pricing, branding & funding — in one call                                    |
| `GET`    | `/api/v1/subaccounts/`                | List subaccounts                                                                                                               |
| `GET`    | `/api/v1/subaccounts/{id}`            | Get a subaccount                                                                                                               |
| `PUT`    | `/api/v1/subaccounts/{id}`            | Update name / contact / metadata                                                                                               |
| `DELETE` | `/api/v1/subaccounts/{id}`            | Delete a subaccount — releases its phone numbers and removes its data; the account stays listed under your deleted subaccounts |
| `POST`   | `/api/v1/subaccounts/{id}/finalize`   | Activate a pending (wizard-created) subaccount                                                                                 |
| `POST`   | `/api/v1/subaccounts/{id}/suspend`    | Suspend (blocks API + UI access)                                                                                               |
| `POST`   | `/api/v1/subaccounts/{id}/reactivate` | Lift a suspension                                                                                                              |

A subaccount created through the multi-step wizard starts as **pending** so an aborted setup never leaves a billing-active tenant behind. `POST /api/v1/subaccounts/{id}/finalize` promotes it to **active** on the final Launch step. It is idempotent — calling it on an already-active subaccount returns `200` and changes nothing. `POST /api/v1/subaccounts/provision` finalizes for you as its last step.

### Single-call provisioning

`POST /api/v1/subaccounts/provision` stands up a complete, branded, funded subaccount in a single request — the API equivalent of the five-step new-subaccount wizard (organization → plan & limits → reseller pricing → funding → branding). Reach for it when you provision tenants from your own portal or back-office automation and don't want to orchestrate the separate create → pricing → branding → transfer-credits → finalize calls yourself.

The body flattens every wizard step. Only `name` is required; everything else is optional:

| Field                          | Type    | Notes                                                                                      |
| ------------------------------ | ------- | ------------------------------------------------------------------------------------------ |
| `name`                         | string  | Display name for the subaccount. **Required.**                                             |
| `slug`                         | string  | Vanity slug; auto-derived from `name` when omitted.                                        |
| `plan`                         | enum    | `starter`, `growth`, `business`, or `enterprise`.                                          |
| `max_team_members`             | integer | Seat cap for the subaccount.                                                               |
| `rate_limit_per_second`        | integer | Per-second API rate limit.                                                                 |
| `reseller_margin_pct`          | number  | Markup applied over Orbit wholesale, `0`–`100`.                                            |
| `monthly_spend_cap_cents`      | integer | Hard monthly spend ceiling, in minor units (cents).                                        |
| `initial_credits_cents`        | integer | Optional credit seed transferred from the parent wallet.                                   |
| `branding`                     | object  | White-label overrides: `primary_color`, `accent_color`, `dashboard_name`, `support_email`. |
| `inherit_branding_from_parent` | boolean | Inherit the parent's branding instead of setting your own.                                 |

The call is atomic: if any step fails after the org is created, the half-provisioned subaccount is rolled back so the slug stays free to retry. On success (`201`) the response carries the new subaccount plus its applied `pricing`, the `branding_applied` fields, the `initial_credits` transfer, and any non-blocking `warnings` — for example, a reseller margin below the recommended floor.

## Usage & credits

| Method | Path                                          | Purpose                                                                                                             |
| ------ | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| `GET`  | `/api/v1/subaccounts/{id}/usage`              | Usage & cost for a single subaccount                                                                                |
| `GET`  | `/api/v1/subaccounts/{id}/usage/statement`    | Billing-grade reseller statement for a period — per day × meter, with your reseller markup and margin earned (JSON) |
| `GET`  | `/api/v1/subaccounts/{id}/usage/export.csv`   | The same statement as a downloadable CSV to invoice your end-customer                                               |
| `GET`  | `/api/v1/subaccounts/usage-rollup`            | Consolidated usage & cost across **every** subaccount for a period                                                  |
| `GET`  | `/api/v1/subaccounts/usage-rollup/export.csv` | The consolidated rollup as a downloadable CSV                                                                       |
| `POST` | `/api/v1/subaccounts/{id}/transfer-credits`   | Move credits from parent to subaccount                                                                              |

`GET /api/v1/subaccounts/usage-rollup?period=YYYY-MM` returns one consolidated report across your whole subaccount tree for a billing period: grand totals plus a per-subaccount breakdown that reconciles line-for-line with each subaccount's own usage. Omit `period` to default to the current UTC month.

`GET /api/v1/subaccounts/{id}/usage/statement?period=YYYY-MM` returns the reseller statement for one subaccount: a line per day × channel/meter carrying quantity, base (wholesale) cost, the marked-up price under that subaccount's reseller margin, and the margin you earned, plus a totals footer. `GET /api/v1/subaccounts/{id}/usage/export.csv` streams the identical figures as a CSV attachment so you can invoice your end-customer or hand it to an auditor. Both default to the current UTC month when `period` is omitted; a malformed `period` returns `422 VALIDATION_ERROR`.

## API keys

| Method | Path                                | Purpose                            |
| ------ | ----------------------------------- | ---------------------------------- |
| `GET`  | `/api/v1/subaccounts/{id}/api-keys` | List the subaccount's API keys     |
| `POST` | `/api/v1/subaccounts/{id}/api-keys` | Issue a new key for the subaccount |

## Branding & custom domains

| Method   | Path                                                 | Purpose                              |
| -------- | ---------------------------------------------------- | ------------------------------------ |
| `GET`    | `/api/v1/subaccounts/{id}/branding`                  | Get effective branding               |
| `PUT`    | `/api/v1/subaccounts/{id}/branding`                  | Override logo / colors / brand name  |
| `POST`   | `/api/v1/subaccounts/{id}/domains`                   | Add a custom domain (CNAME-verified) |
| `GET`    | `/api/v1/subaccounts/{id}/domains`                   | List domains                         |
| `DELETE` | `/api/v1/subaccounts/{id}/domains/{domainId}`        | Remove a domain                      |
| `POST`   | `/api/v1/subaccounts/{id}/domains/{domainId}/verify` | Trigger DNS re-verification          |

## White-label notification email

| Method | Path                                          | Purpose                                                                                     |
| ------ | --------------------------------------------- | ------------------------------------------------------------------------------------------- |
| `GET`  | `/api/v1/subaccounts/{id}/notification-email` | Get the from-name / from-address override, its verification state, and the effective sender |
| `PUT`  | `/api/v1/subaccounts/{id}/notification-email` | Set or clear the notification from-address for the subaccount                               |

Notification emails a subaccount sends can go out under its own sender identity. `PUT /api/v1/subaccounts/{id}/notification-email` accepts `from_name` and `from_address`; the override is saved immediately but only becomes the **effective** sender once its sending domain passes DKIM/SPF. Until then — or when you clear the override by sending an empty `from_address` — resolution falls back to the parent's sender, then the platform default. The `GET` response returns the stored override, its `verified` flag, and the `effective` sender actually in use.

This endpoint shares branding's auth model: a parent admin manages any child's config, and a subaccount's own admin/owner manages its own when `{id}` is the caller's organization.

## Pricing overrides

| Method   | Path                                                     | Purpose                                                          |
| -------- | -------------------------------------------------------- | ---------------------------------------------------------------- |
| `GET`    | `/api/v1/subaccounts/{id}/pricing`                       | Get the subaccount's margin, spend cap, and current-period spend |
| `PUT`    | `/api/v1/subaccounts/{id}/pricing`                       | Set the subaccount's reseller margin and monthly spend cap       |
| `GET`    | `/api/v1/subaccounts/{id}/mccmnc-overrides`              | Per-MCCMNC pricing overrides                                     |
| `POST`   | `/api/v1/subaccounts/{id}/mccmnc-overrides`              | Add an override                                                  |
| `DELETE` | `/api/v1/subaccounts/{id}/mccmnc-overrides/{overrideId}` | Remove an override                                               |

Subaccount pricing is a **flat reseller margin**: a single markup percent (`reseller_margin_pct`, `0`–`100`) applied over Orbit wholesale rates, plus an optional monthly spend cap (`monthly_spend_cap_cents`). It is not priced per channel. When you need finer control for specific mobile destinations, layer per-MCCMNC rate overrides on top.
