لوكلاء AI: ملف markdown لهذه الصفحة — /docs-content-en/infra/wake-schedules.md فهرس التوثيق — /llms.txt

مقالات التوثيق متاحة حاليًا باللغة الإنجليزية فقط.

Scheduled wake

Recurring wake windows for a server in BLACKHOLE mode: the platform starts bringing the server up ahead of the moment set by a cron expression, with a margin for boot, and the task itself is fired by the app's own cron once the machine is up — the platform never reads or runs the app's code.

On a preemptible plan, waking is best-effort, not a guarantee. A server of this type comes up as capacity frees up — through a queue — so there may be no free capacity when the window comes, and the window can be skipped. The create and update responses carry preemptibleAdvisoryCode: "PREEMPTIBLE_BEST_EFFORT" for exactly this case — see Create a window. On a non-preemptible plan, too, the server is not guaranteed to be up by the exact moment: a boot can take several minutes longer. Write a time-critical task so that, once the server starts, it checks whether its run time has already passed and, if so, runs late — or keep the server in the “Always online (24/7)” mode.

A deploy changes neither the windows nor the sleep timer. The wake schedule and the auto-sleep timer are stored on the platform, not in the application code, so shipping a new version does not reset them — the windows keep working with no extra action. The only thing the deploy takes from the schedule is the windows' timezone: on a dedicated virtual machine it lands in the TZ environment variable when every enabled window declares the same zone. Details — Full application deploy.

Creating or updating a wake schedule normally requires a numeric auto-sleep setting. Creating or updating any window while sleepAfterMinutes is null (“Never”) is rejected as an always-on conflict, even when that window is disabled. In the reverse direction, setting null is rejected only while an enabled window exists and the server is not in the SCHEDULE run mode; existing disabled windows neither affect the timeout nor block that sleep-setting change. An explicit numeric sleepAfterMinutes remains the effective timeout and is not shortened by the schedule. Existing older records are not rewritten: if one already contains null plus an enabled and entitled schedule with a computed next wake, the platform's post-window timeout applies — 15 minutes of inactivity by default. When there are no effective windows, null once again means no idle auto-sleep. Creating or updating a window with null is not rejected for an app in a galaxy: the app does not choose its plan but inherits it from the galaxy. Nor is it rejected for a server in the SCHEDULE run mode: its sleep is declared by the schedule.

Scope: vibe:infra

Create a wake window

POST /v1/infra/servers/:id/wake-schedules

Declares a new recurring wake window for a server in BLACKHOLE mode. The body is a flat object, with no fields wrapper.

Parameters

Parameter In Type Required Description
Parameterid Inpath Typestring (UUID) Requiredyes DescriptionID of the BLACKHOLE server

Request fields (body)

Field Type Required Default Description
FieldcronExpr Typestring Requiredyes Default— DescriptionA 5-field cron expression (minute hour day-of-month month day-of-week), 9 to 120 characters
Fieldtimezone Typestring Requiredyes Default— DescriptionIANA timezone of the window, e.g. America/New_York. Checked against Intl.supportedValuesOf('timeZone') — an unknown value is rejected at validation time
Fieldlabel Typestring Requiredno Default— DescriptionDisplay label for the window, up to 80 characters
Fieldlead Typenumber Requiredno Defaultthe server's margin, else the platform's DescriptionMargin, in seconds, before the cronExpr moment by which the server must already be up — covers VM boot time. 0 to 3600. A value below the platform margin is raised to it
Fieldenabled Typeboolean Requiredno Defaulttrue DescriptionWhether the window is active. A disabled window never triggers a wake but stays in the list

The lead margin resolves in three tiers: the window's own value, else a server-level margin set outside this CRUD, else the platform margin. The platform margin is also a floor: a smaller value is stored on the window as sent, but the wake still starts no later than the platform margin before the cronExpr moment. For a server with kind: "GALAXY_APP", the platform margin is larger than for a standalone server: waking runs in two phases — bringing up the host and starting the container.

This schedule write requires a numeric auto-sleep setting. If the server stores sleepAfterMinutes: null (“Never”), the request is rejected as an always-on conflict even when enabled is false. In the reverse direction, setting null is rejected only while an enabled window exists and the server is not in the SCHEDULE run mode; an already stored disabled window neither affects the timeout nor blocks that sleep-setting change. An explicit numeric value remains the effective timeout and is not shortened by the schedule. Existing older records are not rewritten: if one already contains null plus an effective schedule, the platform's post-window fallback applies — 15 minutes of inactivity by default. Creating or updating a window with null is not rejected for an app in a galaxy: the app does not choose its plan but inherits it from the galaxy. Nor is it rejected for a server in the SCHEDULE run mode: its sleep is declared by the schedule.

Examples

curl — personal key

Terminal
curl -X POST "https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/wake-schedules" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "cronExpr": "0 9 * * 1-5",
    "timezone": "America/New_York",
    "label": "daily report",
    "enabled": true
  }'

curl — OAuth application

