Troubleshoot subaccount budget refusals
When a subaccount’s sends or calls start refusing with402, 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.
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 and INSUFFICIENT_BALANCE. The account model is described in Organizations and subaccounts.
Which code fired
Both refusals are402 on the synchronous send path. Read the error.code field of the refusal and the details object beside it:
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. 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).
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, orblockaction.
Fix paths
- Raise the ceiling (parent owner/admin): increase
monthly_spend_cap_centsonPUT /api/v1/subaccounts/:id/pricing, or raise the blocked channel’s threshold onPUT /api/v1/subaccounts/:id/channel-budgets. Takes effect within about a minute; sends resume immediately. - 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.
- Top up only fixes the wallet — adding credits resolves
INSUFFICIENT_BALANCE, never aSUBACCOUNT_*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/pricingreturnsmonthly_spend_cap_cents(null when uncapped) alongsidecurrent_period_spend_cents, the subaccount’s running month-to-date spend the cap is evaluated against.GET /api/v1/subaccounts/:id/channel-budgetsreturns 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.
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 with402 SUBACCOUNT_CHANNEL_BUDGET_EXCEEDED.
- The refusal’s
detailsshowchannel: "sms",threshold_cents: 20000,month_to_date_cents: 20000— the SMS block budget is full. - Read
GET /api/v1/subaccounts/:id/channel-budgetsto confirm the SMS budget’s action isblock, andGET /api/v1/subaccounts/:id/pricingto check how much headroom the aggregate cap still has. - Either raise the SMS threshold (
PUT /api/v1/subaccounts/:id/channel-budgetswith the full budget set, since the call replaces it) or wait for the 1st-of-month UTC reset. - The next send succeeds within about a minute of the raise; nothing queued was lost, only refused.
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_BALANCEcovers 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 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 — the org-level daily and campaign caps.
- INSUFFICIENT_BALANCE (402) — the wallet pre-flight.
- Organizations and subaccounts — the parent/child account model.
- Billing-gate outbound blocks — resuming paused outbound.
- Error codes reference — the canonical list of every enforcement code.