PLAN_RESTRICTED

The action requires a higher plan tier — e.g. purchasing credits on the Free tier.

CodeHTTP statusRetryable?
PLAN_RESTRICTED403No

What this means

PLAN_RESTRICTED fires when an action is gated behind a paid tier and the caller is on Free. The most common trigger is `/v1/billing/credits-checkout` — Free users can RECEIVE credits via admin grants but cannot PURCHASE them. Other gated actions include `/serve/inject` (Pro+) and bulk-export operations on the dashboard.

When you'll see it

HTTP 403. Body always includes code: "PLAN_RESTRICTED". Branch on code, never on the human-readable message — wording can change without notice; the code is the stable contract.

Example response

json
{
  "status": "error",
  "code": "PLAN_RESTRICTED",
  "message": "Free tier cannot purchase credit packs; upgrade to Starter or above"
}

How to handle

Upgrade from app.buildonto.dev/read/billing — the cheapest Read tier is Starter at $9/mo. If you've hit this on a Serve action, the relevant tier is Pro at $19/mo. The dashboard shows exactly which tier each capability requires, so you can match the upgrade to the action.

Do NOT retry blindly. Account-level issue. Escalate to ops; rotating retries won't fix it.

Suggested handling in a Node client:

ts
if (data.code === 'PLAN_RESTRICTED') {
  // Surface upgrade CTA — never retry blindly.
  return res.status(402).json({ error: 'Upgrade required', upgradeUrl: 'https://app.buildonto.dev/read/billing' });
}
CodeStatusWhat it means
PAYMENT_REQUIREDHTTP 402You're past the plan cap AND your credit balance is zero.
UNAUTHORIZEDHTTP 401The Bearer token is missing, malformed, or has been revoked.

See the full error index for the complete catalog with the handling switch statement covering every code at once.