[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"docs-changelog\u002F2026-08-15":3,"docs-tabs-changelog\u002F2026-08-15":6},{"content":4,"lastmod":5},"# API changes: August 15, 2026\n\n[← Changelog](\u002Fdocs\u002Fchangelog) · [August 2026](\u002Fdocs\u002Fchangelog\u002F2026-08)\n\n### BC-0815-1: combo runtimes with a database no longer slip into Galaxy silently\n\n> Old format supported until: not provided\n\n**Before**\n\nDeploying an app into Galaxy with a runtime that promises a database (`node20-pg`, `node20-mysql`, `node20-redis`, `node20-mysql-redis`, `node20-pg-redis`, `node20-rag`, `python311-pg`, `python311-mysql`, `python311-redis`, `python311-rag`, `php83-mysql`) succeeded. The database suffix was stripped and the app got the language image only: no database engine, no connection variables (`DATABASE_URL`, `PG*`). The failure showed up on the first database call.\n\n**After**\n\nSuch a deploy is refused up front: `400` with code `GALAXY_RUNTIME_DB_UNSUPPORTED`, a `details.suggestedRuntime` field (the language replacement — `node20` instead of `node20-pg`, for example) and a recovery hint. The catalog [GET \u002Fv1\u002Finfra\u002Fruntimes](\u002Fdocs\u002Finfra\u002Fdeploy\u002Fruntimes) now returns `supportedPlacements` on every runtime: `[\"standalone\"]` — dedicated virtual machine only, `[\"standalone\",\"galaxy\"]` — Galaxy as well. The `name` and `packages` fields are unchanged: they describe the dedicated-machine install, where a combo runtime really does install the database.\n\n**What integrators should do**\n\nFilter the catalog by `supportedPlacements` containing `galaxy` before a Galaxy deploy. If a Galaxy app needs a database, take a language runtime and pass the connection string of an external database through `env`. If the database must live on the same machine, create a dedicated virtual machine (`placement: \"dedicated\"`, create without `source`) and deploy the original runtime to it in a second step. Apps already running are unaffected: the refusal only happens on a new deploy.\n\n### NEW-0815-2: the bound placements list now states whether the account was checked\n\nThe [GET \u002Fv1\u002Fplacements](\u002Fdocs\u002Fapps\u002Fplacements\u002Flist) response gained three optional fields. The `portalSync` field states how the reconciliation of the list against the Bitrix24 account ended: `ok` — the account returned every bound code, `drift` — the account did not return some of the codes, `unknown` — no reconciliation happened. The reason for a value other than `ok` is returned in `portalSyncReason` — `no_oauth_session`, `empty_vibe_list`, `b24_unreachable`, `unpublished` or `missing_on_portal`. On a divergence the codes that are listed as bound in Vibecode and were not returned by the account are named in `missingOnPortal`, and the same codes get a line in `warnings`.\n\nAn application withdrawn from the catalog is not treated as a divergence: the `unpublished` value states that the platform itself removed the placements from the account and kept the codes for republishing. The reconciliation runs when a session token is passed together with the application key and the application has bound placements. Without those conditions `portalSync` is returned as `unknown` — the response behaviour did not change, it is simply stated explicitly now.\n\nPreviously the outcome had to be inferred from the presence and the length of the `handlers` array, which did not separate \"the account answered and the code is not in the answer\" from \"the account response could not be obtained\": both produced an empty array. The `handlers` field is now absent in the second case, and the reason is visible in `portalSyncReason`. Existing calls keep working, the new fields are additive.\n\n### FIX-0815-3: AI quota is resolved by plan in every Western zone\n\n**Before**\n\nA Bitrix24 account plan is recorded as \"account zone plus edition\" — for example\n`jp_pro100`. The platform stripped the zone prefix for only ten of the Western zones,\nso an account in the `cn`, `id`, `it`, `vn`, `jp`, `ms`, `th`, `hi`, `co` or `ae` zone\nmatched no plan setting at all. Its monthly AI quota was then sized by the fallback\nrule instead of by its own plan.\n\n**After**\n\nThe prefix is stripped in all twenty-one Western zones, and the quota is sized by the\nsetting of the plan the account actually holds. No client-side change is required; for\naffected accounts the monthly quota size changes from the next billing period — up or\ndown, depending on how their plan is configured.\n\n### NEW-0815-4: an app can be added to the Bitrix24 catalog with a dedicated call\n\nA new call is available — [POST \u002Fv1\u002Finfra\u002Fservers\u002F:id\u002Fb24-catalog\u002Fpublish](\u002Fdocs\u002Finfra\u002Fservers\u002Fb24-catalog-publish). It creates the app card in the Vibecode apps catalog on the Bitrix24 account. Previously the card appeared only after a successful deployment, so an app brought up any other way was missing from the catalog, and granting access to people did not surface it.\n\n[GET \u002Fv1\u002Finfra\u002Fservers](\u002Fdocs\u002Finfra\u002Fservers\u002Flist) and [GET \u002Fv1\u002Finfra\u002Fservers\u002F:id](\u002Fdocs\u002Finfra\u002Fservers\u002Fget) now return a `b24CatalogSync` block with `status`, `itemId`, `attempts`, `pendingOp` and `eligible`. A non-null `itemId` is the \"the app is in the catalog\" signal. The `eligible` field answers a different question — whether a card can exist at all: an agent runtime, a galaxy host, a server without a subdomain and a server with no app deployed to it never get one.\n\nExisting calls keep working unchanged: editing the access policy or the access list still does not create a card, it updates an existing one.\n\n### FIX-0815-5: the Cowork monthly limit now follows the tier grid without waiting for a renewal\n\n**Before**\n\n`\u002Fv1\u002Fcowork\u002Fstate` and `\u002Fv1\u002Fcowork\u002Fme` measured a paid seat's monthly window\nagainst the volume frozen when the seat was bought. When a tier's monthly\nlimit was raised, the new value reached the seat only\nat its next renewal: `month.pctUsed` did not move, and a seat sitting at\n`exhausted` stayed blocked until the paid period ended even though the tier\nlimit had already grown. The weekly and five-hour windows updated immediately,\nso the three windows of one seat answered by different rules.\n\n**After**\n\nA paid seat's monthly window is measured against the greater of two values: the\nlive tier limit and the volume sold for the current period. A raise applies at\nonce — `month.pctUsed` drops with no request made, and `month.exhausted` returns\nto `false` when the new limit exceeds what was spent. A cut does not touch the\npaid period: until it ends the seat is measured against the volume sold, and the\nnew value takes effect from the next period. A free seat is still measured\nstrictly against the live limit.\n\nThe response still carries no absolute numbers — only the shares, the\n`exhausted` flag and the `resetAt` moment change. A client caching\n`month.pctUsed` should re-read the state before deciding to block, rather than\nassuming the share only ever grows.\n",null,{},1794739475132]