
## Tier change preview for Cowork/Code

`GET /v1/cowork/subscription/preview`

Returns the amount that will be debited immediately when switching to the specified tier and the date the change takes effect. This previews one specific operation, not a tier's catalog price.

## Parameters

| Parameter | Type | Req. | Description |
|----------|-----|:-----:|----------|
| `tier` (query) | string | yes | Tier to switch to: `FREE`, `PRO`, `MAX`, `ULTRA`. For the tier catalog, see [`GET /v1/cowork/state`](/docs/cowork/state) |

## Examples

### curl — personal key

```bash
curl "https://vibecode.bitrix24.com/v1/cowork/subscription/preview?tier=PRO" \
  -H "X-Api-Key: YOUR_API_KEY"
```

### curl — OAuth application

```bash
curl "https://vibecode.bitrix24.com/v1/cowork/subscription/preview?tier=PRO" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"
```

### JavaScript — personal key

```javascript
const url = 'https://vibecode.bitrix24.com/v1/cowork/subscription/preview?tier=PRO'
const res = await fetch(url, {
  headers: { 'X-Api-Key': 'YOUR_API_KEY' },
})

if (!res.ok) {
  const { error } = await res.json()
  console.error(error.code, error.message)
} else {
  const preview = await res.json()
  console.log(preview.scheduled
    ? `No charge now; the change takes effect on ${preview.effectiveFrom}`
    : `Charge: ${preview.netVibes} Vibe credits`)
}
```

### JavaScript — OAuth application

```javascript
const url = 'https://vibecode.bitrix24.com/v1/cowork/subscription/preview?tier=PRO'
const res = await fetch(url, {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})

const preview = await res.json()
```

## Response fields

| Field | Type | Description |
|------|-----|----------|
| `tier` | string | The tier from the request |
| `chargeVibes` | string | Total price of the operation in Vibe credits, returned as a decimal string. `"0"` when the operation is free |
| `creditVibes` | string | Credit for the unused portion of the paid month. Nonzero only for an upgrade and only when this feature is enabled for the account |
| `netVibes` | string | Amount debited immediately: `chargeVibes` minus `creditVibes`, never below zero. Show this value to the user |
| `effectiveFrom` | string | When the change takes effect, in ISO 8601 format: either the response time or the end of the paid period when `scheduled: true` |
| `scheduled` | boolean | `true` — the change takes effect at the end of the paid period and nothing is debited now |
| `currency` | string or null | ISO 4217 currency code for topping up the wallet, or `null` when top-up is unavailable |
| `topUpAvailable` | boolean | Whether topping up the wallet is available for this account |

Vibe credit amounts are returned as decimal strings with an integer part and up to six digits after the decimal point, using the same format as balances and transactions. Do not convert them to floating-point numbers because this loses precision for fractional amounts.

## Response example

Switching from the free tier to `PRO` when wallet top-up is available:

```json
{
  "tier": "PRO",
  "chargeVibes": "20",
  "creditVibes": "0",
  "netVibes": "20",
  "effectiveFrom": "2026-08-11T11:11:14.115Z",
  "scheduled": false,
  "currency": "USD",
  "topUpAvailable": true
}
```

Selecting the active tier again: the operation is free, and wallet top-up is unavailable.

```json
{
  "tier": "FREE",
  "chargeVibes": "0",
  "creditVibes": "0",
  "netVibes": "0",
  "effectiveFrom": "2026-08-11T11:10:25.859Z",
  "scheduled": false,
  "currency": null,
  "topUpAvailable": false
}
```

## Error response example

400 — the `tier` parameter is missing or has an unsupported value:

```json
{
  "success": false,
  "error": {
    "code": "INVALID_QUERY",
    "message": "Query parameter `tier` is required and must be one of FREE, PRO, MAX, ULTRA."
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|----------|
| 400 | `INVALID_QUERY` | The `tier` parameter is missing, or its value is not one of `FREE`, `PRO`, `MAX`, `ULTRA` |
| 401 | `MISSING_API_KEY` | The `X-Api-Key` header is missing |
| 401 | `INVALID_API_KEY` | Invalid API key |
| 403 | `INSUFFICIENT_SCOPE` | The key lacks the `vibe:cowork` scope |
| 404 | `COWORK_NOT_ACTIVATED` | No Cowork/Code subscription found for the user and portal |
| 429 | `RATE_LIMITED` | The rate limit for the portal-user pair has been exceeded. The platform-wide limit is 30 requests per minute. The limit currently in effect for your key is returned in the `x-ratelimit-limit` header. It is lower than the platform-wide limit because that limit is divided across replicas |
| 503 | `COWORK_FEATURE_DISABLED` | Cowork/Code is disabled at the platform level |

The full list of common API errors — [Errors](/docs/errors).

## Known specifics

**A successful response (200) is the preview object itself, without a `success` wrapper.** Errors arrive in the envelope `{ success: false, error: { code, message } }`. Determine success by the HTTP status (`res.ok`).

**The tier price and the debited amount are different numbers.** The `tiers[].feeVibes` field in the [Cowork/Code subscription state](/docs/cowork/state) is the tier's catalog price. The actual amount differs from it in four cases:

- selecting the active tier again — no charge,
- a downgrade queued for the end of the paid period — no immediate charge,
- requesting a preview for an already queued downgrade — no charge,
- an upgrade with credit for the unused portion of the paid month — full price minus the credit.

The platform enables the last two features, and they become available without a client update. Build the confirmation screen from the preview rather than the catalog price.

**The `netVibes` and `scheduled` fields tell you whether a charge occurs immediately.** Do not reimplement the rules for free tier changes: `netVibes: "0"` together with `scheduled: true` means nothing is charged now and the change takes effect at the end of the paid period.

**If the request fails, show the tier price as the upper bound.** The actual charge never exceeds the tier price, so after a network error or rejected request, show `feeVibes` on the confirmation screen. This avoids overstating the amount and matches the behavior in your Vibecode account.

**Use `topUpAvailable` to decide whether to show the “Top Up” button; do not check only whether the field is present.** A response with `topUpAvailable: false` and `currency: null` is a normal state: top-up is currently unavailable for this account. It is not a request error.

**Amounts are returned only in Vibe credits: the response has no monetary tier price, and `currency` is not one.** `currency` is the currency the wallet owner uses for top-up; there is no amount-and-currency pair for a tier. This is not an omission from the response schema: there is no single Vibe-to-money rate. The rate is determined when a specific top-up package is purchased and varies by package and currency. Vibe credits are based on the amount before tax, while the customer pays the amount including tax. A Bitrix24 promotion changes the amount paid without changing the number of credits granted. Any single number would be a promise the platform does not make.

In the UI, show `netVibes` in Vibe credits and, when `topUpAvailable` is true, provide a link to checkout. Before payment, checkout shows the monetary amount in the user's currency, including tax.

**The platform-wide limit is 30 requests per minute. The limit currently in effect for your key is returned in the `x-ratelimit-limit` header. It is lower than the platform-wide limit because that limit is divided across replicas.** The limit applies to each user in each Bitrix24 account. The response is not cached (`Cache-Control: no-store`): amounts are calculated at request time.

## See also

- [Cowork/Code subscription state](/docs/cowork/state)
- [Cowork/Code subscription summary](/docs/cowork/me)
- [Cowork/Code](/docs/cowork)
- [Errors](/docs/errors)
