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

Terminal
curl -H "X-Api-Key: YOUR_API_KEY" \
  'https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/operations?limit=5'
JSON
{
  "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

  1. 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.
  2. While it is running, wait and poll the list or the addressable endpoint every few seconds.
  3. Use a confirmed succeeded or failed outcome. For unknown or no matching record, reconcile GET /v1/infra/servers/:id and the logs.
  4. If a later request confirms EXEC_BUSY, look at error.hint.holder in that same 409 response: 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 after Retry-After and the guarded POST /v1/infra/servers/:id/unstick, which answers 409 against a live operation as long as no force is 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 unconditional DELETE /lock after it. Then account for the server kind. For STANDALONE, you may call POST /v1/infra/servers/:id/unstick and repeat the read-only checks. A GALAXY_APP uses its shared host's exec channel: tenant unstick is unsupported; wait 30–60 seconds and contact support if EXEC_BUSY persists. 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.

See also