#Infrastructure

Create and manage virtual servers for deploying Bitrix24 applications. Each server is invisible from the internet by default (Black Hole mode) — the application is reachable only through the HTTPS subdomain app-{id}.vibecode.bitrix24.tech. Server management and deployment go through the REST API without SSH.

Scope: vibe:infra (added automatically to every API key) · Base URL: https://vibecode.bitrix24.tech/v1 · Authorization: X-Api-Key header

#Documentation sections

  • Providers and catalogs — list of providers, plans, regions, and OS images (4 endpoints).
  • Servers — create, list, details, delete (4 endpoints).
  • Lifecycle — start, stop, sleep, wake, tunnel repair, provisioning status (9 endpoints).
  • Access and modes — access policy, user/department list, SSH credentials, BLACKHOLE↔OPEN mode (7 endpoints).
  • Deploy API — run commands, upload files, deploy the application, logs, port, metrics, lock, runtimes (8 endpoints).
  • Access tokens — short-lived tokens for e2e checks and shareable links (3 endpoints).
  • What arrives at the application — Gateway injection of X-Vibe-Authorization: Bearer, reading identity via /v1/me, handler skeletons in Node/Python/Go.
  • Portal event subscriptions — delivery of Bitrix24 events (ONTASKADD and similar) to the app through the tunnel, without polling (3 endpoints).

#What to know up front

  1. The application port is always 3000. The Black Hole tunnel proxies exactly this port; you don't need to change it. The server is an isolated environment: :3000 inside the virtual machine has no relation to the ports on your local machine.
  2. Deploy API is BLACKHOLE-only. All of /deploy, /exec, /upload, /logs require servers in BLACKHOLE mode with the tunnel agent in status CONNECTED. For OPEN servers they return an error.
  3. /deploy and /exec return JSON by default. This is safe for AI agents and MCP clients — no extra query parameters are needed. If you genuinely need a streaming response (live deploy-step output in the UI), pass ?stream=true — then you get SSE (Server-Sent Events). The documentation used to claim the opposite (SSE by default, ?stream=false for JSON) — that is outdated and no longer matches the API behavior.
  4. accessPolicy is security. Changing the policy from OWNER_ONLY to PORTAL/AUTHENTICATED/PUBLIC opens the application to other users. Never change accessPolicy without explicit user confirmation.
  5. The server is a clean Ubuntu 24.04 with root access enabled. The virtual machine is created from a stock Ubuntu image with no preinstalled software (except the tunnel agent). The agent runs as the root user — no sudo is needed in preStart, install, or /exec commands. Outbound internet is unrestricted: apt-get, curl, wget, pip work directly. Inbound traffic is blocked except the tunnel connection.
  6. The Bitrix24 plan plays a dual role. First, the Bitrix24 REST API itself is available only on commercial portal plans — without it neither applications, nor the /v1/deals proxy, nor bots, nor any other call proxied into Bitrix24 work. Second, on top of that — creating servers, deploying, and waking require an active BitrixGPT + Marketplace subscription on the portal. AI Router works independently of the Bitrix24 plan — it does not proxy into REST and is available even on free plans (BYOK free; platform models are billed against the VibeCode balance). Details are in the "Plan and access" section below.
  7. User authorization inside the application. On every request the Gateway injects six headers prefixed with X-Vibe-: Request-Id always, plus User-Id, User-Name, User-Role, Portal-Id, Authorization (Bearer vibe_session_<…>) for an authenticated request. The browser never sees or stores the Authorization token — it lives only between the Gateway and the app server. For a quick user identifier the X-Vibe-User-Id header is enough; the full context (scopes, capabilities, plan, application info) comes from a single GET /v1/me call with server-side caching. The user ID in the /v1/me response is data.currentUser.bitrixUserId, the portal domain is data.portal. The full header table, the BFF pattern, and handler skeletons in Node/Python/Go — What arrives at the application.
  8. Creating servers requires a user session for vibe_app_ keys. POST /v1/infra/servers is gated by a plan check that needs to know exactly who is creating the server. For vibe_api_ the user context already lives in the key itself; for vibe_app_ an Authorization: Bearer <session> is required — without it the response is 401 UNAUTHENTICATED with an error.hint pointing at the OAuth flow. Reads and the Deploy API on already-existing servers don't require a session — the "Endpoint authorization" table below collects all the rules in one place.

