[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"docs-infra\u002Fwake-schedules":3,"docs-tabs-infra\u002Fwake-schedules":6},{"content":4,"lastmod":5},"\n# Пробуждение по расписанию\n\nПовторяющиеся окна пробуждения для сервера в режиме BLACKHOLE: платформа поднимает сервер к заданному моменту по cron-выражению, а саму задачу запускает собственный cron внутри уже поднятой машины — платформа не читает и не выполняет код приложения.\n\n**На вытесняемом тарифе подъём — best-effort, не гарантия.** Сервер такого типа поднимается по мере освобождения ёмкости — через очередь, — поэтому к моменту окна свободного места может не оказаться, и окно может быть пропущено. Ответ создания и обновления окна несёт поле `preemptibleAdvisoryCode: \"PREEMPTIBLE_BEST_EFFORT\"` именно для этого случая — см. [Создать окно](.\u002Fwake-schedules\u002Fcreate.md). Для задач, критичных ко времени, используйте невытесняемый тариф или режим «Всегда онлайн (24\u002F7)».\n\nСкоуп: `vibe:infra`\n\n## Операции\n\n- [Создать окно](.\u002Fwake-schedules\u002Fcreate.md) — `POST \u002Fv1\u002Finfra\u002Fservers\u002F:id\u002Fwake-schedules`\n- [Список окон](.\u002Fwake-schedules\u002Flist.md) — `GET \u002Fv1\u002Finfra\u002Fservers\u002F:id\u002Fwake-schedules`\n- [Обновить окно](.\u002Fwake-schedules\u002Fupdate.md) — `PATCH \u002Fv1\u002Finfra\u002Fservers\u002F:id\u002Fwake-schedules\u002F:scheduleId`\n- [Удалить окно](.\u002Fwake-schedules\u002Fdelete.md) — `DELETE \u002Fv1\u002Finfra\u002Fservers\u002F:id\u002Fwake-schedules\u002F:scheduleId`\n\n## Сценарии\n\n**Ночной отчёт по будням:**\n\n1. [`POST \u002Fwake-schedules`](.\u002Fwake-schedules\u002Fcreate.md) с `cronExpr: \"0 9 * * 1-5\"`, `timezone: \"Europe\u002FMoscow\"`.\n2. Ответ несёт `tzWarningCode: \"SINGLE_ZONE\"` — таймзона однозначна, при следующем деплое платформа сама передаст её в переменную окружения `TZ`.\n3. Cron внутри сервера запускает задачу в 9:00 по московскому времени. На невытесняемом тарифе платформа гарантирует, что сервер к этому моменту уже поднят. На вытесняемом тарифе (ответ несёт `preemptibleAdvisoryCode: \"PREEMPTIBLE_BEST_EFFORT\"`) это best-effort: сервер поднимается по мере освобождения ёмкости, и при её нехватке окно может быть пропущено.\n\n**Несколько окон в разных часовых поясах:**\n\n1. Создать окна с разными значениями `timezone` для одного сервера.\n2. Ответ каждой мутации несёт `tzWarningCode: \"MULTI_ZONE\"` — платформа не проставляет `TZ` автоматически, когда окна расходятся по поясам. Пишите обработку времени в приложении в UTC.\n\n**Galaxy-приложение — увеличенный запас на подъём:**\n\n1. Для сервера `kind: \"GALAXY_APP\"` указывайте `lead` с запасом на подъём хоста, туннеля и контейнера — до 900 секунд (15 минут), а не значение по умолчанию, рассчитанное на одиночный сервер.\n2. Сам хост галактики (`kind: \"GALAXY\"`) окна не принимает — расписание объявляется на конкретном приложении, платформа при необходимости поднимает и хост.\n\n## Смотрите также\n\n- [Инфраструктура](\u002Fdocs\u002Finfra)\n- [Что приходит в приложение](\u002Fdocs\u002Finfra\u002Fapp-runtime) — таймзона деплоя и in-VM cron\n- [Жизненный цикл](\u002Fdocs\u002Finfra\u002Flifecycle)\n- [Журнал изменений](\u002Fdocs\u002Fchangelog)\n","2026-07-16",{"wake-schedules\u002Fcreate.md":7,"wake-schedules\u002Flist.md":8,"wake-schedules\u002Fupdate.md":9,"wake-schedules\u002Fdelete.md":10},"## Создать окно пробуждения\n\n`POST \u002Fv1\u002Finfra\u002Fservers\u002F:id\u002Fwake-schedules`\n\nОбъявляет новое повторяющееся окно пробуждения для сервера в режиме BLACKHOLE. Тело передаётся плоским объектом, без обёртки `fields`.\n\n## Параметры\n\n| Параметр | В | Тип | Обяз. | Описание |\n|----------|---|-----|:-----:|----------|\n| `id` | path | string (UUID) | да | ID BLACKHOLE-сервера |\n\n## Поля запроса (body)\n\n| Поле | Тип | Обяз. | По умолч. | Описание |\n|------|-----|:-----:|-----------|----------|\n| `cronExpr` | string | да | — | 5-польное cron-выражение (минута час день-месяца месяц день-недели), от 9 до 120 символов |\n| `timezone` | string | да | — | IANA-таймзона окна, например `Europe\u002FMoscow`. Проверяется по списку `Intl.supportedValuesOf('timeZone')` — незнакомое значение отклоняется на этапе валидации |\n| `label` | string | нет | — | Метка окна для отображения, до 80 символов |\n| `lead` | number | нет | запас сервера, иначе запас платформы | Запас в секундах перед моментом `cronExpr`, на который сервер должен быть уже поднят — покрывает время старта виртуальной машины. От 0 до 3600 |\n| `enabled` | boolean | нет | `true` | Активно ли окно. Отключённое окно не участвует в пробуждении, но остаётся в списке |\n\nЗапас `lead` разрешает три уровня: значение самого окна, иначе запас сервера, заданный отдельно от этого раздела CRUD, иначе запас по умолчанию на платформе — сейчас 180 секунд. Для сервера `kind: \"GALAXY_APP\"` пробуждение проходит два этапа — подъём хоста и старт контейнера, поэтому закладывайте `lead` до 900 секунд.\n\n## Примеры\n\n### curl — личный ключ\n\n```bash\ncurl -X POST \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Finfra\u002Fservers\u002FSERVER_ID\u002Fwake-schedules\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"cronExpr\": \"0 9 * * 1-5\",\n    \"timezone\": \"Europe\u002FMoscow\",\n    \"label\": \"daily report\",\n    \"enabled\": true\n  }'\n```\n\n### curl — OAuth-приложение\n\n```bash\ncurl -X POST \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Finfra\u002Fservers\u002FSERVER_ID\u002Fwake-schedules\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"cronExpr\": \"0 9 * * 1-5\",\n    \"timezone\": \"Europe\u002FMoscow\",\n    \"label\": \"daily report\",\n    \"enabled\": true\n  }'\n```\n\n### JavaScript — личный ключ\n\n```javascript\nconst res = await fetch(\n  `https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Finfra\u002Fservers\u002F${serverId}\u002Fwake-schedules`,\n  {\n    method: 'POST',\n    headers: {\n      'X-Api-Key': 'YOUR_API_KEY',\n      'Content-Type': 'application\u002Fjson',\n    },\n    body: JSON.stringify({\n      cronExpr: '0 9 * * 1-5',\n      timezone: 'Europe\u002FMoscow',\n      label: 'daily report',\n      enabled: true,\n    }),\n  }\n)\nconst body = await res.json()\nif (body.tzWarningCode === 'MULTI_ZONE') {\n  console.warn('Окна расходятся по часовым поясам — TZ в деплое не проставляется')\n}\n```\n\n### JavaScript — OAuth-приложение\n\n```javascript\nconst res = await fetch(\n  `https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Finfra\u002Fservers\u002F${serverId}\u002Fwake-schedules`,\n  {\n    method: 'POST',\n    headers: {\n      'X-Api-Key': 'YOUR_APP_KEY',\n      'Authorization': 'Bearer USER_SESSION_TOKEN',\n      'Content-Type': 'application\u002Fjson',\n    },\n    body: JSON.stringify({\n      cronExpr: '0 9 * * 1-5',\n      timezone: 'Europe\u002FMoscow',\n      label: 'daily report',\n      enabled: true,\n    }),\n  }\n)\n```\n\n## Поля ответа\n\n| Поле | Тип | Описание |\n|------|-----|----------|\n| `success` | boolean | Всегда `true` при успехе |\n| `data.id` | string | ID окна для последующего обновления и удаления |\n| `data.serverId` | string (UUID) | ID сервера-владельца |\n| `data.cronExpr` | string | Сохранённое cron-выражение |\n| `data.timezone` | string | Сохранённая таймзона |\n| `data.label` | string \\| null | Метка окна |\n| `data.lead` | number \\| null | Запас в секундах. `null`, если не задан на уровне окна |\n| `data.enabled` | boolean | Активно ли окно |\n| `data.source` | string | Как создано окно. Всегда `\"MANUAL\"` для окон, созданных через этот CRUD |\n| `data.lastFiredAt` | string (ISO 8601) \\| null | Момент последнего подтверждённого срабатывания. `null` для только что созданного окна |\n| `data.wakeAttemptStartedAt` | string (ISO 8601) \\| null | Служебная метка планировщика — непусто только в течение короткого окна, пока идёт пробуждение. В норме `null` |\n| `data.lastWakeLateAt` | string (ISO 8601) \\| null | Момент последнего пробуждения, сработавшего позже расчётного окна. `null`, если опозданий не было |\n| `data.createdAt` | string (ISO 8601) | Дата создания записи |\n| `data.updatedAt` | string (ISO 8601) | Дата последнего обновления записи |\n| `tzWarning` | string \\| null | Предупреждение о рассинхроне таймзоны — текстом. `null`, если у сервера не осталось активных окон после этой мутации |\n| `tzWarningCode` | string \\| null | Машиночитаемый код того же предупреждения: `\"SINGLE_ZONE\"`, `\"MULTI_ZONE\"` или `null` |\n| `preemptibleAdvisoryCode` | string \\| null | `\"PREEMPTIBLE_BEST_EFFORT\"`, если сервер работает на вытесняемом тарифе — иначе `null` |\n| `preemptibleAdvisory` | string \\| null | Пояснение того же предупреждения текстом (на английском, для не-UI-клиентов API). `null`, если сервер на невытесняемом тарифе |\n\n`tzWarning`, `tzWarningCode`, `preemptibleAdvisoryCode` и `preemptibleAdvisory` — поля верхнего уровня ответа, не вложены в `data`.\n\n## Пример ответа\n\nЕдинственное активное окно сервера — таймзона однозначна:\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"id\": \"cm38x02qp0001ml08g7k3h2a\",\n    \"serverId\": \"e765edfc-ba0a-43de-b8ea-838dd872c522\",\n    \"cronExpr\": \"0 9 * * 1-5\",\n    \"timezone\": \"Europe\u002FMoscow\",\n    \"label\": \"daily report\",\n    \"lead\": null,\n    \"enabled\": true,\n    \"source\": \"MANUAL\",\n    \"lastFiredAt\": null,\n    \"wakeAttemptStartedAt\": null,\n    \"lastWakeLateAt\": null,\n    \"createdAt\": \"2026-07-10T08:12:00.000Z\",\n    \"updatedAt\": \"2026-07-10T08:12:00.000Z\"\n  },\n  \"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.\",\n  \"tzWarningCode\": \"SINGLE_ZONE\",\n  \"preemptibleAdvisoryCode\": null,\n  \"preemptibleAdvisory\": null\n}\n```\n\nСервер на вытесняемом тарифе получил бы `\"preemptibleAdvisoryCode\": \"PREEMPTIBLE_BEST_EFFORT\"` и непустой `preemptibleAdvisory` вместо `null` в тех же двух полях — остальная форма ответа не меняется.\n\n## Пример ответа при ошибке\n\n400 — окно нарушает гарантию сервера «Всегда онлайн»:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"ALWAYS_ON_CONFLICT\",\n    \"message\": \"Scheduled wake conflicts with an always-on (24\u002F7) server, which never auto-sleeps. Turn off the always-on toggle, or set a sleep timeout instead of \\\"Never\\\", to schedule wake windows.\"\n  }\n}\n```\n\n## Ошибки\n\n| HTTP | Код | Описание |\n|------|-----|----------|\n| 400 | `VALIDATION_ERROR` | Нарушена валидация тела — отсутствует `cronExpr`\u002F`timezone`, `timezone` не входит в список IANA-таймзон, `label` длиннее 80 символов, `lead` вне диапазона 0–3600 или в теле лишнее поле |\n| 400 | `BLACKHOLE_ONLY` | Сервер не в режиме BLACKHOLE |\n| 400 | `GALAXY_NOT_SUPPORTED` | Сервер — хост галактики (`kind: \"GALAXY\"`). Вложенные приложения (`kind: \"GALAXY_APP\"`) принимаются, отклоняется только сам хост |\n| 400 | `ALWAYS_ON_CONFLICT` | Сервер работает в режиме «Всегда онлайн» — на невытесняемом тарифе и без авто-сна. Расписание пробуждения тихо нарушило бы эту гарантию |\n| 400 | `CADENCE_TOO_LOW` | Интервал между соседними срабатываниями `cronExpr` меньше минимального, заданного на платформе — сейчас 5 минут |\n| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |\n| 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ |\n| 403 | `WAKE_SCHEDULE_DISABLED` | Пробуждение по расписанию не включено для этого портала |\n| 403 | `WAKE_SCHEDULE_LIMIT` | У сервера уже 50 окон — предел на сервер |\n| 403 | `INFRA_SCOPE_REQUIRED` | У ключа нет скоупа `vibe:infra` |\n| 404 | `NOT_FOUND` | Сервер не найден, удалён или принадлежит другому API-ключу |\n| 429 | `RATE_LIMITED` | Превышен лимит 10 запросов в минуту на этот эндпоинт |\n\nПолный список общих ошибок API — [Ошибки](\u002Fdocs\u002Ferrors).\n\n## Известные особенности\n\n- **Порядок проверок.** Скоуп ключа и владение сервером проверяются раньше остальных гейтов, поэтому `WAKE_SCHEDULE_DISABLED`\u002F`BLACKHOLE_ONLY`\u002F`GALAXY_NOT_SUPPORTED`\u002F`ALWAYS_ON_CONFLICT` увидит только запрос с корректным ключом на существующий свой сервер. Проверка cron-выражения (`VALIDATION_ERROR`, затем `CADENCE_TOO_LOW`) идёт после этих гейтов.\n- **`tzWarning`\u002F`tzWarningCode` — консервативная эвристика.** Платформа не хранит, был ли сервер передеплоен после объявления окна, поэтому предупреждение приходит при любом наборе активных окон после мутации — даже если таймзона уже верно проставлена в переменных окружения. Ориентируйтесь на код: `\"SINGLE_ZONE\"` — таймзона однозначна и попадёт в `TZ` при следующем деплое, `\"MULTI_ZONE\"` — окна в разных поясах, `TZ` не проставляется автоматически.\n- **`preemptibleAdvisoryCode`\u002F`preemptibleAdvisory` — не гейт, а предупреждение.** Окно создаётся или обновляется независимо от значения этих полей — на вытесняемом тарифе платформа не запрещает расписание (это её целевой сценарий), а лишь честно сообщает, что подъём к моменту окна best-effort. Локализуйте по коду `preemptibleAdvisoryCode`, а не по строке `preemptibleAdvisory` — это фиксированная английская строка для не-UI-клиентов, не предназначенная для показа пользователю как есть.\n- **Cron внутри VM платформа не настраивает.** `POST \u002Fwake-schedules` только гарантирует, что сервер поднят к нужному моменту (на вытесняемом тарифе — best-effort, см. `preemptibleAdvisoryCode` выше). Запуск задачи в этот момент — ответственность собственного `cron`\u002Fтаймера внутри приложения.\n\n## Смотрите также\n\n- [Список окон](.\u002Flist.md)\n- [Обновить окно](.\u002Fupdate.md)\n- [Удалить окно](.\u002Fdelete.md)\n- [Что приходит в приложение](\u002Fdocs\u002Finfra\u002Fapp-runtime) — таймзона деплоя и in-VM cron\n","## Список окон пробуждения\n\n`GET \u002Fv1\u002Finfra\u002Fservers\u002F:id\u002Fwake-schedules`\n\nВозвращает все окна пробуждения сервера, включая отключённые. В отличие от создания и обновления, доступен независимо от того, включено ли пробуждение по расписанию для портала — так владелец сервера видит уже объявленные окна, даже если функция сейчас недоступна его порталу.\n\n## Параметры\n\n| Параметр | В | Тип | Обяз. | Описание |\n|----------|---|-----|:-----:|----------|\n| `id` | path | string (UUID) | да | ID BLACKHOLE-сервера |\n\nQuery-параметров нет — фильтрации и пагинации у списка окон одного сервера не предусмотрено, лимит в 50 окон на сервер делает их избыточными.\n\n## Примеры\n\n### curl — личный ключ\n\n```bash\ncurl -H \"X-Api-Key: YOUR_API_KEY\" \\\n  https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Finfra\u002Fservers\u002FSERVER_ID\u002Fwake-schedules\n```\n\n### curl — OAuth-приложение\n\n```bash\ncurl -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\" \\\n  https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Finfra\u002Fservers\u002FSERVER_ID\u002Fwake-schedules\n```\n\n### JavaScript — личный ключ\n\n```javascript\nconst res = await fetch(\n  `https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Finfra\u002Fservers\u002F${serverId}\u002Fwake-schedules`,\n  { headers: { 'X-Api-Key': 'YOUR_API_KEY' } }\n)\nconst { data } = await res.json()\nconsole.log(`Окон: ${data.length}, активных: ${data.filter(w => w.enabled).length}`)\n```\n\n### JavaScript — OAuth-приложение\n\n```javascript\nconst res = await fetch(\n  `https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Finfra\u002Fservers\u002F${serverId}\u002Fwake-schedules`,\n  {\n    headers: {\n      'X-Api-Key': 'YOUR_APP_KEY',\n      'Authorization': 'Bearer USER_SESSION_TOKEN',\n    },\n  }\n)\n```\n\n## Поля ответа\n\n| Поле | Тип | Описание |\n|------|-----|----------|\n| `success` | boolean | Всегда `true` при успехе |\n| `data` | array | Массив окон сервера, включая отключённые |\n| `data[].id` | string | ID окна |\n| `data[].serverId` | string (UUID) | ID сервера-владельца |\n| `data[].cronExpr` | string | Cron-выражение окна |\n| `data[].timezone` | string | IANA-таймзона окна |\n| `data[].label` | string \\| null | Метка окна |\n| `data[].lead` | number \\| null | Запас в секундах перед моментом `cronExpr`. `null` — используется запас сервера или платформы |\n| `data[].enabled` | boolean | Активно ли окно |\n| `data[].source` | string | Как создано окно. Всегда `\"MANUAL\"` для окон, созданных через этот CRUD |\n| `data[].lastFiredAt` | string (ISO 8601) \\| null | Момент последнего подтверждённого срабатывания |\n| `data[].wakeAttemptStartedAt` | string (ISO 8601) \\| null | Служебная метка планировщика, в норме `null` |\n| `data[].lastWakeLateAt` | string (ISO 8601) \\| null | Момент последнего опоздавшего пробуждения. `null`, если опозданий не было |\n| `data[].createdAt` | string (ISO 8601) | Дата создания записи |\n| `data[].updatedAt` | string (ISO 8601) | Дата последнего обновления записи |\n\n## Пример ответа\n\n```json\n{\n  \"success\": true,\n  \"data\": [\n    {\n      \"id\": \"cm38x02qp0001ml08g7k3h2a\",\n      \"serverId\": \"e765edfc-ba0a-43de-b8ea-838dd872c522\",\n      \"cronExpr\": \"0 9 * * 1-5\",\n      \"timezone\": \"Europe\u002FMoscow\",\n      \"label\": \"daily report\",\n      \"lead\": null,\n      \"enabled\": true,\n      \"source\": \"MANUAL\",\n      \"lastFiredAt\": \"2026-07-10T06:00:04.000Z\",\n      \"wakeAttemptStartedAt\": null,\n      \"lastWakeLateAt\": null,\n      \"createdAt\": \"2026-07-03T08:12:00.000Z\",\n      \"updatedAt\": \"2026-07-03T08:12:00.000Z\"\n    },\n    {\n      \"id\": \"cm38x19rt0002ml08a1z9k7b\",\n      \"serverId\": \"e765edfc-ba0a-43de-b8ea-838dd872c522\",\n      \"cronExpr\": \"0 22 * * *\",\n      \"timezone\": \"Europe\u002FMoscow\",\n      \"label\": \"nightly cleanup\",\n      \"lead\": 300,\n      \"enabled\": false,\n      \"source\": \"MANUAL\",\n      \"lastFiredAt\": null,\n      \"wakeAttemptStartedAt\": null,\n      \"lastWakeLateAt\": null,\n      \"createdAt\": \"2026-07-05T11:40:00.000Z\",\n      \"updatedAt\": \"2026-07-08T09:02:00.000Z\"\n    }\n  ]\n}\n```\n\n## Пример ответа при ошибке\n\n404 — сервер не найден:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"NOT_FOUND\",\n    \"message\": \"Server not found\"\n  }\n}\n```\n\n## Ошибки\n\n| HTTP | Код | Описание |\n|------|-----|----------|\n| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |\n| 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ |\n| 404 | `NOT_FOUND` | Сервер не найден, удалён или принадлежит другому API-ключу |\n| 429 | `RATE_LIMITED` | Превышен общий лимит запросов платформы |\n\nПолный список общих ошибок API — [Ошибки](\u002Fdocs\u002Ferrors).\n\n## Известные особенности\n\n- **Не гейтится статусом функции для портала.** В отличие от создания, обновления и удаления, список работает даже когда пробуждение по расписанию не включено для портала (`WAKE_SCHEDULE_DISABLED` здесь не возвращается) — так владелец сервера видит уже объявленные окна независимо от того, доступна ли функция его порталу сейчас.\n- **Порядок элементов.** Массив отсортирован по дате создания окна (`createdAt`, по возрастанию) — новые окна оказываются в конце.\n\n## Смотрите также\n\n- [Создать окно](.\u002Fcreate.md)\n- [Обновить окно](.\u002Fupdate.md)\n- [Удалить окно](.\u002Fdelete.md)\n","## Обновить окно пробуждения\n\n`PATCH \u002Fv1\u002Finfra\u002Fservers\u002F:id\u002Fwake-schedules\u002F:scheduleId`\n\nЗаменяет окно целиком — несмотря на метод `PATCH`, семантика как у полной замены (`PUT`). Непереданные необязательные поля сбрасываются к значениям по умолчанию, а не сохраняют прежнее значение: `enabled` → `true`, `label`\u002F`lead` → пусто. Передавайте полный объект окна, а не только изменившееся поле.\n\n## Параметры\n\n| Параметр | В | Тип | Обяз. | Описание |\n|----------|---|-----|:-----:|----------|\n| `id` | path | string (UUID) | да | ID BLACKHOLE-сервера |\n| `scheduleId` | path | string | да | ID окна. Источник — `data[].id` из [списка окон](.\u002Flist.md) или `data.id` из [создания](.\u002Fcreate.md) |\n\n## Поля запроса (body)\n\nТот же набор полей, что и при [создании окна](.\u002Fcreate.md). Не переданные необязательные поля не сохраняют старое значение, а сбрасываются к значению по умолчанию.\n\n| Поле | Тип | Обяз. | По умолч. при пропуске | Описание |\n|------|-----|:-----:|-----------|----------|\n| `cronExpr` | string | да | — | 5-польное cron-выражение, от 9 до 120 символов |\n| `timezone` | string | да | — | IANA-таймзона окна |\n| `label` | string | нет | сбрасывается в пусто | Метка окна, до 80 символов |\n| `lead` | number | нет | сбрасывается в пусто (используется запас сервера или платформы) | Запас в секундах перед моментом `cronExpr`. От 0 до 3600 |\n| `enabled` | boolean | нет | сбрасывается в `true` | Активно ли окно |\n\n## Примеры\n\n### curl — личный ключ\n\n```bash\ncurl -X PATCH \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Finfra\u002Fservers\u002FSERVER_ID\u002Fwake-schedules\u002FSCHEDULE_ID\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"cronExpr\": \"0 10 * * 1-5\",\n    \"timezone\": \"Europe\u002FMoscow\",\n    \"label\": \"daily report\",\n    \"enabled\": true\n  }'\n```\n\n### curl — OAuth-приложение\n\n```bash\ncurl -X PATCH \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Finfra\u002Fservers\u002FSERVER_ID\u002Fwake-schedules\u002FSCHEDULE_ID\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"cronExpr\": \"0 10 * * 1-5\",\n    \"timezone\": \"Europe\u002FMoscow\",\n    \"label\": \"daily report\",\n    \"enabled\": true\n  }'\n```\n\n### JavaScript — личный ключ\n\n```javascript\nconst res = await fetch(\n  `https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Finfra\u002Fservers\u002F${serverId}\u002Fwake-schedules\u002F${scheduleId}`,\n  {\n    method: 'PATCH',\n    headers: {\n      'X-Api-Key': 'YOUR_API_KEY',\n      'Content-Type': 'application\u002Fjson',\n    },\n    \u002F\u002F Полный объект окна — поля, пропущенные здесь, сбросятся к значениям по умолчанию\n    body: JSON.stringify({\n      cronExpr: '0 10 * * 1-5',\n      timezone: 'Europe\u002FMoscow',\n      label: 'daily report',\n      enabled: true,\n    }),\n  }\n)\n```\n\n### JavaScript — OAuth-приложение\n\n```javascript\nconst res = await fetch(\n  `https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Finfra\u002Fservers\u002F${serverId}\u002Fwake-schedules\u002F${scheduleId}`,\n  {\n    method: 'PATCH',\n    headers: {\n      'X-Api-Key': 'YOUR_APP_KEY',\n      'Authorization': 'Bearer USER_SESSION_TOKEN',\n      'Content-Type': 'application\u002Fjson',\n    },\n    body: JSON.stringify({\n      cronExpr: '0 10 * * 1-5',\n      timezone: 'Europe\u002FMoscow',\n      label: 'daily report',\n      enabled: true,\n    }),\n  }\n)\n```\n\n## Поля ответа\n\n| Поле | Тип | Описание |\n|------|-----|----------|\n| `success` | boolean | Всегда `true` при успехе |\n| `data.id` | string | ID окна |\n| `data.serverId` | string (UUID) | ID сервера-владельца |\n| `data.cronExpr` | string | Обновлённое cron-выражение |\n| `data.timezone` | string | Обновлённая таймзона |\n| `data.label` | string \\| null | Метка окна |\n| `data.lead` | number \\| null | Запас в секундах |\n| `data.enabled` | boolean | Активно ли окно после обновления |\n| `data.source` | string | Как создано окно. Не меняется обновлением |\n| `data.lastFiredAt` | string (ISO 8601) \\| null | Момент последнего подтверждённого срабатывания. Обновление окна это поле не трогает |\n| `data.wakeAttemptStartedAt` | string (ISO 8601) \\| null | Служебная метка планировщика, в норме `null` |\n| `data.lastWakeLateAt` | string (ISO 8601) \\| null | Момент последнего опоздавшего пробуждения |\n| `data.createdAt` | string (ISO 8601) | Дата создания записи |\n| `data.updatedAt` | string (ISO 8601) | Дата этого обновления |\n| `tzWarning` | string \\| null | Предупреждение о рассинхроне таймзоны — текстом. `null`, если у сервера не осталось активных окон после этой мутации |\n| `tzWarningCode` | string \\| null | Машиночитаемый код того же предупреждения: `\"SINGLE_ZONE\"`, `\"MULTI_ZONE\"` или `null` |\n| `preemptibleAdvisoryCode` | string \\| null | `\"PREEMPTIBLE_BEST_EFFORT\"`, если сервер работает на вытесняемом тарифе — иначе `null` |\n| `preemptibleAdvisory` | string \\| null | Пояснение того же предупреждения текстом (на английском, для не-UI-клиентов API). `null`, если сервер на невытесняемом тарифе |\n\n`tzWarning`, `tzWarningCode`, `preemptibleAdvisoryCode` и `preemptibleAdvisory` — поля верхнего уровня ответа, не вложены в `data`.\n\n## Пример ответа\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"id\": \"cm38x02qp0001ml08g7k3h2a\",\n    \"serverId\": \"e765edfc-ba0a-43de-b8ea-838dd872c522\",\n    \"cronExpr\": \"0 10 * * 1-5\",\n    \"timezone\": \"Europe\u002FMoscow\",\n    \"label\": \"daily report\",\n    \"lead\": null,\n    \"enabled\": true,\n    \"source\": \"MANUAL\",\n    \"lastFiredAt\": \"2026-07-10T06:00:04.000Z\",\n    \"wakeAttemptStartedAt\": null,\n    \"lastWakeLateAt\": null,\n    \"createdAt\": \"2026-07-03T08:12:00.000Z\",\n    \"updatedAt\": \"2026-07-10T09:30:00.000Z\"\n  },\n  \"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.\",\n  \"tzWarningCode\": \"SINGLE_ZONE\",\n  \"preemptibleAdvisoryCode\": null,\n  \"preemptibleAdvisory\": null\n}\n```\n\nСервер на вытесняемом тарифе получил бы `\"preemptibleAdvisoryCode\": \"PREEMPTIBLE_BEST_EFFORT\"` и непустой `preemptibleAdvisory` вместо `null` в тех же двух полях — остальная форма ответа не меняется.\n\n## Пример ответа при ошибке\n\n404 — окно не найдено:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"NOT_FOUND\",\n    \"message\": \"Wake window not found\"\n  }\n}\n```\n\n## Ошибки\n\n| HTTP | Код | Описание |\n|------|-----|----------|\n| 400 | `VALIDATION_ERROR` | Нарушена валидация тела — отсутствует `cronExpr`\u002F`timezone`, `timezone` не входит в список IANA-таймзон, `label` длиннее 80 символов, `lead` вне диапазона 0–3600 или в теле лишнее поле |\n| 400 | `BLACKHOLE_ONLY` | Сервер не в режиме BLACKHOLE |\n| 400 | `GALAXY_NOT_SUPPORTED` | Сервер — хост галактики (`kind: \"GALAXY\"`). Вложенные приложения (`kind: \"GALAXY_APP\"`) принимаются, отклоняется только сам хост |\n| 400 | `ALWAYS_ON_CONFLICT` | Сервер работает в режиме «Всегда онлайн» — на невытесняемом тарифе и без авто-сна |\n| 400 | `CADENCE_TOO_LOW` | Интервал между соседними срабатываниями `cronExpr` меньше минимального, заданного на платформе — сейчас 5 минут |\n| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |\n| 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ |\n| 403 | `WAKE_SCHEDULE_DISABLED` | Пробуждение по расписанию не включено для этого портала |\n| 403 | `INFRA_SCOPE_REQUIRED` | У ключа нет скоупа `vibe:infra` |\n| 404 | `NOT_FOUND` | Сервер не найден\u002Fудалён\u002Fпринадлежит другому API-ключу, либо окно с таким `scheduleId` у этого сервера не найдено |\n| 429 | `RATE_LIMITED` | Превышен лимит 10 запросов в минуту на этот эндпоинт |\n\nПолный список общих ошибок API — [Ошибки](\u002Fdocs\u002Ferrors).\n\n## Известные особенности\n\n- **`PATCH` заменяет окно целиком.** Это отклонение от общего стандарта частичного `PATCH` в API Вайбкод — сравните с [обновлением сделки](\u002Fdocs\u002Fentities\u002Fdeals\u002Fupdate), где непереданные поля сохраняют прежнее значение. Отправка только изменившегося поля молча обнулит остальные необязательные поля — `enabled` станет `true`, `label` и `lead` очистятся. Формируйте тело из последнего известного состояния окна, а не только из изменившихся полей.\n- **`preemptibleAdvisoryCode`\u002F`preemptibleAdvisory` — не гейт, а предупреждение.** Окно обновляется независимо от значения этих полей — на вытесняемом тарифе платформа не запрещает расписание, а лишь честно сообщает, что подъём к моменту окна best-effort. Локализуйте по коду `preemptibleAdvisoryCode`, не по строке `preemptibleAdvisory` — она фиксированная и на английском, для не-UI-клиентов.\n- **Существование окна проверяется раньше остальных гейтов.** На несуществующий `scheduleId` вернётся `404 NOT_FOUND`, даже если запрос заодно нарушает `BLACKHOLE_ONLY` или другой гейт режима сервера.\n\n## Смотрите также\n\n- [Список окон](.\u002Flist.md)\n- [Создать окно](.\u002Fcreate.md)\n- [Удалить окно](.\u002Fdelete.md)\n","## Удалить окно пробуждения\n\n`DELETE \u002Fv1\u002Finfra\u002Fservers\u002F:id\u002Fwake-schedules\u002F:scheduleId`\n\nУдаляет одно окно пробуждения сервера. Восстановить удалённое окно через API нельзя — создавайте новое при необходимости.\n\n## Параметры\n\n| Параметр | В | Тип | Обяз. | Описание |\n|----------|---|-----|:-----:|----------|\n| `id` | path | string (UUID) | да | ID BLACKHOLE-сервера |\n| `scheduleId` | path | string | да | ID окна. Источник — `data[].id` из [списка окон](.\u002Flist.md) |\n\n## Примеры\n\n### curl — личный ключ\n\n```bash\ncurl -X DELETE \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Finfra\u002Fservers\u002FSERVER_ID\u002Fwake-schedules\u002FSCHEDULE_ID\" \\\n  -H \"X-Api-Key: YOUR_API_KEY\"\n```\n\n### curl — OAuth-приложение\n\n```bash\ncurl -X DELETE \"https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Finfra\u002Fservers\u002FSERVER_ID\u002Fwake-schedules\u002FSCHEDULE_ID\" \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\"\n```\n\n### JavaScript — личный ключ\n\n```javascript\nconst res = await fetch(\n  `https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Finfra\u002Fservers\u002F${serverId}\u002Fwake-schedules\u002F${scheduleId}`,\n  { method: 'DELETE', headers: { 'X-Api-Key': 'YOUR_API_KEY' } }\n)\nconst body = await res.json()\nif (body.success) console.log('Окно удалено')\n```\n\n### JavaScript — OAuth-приложение\n\n```javascript\nconst res = await fetch(\n  `https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Finfra\u002Fservers\u002F${serverId}\u002Fwake-schedules\u002F${scheduleId}`,\n  {\n    method: 'DELETE',\n    headers: {\n      'X-Api-Key': 'YOUR_APP_KEY',\n      'Authorization': 'Bearer USER_SESSION_TOKEN',\n    },\n  }\n)\n```\n\n## Поля ответа\n\n| Поле | Тип | Описание |\n|------|-----|----------|\n| `success` | boolean | `true` при успешном удалении |\n\nВ отличие от удаления записей CRM-сущностей, этот эндпоинт отвечает `200` с телом `{ \"success\": true }`, а не `204 No Content`.\n\n## Пример ответа\n\n```json\n{\n  \"success\": true\n}\n```\n\n## Пример ответа при ошибке\n\n404 — окно не найдено:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"NOT_FOUND\",\n    \"message\": \"Wake window not found\"\n  }\n}\n```\n\n## Ошибки\n\n| HTTP | Код | Описание |\n|------|-----|----------|\n| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |\n| 401 | `INVALID_API_KEY` | Неверный или просроченный API-ключ |\n| 403 | `INFRA_SCOPE_REQUIRED` | У ключа нет скоупа `vibe:infra` |\n| 404 | `NOT_FOUND` | Сервер не найден\u002Fудалён\u002Fпринадлежит другому API-ключу, либо окно с таким `scheduleId` у этого сервера не найдено |\n| 429 | `RATE_LIMITED` | Превышен лимит 10 запросов в минуту на этот эндпоинт |\n\nПолный список общих ошибок API — [Ошибки](\u002Fdocs\u002Ferrors).\n\n## Известные особенности\n\n- **Работает независимо от статуса функции для портала.** В отличие от создания и обновления, удаление уже существующего окна не гейтится `WAKE_SCHEDULE_DISABLED` — так владелец сервера может убрать окно, даже если пробуждение по расписанию отключили на портале после его создания.\n- **Не проверяет режим и статус сервера.** В отличие от создания и обновления, удаление не запускает проверки `BLACKHOLE_ONLY`\u002F`GALAXY_NOT_SUPPORTED`\u002F`ALWAYS_ON_CONFLICT` — окно можно удалить у сервера в любом режиме, если оно у него есть.\n\n## Смотрите также\n\n- [Список окон](.\u002Flist.md)\n- [Создать окно](.\u002Fcreate.md)\n- [Обновить окно](.\u002Fupdate.md)\n"]