
## List of runtimes

`GET /v1/infra/runtimes`

Returns the IDs of ready-made runtimes to pass into [`POST /v1/infra/servers/:id/deploy`](./deploy.md) (the `runtime` parameter). A runtime is an optional parameter: if the stack you need is in the list, pass its ID and the platform will install the packages automatically. If not — a deploy without `runtime` is fully functional; install the software you need via `preStart` in the request body. On [`POST /v1/infra/servers`](/docs/infra/servers/create) a runtime is NOT accepted since 2026-04-25 — see `RUNTIME_PARAM_REMOVED`. Each runtime is a set of system packages (nodejs, python, nginx, databases) installed on the server. The estimated installation time is 2–4 minutes for the basic ones, up to 4+ minutes for combinations with several packages.

## Examples

### curl — personal key

```bash
curl -H "X-Api-Key: YOUR_API_KEY" \
  https://vibecode.bitrix24.com/v1/infra/runtimes
```

### curl — OAuth application

```bash
curl -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  https://vibecode.bitrix24.com/v1/infra/runtimes
```

### JavaScript — personal key

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/infra/runtimes', {
  headers: { 'X-Api-Key': 'YOUR_API_KEY' },
})
const { data: runtimes } = await res.json()
runtimes.forEach(r => console.log(`${r.id}: ${r.name} (${r.estimatedSetupTime}s)`))
```

### JavaScript — OAuth application

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/infra/runtimes', {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})
```

## Response fields

| Field | Type | Description |
|------|-----|----------|
| `success` | boolean | Always `true` on success |
| `data` | array | Array of runtimes |
| `data[].id` | string | The runtime ID, passed as `runtime` on deploy (`POST /v1/infra/servers/:id/deploy`) |
| `data[].name` | string | Display name for the user |
| `data[].packages` | array\<string\> | List of packages installed on the server (for reference) |
| `data[].estimatedSetupTime` | number | Estimated installation time in seconds |

## Response example

```json
{
  "success": true,
  "data": [
    {
      "id": "node20",
      "name": "Node.js 20",
      "packages": ["nodejs-20", "npm", "pm2"],
      "estimatedSetupTime": 120
    },
    {
      "id": "node20-pg",
      "name": "Node.js 20 + PostgreSQL",
      "packages": ["nodejs-20", "npm", "pm2", "postgresql-16"],
      "estimatedSetupTime": 180
    },
    {
      "id": "python311-rag",
      "name": "Python 3.11 + RAG (pgvector + Redis)",
      "packages": ["python3.11", "pip", "postgresql-16", "pgvector", "redis"],
      "estimatedSetupTime": 240
    }
  ]
}
```

## Error response example

401 — no API key provided:

