
## Выпустить токен доступа

`POST /v1/infra/servers/:id/access-tokens`

Выпускает краткосрочный токен для внешнего доступа к развёрнутому приложению. Два режима: `api-bearer` — JWT для HTTP-заголовка `Authorization`. `share-url` — ссылка, при переходе по которой устанавливается куки.

## Параметры

| Параметр | В | Тип | Обяз. | Описание |
|----------|---|-----|:-----:|----------|
| `id` | path | string (UUID) | да | ID BLACKHOLE-сервера. Список: [`GET /v1/infra/servers`](/docs/infra/servers/list) |

## Поля запроса (body)

| Поле | Тип | Обяз. | По умолч. | Описание |
|------|-----|:-----:|-----------|----------|
| `mode` | string | да | — | `"api-bearer"` или `"share-url"` |
| `ttlSeconds` | number | нет | `86400` | Время жизни токена в секундах. Диапазон: 300–315 360 000 (от 5 минут до 10 лет). Значение 315 360 000 отображается в интерфейсе как «Бессрочно» |
| `identityBound` | boolean | нет | `true` | Только для `share-url`. При `true` — потребует входа через Битрикс24, и в журнале окажется реальный идентификатор пользователя. При `false` — анонимный переход, синтетический идентификатор |
| `name` | string | нет | — | Метка токена для отображения в списке (до 100 символов) |

## Примеры

### curl — личный ключ

```bash
curl -X POST "https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/access-tokens" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "api-bearer",
    "ttlSeconds": 600,
    "name": "ci-smoke"
  }'
```

### curl — OAuth-приложение

```bash
curl -X POST "https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/access-tokens" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "share-url",
    "ttlSeconds": 2592000,
    "identityBound": false,
    "name": "предпросмотр"
  }'
```

### JavaScript — личный ключ

```javascript
const res = await fetch(
  `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/access-tokens`,
  {
    method: 'POST',
    headers: {
      'X-Api-Key': 'YOUR_API_KEY',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ mode: 'api-bearer', ttlSeconds: 600 }),
  }
)
const { data } = await res.json()

// E2E-проверка через публичный путь
const check = await fetch(`${data.appUrl}/api/health`, {
  headers: { Authorization: `Bearer ${data.token}` },
})
console.log(check.status) // 200 — приложение отвечает через Gateway
```

### JavaScript — OAuth-приложение

```javascript
const res = await fetch(
  `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/access-tokens`,
  {
    method: 'POST',
    headers: {
      'X-Api-Key': 'YOUR_APP_KEY',
      'Authorization': 'Bearer USER_SESSION_TOKEN',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      mode: 'share-url',
      ttlSeconds: 2592000,
      name: 'предпросмотр',
    }),
  }
)
const { data } = await res.json()
console.log(data.url) // https://app-xxxx.vibecode.bitrix24.tech/?s=R8k3Zm2P
```

## Поля ответа

Набор полей зависит от режима.

**Режим `api-bearer`:**

| Поле | Тип | Описание |
|------|-----|----------|
| `success` | boolean | Всегда `true` при успехе |
| `data.id` | string | ID токена для последующего отзыва |
| `data.mode` | string | `"api-bearer"` |
| `data.token` | string | JWT для заголовка `Authorization: Bearer`. Сохраните его сразу: повторно эта же строка не отдаётся, свежий JWT для той же записи выдаёт [обновление токена](./refresh.md) |
| `data.expiresAt` | string (ISO 8601) | Срок хранения записи токена — для листинга и отзыва |
| `data.jwtExpiresAt` | string (ISO 8601) | Реальный срок действия Bearer-токена. Ограничен 10 минутами независимо от `ttlSeconds`. После истечения выпустите новый токен |
| `data.note` | string | Пояснение о разнице между `expiresAt` и `jwtExpiresAt` |
| `data.subdomain` | string | Субдомен сервера |
| `data.appUrl` | string | Полный HTTPS-адрес приложения |
| `data.curlExample` | string | Готовый `curl`-пример с токеном для быстрой проверки |

**Режим `share-url`:**

| Поле | Тип | Описание |
|------|-----|----------|
| `success` | boolean | Всегда `true` при успехе |
| `data.id` | string | ID токена для последующего отзыва |
| `data.mode` | string | `"share-url"` |
| `data.shortcode` | string | Код, вставляемый в URL как `?s=<shortcode>` |
| `data.url` | string | Полная распространяемая ссылка |
| `data.identityBound` | boolean | Требует ли переход входа через Битрикс24 |
| `data.expiresAt` | string (ISO 8601) | Момент истечения токена |
| `data.name` | string \| null | Метка, переданная при выпуске |

## Пример ответа

**Режим `api-bearer`:**

