
# Deploy API

If [`GET /v1/me`](/docs/keys-auth/me) includes `deployment.standalone.reuseTarget`, use its `serverId`: inspect the server first, then deploy to that same id. Creating a new VM is unnecessary. Without that signal, check `capabilities.servers.create.available` first. For `TRIAL_PORTAL_LIMIT`, do not cycle through names, keys, providers or plans: follow `userMessage` and `alternatives`. Successful create-reuse returns HTTP 201 with `reused: true`; `APPLICATION_REUSE_CONFLICT` (HTTP 409, `retryable: true`) means a concurrent binding change — retry the request.

Deploying applications to BLACKHOLE servers without SSH. All operations go through the tunnel agent: commands run on the server, files are uploaded through the tunnel, logs are read from the system journal (the `journalctl` utility). AI agents should use this group of endpoints for the full cycle: "pull code from git → install dependencies → start the service → read logs".

**Requirements:** server in `BLACKHOLE` mode, `running` status, `blackholeStatus: CONNECTED`. In OPEN mode the Deploy API returns `NOT_BLACKHOLE`.

There is no need to wake a sleeping standalone virtual machine in advance: a deploy, a command, a file upload and a journal read wake a server in `sleeping` status on their own and wait until it is ready within the same request — up to 6.5 minutes. If the wake does not complete in that window, the request returns `503 WAKE_TIMEOUT`, the server returns to `sleeping`, and a repeat request is safe. Details — [Full application deploy](./deploy/deploy.md), the "Known specifics" section. A sleeping server with a live plan-change operation (`resize`) returns `409 EXEC_BUSY` before waking; wait for that operation to finish.

> **This is the contract for a Black Hole VM (`kind: "STANDALONE"`).** For a Galaxy application (`kind: "GALAXY_APP"`) the `CONNECTED` requirement does not apply — the deploy builds the container itself. The full model and deploy contract for a Galaxy application — [Galaxy app](./galaxy.md).

> **Galaxy application OOM → release to a dedicated server.** If a Galaxy application deploy fails with `502 GALAXY_APP_START_FAILED` specifically due to OOM (the application outgrew the container memory limit of 512 MB), the response contains a structured hint `error.hint` with `recoveryAction: "graduate-to-dedicated-vm"`. The recommended action is to recreate the application on a separate virtual machine: [`POST /v1/infra/servers`](/docs/infra/servers/create) with `placement: "dedicated"` and `graduateFrom` (the identifier of the failed Galaxy application, which will be deleted after the server is created), then `POST /v1/infra/servers/:id/deploy` with the same source code. Duplicate-creation protection via the `Idempotency-Key` header does not extend to this release — together with `graduateFrom` it returns `400 IDEMPOTENCY_UNSUPPORTED_WITH_GRADUATION`. This is allowed when the Bitrix24 account's `serverCreation` policy permits creating servers and you are within quota. A dedicated virtual machine is billed (it sleeps when idle). The hint is added only when the cause is OOM, not on an ordinary crash.

**Response format:** all endpoints return **JSON** by default (201/200 with `{"success": true, ...}`). For `/deploy` and `/exec` a streaming mode is available via `?stream=true` — an SSE (Server-Sent Events) stream with line-by-line progress is returned. For AI agents and MCP clients **always use JSON** (do not add `?stream=true`) — they cannot parse SSE.

**Rate limits:**

| Limit | Value |
|-------------|----------|
| Operations per minute per API-key-and-server pair | 10 |
| Concurrent `exec`/`deploy` | 1 per server |
| `exec` timeout | 1–600 seconds (default 300) |
| Inline body size (base64 in `/upload`, `/deploy source.content`) | 96 MB of body, about 72 MB of archive. Over the cap — `413 INLINE_SOURCE_TOO_LARGE` |
| File size via URL (`/upload url`, `/deploy source.url`) | 500 MB |
| Archive size of a saved version (`/deploy source.versionId`) | 500 MB |
| Multipart archive size in `/deploy` | 500 MB as long as the archive streams into storage. Otherwise about 72 MB — [conditions](./deploy/deploy.md) |

Scope: `vibe:infra`

## Operations

