For AI agents: markdown of this page — /docs-content-en/infra/servers/activity.md documentation index — /llms.txt
Server activity feed
GET /v1/infra/servers/:id/activity
Returns a timeline of failures and key events for a server: undelivered Bitrix24 events, bot delivery problems, deployments, wake-ups and status changes.
Call this first when an application has stopped working, a bot is silent, a Bitrix24 event did not arrive or a deployment failed: an entry names the cause as a machine-readable code, and an entry about a deployment or a command leads to its outcome. The feed does not record API call errors, a bot that polls for events itself, or successful deliveries, so an empty feed does not prove that events were delivered.
The feed is read by the server owner with a personal key or with the key of their own OAuth application from the same Bitrix24 account, and by a development team member whose role includes server settings, with their own personal key. An OAuth application key reads the feed with the rights of its owner: the session user does not affect access, and the session token can be omitted. Keys issued for a narrow task with their own list of routes (an agent maintenance key, an application external API key, a team member key and an external collaborator key) do not read the feed and get 403 with a code of the form …_KEY_OUT_OF_SCOPE. For everyone else, including a Bitrix24 account administrator without a role in the team, the server responds as if it did not exist.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
id (path) |
string | yes | — | Server ID. List: GET /v1/infra/servers |
cursor (query) |
string | no | — | The nextCursor value from the previous page, unchanged. Not passed for the first page |
limit (query) |
integer | no | 50 |
Entries per page, from 1 to 100. A value above 100 is capped at 100. Zero, negative, non-numeric and empty values give 400 INVALID_LIMIT |
severity (query) |
string | no | all | Severities, comma-separated: error, warning, info |
kind (query) |
string | no | all | Entry kinds, comma-separated, for example deploy.failed,wake.failed. The list of kinds is in the table below |
since (query) |
string | no | — | An RFC 3339 date and time with an explicit UTC offset, Z or +03:00, for example 2026-10-06T12:00:00Z. Only entries whose last repetition is not earlier than this moment are returned |
An empty parameter value counts as passed: ?severity= gives 400 INVALID_SEVERITY, not all severities.
Pages. Entries go from newest to oldest by time of first appearance. While the response carries a non-empty nextCursor, pass it in cursor of the next request unchanged. null means the last page.
Examples
curl — personal key
curl -H "X-Api-Key: YOUR_API_KEY" \
"https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/activity?limit=20"
curl — OAuth application
curl -H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
"https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/activity?limit=20"
JavaScript — personal key
const res = await fetch(
`https://vibecode.bitrix24.com/v1/infra/servers/${serverId}/activity?limit=20`,
{ headers: { 'X-Api-Key': 'YOUR_API_KEY' } }
)
const { data } = await res.json()
for (const e of data.events) {
console.log(e.firstAt, e.severity, e.kind, e.code ?? '', e.count > 1 ? `×${e.count}` : '')
if (e.ref?.type === 'deploy_operation') {
console.log(` details: /v1/infra/servers/${serverId}/operations/${e.ref.id}`)
}
}
JavaScript — OAuth application
const res = await fetch(
`https://vibecode.bitrix24.com/v1/infra/servers/${serverId}/activity?limit=20`,
{
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
},
}
)
const { data } = await res.json()
Response fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true on success |
data.events |
array | Feed entries, from newest to oldest |
data.events[].id |
string | Entry identifier |
data.events[].kind |
string | Entry kind — see the table below |
data.events[].severity |
string | Severity: error, warning or info |
data.events[].code |
string | null | Cause from the closed list for the kind. A value that is not in the list arrives as other |
data.events[].meta |
object | null | Kind details — keys from the table below, no free text |
data.events[].ref |
object | null | { type: "deploy_operation", id } on an entry about a deployment or a command that has an operation: its outcome is read through GET /v1/infra/servers/:id/operations/:operationId. On all other entries it is null |
data.events[].firstAt |
string | First appearance, ISO 8601 |
data.events[].lastAt |
string | Last repetition, ISO 8601 |
data.events[].count |
number | How many times the event occurred in the entry's five-minute window |
data.nextCursor |
string | null | Cursor of the next page. null on the last one |
Entry kinds:
kind |
What happened | severity |
code |
meta |
|---|---|---|---|---|
portal_event.delivery_paused |
Delivery of Bitrix24 events to the application is paused | warning |
not_connected, http, http_hard, error |
retryAt |
portal_event.delivery_failed |
A Bitrix24 event was not delivered | error |
http_NNN — the application's response code, not_connected, no_app_url, park_expired, policy_denied |
eventName, attempts |
portal_event.subscription_degraded |
The Bitrix24 event subscription was moved to degraded mode | error |
breaker_trips, max_attempts |
— |
portal_event.dropped |
A Bitrix24 event arrived at an inactive subscription and was dropped | warning |
subscription_inactive |
eventName, subscriptionStatus |
bot.delivery_deferred |
Delivery of an event to the bot was deferred | warning |
NO_TUNNEL, AGENT_NOT_CONNECTED, TUNNEL_SEND_FAILED, GATEWAY_ERROR, BACKLOG |
botId, eventType |
bot.event_dropped |
An undelivered bot event was deleted after 72 hours | error |
outbox_ttl_expired |
botId |
bot.disabled |
The bot was disabled | error |
AUTH_FAILURES, B24_UNREGISTERED, PORTAL_DELETED, USER_BLOCKED |
botId |
bot.event_mode_changed |
The bot was switched between delivery to an address and polling for events | warning |
webhook_to_fetch, fetch_to_webhook |
botId, reason |
deploy.succeeded |
The deployment completed successfully | info |
— | durationMs |
deploy.failed |
The deployment failed | error |
the same code as error.code of the operation outcome, or null — explained in "Known specifics" |
step |
deploy.unknown |
The deployment outcome is unknown | warning |
— | step |
exec.failed |
The command did not run | warning |
failure code — the same as error.code of the operation outcome, or null |
— |
wake.succeeded |
The server woke up through a blocking wake-up | info |
— | trigger |
wake.failed |
The server did not wake up | error |
wake-up failure code | trigger |
server.status_changed |
The server status changed | error on transition to error, warning on a balance freeze, info otherwise |
— | from, to, reason |
meta.trigger — who woke the server: manual, api, deploy, gateway, auto-wake-on-preempt, auto-wake-on-unfreeze, scheduled. meta.from and meta.to are server statuses in lowercase, as in GET /v1/infra/servers/:id. meta.reason of a status change equals billing_freeze when a running server was put to sleep by a balance freeze; otherwise the field is absent.
Response example
{
"success": true,
"data": {
"events": [
{
"id": "0b6f5b0e-3c4d-4a51-9a53-3f1d2c7e8a10",
"kind": "deploy.failed",
"severity": "error",
"code": "DOWNLOAD_HTTP_STATUS",
"meta": {
"step": "download"
},
"ref": {
"type": "deploy_operation",
"id": "cmop1abcdefghijklmnopqrs"
},
"firstAt": "2026-10-06T12:13:32.251Z",
"lastAt": "2026-10-06T12:13:32.251Z",
"count": 1
},
{
"id": "5e2a7c41-9d8b-4f06-8e1a-6b0c4d9f2e33",
"kind": "server.status_changed",
"severity": "info",
"code": null,
"meta": {
"to": "provisioning",
"from": "sleeping"
},
"ref": null,
"firstAt": "2026-10-06T12:13:28.740Z",
"lastAt": "2026-10-06T12:13:28.740Z",
"count": 1
},
{
"id": "a3d9e2f7-6b1c-4e8a-b5d0-7c2f9e4a1b68",
"kind": "server.status_changed",
"severity": "info",
"code": null,
"meta": {
"to": "sleeping",
"from": "running"
},
"ref": null,
"firstAt": "2026-10-06T12:13:28.367Z",
"lastAt": "2026-10-06T12:13:28.367Z",
"count": 1
},
{
"id": "c71f04b2-8e5a-4d93-9f6e-2b8a0d5c3e17",
"kind": "server.status_changed",
"severity": "info",
"code": null,
"meta": {
"to": "running",
"from": "provisioning"
},
"ref": null,
"firstAt": "2026-10-06T12:13:08.096Z",
"lastAt": "2026-10-06T12:13:29.035Z",
"count": 2
}
],
"nextCursor": null
}
}
Error response example
404 — the server does not exist, is unavailable to this key, or the feed is not yet enabled for the server owner:
{
"success": false,
"error": {
"code": "SERVER_NOT_FOUND",
"message": "Server not found"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | INVALID_LIMIT |
limit is zero, negative, non-numeric or empty |
| 400 | INVALID_CURSOR |
cursor was not obtained from nextCursor or was altered |
| 400 | INVALID_SEVERITY |
severity contains a value other than error, warning, info, or the parameter is empty |
| 400 | INVALID_KIND |
kind contains a kind that is not in the kinds table, or the parameter is empty |
| 400 | INVALID_SINCE |
since is not an RFC 3339 date and time or has no UTC offset |
| 401 | MISSING_API_KEY |
The X-Api-Key header was not passed |
| 401 | INVALID_API_KEY |
The key is not recognized |
| 401 | INVALID_SESSION |
An OAuth application key was passed with a session token that is not recognized or has expired |
| 403 | SESSION_APP_MISMATCH |
The session token was issued to a different application or for a different portal than the OAuth application key in X-Api-Key |
| 403 | AGENT_MAINTENANCE_KEY_OUT_OF_SCOPE |
The request was made with an agent maintenance key: it has its own list of routes |
| 403 | APP_API_KEY_OUT_OF_SCOPE |
The request was made with an application external API key: it has its own list of routes |
| 403 | EXTERNAL_COLLABORATOR_KEY_OUT_OF_SCOPE |
The request was made with an external collaborator key: it has its own list of routes |
| 403 | PORTAL_COLLABORATOR_KEY_OUT_OF_SCOPE |
The request was made with a team member key. A team member reads the feed with their personal key |
| 403 | SERVER_ROLE_FORBIDDEN |
You are on the server's development team, but the role does not include server settings |
| 404 | SERVER_NOT_FOUND |
The server does not exist, was deleted, is unavailable to this key, or the feed is not yet enabled for the server owner. The cases are intentionally indistinguishable |
| 429 | RATE_LIMITED |
The limit of 60 requests per minute per key was exceeded. The exact value is in the x-ratelimit-limit header; the ceiling is divided among replicas |
The full list of common API errors is in Errors.
Known specifics
- A repeat does not create a new entry. Identical server events within one five-minute window are merged into one entry:
countgrows andlastAtmoves. Windows are aligned to five-minute UTC boundaries: 12:10–12:15, 12:15–12:20 and so on. The entry does not move to the top of the feed; the order is kept byfirstAt, so paging throughnextCursorhas no gaps or repeats, even if the server keeps failing during reading. The exception is a status change inside a long operation, see below. firstAtis the moment of writing to the feed, not of the event itself. An entry appears a few seconds after the event: the deployment in the response example finished at 12:13:28, and its entry is dated 12:13:32.- A wake-up is visible through status changes. A sleeping standalone virtual machine wakes through the chain
sleeping→provisioning→running, a Galaxy application goes straightsleeping→running. Awake.succeededentry appears only after a blocking wake-up that waited for the server to come up. A non-blocking wake-up leaves only status changes in the feed. - The code in a deployment entry is not the top-level code of the deployment response. The response of
POST /deploycarrieserror.code: "DEPLOY_FAILED"when a step fails, and the step cause inerror.causeCode. Adeploy.failedentry carries the same code aserror.codeof the operation outcome: the step cause if it is known, for exampleDOWNLOAD_HTTP_STATUSwhen a download fails,DEPLOY_STEP_FAILEDif the step failed without a named cause, andDEPLOY_FAILEDon a failure of the platform itself. - The deployment error text is not stored in the feed, only the code. The message and the step are read by
ref.idthroughGET /v1/infra/servers/:id/operations/:operationId, while the platform retains the outcome (7 days). - History depth. Status changes are recorded for every server since the status change recording was released; other entries, since the moment the feed was enabled for the server owner. Entries are kept for 30 days. In the first 30 days after enabling, the history is shorter.
- A status change can appear below an already read page if the status changed inside a long platform operation: the entry carries the start time of that operation. The next read of the feed from the first page will show it.
- The feed belongs to the server. After a server is transferred to another owner, the new owner sees the entries made before the transfer, and the previous one gets
404.