#Quick start

Three calls — create a server and run the application.

#curl — personal key

Terminal
export VIBE_KEY="YOUR_API_KEY"

# 1. Create a server (automatically in Black Hole mode)
curl -X POST https://vibecode.bitrix24.tech/v1/infra/servers \
  -H "X-Api-Key: $VIBE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "bitrix-cloud",
    "name": "my-app",
    "plan": "bc-small",
    "region": "ru-central1-b",
    "image": "fd83esfomhq25p2ono90"
  }'

# 2. Wait until ready: status=running AND blackholeStatus=CONNECTED
curl -H "X-Api-Key: $VIBE_KEY" \
  https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID

# 3. Deploy the application (?stream=false — JSON instead of SSE)
curl -X POST "https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/deploy?stream=false" \
  -H "X-Api-Key: $VIBE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source": { "url": "https://github.com/user/app/archive/main.tar.gz" },
    "runtime": "node20",
    "install": "cd /opt/app && npm install --production",
    "start": "cd /opt/app && node server.js",
    "port": 3000
  }'

The application is reachable at https://app-{id}.vibecode.bitrix24.tech — the appUrl field in the /deploy response.

#curl — OAuth application

Terminal
# Same thing, just add the Authorization: Bearer header with the session token
curl -X POST https://vibecode.bitrix24.tech/v1/infra/servers \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "provider": "bitrix-cloud", "name": "my-app", "plan": "bc-small", "region": "ru-central1-b", "image": "fd83esfomhq25p2ono90" }'

#Full example

A realistic JavaScript scenario — create a server, wait until ready, deploy, get the application URL.

javascript
const VIBE_KEY = process.env.VIBE_KEY
const BASE = 'https://vibecode.bitrix24.tech/v1'

async function api(method, path, body = null) {
  const opts = { method, headers: { 'X-Api-Key': VIBE_KEY } }
  if (body) {
    opts.headers['Content-Type'] = 'application/json'
    opts.body = JSON.stringify(body)
  }
  const res = await fetch(`${BASE}${path}`, opts)
  if (!res.ok) throw new Error(`${method} ${path} → ${res.status}`)
  return res.json()
}

// 1. Pick provider, plan, region, image
const { data: plans } = await api('GET', '/infra/providers/bitrix-cloud/plans')
const { data: regions } = await api('GET', '/infra/providers/bitrix-cloud/regions')
const { data: images } = await api('GET', '/infra/providers/bitrix-cloud/images')

const plan = plans.find(p => p.id === 'bc-small')
const region = regions.find(r => r.id === 'ru-central1-b')
const image = images[0]

// 2. Create a server (always in Black Hole)
const { data: server } = await api('POST', '/infra/servers', {
  provider: 'bitrix-cloud',
  name: 'my-crm-bot',
  plan: plan.id,
  region: region.id,
  image: image.id,
})
console.log(`Server created: ${server.id}, subdomain: ${server.subdomain}`)

// 3. Wait until status becomes running AND blackholeStatus becomes CONNECTED
let info = server
while (info.status !== 'running' || info.blackholeStatus !== 'CONNECTED') {
  await new Promise(r => setTimeout(r, 10000)) // 10 seconds between polls
  const res = await api('GET', `/infra/servers/${server.id}`)
  info = res.data
  console.log(`status=${info.status}, blackhole=${info.blackholeStatus}`)
}

// 4. Deploy the application (?stream=false is required for a JSON response)
const deploy = await api('POST', `/infra/servers/${server.id}/deploy?stream=false`, {
  source: { url: 'https://github.com/user/app/archive/main.tar.gz' },
  runtime: 'node20',
  install: 'cd /opt/app && npm install --production',
  preStart: 'cd /opt/app && npx prisma migrate deploy',
  start: 'cd /opt/app && node server.js',
  port: 3000,
  env: { NODE_ENV: 'production' },
})

console.log(`Application is live: ${deploy.data.appUrl}`)

// 5. (Optional) Configure auto-sleep after 60 minutes of inactivity
await api('PATCH', `/infra/servers/${server.id}/sleep`, { sleepAfterMinutes: 60 })

#Endpoint reference

All 35 endpoints. Links lead to pages with parameters, examples, and error codes.