- [Run a command](./deploy/exec.md) — `POST /v1/infra/servers/:id/exec`
- [Upload a file](./deploy/upload.md) — `POST /v1/infra/servers/:id/upload`
- [Service logs](./deploy/logs.md) — `GET /v1/infra/servers/:id/logs`
- [Full application deploy](./deploy/deploy.md) — `POST /v1/infra/servers/:id/deploy`
- [Operation outcome](./deploy/operation-status.md) — `GET /v1/infra/operations/:operationId`
- [Recent server operations](./deploy/operations.md) — `GET /v1/infra/servers/:id/operations`
- [Operation outcome from the server feed](./deploy/server-operation.md) — `GET /v1/infra/servers/:id/operations/:operationId`
- [Set the application port](./deploy/port.md) — `PATCH /v1/infra/servers/:id/port`
- [Tunnel metrics](./deploy/metrics.md) — `GET /v1/infra/servers/:id/metrics`
- [Release a stuck lock](./deploy/lock.md) — `DELETE /v1/infra/servers/:id/lock`
- [List of runtimes](./deploy/runtimes.md) — `GET /v1/infra/runtimes`

## Capabilities

- [A fast release cycle](./deploy/fast-cycle.md) — techniques that shorten repeat releases without running every step

## Typical scenario

**Full deploy cycle in a single request:**

1. [`POST /v1/infra/servers`](/docs/infra/servers/create) — create a server.
2. Wait for readiness via [`GET /v1/infra/servers/:id`](/docs/infra/servers/get) (`status: "running"` + `blackholeStatus: "CONNECTED"`).
3. [`POST /deploy`](./deploy/deploy.md) — specify `source.url` / `runtime` / `install` / `start` / `port`. All deploy steps run automatically. By default the response is JSON — `?stream=true` is only needed if you want SSE.
4. After the deploy — [`GET /logs?lines=100`](./deploy/logs.md) to verify.
5. While debugging — [`POST /exec`](./deploy/exec.md) for one-off commands.

**Manual cycle (without `/deploy`):**

1. [`POST /upload { source.url }`](./deploy/upload.md) — place the archive, unpack it.
2. [`POST /exec { command: "cd /opt/app && npm install" }`](./deploy/exec.md) — dependencies.
3. [`POST /exec { command: "systemctl start app" }`](./deploy/exec.md) — start the service.
4. [`GET /logs?service=app&lines=50`](./deploy/logs.md) — confirm it works.

[`POST /deploy`](./deploy/deploy.md) does everything at once and checks the application's health itself.

## App icon

The app icon (SVG) appears in the Bitrix24 catalog and as the browser-tab favicon. The format, requirements and order (favicon `<link>` before deploy, `POST /v1/infra/servers/:id/icon` upload after) live on a dedicated page — [App icon](/docs/infra/app-icon).

## Guides

- [Load a database dump onto a server](/docs/recipes/db-dump-restore) — upload a dump and restore the database in the background via `exec`.

## Upload path busy

Another upload is using the source upload path. A synchronous deploy returns `409 GALAXY_UPLOAD_BUSY` with `error.retryable: true`, `error.retryAfter: 10`, a matching `Retry-After: 10` header and `error.hint`. Wait at least 10 seconds and retry the same `POST /v1/infra/servers/:id/deploy` for this app.

The refusal itself preserves the app status and the version already running. When a build starts in the background after server creation, a new app initially remains `provisioning`: its server response and dashboard card show a `buildHint` recommending the same deploy again. If the attempt remains stuck for 20 minutes, the next check within another 5 minutes marks the app `error`, preserving the busy-path reason and `buildHint`. Retry the same deploy after this transition too: a new attempt returns this slot to `provisioning`. The `/data` contents are preserved. A source build started after server creation is not retried automatically. Hermes retries its upload no sooner than after 3 minutes; the existing 30-minute wait limit ends the attempt while retaining the busy-path reason and hint. Do not delete the app, release a lock or call `/unstick`.

## See also

- [Creating a server](/docs/infra/servers/create)
- [Lifecycle](/docs/infra/lifecycle)
- [Switch mode](/docs/infra/access/mode)
- [Root section — Infrastructure](/docs/infra)