Terminal
curl -X POST "https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/wake-schedules" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "cronExpr": "0 9 * * 1-5",
    "timezone": "America/New_York",
    "label": "daily report",
    "enabled": true
  }'

JavaScript — personal key

javascript
const res = await fetch(
  `https://vibecode.bitrix24.com/v1/infra/servers/${serverId}/wake-schedules`,
  {
    method: 'POST',
    headers: {
      'X-Api-Key': 'YOUR_API_KEY',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      cronExpr: '0 9 * * 1-5',
      timezone: 'America/New_York',
      label: 'daily report',
      enabled: true,
    }),
  }
)
const body = await res.json()
if (body.tzWarningCode === 'MULTI_ZONE') {
  console.warn('Windows span more than one timezone — TZ is not injected at deploy time')
}

JavaScript — OAuth application

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

Response fields

Field Type Description
Fieldsuccess Typeboolean DescriptionAlways true on success
Fielddata.id Typestring DescriptionWindow ID for a later update or delete
Fielddata.serverId Typestring (UUID) DescriptionID of the owning server
Fielddata.cronExpr Typestring DescriptionThe stored cron expression
Fielddata.timezone Typestring DescriptionThe stored timezone
Fielddata.label Typestring | null DescriptionWindow label
Fielddata.lead Typenumber | null DescriptionMargin in seconds. null when not set on the window itself
Fielddata.enabled Typeboolean DescriptionWhether the window is active
Fielddata.source Typestring DescriptionHow the window was created. Always "MANUAL" for windows created through this CRUD
Fielddata.lastFiredAt Typestring (ISO 8601) | null DescriptionTimestamp of the last confirmed firing. null for a freshly created window
Fielddata.wakeAttemptStartedAt Typestring (ISO 8601) | null DescriptionInternal scheduler claim marker — non-null only for the short interval while a wake is in flight. Normally null
Fielddata.lastWakeLateAt Typestring (ISO 8601) | null DescriptionTimestamp of the last wake that fired later than its computed window. null if there have been no late wakes
Fielddata.createdAt Typestring (ISO 8601) DescriptionRecord creation date
Fielddata.updatedAt Typestring (ISO 8601) DescriptionDate of the last update to the record
FieldtzWarning Typestring | null DescriptionTimezone-mismatch advisory, as text. null when the server has no active windows left after this mutation
FieldtzWarningCode Typestring | null DescriptionMachine-readable code for the same advisory: "SINGLE_ZONE", "MULTI_ZONE", or null
FieldpreemptibleAdvisoryCode Typestring | null Description"PREEMPTIBLE_BEST_EFFORT" when the server runs on a preemptible plan — otherwise null
FieldpreemptibleAdvisory Typestring | null DescriptionAn explanation of the same advisory, as text (in English, for non-UI API clients). null when the server is on a non-preemptible plan

tzWarning, tzWarningCode, preemptibleAdvisoryCode, and preemptibleAdvisory are top-level response fields, not nested under data.

Response example

The server's only active window — the timezone is unambiguous:

