## Обновить окно пробуждения

`PATCH /v1/infra/servers/:id/wake-schedules/:scheduleId`

Заменяет окно целиком — несмотря на метод `PATCH`, семантика как у полной замены (`PUT`). Непереданные необязательные поля сбрасываются к значениям по умолчанию, а не сохраняют прежнее значение: `enabled` → `true`, `label`/`lead` → пусто. Передавайте полный объект окна, а не только изменившееся поле.

## Параметры

| Параметр | В | Тип | Обяз. | Описание |
|----------|---|-----|:-----:|----------|
| `id` | path | string (UUID) | да | ID BLACKHOLE-сервера |
| `scheduleId` | path | string | да | ID окна. Источник — `data[].id` из [списка окон](./list.md) или `data.id` из [создания](./create.md) |

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

Тот же набор полей, что и при [создании окна](./create.md). Не переданные необязательные поля не сохраняют старое значение, а сбрасываются к значению по умолчанию.

| Поле | Тип | Обяз. | По умолч. при пропуске | Описание |
|------|-----|:-----:|-----------|----------|
| `cronExpr` | string | да | — | 5-польное cron-выражение, от 9 до 120 символов |
| `timezone` | string | да | — | IANA-таймзона окна |
| `label` | string | нет | сбрасывается в пусто | Метка окна, до 80 символов |
| `lead` | number | нет | сбрасывается в пусто (используется запас сервера или платформы) | Запас в секундах перед моментом `cronExpr`. От 0 до 3600 |
| `enabled` | boolean | нет | сбрасывается в `true` | Активно ли окно |

## Примеры

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

```bash
curl -X PATCH "https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/wake-schedules/SCHEDULE_ID" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "cronExpr": "0 10 * * 1-5",
    "timezone": "Europe/Moscow",
    "label": "daily report",
    "enabled": true
  }'
```

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

```bash
curl -X PATCH "https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/wake-schedules/SCHEDULE_ID" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "cronExpr": "0 10 * * 1-5",
    "timezone": "Europe/Moscow",
    "label": "daily report",
    "enabled": true
  }'
```

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

```javascript
const res = await fetch(
  `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/wake-schedules/${scheduleId}`,
  {
    method: 'PATCH',
    headers: {
      'X-Api-Key': 'YOUR_API_KEY',
      'Content-Type': 'application/json',
    },
    // Полный объект окна — поля, пропущенные здесь, сбросятся к значениям по умолчанию
    body: JSON.stringify({
      cronExpr: '0 10 * * 1-5',
      timezone: 'Europe/Moscow',
      label: 'daily report',
      enabled: true,
    }),
  }
)
```

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

