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
curl -X POST "https://vibecode.bitrix24.com/v1/apps/YOUR_APP_ID/unpublish" \
-H "X-Api-Key: YOUR_API_KEY"
curl — OAuth app
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
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
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,
placementsalways arrives as an empty array, andwarningsdoes 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 inwarnings. Determine success by an emptyplacements, not by the200status and not by the presence ofwarnings: the status is200in 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:
{
"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:
{
"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, notPRIVATE. 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
UNPUBLISHEDevery 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 inPUBLISHEDwith no way back.