Providers and catalogs:

Method Path Description
GET `/v1/infra/providers` List of cloud providers
GET `/v1/infra/providers/:providerId/plans` Provider plans
GET `/v1/infra/providers/:providerId/regions` Provider regions
GET `/v1/infra/providers/:providerId/images` OS images

Servers:

Method Path Description
POST `/v1/infra/servers` Create a server (always Black Hole)
GET `/v1/infra/servers` List of your servers
GET `/v1/infra/servers/:id` Server details
DELETE `/v1/infra/servers/:id` Delete a server

Lifecycle:

Method Path Description
POST `/v1/infra/servers/:id/start` Start a stopped/sleeping server
POST `/v1/infra/servers/:id/stop` Stop a running server
POST `/v1/infra/servers/:id/reboot` Reboot the server
POST `/v1/infra/servers/:id/wake` Wake a sleeping server (async or blocking)
POST `/v1/infra/servers/:id/sleep-now` Immediately put a BLACKHOLE server to sleep
PATCH `/v1/infra/servers/:id/sleep` Configure auto-sleep
POST `/v1/infra/servers/:id/refresh` Request status and IP from the provider
POST `/v1/infra/servers/:id/repair` Restore the tunnel via serial console
GET `/v1/infra/servers/:id/repair-status` Tunnel restore progress

Access and modes:

Method Path Description
GET `/v1/infra/servers/:id/ssh` SSH credentials (OPEN only)
PATCH `/v1/infra/servers/:id/mode` Switch BLACKHOLE↔OPEN
PATCH `/v1/infra/servers/:id/access-policy` Application access policy
GET `/v1/infra/servers/:id/access` List of users and departments with access
POST `/v1/infra/servers/:id/access` Add a user or department
DELETE `/v1/infra/servers/:id/access/:accessId` Remove an access entry
GET `/v1/infra/servers/:id/b24-users` Search Bitrix24 portal users

Deploy API:

Method Path Description
POST `/v1/infra/servers/:id/exec` Run a command (SSE or JSON)
POST `/v1/infra/servers/:id/upload` Upload a file (base64 or by URL)
GET `/v1/infra/servers/:id/logs` Service logs (journalctl utility)
POST `/v1/infra/servers/:id/deploy` Full application deploy
PATCH `/v1/infra/servers/:id/port` Set the application port
GET `/v1/infra/servers/:id/metrics` Tunnel activity metrics
DELETE `/v1/infra/servers/:id/lock` Release a stuck operation lock
GET `/v1/infra/runtimes` List of available runtimes

Access tokens:

Method Path Description
POST `/v1/infra/servers/:id/access-tokens` Issue an access token (api-bearer or share-url)
GET `/v1/infra/servers/:id/access-tokens` List of server tokens
DELETE `/v1/infra/servers/:id/access-tokens/:tokenId` Revoke a token

Portal event subscriptions:

Method Path Description
POST `/v1/infra/servers/:id/event-subscriptions` Subscribe the server to a portal event (event.bind under the OAuth app)
GET `/v1/infra/servers/:id/event-subscriptions` List subscriptions + recent deliveries
DELETE `/v1/infra/servers/:id/event-subscriptions/:subId` Remove a subscription

#Endpoint authorization

All infra endpoints require the X-Api-Key header. For vibe_app_ keys (bound to an OAuth application) some POST operations additionally require Authorization: Bearer <session> — without it the response is 401 UNAUTHENTICATED with an error.hint. For vibe_api_ keys the user context already lives in the key itself, so a separate session is not needed.