JSON
{
  "success": true,
  "data": {
    "id": "cm38x02qp0001ml08g7k3h2a",
    "serverId": "e765edfc-ba0a-43de-b8ea-838dd872c522",
    "cronExpr": "0 9 * * 1-5",
    "timezone": "America/New_York",
    "label": "daily report",
    "lead": null,
    "enabled": true,
    "source": "MANUAL",
    "lastFiredAt": null,
    "wakeAttemptStartedAt": null,
    "lastWakeLateAt": null,
    "createdAt": "2026-07-10T08:12:00.000Z",
    "updatedAt": "2026-07-10T08:12: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
}

A server on a preemptible plan would get "preemptibleAdvisoryCode": "PREEMPTIBLE_BEST_EFFORT" and a non-empty preemptibleAdvisory instead of null in those same two fields — the rest of the response shape is unchanged.

Error response example

400 — the window conflicts with an always-on server:

JSON
{
  "success": false,
  "error": {
    "code": "ALWAYS_ON_CONFLICT",
    "message": "Scheduled wake conflicts with an always-on (24/7) server, which never auto-sleeps. Turn off the always-on toggle, or set a sleep timeout instead of \"Never\", to schedule wake windows."
  }
}

Errors

HTTP Code Description
HTTP400 CodeVALIDATION_ERROR DescriptionBody validation failed — missing cronExpr/timezone, timezone not in the IANA timezone list, label over 80 characters, lead outside 0–3600, or an unknown field in the body
HTTP400 CodeBLACKHOLE_ONLY DescriptionThe server is not in BLACKHOLE mode
HTTP400 CodeGALAXY_NOT_SUPPORTED DescriptionThe server is a Galaxy host (kind: "GALAXY"). A host holds no windows at all: the schedule is declared on an app inside the galaxy, not on the host itself
HTTP400 CodeALWAYS_ON_CONFLICT DescriptionThe server runs in always-on mode — no auto-sleep. A wake schedule would silently break that guarantee. An app in a galaxy never receives this code: it inherits the galaxy's plan, and the platform does not treat it as always-on. Nor does a server in the SCHEDULE run mode: its owner has declared sleep explicitly, and the window becomes an extra wake-up on top of the schedule
HTTP400 CodeCADENCE_TOO_LOW DescriptionThe gap between consecutive cronExpr occurrences is below the platform's floor — currently 5 minutes
HTTP401 CodeMISSING_API_KEY DescriptionThe X-Api-Key header is missing
HTTP401 CodeINVALID_API_KEY DescriptionThe key is not recognized — no such key exists on the platform
HTTP403 CodeWAKE_SCHEDULE_DISABLED DescriptionScheduled wake is not enabled for this portal
HTTP403 CodeWAKE_SCHEDULE_GALAXY_DISABLED DescriptionThe server is an app inside a galaxy (kind: "GALAXY_APP"). Such an app can hold windows, but the capability for Galaxy apps is switched off on the platform. The capability is enabled separately from ordinary servers, so a kind: "STANDALONE" server never receives this code
HTTP403 CodeWAKE_SCHEDULE_LIMIT DescriptionThe server already has 50 windows — the per-server cap
HTTP403 CodeINFRA_SCOPE_REQUIRED DescriptionThe key lacks the vibe:infra scope
HTTP403 CodeINFRA_FORBIDDEN_FOR_COWORK_KEY DescriptionThe call was made with a Cowork/Code key — such a key works with data only and cannot perform write operations. To issue a key that can, see Project key for deploy
HTTP403 CodeSERVER_ROLE_FORBIDDEN DescriptionYou are on this server's development team with the Developer role, and this operation is open to the Administrator role. error.hint carries your role, the required threshold and the list of calls that are open to you. Role breakdown — List servers
HTTP404 CodeNOT_FOUND DescriptionThe server was not found, was deleted, or belongs to a different API key while you are not on its development team
HTTP429 CodeRATE_LIMITED DescriptionThe 10-requests-per-minute limit for this endpoint was exceeded. The exact value arrives in the x-ratelimit-limit header (the cap is divided across replicas)

Full list of shared error codes — Errors.

Known specifics

  • Check order. The key's scope and server ownership are checked before the other conditions, so WAKE_SCHEDULE_DISABLED/BLACKHOLE_ONLY/GALAXY_NOT_SUPPORTED/WAKE_SCHEDULE_GALAXY_DISABLED/ALWAYS_ON_CONFLICT only ever surface for a request with a valid key against an owned, existing server, and among themselves these conditions are checked in the order listed. The cron-expression checks (VALIDATION_ERROR, then CADENCE_TOO_LOW) run after these gates.
  • Two different galaxy refusals. GALAXY_NOT_SUPPORTED is about the galaxy host: it holds no windows at all, and enabling the capability will not change that. WAKE_SCHEDULE_GALAXY_DISABLED is about an app inside a galaxy: it can hold windows, but the capability for such apps is switched off on the platform. The first arrives with status 400, the second with 403, so branch on the response code.
  • tzWarning/tzWarningCode are a conservative heuristic. The platform does not track whether the application was redeployed since a window was declared, so the advisory fires for any set of active windows after a mutation — even when the timezone is already correctly set in the environment. Go by the code: "SINGLE_ZONE" means the timezone is unambiguous and lands in TZ on the next deploy of a dedicated virtual machine, "MULTI_ZONE" means the windows span more than one zone and TZ is not auto-injected.
  • preemptibleAdvisoryCode/preemptibleAdvisory are an advisory, not a gate. The window is created or updated regardless of these fields' values — on a preemptible plan the platform does not forbid a schedule (that is its intended use case); it only states up front that waking the server in time for the window is best-effort. Localize by preemptibleAdvisoryCode, not by the preemptibleAdvisory string — that is a fixed English string for non-UI clients, not meant to be shown to a user as-is.
  • null in the sleep setting normally blocks schedule creation and update. It is the stored “Never” choice and disables idle auto-sleep; creating or updating a window while it is stored is rejected as an always-on conflict, even when the submitted window is disabled. Setting null through the sleep endpoint is narrower: that write is rejected only while an enabled window exists and the server is not in the SCHEDULE run mode. If an older record already contains null plus an effective schedule, the platform's post-window timeout applies between windows. V1 does not return the computed session policy: for long-running background work, keep null with no enabled windows or choose a numeric timeout long enough for the task. Creating or updating a window with null is not rejected for an app in a galaxy: the app does not choose its plan but inherits it from the galaxy. Nor is it rejected for a server in the SCHEDULE run mode: its sleep is declared by the schedule.
  • The platform does not configure the cron inside the VM. POST /wake-schedules only brings the server up for the target moment — ahead of time, with a margin for boot, but with no guarantee it is up in time. On a preemptible plan the window can be skipped entirely — see preemptibleAdvisoryCode above. Firing the task at that moment is the job of the app's own cron/timer.

See also