> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.voicebip.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.voicebip.com/_mcp/server.

# Plans & Tier Switching

> Inspect your subscription, switch between Starter / Builder / Scale mid-period with proration, and understand quota carryover.

Voicebip workspaces run on one of three tiered plans or in PAYG mode. You can switch tiers in the middle of a billing period — the platform refunds your unused base, charges the new tier's prorated base, and carries unused quota forward.

| Tier    | Monthly base                                   | Voice             | SMS                | WhatsApp Conversations |
| ------- | ---------------------------------------------- | ----------------- | ------------------ | ---------------------- |
| Starter | Free                                           | Per-minute rate   | Per-message rate   | Per-conv rate          |
| Builder | Per [pricing dashboard](/guides/usage-billing) | Included minutes  | Included messages  | Included conversations |
| Scale   | Per [pricing dashboard](/guides/usage-billing) | Higher includes   | Higher includes    | Higher includes        |
| PAYG    | None                                           | Always per-minute | Always per-message | Always per-conv        |

Live rates are admin-managed; the `/v1/workspace/subscription` endpoint returns whatever your workspace is currently subscribed to.

## Get Your Active Subscription

```bash
curl "https://api.voicebip.com/v1/workspace/subscription" \
  -H "Authorization: Bearer pk_live_your_key"
```

**Response — 200 OK**

```json
{
  "id": "sub_abc123",
  "workspace_id": "ws_abc123",
  "plan": "builder",
  "status": "active",
  "period_start": "2026-05-01T00:00:00Z",
  "period_end": "2026-06-01T00:00:00Z",
  "created_at": "2026-05-01T00:00:00Z",
  "updated_at": "2026-05-01T00:00:00Z"
}
```

| Status | Meaning                                            |
| ------ | -------------------------------------------------- |
| 200    | Active subscription returned                       |
| 404    | No active subscription — workspace is PAYG         |
| 503    | Subscription store unavailable (operational alert) |

## Switch Tiers

```bash
curl -X PATCH "https://api.voicebip.com/v1/workspace/subscription" \
  -H "Authorization: Bearer pk_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{ "plan": "builder" }'
```

**Response — 200 OK**

```json
{
  "subscription": {
    "id": "sub_abc123",
    "workspace_id": "ws_abc123",
    "plan": "builder",
    "status": "active",
    "period_start": "2026-05-01T00:00:00Z",
    "period_end": "2026-06-01T00:00:00Z",
    "last_tier_switch_at": "2026-05-15T14:32:01Z",
    "created_at": "2026-05-01T00:00:00Z",
    "updated_at": "2026-05-15T14:32:01Z"
  },
  "proration": {
    "refund_minor": 8064,
    "charge_minor": 24193,
    "net_minor": 16129,
    "proration_ratio": 0.5484,
    "days_remaining": 17,
    "period_days": 31,
    "currency": "NGN",
    "description": "17 days remaining, upgraded starter → builder"
  },
  "quota_after": {
    "voice_minutes_remaining": 1120,
    "sms_remaining": 4300,
    "whatsapp_remaining": 540,
    "numbers_included": 3
  }
}
```

### Proration Math

Net charge = (new tier base × days remaining ÷ period days) − (old tier base × days remaining ÷ period days).

A `net_minor > 0` means a debit was taken from your balance; `net_minor < 0` means a credit was issued. Both are recorded in the `recurring_charges` ledger and visible on the [usage dashboard](https://app.voicebip.com/billing).

### Quota Carryover

Unused voice minutes, SMS, and WhatsApp conversations from the old tier are **preserved** when you switch. The new tier's included quotas are **prorated** by `days_remaining / period_days` — not granted in full — so oscillating between tiers within one period cannot farm free quota. At the next anniversary the new tier's full monthly quota seeds.

## Errors

| Status | `error_code`               | Cause                                                                                          |
| ------ | -------------------------- | ---------------------------------------------------------------------------------------------- |
| 400    | `NO_OP`                    | Already on the requested plan — no transition needed.                                          |
| 400    | `TIER_SWITCH_UNSUPPORTED`  | Workspace is PAYG. Subscribe first via the dashboard.                                          |
| 400    | `INVALID_PLAN`             | Plan name is not one of `starter`, `builder`, `scale`.                                         |
| 402    | `INSUFFICIENT_BALANCE`     | The net charge would exceed your balance. Top up via [Paystack](/guides/topup-checkout) first. |
| 404    | `NO_ACTIVE_SUBSCRIPTION`   | Nothing to switch — workspace has no live subscription.                                        |
| 404    | `WORKSPACE_NOT_FOUND`      | The workspace could not be resolved.                                                           |
| 429    | `TIER_SWITCH_TOO_FREQUENT` | You changed tiers within the last 24 hours. The cooldown prevents abuse of proration math.     |
| 503    | `STORE_UNAVAILABLE`        | Subscription store temporarily unreachable. Retry.                                             |

## Idempotency

Tier-switch PATCHes are idempotent. If your client retries the same PATCH after a network timeout, the platform either:

* Returns `NO_OP` if the first attempt completed successfully, or
* Replays the first attempt's response (same `proration` payload) if the retry races the original.

You will not be double-billed. The underlying guarantee is a unique index on `(workspace_id, charge_type, period_start, proration_note)` in the `recurring_charges` ledger — a duplicate insert raises a constraint violation that the handler silently absorbs, preventing double-debits on retried requests.

## Cooldown

After a successful tier change, the next PATCH is rejected with `429 TIER_SWITCH_TOO_FREQUENT` for 24 hours. This is enforced server-side via `subscriptions.last_tier_switch_at`. The 24-hour window starts at the moment the transition committed, not at the moment of the next request.

If you need to switch tiers more often than once a day — e.g. during a controlled migration window — contact support and we can clear the cooldown manually.

## What Tier-Switching Does Not Do

* It does **not** change your API keys, agents, or numbers.
* It does **not** change your data residency or NDPR posture.
* It does **not** cancel a subscription. To stop being billed at a tier, switch to `starter` and the next anniversary will not auto-charge. Hard cancellation is not self-serve today — contact support.
* It does **not** affect in-flight calls or messages — they bill at the rate active when the usage event was published.

## Webhook Events

Tier switches do not emit a developer-facing webhook today. The internal `billing.charged` and `billing.pricing.updated` subjects fire but are not delivered. To detect a tier change in your application, poll `GET /v1/workspace/subscription` or watch the dashboard's audit feed.