# Секреты приложения

Хранилище доступно при включённом флаге портала `app-secrets` (по умолчанию выключен). Сейчас значения сохраняются зашифрованными; доставка и применение на сервере ещё не доступны.

**Авторизация:** `X-Api-Key`. Доступ имеют владелец приложения с любым своим ключом, ключ самого приложения и участник команды разработки связанного сервера. Значения задают только владелец и администратор портала в карточке `/applications`; команда видит и заводит имена. API и MCP значения не принимают и не показывают. После появления доставки доступ к выполнению кода на машине позволит прочитать окружение процесса: секреты не скрывают значения от разработчика с таким доступом.

## Операции

### GET /v1/applications/:id/secrets

`GET /v1/applications/:id/secrets`

Возвращает до 100 имён в алфавитном порядке и текущее состояние набора. Значения и шифротекст не возвращаются.

### POST /v1/applications/:id/secrets

`POST /v1/applications/:id/secrets`

Создаёт имя без значения. Тело: `{ "name": "PAYMENT_TOKEN" }`. Успех: 201. При наличии поля `value`, даже пустого, ответ 400 `SECRET_VALUE_NOT_ACCEPTED`; `error.applicationUrl` ведёт на `/applications?app=<id>`. Повтор имени: 409.

### DELETE /v1/applications/:id/secrets/:name

`DELETE /v1/applications/:id/secrets/:name`

Удаляет имя и сохранённое значение. Успех: 200. Желаемая ревизия увеличивается; применение на сервере в этом этапе отсутствует.

## Параметры

| Поле | Описание |
| --- | --- |
| `id` | ID карточки из [GET /v1/applications](/docs/applications); это не ID OAuth-приложения или сервера. |
| `name` | До 128 символов, `^[A-Za-z_][A-Za-z0-9_]*$`. Запрещены `PORT`, префиксы `VIBE_` и `HERMES_EVENT_INGEST_`. Максимум 100 имён на приложение. |
| `value` | Только в кабинете: до 16 КиБ UTF-8, без LF, CR и NUL. Многострочный PEM сначала преобразуйте в base64 и учитывайте размер результата. |

## Пример

```bash
curl -X POST "$BASE_URL/v1/applications/$APPLICATION_ID/secrets" \
  -H "X-Api-Key: $API_KEY" -H 'Content-Type: application/json' \
  -d '{"name":"PAYMENT_TOKEN"}'
```

```javascript
const response = await fetch(`${baseUrl}/v1/applications/${applicationId}/secrets`, {
  method: 'POST',
  headers: { 'X-Api-Key': apiKey, 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'PAYMENT_TOKEN' }),
})
const result = await response.json()
```

```json
{
  "success": true,
  "data": {
    "secret": {
      "name": "PAYMENT_TOKEN",
      "hasValue": false,
      "createdAt": "2026-10-09T09:00:00.000Z",
      "updatedAt": "2026-10-09T09:00:00.000Z",
      "createdBy": "user-id",
      "updatedBy": "user-id",
      "updatedByName": "Owner"
    },
    "state": {
      "desiredRevision": 0,
      "appliedRevision": 0,
      "appliedServerId": null,
      "status": "PENDING",
      "failureCode": null,
      "deliveredNames": [],
      "serviceName": null,
      "updatedAt": "2026-10-09T09:00:00.000Z"
    }
  }
}
```

GET возвращает `data.secrets` и `data.state`; DELETE — `data.secret: null` и `data.state`. `hasValue` показывает наличие значения; даты и авторы относятся к последнему изменению. До первого изменения `state` может быть `null`. `desiredRevision` растёт при записи значения и удалении. Остальные поля отражают сохранённое состояние, без обещания доставки или применения. MCP-инструмент `manage_app_secrets` принимает `applicationId`, `action` (`list`, `create`, `delete`) и `name` для изменения имён.

## Ошибки

| HTTP | Код | Значение |
| --- | --- | --- |
| 400 | `SECRET_VALUE_NOT_ACCEPTED` | Задайте значение в карточке приложения. |
| 400 | `SECRET_INVALID_NAME` | Недопустимое или зарезервированное имя. |
| 400 | `SECRET_INVALID_REQUEST` | Некорректное тело запроса. |
| 400 | `SECRET_LIMIT_REACHED` | Достигнут предел 100 имён. |
| 401 | `MISSING_API_KEY`, `INVALID_API_KEY` | Нет действительного ключа. |
| 403 | `WRITE_BLOCKED_READONLY_KEY` | Ключ только для чтения не может создавать или удалять имена. |
| 403 | `EXTERNAL_COLLABORATOR_KEY_SERVER_MISMATCH` | Ключ привязан к другой машине. |
| 403 | `EXTERNAL_COLLABORATOR_NOT_A_MEMBER` | Вызывающий больше не входит в команду разработки. |
| 404 | `APPLICATION_NOT_FOUND` | Нет приложения или доступа, либо флаг выключен. |
| 404 | `SECRET_NOT_FOUND` | Имя не найдено. |
| 409 | `SECRET_ALREADY_EXISTS` | Имя уже существует. |
| 413 | `SECRET_BODY_TOO_LARGE` | Тело запроса превышает 128 КиБ. |
| 429 | `RATE_LIMIT_EXCEEDED` | Общий предел платформы — 60 запросов в минуту на вызывающего внутри портала, поделённый между репликами. `x-ratelimit-limit` сообщает фактический предел для ключа. |
| 500 | `SECRET_OPERATION_FAILED` | Операция не выполнена; ответ не содержит исходной ошибки. |

## См. также

- [Каталог приложений](/docs/applications)
- [MCP](/docs/mcp)
