For AI agents: markdown of this page — /docs-content-en/infra/deploy/logs.md documentation index — /llms.txt

Service logs

GET /v1/infra/servers/:id/logs

Returns the logs of a BLACKHOLE server via the journalctl system utility. Without the service parameter, the whole system journal is read (all services and system-wide messages). To read the logs of a specific systemd unit, pass service (the deploy creates app.service by default, unless you specified another name). Supports filtering by line count, time window, and substring.

Parameters

Parameter In Type Required Default Description
id path string (UUID) yes BLACKHOLE server ID
service query string no The systemd unit name: app, crm-dashboard, etc. Do not specify the .service extension. By default the whole system journal is read
lines query number no 50 Number of lines, 1–500
since query string no Timestamp in the journalctl format: "1 hour ago", "2026-04-22 10:00:00", "10 minutes ago"
grep query string no Substring to filter by, up to 200 characters

Examples

curl — personal key

Terminal
# Application logs for the last hour with a filter on "error"
curl -H "X-Api-Key: YOUR_API_KEY" \
  "https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/logs?service=app&lines=100&since=1%20hour%20ago&grep=error"

# The whole system journal, last 10 lines (for debugging cloud-init)
curl -H "X-Api-Key: YOUR_API_KEY" \
  "https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/logs?lines=10"

curl — OAuth application

Terminal
curl -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  "https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/logs?service=app&lines=50"

JavaScript — personal key

javascript
const params = new URLSearchParams({
  service: 'app',
  lines: '100',
  since: '30 minutes ago',
})

const res = await fetch(
  `https://vibecode.bitrix24.com/v1/infra/servers/${serverId}/logs?${params}`,
  { headers: { 'X-Api-Key': 'YOUR_API_KEY' } }
)
const { data } = await res.json()
data.logs.forEach(line => console.log(line))

JavaScript — OAuth application

javascript
const res = await fetch(
  `https://vibecode.bitrix24.com/v1/infra/servers/${serverId}/logs?service=app&lines=50`,
  {
    headers: {
      'X-Api-Key': 'YOUR_APP_KEY',
      'Authorization': 'Bearer USER_SESSION_TOKEN',
    },
  }
)

Response fields

Field Type Description
success boolean Always true on success
data.service string | null Echo of the ?service= parameter, or null if it was not passed
data.logs array<string> The main field. Log lines in arrival order (newest at the end of the array)
data.lines array<string> Alias of data.logs (the same array). Kept for backward compatibility — in new code use data.logs
data.requestedLines number Echo of the ?lines= parameter (validated 1–500, default 50)
data.returnedLines number Length of data.logs
data.since string | null Echo of ?since=, or null
data.grep string | null Echo of ?grep=, or null
data.hint string Optional. Diagnostics when data.logs.length === 0

Response example

JSON
{
  "success": true,
  "data": {
    "service": null,
    "logs": [
      "Apr 22 11:17:02 epd65hdv07p8g89c0c06 CRON[1406]: pam_unix(cron:session): session closed for user root",
      "Apr 22 11:17:27 epd65hdv07p8g89c0c06 vibe-agent[1098]: 2026/04/22 11:17:27 [exec] id= timeout=10s workdir=\"\" command=\"uname -a\"",
      "Apr 22 11:17:28 epd65hdv07p8g89c0c06 cloud-init[975]: Reading package lists..."
    ],
    "lines": [
      "Apr 22 11:17:02 epd65hdv07p8g89c0c06 CRON[1406]: pam_unix(cron:session): session closed for user root",
      "Apr 22 11:17:27 epd65hdv07p8g89c0c06 vibe-agent[1098]: 2026/04/22 11:17:27 [exec] id= timeout=10s workdir=\"\" command=\"uname -a\"",
      "Apr 22 11:17:28 epd65hdv07p8g89c0c06 cloud-init[975]: Reading package lists..."
    ],
    "requestedLines": 50,
    "returnedLines": 3,
    "since": null,
    "grep": null
  }
}

Error response example

400 — server in OPEN mode:

JSON
{
  "success": false,
  "error": {
    "code": "NOT_BLACKHOLE",
    "message": "Deployment API only available for BLACKHOLE servers"
  }
}

Errors

HTTP Code Description
400 VALIDATION_ERROR The schema is violated: lines outside 1–500, grep longer than 200 characters
400 NOT_BLACKHOLE Server in OPEN mode — the Deploy API is unavailable
401 MISSING_API_KEY The X-Api-Key header was not provided
401 INVALID_API_KEY Invalid or expired API key
404 NOT_FOUND The server does not exist, was deleted, or belongs to another API key
409 SERVER_NOT_READY The server is not ready for the operation: it is not running or the tunnel is not connected. The response carries a hint field with the reason and the next step. Wake the server or call /repair and repeat the request. The "listed as connected but the Gateway has no live tunnel" case on this route arrives as 502 TUNNEL_NOT_FOUND (see below)
429 RATE_LIMITED The limit of 10 operations per minute per server was exceeded
502 TUNNEL_NOT_FOUND / GATEWAY_UNREACHABLE: … No live tunnel to the server, or the Gateway is unreachable — call /repair and retry. GATEWAY_UNREACHABLE carries details after the colon, so match error.code by prefix, not by an exact comparison
503 GATEWAY_TIMEOUT: … The Gateway did not respond in time. The code also carries details after the colon — compare by prefix
502 LOGS_UNAVAILABLE The agent could not read the system journal: no such unit, an invalid filter, access denied, or journalctl returned an error

Full list of common API errors — Errors.

Known specifics

  • Line format — exactly as journalctl emits it. Each line already contains the time, host name, process name, and its PID — no extra processing on the client is needed. Output the lines as is.
  • The grep filter is a plain substring, not a regular expression. For complex patterns, fetch more lines and filter on the client.
  • The tunnel agent's logs are visible without service — under the name vibe-agent. Useful for diagnostics when the application does not respond through the Deploy API. Simply do not pass the service parameter — you will see the whole system journal, including vibe-agent, cloud-init, and other system-wide messages.
  • The 500-line limit combined with the cap of 10 calls per minute means you can read at most 5000 lines per minute. For a larger volume of logs, make several calls with different since values, staying within the limit.

Galaxy apps

If the server is a galaxy app (kind=GALAXY_APP), the endpoint returns the stdout/stderr of the application container itself (docker logs), not the host system journal. The service parameter does not apply to galaxy apps.

  • Read-only. Requesting logs does not wake a sleeping galaxy. If the galaxy host is asleep or unreachable, the response is an empty data.logs array plus a diagnostic data.hint field. Wake the galaxy (by any request to the app) and retry.
  • since — a duration or RFC3339, not a relative text form. For galaxy apps since accepts only a duration in seconds, minutes, or hours (10m, 2h, 24h) or an RFC3339 timestamp (2026-06-24T10:00:00Z) — use 24h for a one-day window. The relative journalctl text forms ("1 hour ago", "10 minutes ago") are accepted only for Black Hole servers — for a galaxy app such a value returns 400 VALIDATION_ERROR.
  • grep works the same way — a plain substring, filtered platform-side.

See also