Для AI-агентов: markdown этой страницы — /docs-content/infra/servers/create.md индекс документации — /llms.txt
Создать сервер
POST /v1/infra/servers
Создаёт приложение у облачного провайдера. Всегда в режиме Black Hole — iptables блокирует все входящие порты, приложение невидимо из интернета.
На портале есть две модели размещения, и от модели зависит, чего ждать после создания:
- Отдельная виртуальная машина (модель по умолчанию). Ответ возвращается сразу со статусом
provisioning, провижининг занимает 1–3 минуты, после чего нужно опрашиватьGET /v1/infra/servers/:idдоstatus: "running"иblackholeStatus: "CONNECTED". Ответ единственный раз содержит SSH-данныеssh.passwordиssh.privateKey— они будут нужны при переключении в режим OPEN, сохраните их сразу. Эта страница описывает данную модель в полях запроса, полях ответа и таблице ошибок ниже. - Galaxy-приложение — контейнер на общем хосте. Если портал размещает приложения в галактиках, тот же
POST /v1/infra/serversсоздаёт galaxy-приложение, а не виртуальную машину. Признак модели в ответе — полеcreatedViaравноgalaxy. Раздел «Galaxy-приложение» ниже описывает два сценария запуска, полная модель — на странице Galaxy-приложение.
Galaxy-приложение
Если портал размещает приложения в галактиках, POST /v1/infra/servers создаёт galaxy-приложение — контейнер на общем хосте, а не отдельную виртуальную машину. Запрос и порядок вызовов те же, отличается жизненный цикл. Признак модели в ответе — поле createdVia равно galaxy. Полная модель, стоимость и отличия деплоя — на странице Galaxy-приложение.
Не ждите CONNECTED перед загрузкой кода. Galaxy-приложение никогда само не доходит до blackholeStatus: "CONNECTED" — его контейнер собирается при загрузке кода. Если просто опрашивать статус, приложение останется в provisioning, а примерно через 20 минут платформа пометит его как error и запишет в поле provisionError, что код так и не был загружен. Поэтому код загружают сразу — одним из двух сценариев ниже.
Сценарий 1 — прозрачный, рекомендуется
Один запрос. Передайте в POST /v1/infra/servers код приложения в поле source вместе с runtime и start (и при необходимости install, env, port). Сборка пойдёт в фоновом режиме. После ответа опрашивайте GET /v1/infra/servers/:id до status: "running". Отдельный вызов загрузки кода не нужен.
curl -X POST https://vibecode.bitrix24.tech/v1/infra/servers \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "my-crm-app",
"displayName": "Мой CRM-бот",
"source": { "content": "<base64-архив>" },
"runtime": "node20",
"start": "node index.js",
"install": "npm ci",
"port": 3000
}'
Поля source, runtime, start, install, env, port, healthPath совпадают по смыслу с телом POST /:id/deploy:
| Поле | Тип | Обяз. | Описание |
|---|---|---|---|
source |
object | да (для этого сценария) | Источник кода. source.content — архив приложения в base64, до 500 МБ на тело запроса |
runtime |
string | да (если передан source) |
ID рантайма: node20, python311, php83, static и другие. Список — GET /v1/infra/runtimes |
start |
string | да (если передан source) |
Команда запуска приложения, одной строкой. Перенос строки вернёт 400 |
install |
string | нет | Команда установки зависимостей, одной строкой |
env |
object | нет | Переменные окружения { "KEY": "value" }. Подставляются в контейнер при запуске, см. ниже |
port |
number | нет | Порт, на котором приложение слушает |
healthPath |
string | нет | Путь, по которому платформа проверяет готовность приложения внутри контейнера. До 500 символов, начинается со /. По умолчанию /. На создании отдельной виртуальной машины игнорируется |
Без полей runtime и start поле source вернёт 400 — оба поля обязательны. На портале без режима галактик source запрещён и вернётся 400 SOURCE_AT_CREATE_GALAXY_ONLY. Тот же ответ придёт на бесплатном тарифе Битрикс24, пока у аккаунта нет галактики: новая на бесплатном тарифе не создаётся, поэтому разворачивайте в два шага — создание без source, затем POST /v1/infra/servers/:id/deploy.
Сценарий 2 — в два шага
Создайте приложение без source — ответ придёт со статусом provisioning и подсказкой next: "deploy". Сразу вызовите POST /v1/infra/servers/:id/deploy с кодом в source, рантаймом и командой запуска. Загружайте код сразу, не дожидаясь CONNECTED.
# Шаг 1 — создать приложение без кода
curl -X POST https://vibecode.bitrix24.tech/v1/infra/servers \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "provider": "bitrix-cloud", "name": "my-crm-app", "plan": "bc-medium", "region": "ru-central1-a" }'
# Ответ содержит data.id, data.next = "deploy" и data.hint.
# Шаг 2 — сразу загрузить код, не дожидаясь CONNECTED
curl -X POST https://vibecode.bitrix24.tech/v1/infra/servers/SERVER_ID/deploy \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"source": { "content": "<base64-архив>" },
"runtime": "node20",
"start": "node index.js",
"port": 3000
}'
provider и plan обязательны по схеме для создания без source. region необязателен: без него платформа сама подставит регион по умолчанию для выбранного провайдера. Для galaxy-приложения значения информационны — приложение наследует провайдера, план и регион своего хоста.
Если присланное значение расходится с тем, что приложение реально получило, ответ несёт запись в warnings[] рядом с data: она называет разошедшиеся поля, показывает и присланное, и действующее значение и предупреждает, что повторная отправка ничего не изменит. Совпавшие поля не упоминаются, так что корректный вызов остаётся без предупреждения. Нужна машина, у которой провайдера, план и регион выбираете вы, — создавайте её с placement равным dedicated.
Отдельная виртуальная машина вместо galaxy-приложения
Если портал размещает приложения в галактиках, а конкретному приложению нужен свой сервер — передайте поле placement равным dedicated. Пара provider, plan при этом обязательна, region по-прежнему необязателен. Поле source в таком запросе вернёт 400 SOURCE_AT_CREATE_GALAXY_ONLY: отдельная виртуальная машина разворачивается в два шага, код загружают через POST /:id/deploy.
curl -X POST https://vibecode.bitrix24.tech/v1/infra/servers \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"provider": "bitrix-cloud",
"name": "my-crm-app",
"plan": "bc-small",
"region": "ru-central1-b",
"placement": "dedicated"
}'
В ответе kind равен STANDALONE. Дальше действует порядок для отдельной виртуальной машины: дождаться status: "running" и blackholeStatus: "CONNECTED", затем деплой.
Диагностика и переменные окружения
- Поле
provisionError. Если сборка или запуск упали,GET /v1/infra/servers/:idвернёт вdata.provisionErrorпричину сбоя, а при ошибке сборки образа — ещё и хвост лога сборки Docker. Читайте это поле, чтобы понять причину. - Переменные
envподставляются при запуске. Значения изenvпередаются в контейнер во время запуска черезdocker run --env, а не вшиваются в образ. Вместе с ними платформа передаётPORT(равен полюport, по умолчанию3000): ключPORTзарезервирован, присланный свой перекрывается, и ответ несёт строку вwarnings[]— см. POST /v1/infra/servers/:id/deploy. Поэтому ключи API и секреты изenvне попадают в слои образа.
Поля запроса (body)
| Поле | Тип | Обяз. | Описание |
|---|---|---|---|
provider |
string | да | ID провайдера из GET /v1/infra/providers, например bitrix-cloud. 1–50 символов |
name |
string | да | Системное имя сервера — технический идентификатор. 2–63 символа, только строчные латинские буквы, цифры и -, первым символом — буква. Паттерн: ^[a-z][a-z0-9-]*$. Используется в URL поддомена (app-<hex> генерируется отдельно), логах, audit-журнале. Неизменяемый после создания. Для отображаемого имени используйте displayName |
displayName |
string | нет | Отображаемое имя на любом языке (русский, китайский, эмодзи — что угодно). 2–100 символов, без управляющих байтов. Отображается в UI, уведомлениях о падении сервера, security-алертах, биллинг-строках, B24-каталоге. Если не передан — подставится name. Само name остаётся техническим идентификатором, неизменяемым, оно используется в URL поддомена и логах |
description |
string | нет | Описание приложения для карточки каталога Битрикс24, до 500 символов. Переносы строк и табуляции разрешены, прочие управляющие байты запрещены. Значение обрезается по краям. Если не передать — описание останется пустым, задать его позже можно через PATCH /v1/infra/servers/:id |
plan |
string | да | ID тарифа из GET /v1/infra/providers/:providerId/plans, например bc-small |
region |
string | нет | ID региона из GET /v1/infra/providers/:providerId/regions, например ru-central1-b. Без него платформа подставит регион по умолчанию для провайдера |
image |
string | нет | ID образа ОС из GET /v1/infra/providers/:providerId/images. Если не передан — платформа сама подставит актуальный образ провайдера. Если передаёте — берите актуальный из ответа: ID меняется при обновлении сборки |
sshPublicKey |
string | нет | Ваш SSH-публичный ключ (ssh-rsa …, ssh-ed25519 …, ecdsa-sha2-nistp256/384/521 …, security-keys). До 8192 символов. Если не передан — платформа сгенерирует приватный ключ и вернёт его один раз в ssh.privateKey |
placement |
string | нет | Модель размещения: auto (по умолчанию) или dedicated. На портале с режимом «Сначала галактика» (galaxies-only) значение dedicated создаёт отдельную виртуальную машину, а не galaxy-приложение — перенос приложения на собственный сервер. Проходит те же проверки, что и обычное создание сервера: политику serverCreation и квоту серверов на пользователя. При auto поведение прежнее (в режиме «Сначала галактика» создаётся galaxy-приложение) |
graduateFrom |
string | нет | ID вашего galaxy-приложения (kind=GALAXY_APP), которое платформа удалит сразу после того, как создаст для него выделенный сервер — чтобы старое приложение не осталось висеть в галактике. Ограничен владельцем: тот же ключ, тот же портал, kind=GALAXY_APP. Чужой идентификатор или идентификатор не galaxy-приложения вернёт 404, ничего не удаляя. Имеет смысл только вместе с placement: dedicated. Заголовок Idempotency-Key с graduateFrom для выделенного сервера несовместим — см. Идемпотентность |
Примечание: для модели отдельной виртуальной машины параметр
runtimeвPOST /v1/infra/serversне принимается — передача вернёт400 RUNTIME_PARAM_REMOVED. Рантайм устанавливается на этапе деплоя. См. POST /:id/deploy. Исключение — режим галактик: при передаче поляsourceпараметрruntimeобязателен (см. раздел «Galaxy-приложение»), и400 RUNTIME_PARAM_REMOVEDв этом случае не возвращается.
Примеры
curl — личный ключ
# name — только строчные латинские буквы, цифры и дефис, первый символ буква (^[a-z][a-z0-9-]*$)
curl -X POST https://vibecode.bitrix24.tech/v1/infra/servers \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"provider": "bitrix-cloud",
"name": "my-crm-app",
"displayName": "Мой CRM-бот",
"plan": "bc-small",
"region": "ru-central1-b",
"image": "fd83esfomhq25p2ono90"
}'
curl — OAuth-приложение
# name — только строчные латинские буквы, цифры и дефис, первый символ буква (^[a-z][a-z0-9-]*$)
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-crm-app",
"displayName": "Мой CRM-бот",
"plan": "bc-small",
"region": "ru-central1-b",
"image": "fd83esfomhq25p2ono90"
}'
JavaScript — личный ключ
// name — только строчные латинские буквы, цифры и дефис, первый символ буква (^[a-z][a-z0-9-]*$)
const res = await fetch('https://vibecode.bitrix24.tech/v1/infra/servers', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
provider: 'bitrix-cloud',
name: 'my-crm-app',
displayName: 'Мой CRM-бот',
plan: 'bc-small',
region: 'ru-central1-b',
image: 'fd83esfomhq25p2ono90',
}),
})
const { data } = await res.json()
console.log('Server ID:', data.id, 'Subdomain:', data.subdomain)
// Сохраняем SSH-креды на всякий случай — они возвращаются только один раз
if (data.ssh.privateKey) {
await saveLocally(`${data.id}.key`, data.ssh.privateKey)
}
JavaScript — OAuth-приложение
// name — только строчные латинские буквы, цифры и дефис, первый символ буква (^[a-z][a-z0-9-]*$)
const res = await fetch('https://vibecode.bitrix24.tech/v1/infra/servers', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
provider: 'bitrix-cloud',
name: 'my-crm-app',
displayName: 'Мой CRM-бот',
plan: 'bc-small',
region: 'ru-central1-b',
image: 'fd83esfomhq25p2ono90',
}),
})
Поля ответа
| Поле | Тип | Описание |
|---|---|---|
success |
boolean | Всегда true при успехе |
data.id |
string (UUID) | Уникальный идентификатор сервера |
data.status |
string | "provisioning" сразу после создания нового сервера — ждите "running" через 1–3 минуты. В reuse-ответе (reused: true) это статус существующего сервера и он может быть любым, в том числе сразу "running" — тогда ожидание "running" ничего не проверяет |
data.provider |
string | Эхо переданного provider. Исключение — galaxy-приложение (createdVia: "galaxy"): возвращается провайдер хоста-носителя, а не запрошенный |
data.name |
string | Системное имя сервера. Эхо переданного name при создании нового. В reuse-ответе — имя существующего сервера, а запрошенное вами лежит в data.requestedName |
data.kind |
string | Тип сервера, всегда: STANDALONE или GALAXY_APP |
data.galaxyId |
string | Только для galaxy-ветки — ID хоста-галактики. В standalone-ответе ключ отсутствует |
data.displayName |
string | null | Отображаемое имя. Если при создании не передавали displayName — будет равно name |
data.description |
string | null | Эхо переданного description. Ключ есть только в ответе для отдельной виртуальной машины. Для galaxy-приложения, где createdVia равно galaxy, ключа в ответе нет, хотя описание сохраняется — прочитайте его через GET /v1/infra/servers/:id |
data.ip |
string | null | Публичный IP. null сразу после создания, заполнится когда виртуальная машина запустится |
data.ssh.user |
string | Пользователь для SSH: root для новых серверов |
data.ssh.port |
number | Порт SSH: 22 |
data.ssh.password |
string | null | Одноразово! Пароль root. Сохраняйте сразу — позже не вернётся. Нужен при переключении в OPEN-режим |
data.ssh.privateKey |
string | null | Одноразово! Приватный ключ в формате OpenSSH (если sshPublicKey не передавали при создании). Сохраняйте сразу |
data.plan |
string | Эхо переданного plan. Исключение — galaxy-приложение (createdVia: "galaxy"): возвращается тариф хоста-носителя, а не запрошенный |
data.region |
string | Регион, в который сервер реально попал. Может отличаться от запрошенного при переключении на запасную зону (см. «Известные особенности»). Для galaxy-приложения — регион хоста-носителя |
data.image |
string | Эхо переданного image |
data.mode |
string | Всегда "BLACKHOLE" сразу после создания |
data.createdVia |
string | "api" для вызовов через v1 API, "ui" для вызовов из личного кабинета. В reuse-ответе — значение существующего сервера, поэтому на ответ v1-создания может прийти "ui" |
data.subdomain |
string | Субдомен для приложения, например app-92fb1c34. Используется в appUrl |
data.blackholeStatus |
string | Состояние туннеля агента. Сразу после создания — "NONE", затем проходит через WAITING и завершается CONNECTED |
data.accessPolicy |
string | Политика доступа к приложению. По умолчанию "OWNER_ONLY" — только владелец ключа |
data.runtimeId |
string | null | Всегда null при создании. Заполняется при деплое с runtime |
data.runtimeStatus |
string | null | Устаревшее поле, оставлено для совместимости. Для серверов, созданных после 2026-04-25, всегда null. Готовность рантайма после деплоя определяет успех шага runtime в ответе POST /:id/deploy, а не это поле |
data.appUrl |
string | null | HTTPS-адрес приложения: https://{subdomain}.vibecode.bitrix24.tech |
data.createdAt |
string (ISO 8601) | Момент создания |
Пример ответа
Отдельная виртуальная машина:
{
"success": true,
"data": {
"id": "db008c84-91a5-4e15-b9d5-6c6aa2838448",
"status": "provisioning",
"provider": "bitrix-cloud",
"name": "docs-test-temp",
"kind": "STANDALONE",
"ip": null,
"ssh": {
"user": "root",
"port": 22,
"password": "0FPIIR9EfO2OAeSSMK6bKA",
"privateKey": "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmU…\n-----END OPENSSH PRIVATE KEY-----\n"
},
"plan": "bc-agent",
"region": "ru-central1-b",
"image": "fd83esfomhq25p2ono90",
"mode": "BLACKHOLE",
"createdVia": "api",
"subdomain": "app-92fb1c34",
"blackholeStatus": "NONE",
"accessPolicy": "OWNER_ONLY",
"runtimeId": null,
"runtimeStatus": null,
"appUrl": "https://app-92fb1c34.vibecode.bitrix24.tech",
"createdAt": "2026-04-22T10:50:11.477Z"
}
}
Galaxy-приложение по сценарию 1 — source передан, сборка идёт в фоне. Полей ssh и next нет:
{
"success": true,
"data": {
"id": "7c2b1f08-3a4d-4e91-9b6c-2f5e8a1d0c33",
"status": "provisioning",
"provider": "bitrix-cloud",
"name": "my-crm-app",
"kind": "GALAXY_APP",
"galaxyId": "<galaxy-host-id>",
"displayName": "Мой CRM-бот",
"ip": null,
"ssh": null,
"plan": "bc-medium",
"region": "ru-central1-a",
"image": "ubuntu-2404-lts",
"mode": "BLACKHOLE",
"createdVia": "galaxy",
"subdomain": "app-7c2b1f08",
"blackholeStatus": "NONE",
"accessPolicy": "OWNER_ONLY",
"runtimeId": null,
"runtimeStatus": null,
"appUrl": "https://app-7c2b1f08.vibecode.bitrix24.tech",
"createdAt": "2026-04-22T10:50:11.477Z"
}
}
Galaxy-приложение по сценарию 2 — source не передан, появляются next и hint:
{
"success": true,
"data": {
"id": "7c2b1f08-3a4d-4e91-9b6c-2f5e8a1d0c33",
"status": "provisioning",
"provider": "bitrix-cloud",
"name": "my-crm-app",
"kind": "GALAXY_APP",
"galaxyId": "<galaxy-host-id>",
"displayName": "Мой CRM-бот",
"ip": null,
"ssh": null,
"plan": "bc-medium",
"region": "ru-central1-a",
"image": "ubuntu-2404-lts",
"mode": "BLACKHOLE",
"createdVia": "galaxy",
"subdomain": "app-7c2b1f08",
"blackholeStatus": "NONE",
"accessPolicy": "OWNER_ONLY",
"runtimeId": null,
"runtimeStatus": null,
"appUrl": "https://app-7c2b1f08.vibecode.bitrix24.tech",
"createdAt": "2026-04-22T10:50:11.477Z",
"next": "deploy",
"hint": "This is a galaxy app — POST /v1/infra/servers/:id/deploy with source.content now; it will not reach \"running\" on its own."
}
}
Если сборка galaxy-приложения упала, GET /v1/infra/servers/:id вернёт причину в data.provisionError:
{
"success": true,
"data": {
"id": "7c2b1f08-3a4d-4e91-9b6c-2f5e8a1d0c33",
"status": "error",
"createdVia": "galaxy",
"provisionError": "Docker build failed: npm ci exited with code 1"
}
}
Пример ответа при ошибке
400 — нарушена валидация (имя начинается с заглавной):
{
"success": false,
"error": {
"code": "INVALID_REQUEST",
"message": "name: Name must start with a letter and contain only lowercase letters, digits, and hyphens"
}
}
Ошибки
| HTTP | Код | Описание |
|---|---|---|
| 400 | INVALID_REQUEST |
Нарушена валидация полей (неверный формат имени, отсутствует обязательное поле, неверный SSH-ключ и т. д.). Поле message содержит конкретную причину. Если на портале с размещением в галактике не передано ни source, ни тройка provider + plan + region — добавляется объект error.hint (см. ниже) |
| 400 | SOURCE_AT_CREATE_GALAXY_ONLY |
Поле source передано на портале без режима галактик либо вместе с placement: "dedicated". Загружайте код через POST /:id/deploy после создания |
| 400 | GALAXY_SOURCE_URL_NOT_ALLOWED |
Ссылка в source.url не прошла проверку до отправки на хост галактики. Три причины: значение не является абсолютным URL, схема не http и не https, адрес ведёт не в публичную сеть — на локальный, внутренний или служебный узел. Текст ответа называет сработавшее правило. Та же проверка стоит на выкладке кода |
| 400 | RUNTIME_PARAM_REMOVED |
Параметр runtime передан без source. Указывайте рантайм в POST /:id/deploy либо передайте runtime, start и source вместе в этом же запросе. На портале с размещением в галактике добавляется объект error.hint (см. ниже) |
| 400 | UNKNOWN_PARAM |
В теле есть неизвестное поле (например deployMode вместо placement). details.unknownFields перечисляет лишние поля, details.suggestions подсказывает правильное имя, details.validParams — полный список допустимых полей |
| 400 | INVALID_PLAN |
Тариф из поля plan отсутствует в каталоге провайдера. Список — GET /v1/infra/providers/:providerId/plans |
| 400 | INVALID_REGION |
Присланный region отсутствует в каталоге провайдера. Список — GET /v1/infra/providers/:providerId/regions. Второй случай: region не передан, а у провайдера нет ни одного региона — тогда message называет провайдера, и подставлять значение по умолчанию платформе не из чего |
| 401 | MISSING_API_KEY |
Не передан заголовок X-Api-Key |
| 401 | INVALID_API_KEY |
Неверный или просроченный API-ключ |
| 402 | COMMERCIAL_PLAN_REQUIRED |
Бесплатный тариф Битрикс24 и пробный период недоступны (пробный уже использован). См. раздел «Тариф и доступ» |
| 402 | TRIAL_EXPIRED |
Trial использован и завершился |
| 402 | TRIAL_PORTAL_LIMIT |
Превышена квота серверов портала на trial |
| 402 | TRIAL_USER_LIMIT |
Превышена квота серверов на пользователя на trial |
| 402 | PLAN_NOT_ALLOWED_ON_TRIAL |
На trial разрешён только тариф bc-micro |
| 402 | ACCOUNT_FROZEN |
Баланс Вайбкод заморожен, нужно пополнить |
| 403 | INFRA_NOT_PERMITTED |
Инфраструктура отключена на платформе или на портале |
| 403 | SERVER_CREATION_DISABLED |
Создание серверов запрещено политикой портала |
| 403 | MAX_SERVERS_REACHED |
Превышен лимит серверов на API-ключ. Удалите ненужные через DELETE или создавайте новый API-ключ |
| 403 | WRITE_BLOCKED_READONLY_KEY |
У ключа режим «только чтение», а создание сервера — операция записи. Переключите ключ на чтение и запись, порядок — Режим доступа |
| 403 | INFRA_SCOPE_REQUIRED |
У ключа нет скоупа vibe:infra — управление инфраструктурой недоступно. Добавьте скоуп или используйте ключ с правами на инфраструктуру |
| 403 | INFRA_FORBIDDEN_FOR_COWORK_KEY |
Вызов сделан ключом Cowork. Такой ключ работает только с данными и не управляет серверами. В error.details.requiredAction приходит порядок получения ключа с правами на деплой |
| 404 | NO_CREDENTIALS |
Провайдер provider не сконфигурирован на платформе |
| 502 | PROVIDER_ERROR |
Облачный провайдер вернул ошибку при создании виртуальной машины. Запись сервера помечается как удалённая, квота не расходуется — можно сразу повторить попытку. Поле message содержит локализованное описание сбоя и код инцидента — сырой ответ провайдера в тело не попадает, он остаётся в логах платформы. Назовите код инцидента поддержке |
| 429 | RATE_LIMITED |
Превышен общий лимит запросов платформы |
| 429 | DEPLOY_BACKEND_BUSY |
Запрос нёс архив в source.content, а на бэкенде уже идёт предельное число таких же тяжёлых запросов (общий счётчик с POST /:id/deploy и POST /:id/upload). В ответе заголовок Retry-After: 30 — повторите через полминуты. Чтобы не зависеть от очереди, создайте сервер без source, а код загрузите отдельным запросом со ссылкой {source: {url: ...}} — у этого пути ограничения на одновременность нет |
| 503 | POOL_EXHAUSTED |
Сервис временно перегружен — исчерпан пул соединений с базой данных. В ответе retryAfter и заголовок Retry-After, повторите через несколько секунд |
Полный список общих ошибок API — Ошибки.
Подсказка `error.hint`
На портале с размещением в галактике ошибки INVALID_REQUEST и RUNTIME_PARAM_REMOVED дополняются объектом error.hint. Он называет причину отказа и даёт готовое тело запроса. Условие у двух кодов разное. У INVALID_REQUEST подсказка приходит, когда в теле нет ни source, ни полной тройки provider + plan + region. У RUNTIME_PARAM_REMOVED — когда передан runtime без source, причём тройка при этом может быть заполнена полностью. На портале с отдельными виртуальными машинами подсказки нет ни в одном из случаев.
Не путайте с data.hint из успешного ответа: там строка про следующий шаг после создания приложения по сценарию 2, здесь — объект внутри error.
| Поле | Тип | Описание |
|---|---|---|
error.hint.reason |
string | Почему запрос отклонён |
error.hint.recovery |
string | Что изменить в запросе, чтобы он прошёл |
error.hint.example |
object | Готовое тело запроса, которое можно взять за основу |
{
"success": false,
"error": {
"code": "INVALID_REQUEST",
"message": "provider: Required; plan: Required",
"hint": {
"reason": "This portal places new apps on shared galaxy hosts, and the request lacked `source` and the full provider/plan/region tuple.",
"recovery": "RECOMMENDED: create-and-deploy in ONE call — POST /v1/infra/servers { name, source: { content }, runtime, start }; OMIT provider/plan/region. Two-step also works: pass provider/plan/region (informational for a galaxy — values from GET /v1/infra/providers catalogs) to create an empty slot, then POST /v1/infra/servers/:id/deploy with the source. See GET /v1/me -> deployment.galaxyApp.checklist. For a deliberate dedicated standalone VM pass placement: \"dedicated\" together with provider/plan/region.",
"example": {
"name": "<slug>",
"source": { "content": "<base64 gzip-tar of the app>" },
"runtime": "node20",
"start": "node server.js",
"port": 3000
}
}
}
}
Если в теле передан placement: "dedicated", подсказка другая: она предлагает добавить provider, plan и region, сохранив выделенный сервер, а не переводить приложение в контейнер галактики.
Переиспользование сервера приложения
Ключ вызова принадлежит приложению из раздела «Приложения», и приложению можно привязать ровно один сервер. Если сервер уже привязан и работает, POST /v1/infra/servers не создаёт второй, а возвращает 201 с уже существующим сервером. Имя, которое вы передали в name, в этом решении не участвует — повтор платформа определяет по вызывающему ключу, а не по имени.
В reuse-ответе (reused: true) все поля data описывают существующий привязанный сервер, а не ваш запрос — status, provider, plan, region, image, createdVia, createdAt относятся к нему. Статус может быть любым, поэтому «дождаться running» не является проверкой того, что сервер ваш. Проверка — это reused и пара name ⊕ requestedName.
Ответ на такой запрос всегда несёт data.reused: true и рядом с data — массив warnings минимум с одной записью. Сравните data.name с data.requestedName: они различаются, если сервер приложения был создан раньше и под другим именем.
| Поле | Тип | Когда |
|---|---|---|
data.reused |
boolean | Всегда на таком ответе. Новый сервер не создан |
data.reusedReason |
string | APPLICATION_ALREADY_HAS_SERVER |
data.requestedName |
string | Эхо вашего name — всегда, даже если совпадает с именем существующего сервера |
data.sourceIgnored |
boolean | Переданный source не развёрнут и отброшен |
data.deploying |
boolean | Переданный source собирается на контейнер приложения прямо сейчас |
data.metaIgnored |
boolean | Переданные displayName/description не применены |
warnings |
array | Рядом с data, не внутри. Минимум одна запись |
Что делать перед деплоем. Запросите GET /v1/infra/servers/:id и посмотрите, что на сервере уже развёрнуто. Деплой заменяет работающий код, он не добавляет к нему. Если это не тот сервер, который вы имели в виду, остановитесь и спросите пользователя, с каким приложением должен работать этот ключ.
Про переданный source. Одношаговое создание разворачивает исходники в переиспользуемое galaxy-приложение только тогда, когда контейнера ещё нет (ни разу не деплоилось, либо прошлая сборка упала) — в ответе будет deploying: true, опрашивайте GET /v1/infra/servers/:id до running. Во всех остальных случаях, включая переиспользованную отдельную виртуальную машину, архив отбрасывается и в ответе появляется sourceIgnored: true — разверните его явно через POST /v1/infra/servers/:id/deploy, когда убедитесь, что сервер тот.
Про переданные displayName и description. Переиспользование никогда не переименовывает сервер, который отдаёт: у него остаются собственные имя и описание, а переданные вами значения отбрасываются — в ответе это видно по data.metaIgnored: true и отдельному предупреждению. Переименуйте осознанно через PATCH /v1/infra/servers/:id, убедившись, что сервер тот.
Про data.next. В reuse-ответе поле приходит только тогда, когда на возвращённом сервере нечего перезаписывать — это galaxy-приложение без контейнера, прикреплённое к своему galaxy-хосту. Если контейнера нет, но приложение откреплено от хоста, деплоить некуда — next тоже не придёт. Если сервер может выполнять код, next в ответе отсутствует намеренно — отсутствие рекомендации и есть сигнал: сначала разберитесь, тот ли это сервер. Не трактуйте отсутствие next как ошибку.
Как получить для приложения другой сервер. Отдельного вызова, меняющего привязку, нет. Если нужна отдельная виртуальная машина и привязку трогать не надо — создайте её с placement: "dedicated": переиспользование не сработает, но и к приложению новый сервер привязан не будет. Если нужно именно сменить привязанный сервер — удалите текущий через DELETE /v1/infra/servers/:id, и следующий POST /v1/infra/servers тем же ключом снимет устаревшую привязку и привяжет вновь созданный сервер. Удаление необратимо и уничтожает всё, что развёрнуто на сервере, — сначала убедитесь по GET /v1/infra/servers/:id, что это не чужая работа.
Создание с placement: "dedicated" переиспользование не затрагивает.
Идемпотентность
Передайте необязательный заголовок Idempotency-Key, чтобы безопасно повторять создание отдельного сервера (standalone). Если ответ на первый запрос потерялся (обрыв сети, таймаут балансировщика), повтор с тем же ключом не создаст второй сервер — вернётся тот же самый сервер, что и в первый раз, со статусом 201 и заголовком ответа Idempotent-Replayed: true.
- Ключ — строка 1–255 символов из набора
[A-Za-z0-9_.:-]. Область действия — ваш API-ключ. - При повторе одноразовые SSH-данные не выдаются повторно. В теле ответа
ssh.privateKeyиssh.passwordбудутnull, а полеnoteпояснит это. Сохраняйте данные из ответа первого создания. - Заголовок работает только для standalone-серверов. На порталах с размещением в галактике корректный ключ игнорируется без ошибки, и защита от повторного создания на этот путь не распространяется.
- Заголовок несовместим с
graduateFromдля выделенного сервера — вернётся400 IDEMPOTENCY_UNSUPPORTED_WITH_GRADUATION. - Ключ не защищает от повторной сборки на переиспользованном сервере. Ответ с
reused: trueключом не помечается, поэтому повтор запроса сsourceна переиспользованное galaxy-приложение, у которого ещё нет контейнера, запустит сборку заново. Сначала опроситеGET /v1/infra/servers/:id.
| Код | code |
Когда |
|---|---|---|
| 400 | INVALID_IDEMPOTENCY_KEY |
Ключ не проходит валидацию (длина или недопустимые символы) |
| 400 | IDEMPOTENCY_UNSUPPORTED_WITH_GRADUATION |
Ключ вместе с graduateFrom для выделенного сервера |
| 409 | IDEMPOTENCY_KEY_ALREADY_USED |
Ключ уже использован для сервера, который затем был удалён — возьмите новый ключ |
| 409 | IDEMPOTENCY_CONCURRENT_RETRY |
Параллельный запрос с тем же ключом ещё выполняется — повторите чуть позже |
Известные особенности
- Примеры корректных и некорректных имён по паттерну
^[a-z][a-z0-9-]*$:- Правильно:
my-app,bot-1,crm-dashboard. - Неправильно:
My-App(заглавная),bot_1(подчёркивание),my.app(точка),кириллица.
- Правильно:
sshPublicKeyvs автогенерация. Если передаёте свой публичный ключ — платформа не генерирует приватный, иssh.privateKeyв ответе будетnull. Пароль вssh.passwordвсё равно возвращается.- Когда
regionв ответе отличается от запрошенного. В запрошенной зоне могли кончиться IP-адреса (Address space exhausted) — тогда платформа автоматически пробует следующие зоны в порядке изGET /v1/infra/providers/:providerId/regions, и фиксирует это в аудит-логе событиемSERVER_ZONE_FALLBACK. - Таймаут провижининга — 15 минут. Если
statusдержится вprovisioningдольше, платформа переводит сервер вerrorи заполняетprovisionErrorиprovisionErrorCode. Дальше остаётся вызватьDELETEи создать новый. - Рантайм устанавливается на этапе деплоя. Параметр
runtimeбыл удалён изPOST /v1/infra/servers(вернёт400 RUNTIME_PARAM_REMOVED). Указывайтеruntimeв телеPOST /:id/deploy— он установится между извлечением архива и запуском приложения. - Кириллица в
displayNameиdescriptionиз Windows PowerShell. Отправленная без явной сериализации в UTF-8, она сохраняется знаками вопроса (?): байты теряются на стороне клиента, до отправки запроса. Готовый вызов сUTF8.GetBytes— Windows / PowerShell и UTF-8.