For AI agents: markdown of this page — /docs-content-en/apps/create.md documentation index — /llms.txt
Create an application
POST /v1/apps
Registers an OAuth application in your Bitrix24 account and creates a paired API key. The body is passed flat, without a wrapper.
Request fields (body)
| Field | Type | Req. | Description |
|---|---|---|---|
title |
string | yes | Application name, from 1 to 255 characters |
scopes |
array | yes | Set of application scopes — access to Bitrix24 account data, at least one. To publish the application later, the set must include placement. The platform vibe:* scopes are listed only when the request comes from a key with a fixed rights set. In every other case the paired key receives them on its own — see "Known specifics". The list — Scopes |
description |
string | no | Application description, up to 2000 characters |
appUrl |
string | no | Application URL, only http:// or https://. An empty string is saved as null |
redirectUris |
array | no | OAuth redirect URLs. Defaults to the authorization completion URL and http://localhost |
mode |
string | no | Access mode of the paired key: READONLY or READWRITE. Defaults to the Bitrix24 account policy |
mobile |
boolean | no | The application supports the Bitrix24 mobile client — the account receives this flag at registration. Defaults to false. Can only be set at creation, see "Known specifics" |
handlerUrl is set by the platform — it is not accepted in the body. OAuth callbacks and opening a placement go through it. For the difference between appUrl and handlerUrl, see the Applications section.
Examples
curl — personal key
curl -X POST https://vibecode.bitrix24.com/v1/apps \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Sales dashboard",
"scopes": ["crm", "user", "placement"],
"appUrl": "https://app-abc12345.vibecode.bitrix24.com"
}'
curl — OAuth application
curl -X POST https://vibecode.bitrix24.com/v1/apps \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Sales dashboard",
"scopes": ["crm", "user", "placement"],
"appUrl": "https://app-abc12345.vibecode.bitrix24.com"
}'
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/apps', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: 'Sales dashboard',
scopes: ['crm', 'user', 'placement'],
appUrl: 'https://app-abc12345.vibecode.bitrix24.com',
}),
})
const { data } = await res.json()
// Save data.rawKey immediately — it is returned only once
console.log('App ID:', data.id)
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/apps', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: 'Sales dashboard',
scopes: ['crm', 'user', 'placement'],
appUrl: 'https://app-abc12345.vibecode.bitrix24.com',
}),
})
const { data } = await res.json()
Response fields
| Field | Type | Description |
|---|---|---|
data.id |
string | Application identifier |
data.title |
string | Name |
data.description |
string | null | Description |
data.scopes |
array | Set of application scopes — exactly what you passed in the body. The paired key's scopes are wider — see "Known specifics" |
data.handlerUrl |
string | Handler URL, set by the platform |
data.appUrl |
string | null | Application URL |
data.redirectUris |
array | OAuth redirect URLs |
data.bitrixClientId |
string | null | OAuth client identifier in the Bitrix24 account |
data.authorId |
string | Author identifier |
data.authorBitrixUserId |
integer | null | Bitrix24 employee id of whoever created the app — the same identifier id carries in GET /v1/users. null when the id is unknown |
data.authorBitrixUserIdSource |
string | null | Where the id came from: member — the author's confirmed membership of the account, snapshot — a value captured when the app was created, null — no id |
data.portalId |
string | Bitrix24 portal identifier |
data.createdAt |
string | Creation date, ISO 8601 |
data.updatedAt |
string | Modification date, ISO 8601 |
data.placements |
array | Placements, empty before publishing |
data.catalogStatus |
string | Catalog status. For a new application — always PRIVATE |
data.publishedAt |
string | null | Publication date, ISO 8601. For a new application — null |
data.mobile |
boolean | The "Supports BitrixMobile" flag the platform actually sent to the Bitrix24 account at registration. false when the field was not sent or the flag could not be applied, in which case the reason arrives in warnings |
data.rawKey |
string | Ready-to-use authorization key vibe_app_…. This is the only vibe_app_… value in the response — use exactly this one as X-Api-Key. Returned only in this response and never shown again |
warnings |
array<string> | Returned only when there is something to report. Two reasons: a title that lost its non-ASCII characters on the way in, and a mobile flag that could not be applied on the account at registration (see "Known specifics"). The application is still created and the response stays 201 |
Response example
rawKey is shown with a truncated secret — this is not a working value.
{
"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",
"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-24T09:12:45.781Z",
"placements": [],
"catalogStatus": "PRIVATE",
"publishedAt": null,
"mobile": false,
"rawKey": "vibe_app_local_7c3d4e5f6a7b80_55556666_…_6666"
}
}
Error response example
400 — validation failed:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "title: Required"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | VALIDATION_ERROR |
Body validation failed: missing title, empty scopes, invalid appUrl |
| 400 | REST_REGISTRATION_FAILED |
Bitrix24 refused to register the application or its webhook and gave no reason. The response carries error.details.incidentCode — a six-character support reference that locates the log entry. Quote it when you contact support |
| 402 | INT_TARIFF_REQUIRED |
The route checks account access to the platform before anything else. The account is on a free Bitrix24 plan, so creation never starts. The response carries userMessage, the ways to resolve the refusal in error.alternatives, and the current and required plans with the upgrade link in error.details. The same code appears in the 403 row below, and these are different checks: 402 comes from the account access check that runs before any work starts, 403 from the refusal to issue the paired key |
| 402 | INT_VIBE_PLUS_REQUIRED |
Account access is narrowed to a paid Vibe+ plan, and an ordinary commercial Bitrix24 plan is no longer enough. An account on a trial plan keeps its trial access and does not receive this code |
| 403 | INFRA_DISABLED_FOR_PORTAL |
scopes explicitly asks for vibe:infra and the Bitrix24 account administrator has turned server management off. The application is not created. A request without that scope goes through on such an account as well: the scope the platform appends by default is dropped there silently |
| 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 |
| 403 | APP_CREATION_RESTRICTED |
The portal policy does not allow the caller to create applications: creation is disabled entirely, limited to Bitrix24 account administrators, or restricted to a list the caller is not on. A Bitrix24 account administrator grants the right. More — Creation rights |
| 403 | KEY_POLICY_READONLY_REQUIRED |
The portal policy allows only READONLY, but READWRITE was requested |
| 403 | WRITE_BLOCKED_READONLY_KEY |
The request comes from a key in read-only mode while the paired key is being created in READWRITE mode. Such a key can only create an application with mode: "READONLY". More — Access mode |
| 403 | INT_TARIFF_REQUIRED |
The account gets access through its Bitrix24 plan, and issuing the paired authorization key requires a commercial plan. error.details.upgradeUrl is not returned. The same code with 402 above is a different check — it runs earlier and concerns account access rather than key issuance |
| 403 | PORTAL_TARIFF_UNREADABLE |
The account plan could not be read, so the response does not name the plan that is missing: error.details.requiredTariffs is empty and the button points to support. Buying a plan does not clear this refusal |
| 403 | SCOPE_GRANT_REQUIRES_CONSENT |
The request comes from a key with a fixed rights set and declares a platform vibe:* scope that the calling key itself does not hold. The list of such scopes arrives in error.details.unconsented. The rights set is fixed for a partner key, for a Cowork project key, for a personal key issued by the Vibecode dashboard form (it grants exactly the rights that were ticked) and for a key issued with exactScopes: true — Management keys. Scopes confirmed to the partner key on the consent page can be declared. How to identify such a key — "Known specifics" |
| 403 | CONNECTOR_APP_INSTALL_FORBIDDEN |
A Bitrix24 account administrator has barred this employee from installing applications. It arrives where the application is installed by the connector module: on a self-hosted account, and on a cloud account once that issuance path is enabled for it. Retrying does not change the state; the right is granted by an account administrator. More — Creation rights |
| 409 | KEY_LIMIT_REACHED |
The per-user key limit for the portal has been reached. error.details carries the quota state: limit — how many keys are allowed, used — how many are taken. used also counts application authorization keys and keys the platform issued itself, so the total can exceed what the key list in the dashboard shows — more |
| 409 | CONNECTOR_MODULE_NOT_INSTALLED |
The connector module is not installed on the Bitrix24 account — an application cannot be installed and a paired key cannot be issued through it. The state is permanent; retrying without installing the module will not help |
| 409 | B24_USER_DELETED |
The Bitrix24 employee who owns the paired key is no longer active on the account. The state is permanent: neither a retry nor freeing a key slot helps — the employee has to be restored on the account, or the application created under another user |
| 502 | CONNECTOR_APP_INSTALL_FAILED |
The connector module failed to install the application for another reason. Neither the application nor the paired key is created, and the request can be retried |
| 502 | CONNECTOR_REST_UNAVAILABLE |
The account's plan or trial period is active, but Bitrix24 refused to issue the paired key. It arrives where the other connector codes do — when the application is installed by the connector module. The original refusal reason arrives in error.details.reason, and error.details.retryable: true says the state is transient — retry the request, and contact support if it repeats. The response carries no upgrade offer: there is nothing to buy |
| 502 | CONNECTOR_PLAN_REQUIRED |
Bitrix24 refused to issue the paired key: the account plan does not include Vibecode. It arrives where there is nothing to offer — a self-hosted account, an account already on a paid plan, an unrecognised region. The human-readable cause arrives in error.userMessage. The state is permanent: retrying will not help until the Bitrix24 plan changes. Where access is sold, the same refusal arrives as 402 with a plan paywall code from the table above |
The full list of general API errors — Errors.
Known specifics
- The platform reports non-ASCII characters lost from the title. A value sent without explicit UTF-8 serialization arrives with question marks instead of letters: the bytes are lost on the client side, before the request is sent. Windows PowerShell sends values this way. The application is still created as is, and the response carries
warningsnaming the field — the title becomes the Bitrix24 catalog card name on publish, so fix it right away. A ready-to-run call withUTF8.GetBytes— Windows / PowerShell and UTF-8. - The authorization key is returned only once. The
rawKeyfield is present in the creation response and nowhere else — neither in application data nor in the list. If you did not save it at creation, recreate the application. - A pair is created: an application and an API key. Registration creates an application record and a paired authorization key in one step. This affects deletion: the key frees a slot in the per-user limit only after deleting the application.
- Application scopes and paired-key scopes are different sets. In
scopesyou declare access to Bitrix24 account data —crm,user,placement. If the calling key's rights set is not fixed, the paired key receives that set plus four platform scopes:vibe:infra— servers and agents,vibe:ai— model calls,vibe:search— web search and research,vibe:storage— object storage. The authorization key can then create servers throughPOST /v1/infra/serversright away, even thoughvibe:infrawas never in the create body. Thedata.scopesfield of the response shows the application declaration, not the key's effective set — read the effective set fromdata.scopesofGET /v1/mecalled with that key. - A key with a fixed rights set grants the paired key exactly what was declared. The rights set is fixed for a partner key, for a Cowork project key, for a personal key issued by the Vibecode dashboard form and for a key issued with
exactScopes: true— Management keys. An application created with such a key gets a paired key holding exactly what is listed inscopes— no platform scopes are added to it. If you need infrastructure, listvibe:infrainscopesat creation time, otherwisePOST /v1/infra/serversanswers403 INFRA_SCOPE_REQUIRED. The same goes forvibe:ai,vibe:searchandvibe:storage. You can only declare a right that the calling key itself holds, otherwise the answer is403 SCOPE_GRANT_REQUIRES_CONSENT. Adding the right later through updating the application does not work:vibe:*propagation never reaches a key with a fixed set. - You can identify a key with a fixed rights set before creating the application. Call
GET /v1/mewith the key you plan to create the application with. The set is fixed whendata.scopesmatches what was ticked when the key was issued. Other keys carryvibe:aiandvibe:searchin the set even when those were not ticked. - The
mobileflag can only be set at creation. Bitrix24 has no method for updating a local application, soPATCH /v1/apps/:iddoes not acceptmobile— a sent value is ignored, see Update an application. For an existing application, turn the flag on in the application card on the Bitrix24 account, or create the application again. - The
mobileflag may not be applied at registration. When the Bitrix24 account registers the application through a path that cannot carry the flag, the application is still created,data.mobileisfalsein the response, andwarningscarries a line starting withmobile:. In that case, turn the flag on in the application card on the account.