> ## 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.

# Troubleshoot subaccount budget refusals (SUBACCOUNT_CHANNEL_BUDGET_EXCEEDED, SUBACCOUNT_MONTHLY_SPEND_CAP_EXCEEDED)

> Your subaccount's sends refuse with 402 — determine which subaccount-scoped cap tripped, read its live usage, and raise the budget or wait for the monthly reset.

# Troubleshoot subaccount budget refusals

When a **subaccount's** sends or calls start refusing with `402`, one of two parent-set subaccount budgets is full: the per-channel monthly budget (`SUBACCOUNT_CHANNEL_BUDGET_EXCEEDED`) or the subaccount's aggregate monthly spend cap (`SUBACCOUNT_MONTHLY_SPEND_CAP_EXCEEDED`). The request never leaves the platform and nothing is billed for it. These are budget ceilings **you set on the subaccount** from the parent organization — they are not a wallet problem and they are not the org-level daily caps.

This page answers: **which subaccount budget fired, how it differs from the org-level gates, where to raise it, and how to read live usage while you wait for the reset.**

<Note>
  Subaccounts are child organizations under a parent (reseller or platform) account. If your account has no parent, the org-level pages apply instead: [spend-cap refusals](/troubleshooting/spend-caps-hit) and [INSUFFICIENT\_BALANCE](/troubleshooting/insufficient-balance). The account model is described in [Organizations and subaccounts](/concepts/org-and-subaccount-model).
</Note>

## Which code fired

Both refusals are `402` on the synchronous send path. Read the `error.code` field of the refusal and the `details` object beside it:

| Code | Scope | HTTP status | Where the ceiling is set | What trips it |
| - | - | - | - | - |
| `SUBACCOUNT_CHANNEL_BUDGET_EXCEEDED` | One channel (for example `sms` or `voice`) on one subaccount, per UTC month. | 402 | Parent-side: `PUT /api/v1/subaccounts/:id/channel-budgets` with `action: "block"` for that channel, or the channel-budget editor on the subaccount page in the dashboard. | The channel's month-to-date spend has reached its budget. `details` carries `channel`, `threshold_cents`, and `month_to_date_cents`. |
| `SUBACCOUNT_MONTHLY_SPEND_CAP_EXCEEDED` | The whole subaccount, all channels blended, per UTC month. | 402 | Parent-side: `PUT /api/v1/subaccounts/:id/pricing` with `monthly_spend_cap_cents`, or the spend-cap field on the subaccount page in the dashboard. | The subaccount's blended month-to-date spend has reached the cap. `details` carries `monthly_spend_cap_cents` and `month_to_date_cents`. Tripping it also pauses the subaccount's outbound until it is raised, resumed, or the month rolls over. |

Only a budget whose action is `block` refuses sends. A per-channel budget set to `alert` or `throttle` reports usage but never refuses; the aggregate cap has no action choice and always blocks once reached. Budgets with no configured value enforce nothing — an unset budget or cap is the uncapped default.

## Distinguish subaccount budgets from org-level gates

Three different families stop outbound with budget-shaped errors. Work the code against the response:

* **`SUBACCOUNT_*` 402 (this page)** — a ceiling set **on a child organization** from the parent. The wallet can read fine and the org-level caps can be untouched; the refusal names the subaccount's own budget. A top-level (parent) org is never refused by these two codes.
* **Org-level spend-cap `429`** (`SMS_DAILY_SPEND_CAP`, `CHANNEL_DAILY_SPEND_CAP`, `VOICE_DAILY_SPEND_CAP`, `CAMPAIGN_VOICE_SPEND_CAP_REACHED`) — daily or campaign ceilings on the **organization itself**, covered in [spend-cap refusals](/troubleshooting/spend-caps-hit). They reset at UTC midnight, not at the month boundary.
* **`INSUFFICIENT_BALANCE` (402)** — the **wallet pre-flight**: the org's credit balance cannot cover the send estimate. Top-up resolves it; raising a subaccount budget does not. See [INSUFFICIENT\_BALANCE (402)](/troubleshooting/insufficient-balance).

The practical tell: a subaccount budget refusal arrives while `balance_cents` reads fine **and** no org-level daily cap is tripped, and its `details` name a subaccount-scoped field (`threshold_cents` with a `channel`, or `monthly_spend_cap_cents`).

## View and raise the budget in the dashboard

Both controls live on the parent organization's subaccount page, **Settings → Subaccounts → the subaccount → pricing**, because they are parent-side governance over a child's spend:

