Para agentes de IA: markdown desta página — /docs-content-en/infra/galaxy.md índice da documentação — /llms.txt
Os artigos da documentação estão disponíveis atualmente em inglês.
Galaxy app
A Galaxy app is a separate Black Hole application that lives in a container on a shared host — a galaxy — together with other such apps. Each app gets its own HTTPS subdomain and the same isolation as a separate virtual machine, but they all share one galaxy — and that is many times cheaper than keeping a separate server per app. If the Bitrix24 account administrator has enabled placement in galaxies, the same POST /v1/infra/servers call creates a Galaxy app instead of a virtual machine.
Scope: vibe:infra · Base URL: https://vibecode.bitrix24.com/v1 · Authorization: X-Api-Key header
Who chooses the placement model
The Bitrix24 account administrator chooses the placement mode in the Vibecode dashboard, on the Galaxies page, in the App placement mode section. A regular Bitrix24 account member sees the mode as read-only, and the API caller does not set it. The same POST /v1/infra/servers request creates either a separate virtual machine or a Galaxy app, depending on the placement mode. There is no "create a Galaxy app specifically" parameter in the request.
The placement mode is one of three:
- Galaxy First (
galaxies-only) — new apps are placed densely inside galaxies. If an app outgrows its container, it is moved to a separate Black Hole server. - Hybrid (
both) — an app lands in a galaxy when there is room, otherwise it is deployed on a separate virtual machine. - Standalone only (
standalone-only) — galaxies are not used, and each app gets its own virtual machine.
What the caller should do about it:
- Detect the model from the response; do not set it. A Galaxy app is identified by
createdViaequal togalaxyin the create response. The full list of markers is in the "How to identify a Galaxy app in the response" section below. - Need a separate virtual machine — request it explicitly. If your Bitrix24 account places apps in galaxies but a particular app needs a dedicated server, set the
placementfield todedicatedin the body ofPOST /v1/infra/servers— the platform will create a separate virtual machine instead of a Galaxy app. By defaultplacementisauto, and your Bitrix24 account's placement mode applies.
During the trial period, a new galaxy is not created. Before creating an app, read the deployment block from GET /v1/me:
- When Galaxy mode is enabled but there is no host, the
galaxyAppblock is absent. The two-step path is available only whilecapabilities.servers.create.availableistrue: select an allowed plan ID fromcapabilities.servers.create.limits.allowedPlans, callPOST /v1/infra/serverswithoutsource, thenPOST /v1/infra/servers/:id/deploy. Whenavailableisfalse, follow that slot'suserMessageandalternatives. - When Galaxy mode is disabled,
placementNoteis absent and a one-shot request carryingsourcereturns400 SOURCE_AT_CREATE_GALAXY_ONLY. For a dedicated virtual machine, use the same conditional two-step path throughcapabilities.servers.create.availableand select an allowed plan ID fromcapabilities.servers.create.limits.allowedPlans. - When an existing host passes the preliminary stored-state check, the
galaxyAppblock is present and a one-shot create carryingsourceis worth trying. This is not a guarantee: onlyPOST /v1/infra/serverschecks live capacity. - When an existing host is unsuitable, the
galaxyAppblock is absent. Whilecapabilities.servers.create.availableisfalse,placementNoterules out the two-step path: with trial enforcement active, the occupied slot returns402 TRIAL_PORTAL_LIMIT. To retry one-shot creation, wait for the host to recover, ask an administrator to repair it, or upgrade the plan. After removing the host, re-readGET /v1/meand use the two-step path advertised there. - A commercial Bitrix24 plan lifts the trial restriction, but the create request still checks host suitability.
Readiness is determined differently for each model:
- Separate virtual machine — by
status: "running"andblackholeStatus: "CONNECTED". - Galaxy app — only through a code upload. Waiting for
CONNECTEDdoes not work here (see "Lifecycle" below).
Galaxy availability
Galaxies are enabled in two steps, and both are done on the Vibecode side: first the platform team turns them on for the platform, then the Bitrix24 account administrator turns them on for their own account. Apps are placed in galaxies only when both steps are done. The pre-call signal is the deployment block in the GET /v1/me response:
galaxyEnabled— whether galaxies are open to the Bitrix24 account. A value offalsemeans at least one of the two steps has not been done.galaxyApp— a nested block with the Galaxy app deploy contract. During trial access, it arrives only when galaxies are open, the placement mode is not "Standalone only", and the stored state shows a suitable host. The block is advisory:POST /v1/infra/serverschecks actual host suitability.primary— the placement model the platform treats as primary for this Bitrix24 account:galaxyApporstandalone.
The resolvedDeployMode field shows the placement mode chosen in the dashboard and is always populated, regardless of availability. A value of both with galaxyEnabled equal to false means the mode is selected in the dashboard, but galaxies are not open for the Bitrix24 account — apps are deployed on separate virtual machines.
How to enable them:
- The platform team turns galaxies on for the platform. Until that is done, the Galaxies toggle is not shown in the Settings section of the dashboard. You cannot enable them yourself — contact support.
- The Bitrix24 account administrator turns galaxies on for their own account, with the Galaxies toggle in that same Settings section. A regular Bitrix24 account member does not change this setting.
Turning galaxies off blocks not only the placement of new apps but also the management of existing ones: while the toggle is off, mutating calls on a Galaxy app and on its galaxy return 403 GALAXY_DISABLED. Reading, status refresh (POST /:id/refresh) and deletion stay available at all times — leaving galaxies and cleaning up is possible even after they are turned off.
Cost and limits for a Galaxy app are counted differently from a separate virtual machine — see the "Cost" section below.
How to identify a Galaxy app in the response
| Field | Where | Value |
|---|---|---|
createdVia |
response of POST /v1/infra/servers |
galaxy for a Galaxy app |
kind |
response of POST /v1/infra/servers and GET /v1/infra/servers/:id |
GALAXY_APP — a Galaxy app (container), GALAXY — a galaxy (the carrier host), STANDALONE — a separate virtual machine |
galaxyId |
response of POST /v1/infra/servers and GET /v1/infra/servers/:id |
ID of the galaxy the app runs in. null for other types |
appCount |
response of GET /v1/infra/servers/:id |
For a galaxy (GALAXY) — the number of non-deleted apps in it. null for other types |
A Galaxy app has no SSH access of its own (ssh equals null), no public IP address and no external virtual-machine identifier — a container has none of these. The region and plan fields in the response are the region and plan of the carrier galaxy: the values passed at creation have no effect — the platform chooses placement itself.
Lifecycle — build on code upload
A Galaxy app never reaches blackholeStatus: "CONNECTED" on its own. Its container and tunnel agent are created by the code upload itself — there is no separate provisioning step here, as there is for a virtual machine.
This leads to the main rule: upload the code right after creation, without waiting for CONNECTED. If you create a Galaxy app and just poll the status, it stays in provisioning, and after about 20 minutes the platform marks it as error and records in the provisionError field that the code was never uploaded.
Creating and uploading code
Creation goes through the same POST /v1/infra/servers call. The code is uploaded in one of two scenarios.
- Scenario 1 — single request. Pass the code in the
sourcefield together withruntimeandstartright inPOST /v1/infra/servers. The build runs in the background — no separate upload call is needed. - Scenario 2 — two steps. Create the app without
source, passing the requiredproviderandplan(regionis optional and defaults to the chosen provider's region), getnext: "deploy"in the response, then upload the code viaPOST /v1/infra/servers/:id/deploy. For a Galaxy app the values are informational — see the example in create.md.
Full request bodies, fields and examples for both scenarios are on the Create a server page.
Creating a Galaxy app via scenario 1 — source passed, build running in the background. The model is identified by createdVia equal to galaxy:
{
"success": true,
"data": {
"id": "7c2b1f08-3a4d-4e91-9b6c-2f5e8a1d0c33",
"status": "provisioning",
"name": "my-crm-app",
"kind": "GALAXY_APP",
"galaxyId": "<galaxy-host-id>",
"ssh": null,
"ip": null,
"plan": "bc-medium",
"region": "bc-eu-central",
"mode": "BLACKHOLE",
"createdVia": "galaxy",
"subdomain": "app-7c2b1f08",
"blackholeStatus": "NONE",
"appUrl": "https://app-7c2b1f08.vibecode.bitrix24.com",
"createdAt": "2026-04-22T10:50:11.477Z"
}
}
Deploy
Deploying a Galaxy app differs from deploying a virtual machine. The full contract is on the Full application deploy page.
- The code source is the inline
source.content(a base64 archive). Thesource.urlandsource.versionIdvariants are available where the platform has enabled link deploys for you. Otherwise they are rejected with400 GALAXY_DEPLOY_CONTENT_ONLY. With a link, the host downloads the archive itself, so a large archive never travels through the request body. The link must point at source storage — an outside address is rejected with400 GALAXY_SOURCE_URL_NOT_ALLOWED, so a large archive is first saved as a version and then deployed bysource.versionId. - The
runtimeandstartfields are required. Withoutruntimethe request returns400 GALAXY_DEPLOY_RUNTIME_REQUIRED. The runtime list is atGET /v1/infra/runtimes. - You do not need to supply your own
Dockerfile— the platform generates it from theruntime,portandstartfields. - The
envvariables are injected into the container at startup, not baked into the image, so secrets do not end up in the image layers. Alongside them the platform addsPORT— the app port. ThePORTkey is reserved — see POST /v1/infra/servers/:id/deploy for details. - The container working directory is
/opt/app, and the/apppath is also a link to it. Store persistent data in the/datavolume.
Lifecycle management
A Galaxy app lives in a container on a shared host and has no cloud virtual machine of its own. Some lifecycle operations therefore work through the host, and some do not apply to the app at all. The full map is below — the individual operation pages keep only what is specific to each call.
| Operation | What happens to a Galaxy app |
|---|---|
POST /:id/start, POST /:id/wake |
Both calls bring the app up through the host: the platform starts the galaxy if needed, then starts the container. The response arrives immediately — track readiness by polling GET /v1/infra/servers/:id, because ?wait=true does not wait here. A wake block on the host stops both calls, and /start does not clear it: the refusal comes as 403 SERVER_WAKE_BLOCKED, and when the cause is the Bitrix24 account plan, as 402 with INT_TARIFF_REQUIRED or INT_VIBE_PLUS_REQUIRED, depending on that plan. An app in error status is fixed by a new deploy, not by these calls |
POST /:id/reboot |
Restarts the container on the host. The persistent /data volume is preserved |
POST /:id/stop |
Does not apply. A running app gets 422 VM_MISSING — there is nothing to stop, because the container has no machine. An app that is not in running status is rejected earlier, with 422 SERVER_WRONG_STATE. To remove the app, call DELETE /v1/infra/servers/:id |
PATCH /:id/sleep |
Does not apply — 400 GALAXY_APP_USE_GALAXY_ROUTE. The app sleeps together with its host, and its idle timer is not set through the Vibecode API |
POST /:id/sleep-now |
Does not apply — 400 GALAXY_APP_USE_GALAXY_ROUTE |
PATCH /:id/port |
Does not apply — 400 GALAXY_APP_USE_GALAXY_ROUTE. The container port is pinned to the host and is set by the port field when you upload code |
POST /:id/repair |
Does not apply — 400 INVALID_INPUT. Repair reinstalls the agent on a cloud virtual machine, and the container has none |
POST /:id/refresh |
Returns the current status of the record. The cloud is not queried — there is nothing to query |
| Wake windows: create, update | 403 WAKE_SCHEDULE_GALAXY_DISABLED — the capability is not yet available for apps |
DELETE /:id |
Works — the platform tears the container down inside the galaxy. Details are in the "Deletion" section below |
Three calls from the table — PATCH /:id/sleep, POST /:id/sleep-now and PATCH /:id/port — answer with the same GALAXY_APP_USE_GALAXY_ROUTE code. The server kind is checked before status and mode, so the app gets this code in any state, never NOT_RUNNING or 404. Only the request-value checks run before the kind check: an invalid sleepAfterMinutes or a port outside 0–65535 returns VALIDATION_ERROR for a Galaxy app too, and a system port 1–1023 returns PORT_RESTRICTED.
Commands, deploys and files — by the app id
The server list returns both the app (kind: "GALAXY_APP") and the machine carrying it (kind: "GALAXY"), so a caller holds two different ids. Use the app id. The machine is shared: it also carries containers belonging to other keys of the same Bitrix24 account, so the platform refuses client operations addressed by its id.
| Operation | By the app ID (kind: "GALAXY_APP") |
By the machine ID (kind: "GALAXY") |
|---|---|---|
POST /:id/exec |
Works — the command runs inside the app container. The workdir and env fields are not supported: 400 GALAXY_EXEC_NO_WORKDIR_ENV. Prefix the command itself instead: cd /opt/app; FOO=bar node script.js |
403 GALAXY_HOST_EXEC_FORBIDDEN |
POST /:id/deploy |
Works — this is the main way to ship code, see the "Deploy" section above | 400 GALAXY_HOST_NOT_A_DEPLOY_TARGET |
POST /:id/upload |
Does not apply: the container has no tunnel of its own, so the call fails the server readiness check. Put files into the deploy archive, or create them with a command through /exec |
400 GALAXY_HOST_NOT_A_DEPLOY_TARGET |
A refusal against the machine id arrives before the platform does anything to the server and leaves no lock on it — repeating the same call is pointless. Take your app's row from the server list (kind equals GALAXY_APP) and address it by that id.
Log reading is not affected by this boundary: GET /:id/logs against the machine id still returns its system journal.
Free disk space in a galaxy
The disk usage of a galaxy host machine is visible in your Vibecode account, on the galaxy card in the "Galaxies" section: how much is used out of the total, and when the measurement was taken. The platform does not probe a sleeping machine and shows the last known value — which is why the measurement time sits next to the figure itself. When little free space is left, the card shows a hint with two actions already available to you: expand the galaxy disk, or move the app to another galaxy.
This figure used to be read with a df command against the machine id — that call is now refused (403 GALAXY_HOST_EXEC_FORBIDDEN). Instead, a galaxy host row in GET /v1/infra/servers and in the single-server response carries four fields:
| Field | Meaning |
|---|---|
diskTotalMb |
disk size in mebibytes |
diskFreeMb |
free space in mebibytes |
diskState |
the verdict: ok, warning, critical, or unknown when nothing has been measured yet |
diskProbedAt |
measurement time in ISO-8601 |
The verdict is computed from the same threshold that decides whether an app build has enough room: critical means free space has dropped below that threshold and a build will be refused, warning means you are approaching it. So the warning arrives early, before the first refusal. For STANDALONE machines and for Galaxy apps, all four fields are null: the former are never probed, the latter have no disk of their own.
Outbound IP
A Galaxy app has no static outbound IP address of its own. The app's requests to the outside — to external databases, payment gateways, third-party services — leave through the public IP of the carrier galaxy host, which all apps on that host share.
That address is dynamic. The platform chooses placement itself, and the outbound IP may change when the host is stopped and woken, on a scheduled infrastructure restart, and when the app is migrated to another galaxy. There is no separate endpoint that returns an app's outbound IP.
A dedicated virtual machine does have a public address of its own — it arrives in the ip field of GET /v1/infra/servers/:id. That address is not reserved for the machine: on every wake the machine receives a new one, so after a few sleep cycles the ip in the single-server response returns a different value. This applies to all plans.
The platform provides no permanent outbound address in any placement model. An IP allowlist on the side of an external service — a managed PostgreSQL, for instance — stops matching the actual address both for a Galaxy app and for a dedicated virtual machine.
Cost
Cost is counted per galaxy, not per app. Several Galaxy apps in one galaxy share its cost — five apps on a bc-small plan cost roughly the same as one galaxy, not as five servers. Galaxy apps do not count toward the per-API-key server limit (GET /v1/me → infra.limits.used) — it counts only separate virtual machines.
Logs
For a Galaxy app, GET /v1/infra/servers/:id/logs returns the output stream of the container itself (stdout and stderr), not the galaxy system journal. Reading logs does not wake a sleeping galaxy. If the galaxy is asleep or unreachable, the response is an empty data.logs array plus a diagnostic data.hint field. The since parameter for a Galaxy app accepts only a duration (10m, 2h, 24h) or a timestamp in RFC 3339 format (for example, 2026-04-22T10:50:11Z).
Deletion
A Galaxy app is removed with the same DELETE /v1/infra/servers/:id call — the platform tears down its container in the galaxy and marks the record deleted. The platform wakes a sleeping galaxy itself before deletion. A galaxy with non-deleted apps is not deleted by this call — remove its apps first.
Error codes
| HTTP | Code | Description |
|---|---|---|
| 400 | GALAXY_APP_USE_GALAXY_ROUTE |
A Galaxy app received a call that belongs to a dedicated virtual machine — PATCH /:id/sleep, POST /:id/sleep-now or PATCH /:id/port. What does apply to an app is in the "Lifecycle management" section above |
| 403 | GALAXY_DISABLED |
Galaxies are disabled for the portal — by the platform or by the portal administrator. Any mutating call on a Galaxy app and on its galaxy answers this way; reading, POST /:id/refresh and deletion stay available. How to enable them — see the "Galaxy availability" section above |
| 403 | GALAXY_HOST_EXEC_FORBIDDEN |
A command was addressed to a galaxy host machine ID (kind equals GALAXY). Run it on the app, by its own ID — see the "Commands, deploys and files" section above |
| 400 | GALAXY_HOST_NOT_A_DEPLOY_TARGET |
A deploy or a file upload was addressed to a galaxy host machine ID (kind equals GALAXY). The machine carries containers and is not a deploy target: address the app by its ID |
| 400 | GALAXY_EXEC_NO_WORKDIR_ENV |
A command for a Galaxy app carried workdir or env — the container run does not accept them. Prefix the command itself instead: cd /opt/app; FOO=bar node script.js |
| 400 | SOURCE_AT_CREATE_GALAXY_ONLY |
The source field was passed at creation on a portal without Galaxy mode, or together with placement: "dedicated". Upload the code via POST /:id/deploy after creation |
| 400 | GALAXY_DEPLOY_CONTENT_ONLY |
Deploying a Galaxy app with source.url or source.versionId where link deploys are not enabled for you. Send the archive as the inline source.content |
| 400 | GALAXY_DEPLOY_RUNTIME_REQUIRED |
Deploying a Galaxy app without runtime. Specify a runtime, for example node20 |
| 502 | GALAXY_BASE_IMAGE_UNAVAILABLE |
The build could not fetch its base image — the image registry was unreachable. This is transient: retry the same deploy every few minutes — see Upload code |
| 502 | GALAXY_LOW_DISK |
The host ran out of free disk space during the build. This is retryable: the app is not marked broken, the slot and its /data volume are intact, and the version already running keeps serving requests. Retry the deploy once space has been freed on the host — see Upload code. Creating a server with source in the same request does not mark the app broken either |
| 502 | GALAXY_APP_BUILD_FAILED |
The container build failed. The tail of the build log arrives in the buildLog field, and the breakdown of the cause in error.category and error.buildHint — see Upload code |
| 502 | GALAXY_APP_START_FAILED |
The container built but crashed or went into a restart loop due to lack of memory right after start. The log tail arrives in the buildLog field, and the breakdown of the cause in error.category and error.buildHint — see Upload code |
| 409 | GALAXY_FULL |
There is no room for another Galaxy app. Before refusing, the platform tries to place the app on another galaxy, so this response means there really is no room left. Delete an unneeded Galaxy app, or ask for a dedicated machine — the placement field with the value dedicated, see Create a server |
| 409 | GALAXY_HAS_APPS |
The server being deleted is a galaxy that still has non-deleted apps. The body contains appCount. Deleting a galaxy together with its apps is available in your Vibecode account |
| 409 | GALAXY_HOST_WAKE_BLOCKED |
An app is being deleted on a galaxy that is blocked from waking — for example, billing is frozen. The refusal is terminal: retrying will not help until the cause is cleared. The cause arrives in error.reason — BILLING_FROZEN, ACCESS_EXPIRED, STOPPED or UNKNOWN. This response carries no error.hint |
| 502 | GALAXY_DEPLOY_INTERRUPTED |
The deploy could not be confirmed. When the durable operation status is unknown, the response carries retryable: false: read the operation list, server state, and logs first; do not repeat the deploy blindly. Only a proven failed operation whose hint permits the same request carries retryable: true. Your app slot and the /data volume are preserved. error.subcause names the cause (http_window_exhausted, exec_channel_busy, no_this_deploy_container, tail_unreached, source_fetch_interrupted), and error.repeated with the value true requires stopping the retry loop and inspecting the app's own startup or contacting support, see Upload code |
| 502 | GALAXY_HOST_UNREACHABLE |
The galaxy is unreachable — its tunnel is not in CONNECTED status. For deploy, retryable: false means the durable outcome is unknown: read the operation list, server state, and logs first; do not repeat the deploy blindly. In other cases follow error.hint, see below. If waking is blocked, a terminal 409 GALAXY_HOST_WAKE_BLOCKED arrives instead — it carries no error.hint |
The full reference of common API errors is on the Errors page.
The `error.hint` field of `GALAXY_HOST_UNREACHABLE`
A 502 GALAXY_HOST_UNREACHABLE response carries an error.hint object with four string fields:
| Field | What it holds |
|---|---|
reason |
Why the galaxy is unreachable right now — its virtual machine is waking up, or the agent is reconnecting the tunnel |
recovery |
What to do. The wording depends on where the error came from — see the three branches below |
recoveryAction |
The concrete action to retry. Also depends on the source of the error |
note |
A caveat: the galaxy status in the listing can lag behind the real tunnel state. If the state persists for more than 15 minutes, the galaxy really is unreachable |
The reason and note fields are always the same, while recovery and recoveryAction differ by the source of the error:
| Source | What the hint advises |
|---|---|
Code upload (POST /v1/infra/servers/:id/deploy) |
With retryable: false, read the operation list, server state, and logs first; do not repeat the deploy blindly. Without retryable: false, the build was not dispatched: wait for the tunnel to recover and follow the hint. A sleeping galaxy is woken by the deploy itself |
Command execution (POST /v1/infra/servers/:id/exec) |
Important: if the galaxy is asleep, retries will not wake it — wake it first with a deploy or from the dashboard, and only then retry. If the galaxy was running, wait 1–2 minutes for the tunnel to reconnect |
Deletion (DELETE /v1/infra/servers/:id) |
Wait 1–2 minutes and retry the deletion. The server record is preserved until the teardown actually runs on the galaxy |
In all three cases there is no need to delete and recreate the app: the slot, its container and its /data volume are intact, and a fresh slot would land on the same galaxy and run into the same state.