```javascript
const res = await fetch(
  `https://vibecode.bitrix24.tech/v1/infra/servers/${serverId}/wake-schedules/${scheduleId}`,
  {
    method: 'PATCH',
    headers: {
      'X-Api-Key': 'YOUR_APP_KEY',
      'Authorization': 'Bearer USER_SESSION_TOKEN',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      cronExpr: '0 10 * * 1-5',
      timezone: 'Europe/Moscow',
      label: 'daily report',
      enabled: true,
    }),
  }
)
```

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

| Поле | Тип | Описание |
|------|-----|----------|
| `success` | boolean | Всегда `true` при успехе |
| `data.id` | string | ID окна |
| `data.serverId` | string (UUID) | ID сервера-владельца |
| `data.cronExpr` | string | Обновлённое cron-выражение |
| `data.timezone` | string | Обновлённая таймзона |
| `data.label` | string \| null | Метка окна |
| `data.lead` | number \| null | Запас в секундах |
| `data.enabled` | boolean | Активно ли окно после обновления |
| `data.source` | string | Как создано окно. Не меняется обновлением |
| `data.lastFiredAt` | string (ISO 8601) \| null | Момент последнего подтверждённого срабатывания. Обновление окна это поле не трогает |
| `data.wakeAttemptStartedAt` | string (ISO 8601) \| null | Служебная метка планировщика, в норме `null` |
| `data.lastWakeLateAt` | string (ISO 8601) \| null | Момент последнего опоздавшего пробуждения |
| `data.createdAt` | string (ISO 8601) | Дата создания записи |
| `data.updatedAt` | string (ISO 8601) | Дата этого обновления |
| `tzWarning` | string \| null | Предупреждение о рассинхроне таймзоны — текстом. `null`, если у сервера не осталось активных окон после этой мутации |
| `tzWarningCode` | string \| null | Машиночитаемый код того же предупреждения: `"SINGLE_ZONE"`, `"MULTI_ZONE"` или `null` |
| `preemptibleAdvisoryCode` | string \| null | `"PREEMPTIBLE_BEST_EFFORT"`, если сервер работает на вытесняемом тарифе — иначе `null` |
| `preemptibleAdvisory` | string \| null | Пояснение того же предупреждения текстом (на английском, для не-UI-клиентов API). `null`, если сервер на невытесняемом тарифе |

`tzWarning`, `tzWarningCode`, `preemptibleAdvisoryCode` и `preemptibleAdvisory` — поля верхнего уровня ответа, не вложены в `data`.

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

```json
{
  "success": true,
  "data": {
    "id": "cm38x02qp0001ml08g7k3h2a",
    "serverId": "e765edfc-ba0a-43de-b8ea-838dd872c522",
    "cronExpr": "0 10 * * 1-5",
    "timezone": "Europe/Moscow",
    "label": "daily report",
    "lead": null,
    "enabled": true,
    "source": "MANUAL",
    "lastFiredAt": "2026-07-10T06:00:04.000Z",
    "wakeAttemptStartedAt": null,
    "lastWakeLateAt": null,
    "createdAt": "2026-07-03T08:12:00.000Z",
    "updatedAt": "2026-07-10T09:30:00.000Z"
  },
  "tzWarning": "The VM may have been deployed with a different timezone (or not redeployed since this window was declared) — verify the in-VM cron or redeploy the app so TZ is re-injected.",
  "tzWarningCode": "SINGLE_ZONE",
  "preemptibleAdvisoryCode": null,
  "preemptibleAdvisory": null
}
```

Сервер на вытесняемом тарифе получил бы `"preemptibleAdvisoryCode": "PREEMPTIBLE_BEST_EFFORT"` и непустой `preemptibleAdvisory` вместо `null` в тех же двух полях — остальная форма ответа не меняется.

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

404 — окно не найдено:

```json
{
  "success": false,
  "error": {
    "code": "NOT_FOUND",
    "message": "Wake window not found"
  }
}
```

## Ошибки

| HTTP | Код | Описание |
|------|-----|----------|
| 400 | `VALIDATION_ERROR` | Нарушена валидация тела — отсутствует `cronExpr`/`timezone`, `timezone` не входит в список IANA-таймзон, `label` длиннее 80 символов, `lead` вне диапазона 0–3600 или в теле лишнее поле |
| 400 | `BLACKHOLE_ONLY` | Сервер не в режиме BLACKHOLE |
| 400 | `GALAXY_NOT_SUPPORTED` | Сервер — хост галактики (`kind: "GALAXY"`). Вложенные приложения (`kind: "GALAXY_APP"`) принимаются, отклоняется только сам хост |
| 400 | `ALWAYS_ON_CONFLICT` | Сервер работает в режиме «Всегда онлайн» — на невытесняемом тарифе и без авто-сна |
| 400 | `CADENCE_TOO_LOW` | Интервал между соседними срабатываниями `cronExpr` меньше минимального, заданного на платформе — сейчас 5 минут |
| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |
| 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ |
| 403 | `WAKE_SCHEDULE_DISABLED` | Пробуждение по расписанию не включено для этого портала |
| 403 | `INFRA_SCOPE_REQUIRED` | У ключа нет скоупа `vibe:infra` |
| 404 | `NOT_FOUND` | Сервер не найден/удалён/принадлежит другому API-ключу, либо окно с таким `scheduleId` у этого сервера не найдено |
| 429 | `RATE_LIMITED` | Превышен лимит 10 запросов в минуту на этот эндпоинт |

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

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

- **`PATCH` заменяет окно целиком.** Это отклонение от общего стандарта частичного `PATCH` в API Вайбкод — сравните с [обновлением сделки](/docs/entities/deals/update), где непереданные поля сохраняют прежнее значение. Отправка только изменившегося поля молча обнулит остальные необязательные поля — `enabled` станет `true`, `label` и `lead` очистятся. Формируйте тело из последнего известного состояния окна, а не только из изменившихся полей.
- **`preemptibleAdvisoryCode`/`preemptibleAdvisory` — не гейт, а предупреждение.** Окно обновляется независимо от значения этих полей — на вытесняемом тарифе платформа не запрещает расписание, а лишь честно сообщает, что подъём к моменту окна best-effort. Локализуйте по коду `preemptibleAdvisoryCode`, не по строке `preemptibleAdvisory` — она фиксированная и на английском, для не-UI-клиентов.
- **Существование окна проверяется раньше остальных гейтов.** На несуществующий `scheduleId` вернётся `404 NOT_FOUND`, даже если запрос заодно нарушает `BLACKHOLE_ONLY` или другой гейт режима сервера.

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

- [Список окон](./list.md)
- [Создать окно](./create.md)
- [Удалить окно](./delete.md)