```json
{
  "success": false,
  "error": {
    "code": "MISSING_API_KEY",
    "message": "API key required. Pass via X-Api-Key header."
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|----------|
| 401 | `MISSING_API_KEY` | The `X-Api-Key` header was not provided |
| 401 | `INVALID_API_KEY` | Invalid or expired API key |
| 429 | `RATE_LIMITED` | The platform's overall request limit was exceeded |

Full list of common API errors — [Errors](/docs/errors).

## Known specifics

- **As of 2026-04-22 the platform offers 15 runtimes:** six Node.js 20 variants (plain, with PostgreSQL, MySQL, Redis, combinations, the RAG stack), five Python 3.11 variants (similarly), two PHP 8.3 variants (plain and with MySQL), and `static` for SPA static content. The current snapshot is always in the endpoint's response.
- **RAG runtimes** (`node20-rag`, `python311-rag`) — a ready-made environment for the RAG pattern (retrieval-augmented generation — an LLM response enriched with context from external sources): PostgreSQL with the pgvector extension for vector representations and Redis for caching. Right after installation you can connect LlamaIndex / LangChain.
- **`static`** — a runtime for single-page applications and static sites: it installs nginx. After installation nginx runs as a system service on port 80 with the default configuration and the `/var/www/html` directory — it does **not** serve the extracted archive and does not listen on port 3000. To serve the build from `/opt/app` on port 3000 with a fallback to `index.html` for client-side routes, set a `preStart` that creates an nginx server block and frees port 80, and run nginx in the foreground via `start`:

    ```bash
    # preStart: nginx server block on port 3000 + disable the system nginx on port 80
    cat >/etc/nginx/conf.d/app.conf <<'NGINX'
    server {
      listen 3000 default_server;
      listen [::]:3000 default_server;
      root /opt/app;
      index index.html;
      location / { try_files $uri $uri/ /index.html; }
    }
    NGINX
    rm -f /etc/nginx/sites-enabled/default
    systemctl disable --now nginx
    nginx -t
    ```

    In the deploy body: `preStart` is the command above, `start` is `nginx -g 'daemon off;'`, `port` is `3000`, and `hardening` is `"off"`. The `start` field is required: the platform runs the app as the `app.service` systemd unit and the runtime does not create a separate unit for nginx. Suitable for React/Vue/Svelte builds — put `dist/` into the archive.

    The `"hardening": "off"` value is required here. By default the platform starts the app under an unprivileged account, and nginx in this recipe writes its service files and logs outside the application directory — under such an account it does not start. The platform restores the previous mode on its own, but the failed attempt and its health check cost about a minute on every deploy. The field is described on [Full deploy](./deploy.md).
- **The `php83` and `php83-mysql` runtimes, and the MySQL variants (`node20-mysql`, `node20-mysql-redis`, `python311-mysql`), need `"hardening": "off"`.** After installation MySQL admits only the administrator over the local socket, and PHP-FPM runs as a separate system service — under an unprivileged account the app cannot reach the database. The platform restores the previous mode on its own, but the attempt and its health check cost time on every deploy. Pass `"hardening": "off"` in the deploy body to skip it. Apps that reach MySQL over TCP with a password do not need this.
- **In Galaxy mode the combo runtimes do NOT bring up a database.** For a Galaxy app (a container on a shared host, not a dedicated virtual machine) the `-pg` / `-mysql` / `-redis` / `-rag` suffixes are informational: only the base language (Node.js / Python / PHP) is installed, while PostgreSQL / MySQL / Redis are NOT started and connection variables (`DATABASE_URL`, `PG*`, etc.) are NOT injected. The "database on the same machine" model above (`apt` package `postgresql-16`, `DATABASE_URL: postgresql://localhost/...`) applies to a dedicated virtual machine (standalone), not to Galaxy. If a Galaxy app needs a database, use an external (managed) DB and pass the connection string via `env`, or deploy the app to a dedicated virtual machine.
- **The same runtime ID can mean different patch versions in Galaxy versus on a dedicated virtual machine.** In Galaxy the runtime is built from an official Docker image (`node:20-slim`, `python:3.11-slim`, `php:8.3-cli`, `nginx:alpine`) — the version follows the image tag. On a dedicated virtual machine the major version is pinned and matches what is advertised (Node.js 20, Python 3.11, PHP 8.3, PostgreSQL 16); the patch version follows the install source. If the exact version is critical, check it inside the app on the target host kind rather than relying on the runtime ID alone.
- **`estimatedSetupTime` is an estimate, not a guarantee.** It depends on the load of the apt mirrors, the network speed of the virtual machine, and the specific Ubuntu image build. Budget 2× the stated value when automating.
- **If the stack you need is not in the list — use `preStart`.** The server is a clean Ubuntu 24.04 with root access. In the deploy's `preStart` field you can run any `apt-get install`, download binaries, set up the environment. The result is preserved between deploys (except for the `extractTo` directory, which `cleanDeploy: true` cleans). For one-off operations — [`POST /exec`](./exec.md).

## See also

- [Create a server](/docs/infra/servers/create) — `POST /v1/infra/servers` (the `runtime` parameter is NOT accepted since 2026-04-25).
- [Full deploy](./deploy.md) — `runtime` at the deploy stage (the only supported path).
- [Get a server](/docs/infra/servers/get) — the `runtimeStatus` field: `installing` / `ready` / `error`.
