For AI agents: markdown of this page — /docs-content-en/applications/app-secrets.md documentation index — /llms.txt
Application secrets
Secrets store an application's tokens and passwords: the value is set on the application card, and the platform passes it to the running application as an environment variable.
A value set on the card never passes through a conversation with an AI agent and is not sent in a deploy call. If the feature is not enabled for the Bitrix24 account, the card has no "Secrets" block and the methods below return 404 APPLICATION_NOT_FOUND.
Authorization: X-Api-Key. The methods can be called by the application owner with any of their keys, by the application's own key, and by members of the linked server's development team. Through the API and MCP you can list names, create names and delete them. Only the owner and a Bitrix24 account administrator set and replace values, on the /applications card. The API and MCP never accept or return a value. The dashboard does not show it after saving either: a value can only be replaced. The card's secrets history records when and by whom a name was created or a value was set, replaced or deleted, and the outcome of applying the change. The history contains no values.
The MCP tool manage_app_secrets accepts applicationId, action — list, create or delete — and name for create and delete. It does not accept a value.
Typical scenario
- Create the name:
POST /v1/applications/:id/secretswith the body{ "name": "PAYMENT_TOKEN" }. The response hashasValueset tofalse. - The owner or a Bitrix24 account administrator opens the application card
/applications?app=<id>and sets the value. The platform applies it without a deploy. - Check the result:
GET /v1/applications/:id/secrets. The name hashasValueset totrue, andstate.statusisAPPLIEDonce the application has received the set.
Secret value
A value is set only on the application card. It is a single line of up to 16 KiB, counted in UTF-8 bytes. LF and CR line breaks and the NUL character are not allowed. Encode multiline data, such as a PEM key, as base64 first and decode it in the application: the platform does not do this. The limit applies to the encoded string.
Author secrets and system secrets
The kind field in responses tells two kinds of secrets apart. user is a secret of the application author: the methods below create and delete its name. system is a platform system secret: VIBE_AUTH_SECRET, VIBE_AUTH_SECRET_PREVIOUS and VIBE_AUTH_SECRET_REVOKED. The platform manages system secrets itself.
System secrets come first in the list and do not count toward the 100-name limit: the limit counts author secrets only. A system secret name cannot be created or deleted through the API — the answer is 409 SECRET_SYSTEM, even if the application has no such secret.
How secrets reach the application
The application receives secrets as environment variables of its process and reads them the same way as variables from env: moving a value from env to a secret needs no change to the application code. A name without a value is not passed to the application.
On a standalone server, the platform writes the values to /var/lib/vibe/app-secrets/<service>.env and attaches the file to the application's systemd service. In Galaxy, the values are added to the container's environment when the container starts, not when the image is built. Details, including systemd: false, are in the "Application secrets" section of Full application deploy.
On deploy
Every deploy passes the current set of secrets to the application.
- A secret with a value takes precedence over a variable with the same name in the deploy's
env. The application receives the secret's value, andwarningsin the deploy response reports that theenvvalue was not applied. - A name without a value does not override
env: if the variable is passed inenv, the application receives it.warningsasks for the value to be set, with a link to the card. - The platform sets
PORT. The namesPORT,VIBE_*andHERMES_EVENT_INGEST_*cannot be secrets. - The
installandpreStartcommands, and in Galaxy the image build, do not receive secrets: the values exist only in the running application's environment. If a migration needs a secret, run it from the application itself at startup. - In Galaxy, a name that was previously delivered as a secret and then deleted reaches the container empty, even if the deploy's
envpasses it. This keeps the old value from coming back from an image. To pass that variable throughenvagain, create the name without a value.
Without a deploy
Saving a value on the card and deleting a secret take effect on their own, with no deploy. After "Save" or a deletion, the platform restarts the running application in the background with the new environment. On a standalone server the application's service restarts. In Galaxy, the container is recreated from the current image. The application does not respond while it restarts. Creating a name without a value applies nothing.
On a standalone server, the platform records the application's service on every successful deploy, even if the application has no secrets yet. An application last deployed before the feature was enabled for the Bitrix24 account does not receive the first change: the card shows "Could not apply: the application needs to be redeployed" with a hint. Deploy once: the change applies during that deploy, and later changes apply without one.
Sleeping machine
A change does not wake the machine. While it sleeps, the card shows "Will apply when the machine wakes up", and status in the API is PENDING. After the machine wakes up, the platform applies the current set on its own. In Galaxy, the container is recreated with the new environment on wake. A standalone server first starts the application with the old values and restarts it once the server is back in contact with the platform.
Failure and retry
If applying fails, the card shows "Could not apply" with the reason, status in the API is FAILED, and the reason is in failureCode. While the machine is running, the platform retries on its own, at most once a minute. The "Retry" button on the card starts an attempt right away. It is available to the owner and a Bitrix24 account administrator. The API has no separate retry method. The exception is the reason SECRET_SERVICE_UNKNOWN: a retry cannot fix it without a deploy, so the platform does not retry on its own and the card has no "Retry" button.
failureCode |
Card label | What happened |
|---|---|---|
failureCodeSECRET_SERVICE_UNKNOWN |
Card labelthe application needs to be redeployed | What happenedStandalone server: the platform does not know the application's service yet because the application has not been deployed since secrets were enabled. Deploy the application, and the change applies during the deploy. |
failureCodeSECRET_INVALID_SERVICE |
Card labelapplication service is not configured | What happenedStandalone server: the stored service name is not valid. Deploy the application. |
failureCodeSECRET_RESTART_FAILED |
Card labelapplication restart failed | What happenedStandalone server: the service did not start with the new environment. |
failureCodeSECRET_CONTAINER_UNAVAILABLE |
Card labelcontainer is unavailable | What happenedGalaxy: the platform could not prepare to recreate the container. |
failureCodeSECRET_RECREATE_FAILED |
Card labelapplication restart failed | What happenedGalaxy: the new container did not start. |
failureCodeSECRET_DELIVERY_FAILED |
Card labeldelivery failed | What happenedThe values could not be delivered to the machine, including when the deploy that was delivering them failed. |
Migration and restore
Secrets belong to the application card, not to the machine. A redeploy and a migration of the application to another galaxy keep them: the application receives the current set again.
A restore from a backup takes the current values from the card, not the values as of the backup date. A restored machine receives the set again. When a container is restored into a new application, secrets are copied from the source application's card if that application still exists and both applications have the same owner and the same Bitrix24 account. Otherwise, set the secrets on the new application's card.
Protection boundaries
The dashboard, the API and MCP never return a value. It is not in the secrets history, the audit log or the deploy step output. However, the running application's environment and the secrets file can be read by anyone who runs commands on the machine: a development team member, an AI agent calling POST /exec, the install and preStart commands. The application's own code sees its environment variables. Secrets keep a value out of conversations and out of the API, but they do not hide it from anyone with access to the machine. Grant that access only to people allowed to know the values.
A secret does not revoke access in the external system. If a value leaks, change it in the external system, then replace the secret on the card. A deleted value can remain in older backups of the machine or the container.
List application secrets
GET /v1/applications/:id/secrets
Returns the application's secret names and the state of applying them, so you can check which names are waiting for a value and whether the application has received the current set.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
Parameterid (path) |
Typestring | Requiredyes | DescriptionApplication card ID. This is not the ID of an OAuth application or a server. List: GET /v1/applications |
Examples
curl — personal key
curl -H "X-Api-Key: YOUR_API_KEY" \
https://vibecode.bitrix24.com/v1/applications/cmsw806qi0000tdskiw2aegii/secrets
curl — OAuth application
curl -H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
https://vibecode.bitrix24.com/v1/applications/cmsw806qi0000tdskiw2aegii/secrets
JavaScript — personal key
const id = 'cmsw806qi0000tdskiw2aegii'
const res = await fetch(`https://vibecode.bitrix24.com/v1/applications/${id}/secrets`, {
headers: { 'X-Api-Key': 'YOUR_API_KEY' },
})
const { data } = await res.json()
const waiting = data.secrets.filter((secret) => !secret.hasValue).map((secret) => secret.name)
console.log('Waiting for a value:', waiting, 'apply status:', data.state?.status ?? 'no changes yet')
JavaScript — OAuth application
const id = 'cmsw806qi0000tdskiw2aegii'
const res = await fetch(`https://vibecode.bitrix24.com/v1/applications/${id}/secrets`, {
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
},
})
const { data } = await res.json()
Response fields
| Field | Type | Description |
|---|---|---|
Fieldsuccess |
Typeboolean | Descriptiontrue on success |
Fielddata.secrets |
Typearray | DescriptionSystem secrets first, then up to 100 author names, each group in alphabetical order. Values and ciphertext are not returned |
Fielddata.secrets[].name |
Typestring | DescriptionSecret name |
Fielddata.secrets[].kind |
Typestring | Descriptionuser for a secret of the application author, system for a platform system secret. See "Author secrets and system secrets" on Application secrets |
Fielddata.secrets[].hasValue |
Typeboolean | DescriptionWhether a value is set. false means the name is waiting for a value |
Fielddata.secrets[].createdAt |
Typestring | DescriptionWhen the name was created, ISO 8601 |
Fielddata.secrets[].createdBy |
Typestring | DescriptionID of the user who created the name |
Fielddata.secrets[].updatedAt |
Typestring | DescriptionTime of the last change, ISO 8601 |
Fielddata.secrets[].updatedBy |
Typestring | DescriptionID of the author of the last change |
Fielddata.secrets[].updatedByName |
Typestring | DescriptionName of the author of the last change |
Fielddata.state |
Typeobject | null | DescriptionState of applying the set. null until a secret is created, changed or deleted for the application, or the application is deployed to a standalone machine after the feature is enabled |
Fielddata.state.desiredRevision |
Typenumber | DescriptionNumber of the current set. Increases when a value is saved and when a secret is deleted. Creating a name does not change it |
Fielddata.state.appliedRevision |
Typenumber | DescriptionNumber of the set the application has confirmed receiving. Equals desiredRevision when everything is applied |
Fielddata.state.appliedServerId |
Typestring | null | DescriptionID of the server where the set is applied. Matches server.id in GET /v1/applications/:id |
Fielddata.state.status |
Typestring | DescriptionPENDING — waiting to be applied, including while the machine sleeps. APPLYING — being applied. APPLIED — applied. FAILED — failed, the reason is in failureCode |
Fielddata.state.failureCode |
Typestring | null | DescriptionFailure reason when FAILED. The codes are in the "Failure and retry" section of Application secrets |
Fielddata.state.deliveredNames |
Typearray | DescriptionNames the platform has already passed to the application, including deleted ones |
Fielddata.state.serviceName |
Typestring | null | DescriptionThe application's service on a standalone machine, recorded by the platform on deploy. In Galaxy and before such a deploy — null |
Fielddata.state.updatedAt |
Typestring | DescriptionTime of the last state change, ISO 8601 |
Response example
{
"success": true,
"data": {
"secrets": [
{
"name": "PAYMENT_TOKEN",
"kind": "user",
"hasValue": false,
"createdAt": "2026-10-22T13:05:39.970Z",
"updatedAt": "2026-10-22T13:05:39.988Z",
"createdBy": "3f6c1a52-8b1e-4c7a-9d2f-5e0b7a4c1d93",
"updatedBy": "3f6c1a52-8b1e-4c7a-9d2f-5e0b7a4c1d93",
"updatedByName": "Anna Smith"
},
{
"name": "SMTP_PASSWORD",
"kind": "user",
"hasValue": false,
"createdAt": "2026-10-22T13:05:41.810Z",
"updatedAt": "2026-10-22T13:05:42.007Z",
"createdBy": "3f6c1a52-8b1e-4c7a-9d2f-5e0b7a4c1d93",
"updatedBy": "3f6c1a52-8b1e-4c7a-9d2f-5e0b7a4c1d93",
"updatedByName": "Anna Smith"
}
],
"state": {
"desiredRevision": 1,
"appliedRevision": 0,
"appliedServerId": null,
"status": "PENDING",
"failureCode": null,
"deliveredNames": [],
"serviceName": null,
"updatedAt": "2026-10-22T12:46:24.093Z"
}
}
}
Error response example
404 — the application does not exist, there is no access to it, or secrets are not enabled for the Bitrix24 account:
{
"success": false,
"error": {
"code": "APPLICATION_NOT_FOUND",
"message": "APPLICATION_NOT_FOUND"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| HTTP404 | CodeAPPLICATION_NOT_FOUND |
DescriptionThe application does not exist or there is no access to it, including an application on a different machine than the one the development member's key is linked to. Or the feature is not enabled for the portal |
| HTTP401 | CodeMISSING_API_KEY |
DescriptionThe X-Api-Key header is missing |
| HTTP401 | CodeINVALID_API_KEY |
DescriptionKey not found |
| HTTP403 | CodeEXTERNAL_COLLABORATOR_KEY_SERVER_MISMATCH |
DescriptionThe external development member's key is not linked to a machine, and the application has no machine either |
| HTTP403 | CodeEXTERNAL_COLLABORATOR_NOT_A_MEMBER |
DescriptionKey of an external development member whose membership on the machine was revoked or has expired |
| HTTP403 | CodePORTAL_COLLABORATOR_NOT_A_MEMBER |
DescriptionKey of a development team member who is no longer in the machine's team or is not linked to it |
| HTTP429 | CodeRATE_LIMIT_EXCEEDED |
DescriptionThe secrets methods limit is 60 requests per minute per user within a portal, shared by the list, create and delete methods and split across replicas. A rejection by the general API request limit comes with the same code. x-ratelimit-limit reports the effective limit for the key |
| HTTP500 | CodeSECRET_OPERATION_FAILED |
DescriptionThe operation failed. The response does not include the original error |
Full list of common API errors — Errors.
Known specifics
Empty list and state. After the last name is deleted, data.state stays an object and its desiredRevision keeps growing, so an empty data.secrets does not mean the state has been reset.
Applying for an application without a machine. While the application has no machine to pass the set to, state.status stays PENDING and appliedRevision does not catch up with desiredRevision.