
## Application card

`GET /v1/applications/:id`

Returns one application of the Bitrix24 account together with a summary of its server, saved sources and any operation in flight. The card is available to the owner and to whoever the application was shared with — personally or through the server policy. Administering the Bitrix24 account plays no part here: an administrator who neither owns the application nor was given access gets `403 FORBIDDEN` like any other viewer.

## Parameters

| Parameter | Type | Req. | Description |
|-----------|------|:----:|-------------|
| `id` (path) | string | yes | Application id. List: [`GET /v1/applications`](./list.md) |

## Examples

### curl — personal key

```bash
curl -H "X-Api-Key: YOUR_API_KEY" \
  https://vibecode.bitrix24.com/v1/applications/cmsw806qi0000tdskiw2aegii
```

### curl — OAuth application

```bash
curl -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  https://vibecode.bitrix24.com/v1/applications/cmsw806qi0000tdskiw2aegii
```

### JavaScript — personal key

```javascript
const id = 'cmsw806qi0000tdskiw2aegii'
const res = await fetch(`https://vibecode.bitrix24.com/v1/applications/${id}`, {
  headers: { 'X-Api-Key': 'YOUR_API_KEY' },
})
const { data: application } = await res.json()

console.log(application.name, application.server?.status ?? 'no server')
if (application.sources.hasVersions) {
  console.log('Latest version:', application.sources.latestVersionId)
}
```

### JavaScript — OAuth application

```javascript
const id = 'cmsw806qi0000tdskiw2aegii'
const res = await fetch(`https://vibecode.bitrix24.com/v1/applications/${id}`, {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})
const { data: application } = await res.json()
```

## Response fields

| Field | Type | Description |
|-------|------|-------------|
| `success` | boolean | Always `true` on success |
| `data.id` | string | Application id |
| `data.name` | string | Application name |
| `data.description` | string \| null | Description. `null` when none was set |
| `data.type` | string | How the application was created: `SHARED` — with a server and/or an authorization key up front, `PERSONAL` — without them. The value is stamped at creation and never recomputed, so a `PERSONAL` application can own a server too |
| `data.iconUrl` | string \| null | Host-less relative path to the icon, e.g. `/api/app-icons/7f3…?v=1755500000000`. The serve endpoint is anonymous: no key, no signature, no expiry — join the path with your API base URL and drop it straight into `<img src>`. A 256×256 PNG is returned with `Cache-Control: public, max-age=300, must-revalidate` and an ETag. `null` when the card holds no icon pointer |
| `data.createdAt` | string | When the application was created, ISO 8601 |
| `data.updatedAt` | string | When the card was last written to, ISO 8601. A deployment does not touch the card — to see how fresh the code is, read `sources.latestSavedAt` |
| `data.viewerState` | string | The viewer's relation to the application: `owner` — the owner, `shared` — access granted personally, through the server's access policy, or through being a member of that server's development team, `usable` — the application has no server and is open to the whole Bitrix24 account, `requestable` — no access. When an application has a server, its access is decided by the server policy, and an application open to everyone arrives as `shared` |
| `data.pinned` | boolean | Whether this viewer pinned the application |
| `data.author.name` | string | Display name of the application owner |
| `data.openUrl` | string \| null | The address the application is opened at. It carries the application server address when there is one. `null` means "nowhere to open it" and is a normal value |
| `data.openTarget` | string \| null | What exactly `openUrl` holds. Today there is a single value — `app`, the address of the application server. `null` arrives together with a `null` in `openUrl`. A value your client does not know should be read as "nowhere to open it", not as a malformed response: the set is closed but open to additions |
| `data.isEmbedded` | boolean | The application is embedded into the Bitrix24 interface — that is, at least one [placement](/docs/apps/placements) is bound to it. This is the only thing that tells "embedded, opens inside Bitrix24" apart from "not published yet": both arrive with `openUrl` and `openTarget` set to `null`. The flag does not depend on the server — an embedded application without a server of its own is a normal state. Disclosed to everyone who can see the card |
| `data.server` | object \| null | Summary of the application server. `null` when there is no server, or it was deleted or torn down |
| `data.server.id` | string | Server id — the same id used in the [Servers](/docs/infra/servers) paths |
| `data.server.status` | string | Server state: `PROVISIONING`, `RUNNING`, `STOPPED`, `SLEEPING`, `ERROR`. **Uppercase here** — [`GET /v1/infra/servers`](/docs/infra/servers/list) reports the very same value for the very same server in lowercase, so normalize the case before comparing strings from the two sections. A torn-down server never appears here at all: its `server` is `null`. Read an unfamiliar value as "a state your client does not know", not as a malformed response |
| `data.server.url` | string \| null | Application address. `null` until a subdomain is issued — there is no separate "has an address" flag; this check is the flag. Moving the container between galaxies does not change the address: it is derived from the subdomain, and the move does not touch the subdomain |
| `data.server.kind` | string | Resource type: `STANDALONE` — a dedicated virtual machine, `GALAXY_APP` — an application on a shared galaxy host |
| `data.server.reachable` | boolean | The server both runs and answers over the network. Not the same question as `status`: a container can be up while the tunnel to it has never come up at all. The flag already implies `status === "RUNNING"` — it never arrives true for another state, so there is nothing to conjoin. ⚠️ For `kind: "GALAXY_APP"` its second half is taken from the galaxy HOST rather than from the container itself; see "Known specifics" |
| `data.server.lastDeployedAt` | string \| null | When the application was last deployed SUCCESSFULLY, ISO 8601 — the only signal in this section that an application is actually lived in, rather than merely having a server that is up. Distinct from `updatedAt` (which moves when the card is edited and never sees a deployment) and from `sources.latestSavedAt` ("code saved", not "deployed", and disclosed to the owner only). ⚠️ `null` does not mean "never deployed": for servers created before 2026-08-18 the field stays empty until their next deployment — the history was deliberately not reconstructed, see "Known specifics" |
| `data.sources` | object | Summary of the saved source versions. Filled in only for whoever manages the application |
| `data.sources.hasVersions` | boolean | Whether at least one saved version exists |
| `data.sources.latestVersionId` | string \| null | Latest version in the `v<N>` shape — exactly the shape [`GET /v1/infra/servers/:id/sources/:versionId/download`](/docs/source-storage) accepts. It is not the record's primary key, and no separate call for the version list is needed. `null` when there are no versions |
| `data.sources.latestSavedAt` | string \| null | When the latest version was saved, ISO 8601 |
| `data.activeOperation` | object \| null | Operation in flight on the server. Filled in only for whoever manages the application. The `null` case is covered in "Known specifics" |
| `data.activeOperation.kind` | string | Operation kind: `deploy` — deployment, `repair` — repair, `resize` — server plan change, `migrate` — moving a container between galaxies |
| `data.activeOperation.status` | string | `running` — the operation is in flight. `unknown` — the operation did start and its outcome is not known |
| `data.activeOperation.step` | string \| null | The step the operation is on. A free-form string, not an enumeration |
| `data.activeOperation.startedAt` | string | When the operation started, ISO 8601 |

## Response example

```json
{
  "success": true,
  "data": {
    "id": "cmsw806qi0000tdskiw2aegii",
    "name": "Deal report",
    "description": "Pipeline summary for the period",
    "type": "PERSONAL",
    "iconUrl": null,
    "createdAt": "2026-08-16T19:51:18.810Z",
    "updatedAt": "2026-08-16T19:51:18.810Z",
    "viewerState": "owner",
    "pinned": false,
    "author": { "name": "Application author" },
    "isEmbedded": false,
    "openUrl": "https://app-05b67cf7.vibecode.bitrix24.com",
    "openTarget": "app",
    "server": {
      "id": "5cbb50f9-f95f-4ddf-ba3b-b771209cb6fb",
      "status": "RUNNING",
      "url": "https://app-05b67cf7.vibecode.bitrix24.com",
      "kind": "STANDALONE",
      "reachable": true,
      "lastDeployedAt": "2026-08-16T19:50:41.302Z"
    },
    "sources": {
      "hasVersions": true,
      "latestVersionId": "v2",
      "latestSavedAt": "2026-08-16T19:41:18.818Z"
    },
    "activeOperation": {
      "kind": "deploy",
      "status": "running",
      "step": "build",
      "startedAt": "2026-08-16T19:50:33.822Z"
    }
  }
}
```

An application with no server returns `server: null`, an empty `sources` summary and `activeOperation: null`. There is nowhere to open it, so `openUrl` and `openTarget` arrive `null` too — the application in the example is embedded in Bitrix24, which is exactly that case:

```json
{
  "success": true,
  "data": {
    "id": "cmsw806qp0001tdskzf6mitka",
    "name": "Draft with no server",
    "description": null,
    "type": "PERSONAL",
    "iconUrl": null,
    "createdAt": "2026-08-16T19:51:18.817Z",
    "updatedAt": "2026-08-16T19:51:18.817Z",
    "viewerState": "owner",
    "pinned": false,
    "author": { "name": "Application author" },
    "isEmbedded": true,
    "openUrl": null,
    "openTarget": null,
    "server": null,
    "sources": { "hasVersions": false, "latestVersionId": null, "latestSavedAt": null },
    "activeOperation": null
  }
}
```

## Error response example

404 — no application with that id on the Bitrix24 account:

```json
{
  "success": false,
  "error": {
    "code": "APPLICATION_NOT_FOUND",
    "message": "Application not found"
  }
}
```

## Errors

| HTTP | Code | Description |
|------|------|-------------|
| 404 | `APPLICATION_NOT_FOUND` | No application with that `id` on the key's portal. An id from another portal and a deleted application answer the same way |
| 403 | `FORBIDDEN` | The application exists, but the viewer has no access to it |
| 401 | `NO_PORTAL` | The key is not bound to an account — the actual answer for this case |
| 403 | `MANAGEMENT_KEY_NO_ENTITY_ACCESS` | A management key: an API key or an authorization key is required |
| 403 | `PORTAL_KEY_REQUIRED` | The section's safety net: a damaged key row with no owner. The ordinary "key with no account" is `401 NO_PORTAL` above |
| 401 | `MISSING_API_KEY` | The `X-Api-Key` header was not sent |
| 401 | `INVALID_API_KEY` | Invalid or expired API key |
| 429 | `RATE_LIMITED` | Rate exceeded. 120 requests per minute is the platform-wide limit; one replica's share today is 40 — read `X-RateLimit-Limit` from the response. The card keeps its own counter, noticeably more generous than the one for the list. A `Retry-After` header carries the pause in whole seconds |
| 429 | `QUOTA_EXCEEDED` | The key's daily free-call quota is exhausted. Same status, different cause: waiting does not help |

The `error.message` text is always English and meant for logs rather than for people: build your interface texts from `error.code`. The full list of common API errors — [Errors](/docs/errors).

## Known specifics

- **The card is open to more than just the owner.** An application shared with you personally, through the server, or through membership in its development team is readable via a direct link — the card answers with the `owner`, `shared` and `usable` states. A viewer with no access gets `403 FORBIDDEN`, so the value `requestable` never appears in a card.
- **An embedded application has nowhere to open, and both fields arrive `null`.** The platform does not yet know the address an embedded application is opened at inside the Bitrix24 account. An empty slot here is the normal answer, not a failure: an invented link would take the person somewhere else, and they could not tell that from a working one.
- **The server address is not substituted into `openUrl`, and you must not substitute it yourself.** For an embedded application `server.url` arrives as usual, but it is not the place to open: it serves the gateway login page with a `200`, so the move looks successful without being it. A client that "fixes" an empty `openUrl` by substituting `server.url` gets exactly that silent refusal.
- **`openUrl` is not suppressed when the server is unreachable.** The address arrives even with `server.reachable: false`. A person cannot diagnose a greyed-out button, but they can diagnose a refusal they are shown.
- **`isEmbedded`, and nothing else, tells an empty open pair apart.** "Embedded, opens inside Bitrix24" and "not published yet" both arrive with `openUrl: null` and `openTarget: null`, yet a person must be shown different things. Do NOT infer embedding from the presence of a server: an embedded application with no server of its own is a normal state (embedded before the code was ever deployed), and conversely an embedded application WITH a server reports `server.url` as usual while that address is not where it opens.
- **For an application inside a galaxy, the second half of `reachable` is about the host, not the container.** With `server.kind: "GALAXY_APP"` the connectivity is held by the shared galaxy host; the container itself has no tunnel of its own by design. So `true` here means three things at once: the container runs, the host runs, and the host's tunnel is up — the flag implies `status === "RUNNING"` and is never true without it. The consequence runs the other way: a freshly created container that has not reached `RUNNING` yet (it only does so after its first source upload) arrives with `reachable: false` on a perfectly healthy host. That is "the container is not up yet", not "the host is unreachable", and the flag alone does not tell the two apart — read `status` for that. `STANDALONE` has no such split: there both facts are about one machine.
- **`lastDeployedAt` fills forward, not backward.** The stamp is written by the deployment itself, in the same moment it records success, so it cannot drift from the outcome: a failed deployment never moves it. But the field carries no history: for servers that existed before 2026-08-18 it stays empty until their next deployment. Reconstructing the history was only possible from the operations journal, which covers one of the three deployment paths — a date would then be present for applications on a dedicated machine and missing for applications inside a galaxy, and that emptiness would read as "galaxy applications are dead". A uniform "no deployments since" is more honest. So a `null` in the first weeks is normal, not a sign of an abandoned application.
- **A torn-down server arrives as `server: null`, not as a separate status.** You will not see values such as `deleted`, `terminated`, `destroyed` or `archived` in `server.status` — but for different reasons, and the difference is worth keeping: the last three do not exist in the platform at all, while the "torn down" state does exist and simply is not published by this section. Once a server is torn down the card returns `server: null` outright, together with `openUrl: null`. If you normalize statuses coming from [`GET /v1/infra/servers`](/docs/infra/servers/list), note that its value set is different — that section reports the status in lowercase and, with the `includeDeleted` parameter, shows deleted servers as well. This section has no such parameter.
- **An application of another Bitrix24 account is indistinguishable from a missing one.** An id from another account answers `404 APPLICATION_NOT_FOUND` rather than `403`: the section does not even confirm that such a record exists.
- **The source summary and the operation in flight are filled in only for whoever manages the application.** A viewer the application was merely shared with gets an empty `sources` and `activeOperation: null`, and the response shape does not change. So an empty summary on its own does not mean "there are no versions": it has three causes, identical from the outside — the application has no server, there really are no versions, or the application is someone else's and the data is not disclosed to you. A client that renders "no code" from an empty `sources` will be wrong on every application belonging to someone else.
- **`activeOperation: null` does not mean "nothing is happening to this application".** The field is reliable only for operations with a stored record — deployment, repair, a server plan change and moving a container between galaxies. The platform does not record anything else, and such actions never surface in this field. The value `unknown` in `status` is a third state: the operation did start and its outcome is not known — waiting for it to finish is pointless; re-read the state from the server itself.
- **Server state arrives in upper case.** In the card, `server.status` for a running server is `RUNNING`, while [`GET /v1/infra/servers`](/docs/infra/servers/list) reports the same server at the same moment as `running`. A client comparing strings from both sections must normalize the case.

## See also

- [List applications](./list.md)
- [Application catalog](/docs/applications)
- [Servers](/docs/infra/servers)
- [Source storage](/docs/source-storage)
- [Keys and authorization](/docs/keys-auth)
- [Errors](/docs/errors)
