# Activate the Marketplace trial

`POST /v1/portals/:id/activate-market-trial`

Activates the one-time Bitrix24 Marketplace trial for the Bitrix24 account the calling key is bound to. The result is the same as starting the trial in the Vibecode dashboard, but without a browser. Availability depends on the account region: an account in an international region cannot activate the trial — the call is refused and nothing changes.

## Parameters

| Parameter | Type | Required | Description |
|----------|-----|:-----:|----------|
| `id` (path) | string (UUID) | yes | Bitrix24 account identifier. Must match the account of the calling key. A personal key takes the value from the `portalId` field of the records returned by `GET /v1/apps` — [List of apps](/docs/apps/list). The list of all accounts with their identifiers is returned by `GET /v1/portals` — [Management keys](/docs/management-keys) |

No request body is required, so send the request without a `Content-Type` header. A client that sets `Content-Type: application/json` on every request must send the body `{}` — a request with that header and an empty body is rejected before the call is processed.

## Examples

### curl — personal key

```bash
curl -X POST \
  -H "X-Api-Key: YOUR_API_KEY" \
  https://vibecode.bitrix24.com/v1/portals/YOUR_PORTAL_ID/activate-market-trial
```

### curl — OAuth application

```bash
curl -X POST \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  https://vibecode.bitrix24.com/v1/portals/YOUR_PORTAL_ID/activate-market-trial
```

### JavaScript — personal key

```javascript
const res = await fetch(
  `https://vibecode.bitrix24.com/v1/portals/${portalId}/activate-market-trial`,
  {
    method: 'POST',
    headers: { 'X-Api-Key': 'YOUR_API_KEY' },
  },
)

const { success, data } = await res.json()
if (success) {
  // activated — activated by this call, already_active — access existed before the call
  console.log(data.status, data.trialEndsAt)
}
```

### JavaScript — OAuth application

```javascript
const res = await fetch(
  `https://vibecode.bitrix24.com/v1/portals/${portalId}/activate-market-trial`,
  {
    method: 'POST',
    headers: {
      'X-Api-Key': 'YOUR_APP_KEY',
      'Authorization': 'Bearer USER_SESSION_TOKEN',
    },
  },
)

const { success, data } = await res.json()
```

## Response fields

| Field | Type | Description |
|------|-----|----------|
| `success` | boolean | Always `true` on success |
| `data.status` | string | `activated` — the trial was activated by this call. `already_active` — the account already had access and the call changed nothing |
| `data.trialEndsAt` | string \| null | End date and time of the trial in ISO 8601 format. Returned only when the status is `activated`. The value `null` means Bitrix24 did not return the date |

## Response example

The trial was activated by this call:

```json
{
  "success": true,
  "data": {
    "status": "activated",
    "trialEndsAt": "2026-08-01T00:00:00.000Z"
  }
}
```

The account already had access — the response carries no `trialEndsAt` field:

```json
{
  "success": true,
  "data": {
    "status": "already_active"
  }
}
```

## Error response example

403 — the identifier in the path belongs to another account:

```json
{
  "success": false,
  "error": {
    "code": "PORTAL_MISMATCH",
    "message": "This key is not authorized for the requested portal"
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|----------|
| 400 | `FST_ERR_CTP_EMPTY_JSON_BODY` | The `Content-Type: application/json` header was sent, but the body is empty. Send the body `{}` or drop the header |
| 403 | `PORTAL_MISMATCH` | The identifier in the path does not match the account of the key. A management key gets the same code — it is not bound to an account and cannot activate the trial |
| 403 | `WRITE_BLOCKED_READONLY_KEY` | The key works in read-only mode. The URL of the page where the mode can be switched is returned in `error.details.switchUrl` — [Access mode](/docs/keys-auth/access-mode) |
| 403 | `PURPOSE_KEY_FORBIDDEN` | A special-purpose service key — a [Cowork](/docs/cowork) desktop app key or a Cowork project deploy key |
| 403 | `AGENT_MAINTENANCE_KEY_OUT_OF_SCOPE` | An agent maintenance key. It is allowed only for server operations, so it never reaches trial activation |
| 403 | `INFRA_FORBIDDEN_FOR_COWORK_KEY` | A key with the `vibe:cowork` scope and no special-purpose tag — a [Cowork](/docs/cowork) agent workspace key, for example. It works with data only and does not change the account state. A desktop app key is refused earlier, with `PURPOSE_KEY_FORBIDDEN`. The `error.details.requiredAction` field suggests issuing a project deploy key, but that key does not work for this operation either: use a personal key or an app key |
| 404 | `NOT_FOUND` | The account was deleted between the key check and the request handling. A deleted account is refused earlier, with `403 PORTAL_DELETED` — see [Bitrix24 account state](/docs/errors#bitrix24-account-state) |
| 409 | `ALREADY_ACTIVATED` | The trial for this account has already been activated through Vibecode |
| 409 | `TRIAL_ACTIVATION_UNAVAILABLE` | The trial is unavailable for the account. The conditions are listed under "Known specifics" |
| 415 | `FST_ERR_CTP_INVALID_MEDIA_TYPE` | The body was sent with a type other than `application/json` |
| 429 | `RATE_LIMITED` | The limit of three requests per hour per account is exceeded. The remaining quota and the reset time are returned in the `X-RateLimit-Remaining` and `X-RateLimit-Reset` headers, and the recommended pause in the `Retry-After` header |
| 503 | `TRIAL_ACTIVATION_RETRY` | A temporary failure on the Bitrix24 side. Retry in a few minutes |

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

## Known specifics

**The `GET /v1/me` response carries no account identifier.** It returns only the domain. A personal key takes the identifier from the `portalId` field of the records returned by [`GET /v1/apps`](/docs/apps/list) — this works when the account has at least one app. The other sources are the `GET /v1/portals` response for a [management key](/docs/management-keys) or the Vibecode dashboard. Without the identifier the call runs into `403 PORTAL_MISMATCH`.

**A repeat call after a successful activation changes nothing.** An account whose trial was already activated through Vibecode gets `409 ALREADY_ACTIVATED` — the platform remembers the activation and does not call Bitrix24 a second time.

**A `200` response does not mean the call changed anything.** An account that already has access gets `200` with status `already_active` instead of a refusal. Distinguish "activated now" from "access already existed" by the `data.status` field, not by the response code.

**The response does not disclose the reason for unavailability.** The code `409 TRIAL_ACTIVATION_UNAVAILABLE` is returned for every condition with the same wording. The main ones are: the account is self-hosted, the account region is not eligible for the Marketplace trial, the trial on the Bitrix24 side is already used up, and the account has no developer key. An account in an international region is never eligible, so every call for such an account ends in this code. The list is not limited to those: the same code is also returned for a platform-side failure that only support can clear. So a refusal that contradicts the state of the account is worth forwarding to support rather than treating as final.

**The rate limit is counted per account and is consumed by refusals as well.** The cap is three requests per hour, and the check runs before the other conditions, so a failed attempt — with another account's identifier or with a read-only key — reduces the remaining quota just as a successful one does. The remaining quota and the reset time are returned in the `X-RateLimit-Remaining` and `X-RateLimit-Reset` headers.

## See also

- [Management keys](/docs/management-keys)
- [List of apps](/docs/apps/list)
- [Keys and authorization](/docs/keys-auth)
- [Access mode](/docs/keys-auth/access-mode)
- [Create an application](/docs/apps/create)
- [Errors](/docs/errors)