```json
{
  "success": true,
  "data": {
    "id": "9f1c4b7e-3d52-4a18-9c0e-7b2a1f6d84c3",
    "mode": "api-bearer",
    "token": "eyJhbGciOiJFUzI1NiJ9...",
    "expiresAt": "2026-05-18T10:50:00.000Z",
    "jwtExpiresAt": "2026-05-18T10:40:10.000Z",
    "subdomain": "app-91306a4c",
    "appUrl": "https://app-91306a4c.vibecode.bitrix24.tech",
    "curlExample": "curl -H \"Authorization: Bearer eyJhbGciOiJFUzI1NiJ9...\" https://app-91306a4c.vibecode.bitrix24.tech/api/health",
    "note": "JWT is a 10-minute Gateway session token. The row's `expiresAt` is the long-lived TTL for listing/revoking, but the Bearer token itself stops working at `jwtExpiresAt`. To keep a long-running client authenticated, POST /v1/infra/servers/:id/access-tokens/:tokenId/refresh before jwtExpiresAt to re-mint a fresh JWT for the SAME token (no new row — does not consume the active-token cap or mint rate-limit), or use mode=share-url for browser links that auto-refresh on each visit."
  }
}
```

**Режим `share-url`:**

```json
{
  "success": true,
  "data": {
    "id": "2a7d5e61-84bc-4f39-b0d7-5e6c9a3f1b28",
    "mode": "share-url",
    "shortcode": "R8k3Zm2P",
    "url": "https://app-91306a4c.vibecode.bitrix24.tech/?s=R8k3Zm2P",
    "identityBound": false,
    "expiresAt": "2026-06-17T08:44:00.000Z",
    "name": "предпросмотр"
  }
}
```

## Пример ответа при ошибке

429 — превышен лимит выпуска токенов:

```json
{
  "success": false,
  "error": {
    "code": "TOKEN_MINT_RATE_LIMIT",
    "message": "Rate limit: 50 mints/hour per API key"
  }
}
```

## Ошибки

| HTTP | Код | Описание |
|------|-----|----------|
| 400 | `INVALID_MODE` | Передан недопустимый `mode` либо неверный тип значения в теле запроса |
| 400 | `UNKNOWN_PARAM` | В теле запроса есть неизвестное поле. Ответ содержит `details` со списком допустимых полей и подсказкой |
| 400 | `INVALID_TTL` | `ttlSeconds` вне допустимого диапазона [300, 315 360 000] |
| 400 | `NAME_TOO_LONG` | `name` превышает 100 символов |
| 400 | `SERVER_NO_SUBDOMAIN` | У сервера нет субдомена, обращаться не к чему |
| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |
| 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ |
| 403 | `TOKEN_OWNER_MISMATCH` | Сервер принадлежит другому API-ключу. Членство в команде разработки сервера эту операцию не открывает — она требует управляющего ключа при любой роли. |
| 403 | `AGENT_OWNER_ONLY` | Сервер создан под AI-агента — токены доступа для него отключены |
| 403 | `INFRA_FORBIDDEN_FOR_COWORK_KEY` | Вызов сделан ключом Cowork/Code — такой ключ работает только с данными, изменяющие операции ему закрыты. Что делать — [Проектный ключ для деплоя](/docs/cowork/deploy-key) |
| 404 | `SERVER_NOT_FOUND` | Сервер не найден или удалён |
| 409 | `ACTIVE_TOKEN_LIMIT` | Достигнут лимит 100 активных токенов на сервер |
| 429 | `TOKEN_MINT_RATE_LIMIT` | Превышен лимит 50 выпусков в час на API-ключ. Заголовок `Retry-After: 3600` |
| 503 | `FEATURE_DISABLED` | Раздел токенов доступа выключен на платформе. Признак до вызова и запасной путь — [Доступность](/docs/infra/access-tokens#доступность) |

Полный список общих ошибок API — [Ошибки](/docs/errors).

## Известные особенности

- **Выдача ссылки записывается в журнал доступа портала.** Успешный выпуск в режиме `share-url` попадает в журнал, когда сервер привязан к порталу, и от настроек портала не зависит. Смотреть журнал и получать уведомления администратор может там, где платформа открыла порталу раздел «Приложения»: тогда администратор видит в нём, что приложение открыли ссылкой, а если ссылка не требует входа в Битрикс24, то есть `identityBound` равен `false`, и приложение до этого не было открыто наружу — администраторы дополнительно получают сообщение в чат-бот со ссылкой на список открытых приложений. Формат запроса, ответа и коды отказов при этом не меняются.
- **Продление доступа дешевле повторного выпуска.** [Обновление токена](./refresh.md) выдаёт свежий JWT для той же записи и не расходует ни лимит активных токенов, ни лимит выпусков в час.
- **У `api-bearer` идентификатор в журнале всегда один.** Это UUID владельца API-ключа, поле `identityBound` на него не влияет и в ответе списка приходит как `true`.
- **`api-bearer` подтверждает, что запрос сделан владельцем ключа, но не создаёт сессию пользователя Битрикс24.** Токен аутентифицирует запрос как владельца API-ключа и открывает доступ к приложению по его политике доступа. Он не подставляет заголовок `X-Vibe-Authorization` и не даёт `currentUser` в ответе `GET /v1/me`. Поэтому маршрут приложения, который проверяет администратора Битрикс24 через `X-Vibe-Authorization` и `GET /v1/me`, под `api-bearer`-токеном получит `currentUser: null`. Такому маршруту нужна полноценная авторизация пользователя через OAuth-приложение (`placement`) — см. [Что приходит в приложение](/docs/infra/app-runtime).

## Смотрите также

- [Обновить токен](./refresh.md)
- [Список токенов](./list.md)
- [Отозвать токен](./delete.md)
- [Токены доступа](/docs/infra/access-tokens)
- [Deploy API](/docs/infra/deploy)
