For AI agents: markdown of this page — /docs-content-en/infra/deploy/operations.md documentation index — /llms.txt
Recent server operations
GET /v1/infra/servers/:id/operations
Returns recent operations on a server started by the current API key, newest first. There are two kinds of operation — deploys POST /deploy and commands POST /exec — and every row names its own kind in the kind field. By default the list returns deploys only: this endpoint predates commands, so without the parameter the same set of rows arrives as before. The rows themselves additionally carry a kind field. kind=exec shows commands and kind=all returns a mixed feed. This is the recovery channel when the response is lost before the client receives an operationId — notably when a connection drops during a Galaxy application build, or when the wait for a long command is interrupted.
The endpoint only reads the shared outcome record: it does not wake the server, repair the tunnel, or release the mutex. Server access matches deploy access, while rows are additionally filtered by the exact API key that started the operation. An application-linked key therefore sees only its own runs, and the shared Galaxy host ID does not expose its applications' runs. An owner can reconcile their operations after the server is soft-deleted.
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
id |
path | string | yes | Server or Galaxy application ID |
limit |
query | integer | no | Number of rows: 5 by default, maximum 20. Zero is clamped to 1 and an integer above 20 to 20; a negative value, a fraction, a non-number, or an empty value returns 400 INVALID_LIMIT |
kind |
query | string | no | Which kind of operation to return: deploy (the default), exec, or all for both. Any other value, an empty one included, returns 400 INVALID_KIND |
Example
curl -H "X-Api-Key: YOUR_API_KEY" \
'https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/operations?limit=5'
{
"success": true,
"data": {
"operations": [
{
"operationId": "clz9k2m4x0001qw8h3f7d2n5p",
"kind": "deploy",
"serverId": "8f14e45f-ceea-467a-9c8d-2f1c5a6b7e30",
"status": "running",
"outcomeAvailable": true,
"step": "build",
"startedAt": "2026-08-26T09:14:22.117Z",
"finishedAt": null,
"error": null
}
]
}
}
An empty parameter value is a value that was sent, not an omitted parameter. ?kind= and ?limit= come from a template with an unfilled variable — the caller meant to narrow the feed and failed. Such a call is rejected instead of silently defaulted: falling back would hand back a feed the caller never asked for. The kind=deploy and limit=5 defaults apply only when the key is absent from the query string altogether.
Operation fields
| Field | Type | Description |
|---|---|---|
operationId |
string | Identifier for GET /v1/infra/operations/:operationId |
kind |
string | Operation kind: deploy or exec |
serverId |
string | Server or Galaxy application ID |
outcomeAvailable |
boolean | Whether the operation outcome is still stored |
status |
string | running, succeeded, failed, or unknown; absent for an expired terminal outcome |
step |
string | null | Last observed step. Always null on kind: "exec" rows — a command has no steps. Absent for an expired terminal outcome |
exitCode |
number | null | kind: "exec" rows only. Exit status of the command when the agent proved one, otherwise null. On a deploy row the field is absent rather than null. Also absent for an expired terminal outcome |
startedAt |
string | Start time, ISO 8601 |
finishedAt |
string | null | Finish time; absent for an expired terminal outcome |
error |
object | null | { code, message } for failed only; absent for an expired terminal outcome |
On kind: "exec" rows, judge by the pair exitCode + status, never by one field alone. A number arrives only with succeeded and means the command ran to completion. null on its own does NOT mean "the outcome is not proven": with succeeded it means the command ran but the agent named no code, so do not re-run it; with failed it means the command never started and a retry is safe; with running it means the run is still in flight; and only with unknown is nothing proven. The statuses are covered in detail in GET /v1/infra/operations/:operationId.
A terminal outcome is retained for 7 days. The row then remains in the list for a while with outcomeAvailable: false, but its status, step, and error are no longer exposed. unknown is a stable terminal answer when the platform cannot prove the remote outcome, for example after GATEWAY_UNREACHABLE; an expired operation still marked running is also shown as unknown.
Safe recovery after a dropped connection
- Do not redeploy or re-run a state-changing command blindly. Find this key's recent operation in the list. Looking for a command — pass
kind=exec: without the parameter the list shows deploys only. - While it is
running, wait and poll the list or the addressable endpoint every few seconds. - Use a confirmed
succeededorfailedoutcome. Forunknownor no matching record, reconcileGET /v1/infra/servers/:idand the logs. - If a later request confirms
EXEC_BUSY, look aterror.hint.holderin that same409response: it names the operation holding the lock regardless of which key started it. A holder means an operation is running: wait, do not force-release. The operation list does not answer this question: it shows only the runs of your own key, so an operation started by another key of the same account is absent from it, and an empty list is no proof that the server is idle. No holder is NOT the mirror proof of an idle server: that read is fail-open, so "no holder" is also what arrives when it could not be read. Absence earns a normal retry afterRetry-Afterand the guardedPOST /v1/infra/servers/:id/unstick, which answers409against a live operation as long as noforceis passed. The independent idleness check — the server state (GET /v1/infra/servers/:id) and the logs — gates BOTH steps:/unstick, whose tunnel bounce kills whatever the agent is running, and all the more the unconditionalDELETE /lockafter it. Then account for the server kind. ForSTANDALONE, you may callPOST /v1/infra/servers/:id/unstickand repeat the read-only checks. AGALAXY_APPuses its shared host's exec channel: tenantunstickis unsupported; wait 30–60 seconds and contact support ifEXEC_BUSYpersists. After either recovery, reconcile the list, state, and logs again before redeploying.
A standalone deploy response with a transport reason of GATEWAY_UNREACHABLE, DEPLOY_CONNECTION_TERMINATED, DEPLOY_TIMEOUT, or DEPLOY_TUNNEL_STALE, and post-drop Galaxy GALAXY_DEPLOY_INTERRUPTED or GALAXY_HOST_UNREACHABLE responses, carry this read-first sequence in error.hint. A Galaxy response in this state carries error.retryable: false: the dropped connection by itself proves neither success nor failure. The slot, container, and /data are preserved while the outcome is unknown — do not delete or recreate the app.
Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | INVALID_LIMIT |
limit is negative, fractional, non-numeric, empty, or exceeds the safe-integer range |
| 400 | INVALID_KIND |
kind was sent but is none of deploy, exec, all. An empty value counts as sent |
| 401 | MISSING_API_KEY |
The X-Api-Key header was not provided |
| 401 | INVALID_API_KEY |
The key is not recognized — no such key exists on the platform |
| 404 | SERVER_NOT_FOUND |
The server is not available to this key |
| 429 | RATE_LIMITED |
The limit of 60 requests per minute per key was exceeded. The exact value arrives in the x-ratelimit-limit header (the cap is divided across replicas) |
Full list of common API errors — Errors.