* **Monthly spend cap** — the aggregate ceiling in cents; clear it to remove the cap.
* **Channel budgets** — one row per channel with a threshold and an `alert`, `throttle`, or `block` action.

The subaccount's own admins see their spend against these ceilings but cannot raise them: you chose the budgets, and the same surface shows the running month-to-date spend they are evaluated against. Only an owner or admin role on the **parent** organization can edit either control.

Raising the cap or budget resumes sends on the next attempt, within about a minute of saving. When the aggregate cap trips it also pauses the subaccount's outbound; if sends still refuse with a billing-pause message after you raise the cap, resume the subaccount as described in [billing-gate outbound blocks](/troubleshooting/billing-pause-block-recovery).

## Fix paths

1. **Raise the ceiling** (parent owner/admin): increase `monthly_spend_cap_cents` on `PUT /api/v1/subaccounts/:id/pricing`, or raise the blocked channel's threshold on `PUT /api/v1/subaccounts/:id/channel-budgets`. Takes effect within about a minute; sends resume immediately.
2. **Wait for the monthly reset** — both counters are per UTC calendar month and reset on the 1st at 00:00 UTC. A pause caused by the aggregate cap clears on rollover as well.
3. **Top up only fixes the wallet** — adding credits resolves `INSUFFICIENT_BALANCE`, never a `SUBACCOUNT_*` refusal. A subaccount with a full budget still refuses on a fully funded wallet. Conversely, raising a subaccount budget never spends wallet credits by itself; it only widens the child's envelope.

## Read current usage over the API

Both read endpoints require owner or admin on the parent organization:

* `GET /api/v1/subaccounts/:id/pricing` returns `monthly_spend_cap_cents` (null when uncapped) alongside `current_period_spend_cents`, the subaccount's running month-to-date spend the cap is evaluated against.
* `GET /api/v1/subaccounts/:id/channel-budgets` returns each configured channel budget (channel, threshold, period, action). The per-channel live spend that the block gate compares against is the same running counter surfaced on the subaccount page in the dashboard.

Thresholds and spend are expressed in US cents; divide by 100 to read dollars. Compare `current_period_spend_cents` against the cap before a batch or campaign launch rather than discovering the ceiling mid-run.

## Worked example — reseller whose client subaccount hits a channel block

You operate a platform account with a child org per client. One client's SMS traffic stops mid-month with `402 SUBACCOUNT_CHANNEL_BUDGET_EXCEEDED`.

1. The refusal's `details` show `channel: "sms"`, `threshold_cents: 20000`, `month_to_date_cents: 20000` — the SMS block budget is full.
2. Read `GET /api/v1/subaccounts/:id/channel-budgets` to confirm the SMS budget's action is `block`, and `GET /api/v1/subaccounts/:id/pricing` to check how much headroom the aggregate cap still has.
3. Either raise the SMS threshold (`PUT /api/v1/subaccounts/:id/channel-budgets` with the full budget set, since the call replaces it) or wait for the 1st-of-month UTC reset.
4. The next send succeeds within about a minute of the raise; nothing queued was lost, only refused.

The client's other channels kept sending the whole time — a `block` budget shapes one channel, and only the aggregate cap pauses the whole child.

## Anti-patterns

* **Retrying without raising the ceiling.** A `SUBACCOUNT_*` refusal re-evaluates only when the budget changes or the month rolls over. A retry loop burns rate-limit headroom and queue depth for the same 402.
* **Assuming `INSUFFICIENT_BALANCE` covers it.** The wallet gate and the subaccount budgets are separate pre-flight checks; topping up credits leaves a full budget exactly as full.
* **Assuming the org-level pages cover it.** [Spend-cap refusals](/troubleshooting/spend-caps-hit) documents the organization's daily and campaign caps; the subaccount family on this page is a different envelope with a monthly window.
* **Raising one ceiling to fix the other code.** A channel-block refusal persists while only the aggregate cap is raised, and vice versa. Raise the envelope the refusal names.

## See also

* [Spend-cap refusals](/troubleshooting/spend-caps-hit) — the org-level daily and campaign caps.
* [INSUFFICIENT\_BALANCE (402)](/troubleshooting/insufficient-balance) — the wallet pre-flight.
* [Organizations and subaccounts](/concepts/org-and-subaccount-model) — the parent/child account model.
* [Billing-gate outbound blocks](/troubleshooting/billing-pause-block-recovery) — resuming paused outbound.
* [Error codes reference](/reference/error-codes) — the canonical list of every enforcement code.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.