Endpoint X-Api-Key Authorization: Bearer for vibe_app_ When Bearer is required
GET /v1/infra/providers/* yes no
GET /v1/infra/servers, GET /v1/infra/servers/:id yes no
GET /v1/infra/servers/:id/logs, /metrics, /access, /access-tokens, /b24-users, /ssh yes no
GET /v1/infra/runtimes yes no
POST /v1/infra/servers (create a server) yes yes Plan gate: the platform needs to know exactly who is creating the server.
POST /v1/infra/servers/:id/deploy, /exec, /upload yes no The vibe:infra scope on the key is enough.
POST /v1/infra/servers/:id/start, /stop, /reboot, /wake, /sleep-now, /refresh, /repair, PATCH /sleep yes no
PATCH /v1/infra/servers/:id/mode, /access-policy, /port yes no
POST /v1/infra/servers/:id/access, DELETE /v1/infra/servers/:id/access/:accessId yes no
POST /v1/infra/servers/:id/access-tokens, DELETE .../:tokenId yes no The platform flag accessTokensEnabled must be enabled; otherwise 503 FEATURE_DISABLED.
POST/GET/DELETE /v1/infra/servers/:id/event-subscriptions yes no The server must be backed by an OAuth app with an application_token; otherwise 400 NOT_OAUTH_APP.
DELETE /v1/infra/servers/:id yes no
DELETE /v1/infra/servers/:id/lock yes no

Quick check before calling: GET /v1/medata.capabilities.servers.create.available. For vibe_app_ without a session it returns false with reason: "SESSION_REQUIRED" and a hint in userMessage — the model immediately sees that it needs to go through the OAuth flow rather than hitting a 401 on the POST /v1/infra/servers itself.

#Limits

Limit Value
Servers per API key 3
Deploy API operations per minute per server 10
Concurrent exec/deploy per server 1
exec timeout 1–600 seconds (default 300)
base64 body size (upload inline, source.content) 500 MB
File size via source.url / upload url 500 MB
multipart archive size in deploy 500 MB
/ssh request rate up to 10 per minute

The platform rate limit is shared across all V1 endpoints, see the "Limits and optimization" section.

#Server statuses

Status Description
provisioning The virtual machine is being created at the provider (1–3 minutes)
running The virtual machine is running, IP assigned. For the tunnel you also need blackholeStatus: CONNECTED
sleeping Stopped by the sleep timer or manually. Wakes automatically on a request to the HTTPS subdomain or a /deploy//start//wake call
error The server is not in a working state: the virtual machine was deleted at the provider, the agent hasn't connected for a long time, the external externalId is missing
deleted The server is deleted (soft-delete). Cannot be restored

The blackholeStatus field describes the agent tunnel state independently of status:

Value Description
NONE Right after server creation, before the agent's first connection attempt
WAITING The agent is preparing to connect
CONNECTED The tunnel is active, the Deploy API is available
DISCONNECTED The agent was connected, now there is no link — try `/repair`

The runtimeStatus field is deprecated, kept for compatibility. For servers created after 2026-04-25 (when the runtime parameter was removed from `POST /v1/infra/servers`) it always returns null. The runtime is now installed at the `POST /:id/deploy` stage, and the readiness signal is the success of the runtime step itself in the deploy response.

#Plan and access

VibeCode infrastructure has two levels of access conditions.

Level 1 — Bitrix24 REST API. Bitrix24 itself opens the REST API only on commercial portal plans. This is not about VibeCode: on free Bitrix24 plans it simply does not return REST responses. So without a commercial Bitrix24 plan the following do not work:

  • Creating and publishing applications (POST /api/apps) — registered on the portal via REST.
  • REST proxy: /v1/deals, /v1/contacts, /v1/batch, /v1/bots, /v1/tasks and all other entities.
  • Bots, chats, tasks — everything proxied into Bitrix24.

Level 2 — VibeCode infrastructure. On top of the first condition, creating servers, deploying, and waking require an active BitrixGPT + Marketplace subscription on the portal:

  • POST /v1/infra/servers — creating a server.
  • POST /v1/infra/servers/:id/deploy — deploying the application.
  • POST /v1/infra/servers/:id/wake and automatic waking when preventWake=true.
  • Creating agents and managed bots (they provision servers under the hood).

What works on any Bitrix24 plan, including free:

  • AI Router — POST /v1/chat/completions, POST /v1/audio/transcriptions, GET /v1/models. Does not proxy into Bitrix24, goes directly to LLM providers. With BYOK keys — free; with platform models — billed against the VibeCode balance.
  • Basic platform endpoints: GET /v1/me, GET /v1/feedback, GET /v1/guide — for AI-agent self-orientation.

Check before calling: GET /v1/me → the capabilities.servers.create.available field. If false — the capabilities.servers.create.userMessage field contains a translated explanation for the user.

Force refresh after an upgrade: GET /v1/me?refresh=tariff — skips the cache (1 hour by default) and makes a fresh app.info request.

Access to servers: the single signal is capabilities.servers.create in the GET /v1/me response (see above). If access is closed, POST /v1/infra/servers returns 402 (or 403 for REGION_NOT_SUPPORTED) with the access-gate code (see "Error codes" below). Access is governed by the BitrixGPT + Marketplace subscription on the portal.

Response headers of the infra endpoints:

Header Value
X-Tariff-Checked-At ISO timestamp of the last reconciliation via app.info (max 1 hour of cache)
X-Tariff-Is-Commercial "true" or "false"

The access-gate error codes are listed in the "Error codes" section below.

#Error codes

#Infrastructure errors

Code HTTP Description
NOT_FOUND 404 Server not found or belongs to a different API key
INVALID_REQUEST 400 Validation error (invalid name, plan, region, image)
INFRA_NOT_PERMITTED 403 Infrastructure disabled on the platform or on the portal
SERVER_CREATION_DISABLED 403 Server creation forbidden by portal policy
MAX_SERVERS_REACHED 403 The limit of 3 servers per API key is exceeded
NO_CREDENTIALS 404 The provider is not configured on the platform
SERVER_NOT_READY 409 The server is still being created, the operation is not available yet
CONFLICT 409 The server is in a status from which the action cannot be performed (e.g. start on a running one)
PROVIDER_ERROR 502 The cloud provider returned an error
VM_MISSING 422 The record has no externalId — the virtual machine was not created at the provider or was deleted externally. Delete the server via DELETE and create a new one
PORT_RESTRICTED 400 Port 1–1023 (system ports forbidden). Allowed: 0 (auto-detect) and 1024–65535
BLACKHOLE_ONLY 400 The endpoint works only for BLACKHOLE servers (applies to /sleep-now, /sleep, /metrics)
OPEN_MODE_NOT_ALLOWED 403 Switching to OPEN is forbidden by the portal policy allowOpenMode
SAME_MODE 400 The server is already in the requested mode
NOT_IMPLEMENTED 501 The action is not supported by the provider (e.g. /reboot on some plugins)
REPAIR_BLOCKED 409 Repair is blocked (preventWake=true or the server is deleted)

#Deploy API errors

Code HTTP Description
AGENT_NOT_CONNECTED 409 The tunnel agent is not in status CONNECTED
EXEC_BUSY 409 Another operation is already running on the server. Use `/lock` to release a stuck lock
EXEC_TIMEOUT 504 Execution timeout exceeded
EXEC_FAILED 500 Command execution error on the agent
UPLOAD_PATH_DENIED 403 Forbidden upload path
DEPLOY_FAILED 500 Error during the deploy process (see the step field in the response)
VALIDATION_ERROR 400 Malformed Deploy API request body

#Access-gate and billing errors

Code HTTP Description
MARKETPLACE_REQUIRED 402 The portal has no active BitrixGPT + Marketplace subscription — subscribe to unlock server creation, deployment, and waking
KZ_PAID_ONLY 402 In Kazakhstan the BitrixGPT + Marketplace subscription is available only on a paid plan (no demo access)
REGION_NOT_SUPPORTED 403 The BitrixGPT + Marketplace subscription is not yet available in the portal's region
COMMERCIAL_PLAN_REQUIRED 402 Free Bitrix24 plan without an active BitrixGPT + Marketplace subscription
TRIAL_PORTAL_LIMIT 402 The per-portal server limit for RU/BY demo access is exceeded (1 server per portal)
PLAN_NOT_ALLOWED_ON_TRIAL 402 The requested plan is not available on RU/BY demo access (only bc-micro is allowed)
ACCOUNT_FROZEN 402 The VibeCode balance is frozen. A top-up is required
BILLING_EXHAUSTED 402 The VibeCode balance is exhausted. Waking and deployment are blocked
SERVER_WAKE_BLOCKED 403 Waking is blocked (not due to billing: administrative block, security)

#System errors

Code HTTP Description
MISSING_API_KEY 401 The X-Api-Key header was not provided
INVALID_API_KEY 401 Invalid or expired API key
SCOPE_DENIED 403 The key does not have the vibe:infra scope
RATE_LIMIT_EXCEEDED 429 Rate limit exceeded
INTERNAL_ERROR 500 Internal server error

The full reference of common errors — Errors.

#See also