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

Unpublish

POST /v1/apps/:id/unpublish

Moves a published app to UNPUBLISHED and unbinds placements from the Bitrix24 account.

Parameters

Parameter Type Required Description
id (path) string yes Identifier of an app in PUBLISHED status. List: GET /v1/apps

No request body is required — an empty body is allowed.

Examples

curl — personal key

Terminal
curl -X POST "https://vibecode.bitrix24.com/v1/apps/YOUR_APP_ID/unpublish" \
  -H "X-Api-Key: YOUR_API_KEY"

curl — OAuth app

Terminal
curl -X POST "https://vibecode.bitrix24.com/v1/apps/YOUR_APP_ID/unpublish" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"

JavaScript — personal key

javascript
const res = await fetch(
  'https://vibecode.bitrix24.com/v1/apps/YOUR_APP_ID/unpublish',
  {
    method: 'POST',
    headers: { 'X-Api-Key': 'YOUR_API_KEY' },
  }
)
const body = await res.json()
if (!body.success) throw new Error(body.error.code)
console.log(body.data.placements)

JavaScript — OAuth app

javascript
const res = await fetch(
  'https://vibecode.bitrix24.com/v1/apps/YOUR_APP_ID/unpublish',
  {
    method: 'POST',
    headers: {
      'X-Api-Key': 'YOUR_APP_KEY',
      'Authorization': 'Bearer USER_SESSION_TOKEN',
    },
  }
)

Response fields

Field Type Description
success boolean true on a successful unpublish
data object The app after unpublish — the same set of fields returned by Application data
data.placements string[] Placements whose removal was not confirmed. What an empty array means depends on the rollout — see the breakdown in the note below
data.catalogStatus string After unpublish — UNPUBLISHED
data.publishedAt string | null The last publication date is kept — unpublishing does not reset it
warnings string[] Entries explaining how the removal went. The field sits next to data, not inside it. The set of entries is open — see the breakdown under the note below

The account-side removal check is currently rolling out per account, so there are two cases:

  • While the capability is not enabled on the account — unbinding runs without waiting for the result for each placement code, placements always arrives as an empty array, and warnings does not arrive at all. An empty list here means neither "the account confirmed the removal" nor "the unbind was sent": the list is cleared regardless of the outcome. There may be no removal transport available at all — for example, when the account was reconnected, when the app's token was revoked, or when refreshing it failed — in which case no unbind is sent and the binding survives the unpublish.
  • Once enabled — the platform waits for the account's response. Codes that could not be removed stay in placements, and the explanations arrive in warnings. Determine success by an empty placements, not by the 200 status and not by the presence of warnings: the status is 200 in both cases, because unpublishing is never rejected.

A non-empty warnings does not by itself mean a refusal. The entries come in four kinds, and two of them describe success: the removal was confirmed by the only available transport, the removal went through while one of the two transports refused, the code could not be removed, and there was no way to remove it. On an account with a single available transport — a cloud account without a developer key, for example — an entry arrives for EVERY placement removed normally. You do not need to parse these entries in code — they are meant for humans.

Response example

The data field mirrors the app object with an empty placements array — what an empty array means is covered in the note above:

JSON
{
  "success": true,
  "data": {
    "id": "33c4d5e6-f7a8-49b0-1234-5c6d7e8f9012",
    "title": "Sales dashboard",
    "description": null,
    "scopes": ["crm", "user", "placement"],
    "handlerUrl": "https://vibecode.bitrix24.com/v1/bitrix-handler",
    "appUrl": "https://app-abc12345.vibecode.bitrix24.com",
    "redirectUris": [
      "https://vibecode.bitrix24.com/oauth/complete",
      "http://localhost"
    ],
    "bitrixClientId": "local.7c3d4e5f6a7b80.55556666",
    "prefix": "vibe_app_local_7c3",
    "suffix": "6666",
    "authorId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "authorBitrixUserId": 42,
    "authorBitrixUserIdSource": "member",
    "portalId": "8b1f0e2a-3c4d-5e6f-7a8b-9c0d1e2f3a4b",
    "createdAt": "2026-06-24T09:12:45.781Z",
    "updatedAt": "2026-06-24T12:47:05.930Z",
    "placements": [],
    "catalogStatus": "UNPUBLISHED",
    "publishedAt": "2026-06-24T10:03:18.204Z"
  }
}

Error response example

404 — the app is not published:

JSON
{
  "success": false,
  "error": {
    "code": "NOT_FOUND",
    "message": "Published app not found"
  }
}

Errors

HTTP Code Description
403 INFRA_FORBIDDEN_FOR_COWORK_KEY The call was made with a Cowork/Code key — such a key works with data only and cannot perform write operations. To issue a key that can, see Project key for deploy
404 NOT_FOUND App does not exist, belongs to another portal, or is not in PUBLISHED status
403 FORBIDDEN The call was made with an authorization key vibe_app_… issued for a different application. Such a key unpublishes only its own application, even when both applications were created by the same author
403 FORBIDDEN Request is not from the app author and not from a Bitrix24 account administrator

Full list of common API errors — Errors.

Known specifics

  • Returns to UNPUBLISHED, not PRIVATE. Catalog metadata — title, description, icon — is preserved, so publishing the app again with an empty body restores it without re-entering the metadata.
  • Unbinding placements does not block unpublishing under any rollout. A failure to unbind an individual placement does not interrupt the operation: the app moves to UNPUBLISHED every time. Refusing here is impossible by design — on a cloud account without a developer key there is only one removal transport, and a refusal on it would lock the app in PUBLISHED with no way back.

See also