لوكلاء AI: ملف markdown لهذه الصفحة — /docs-content-en/source-storage.md فهرس التوثيق — /llms.txt
مقالات التوثيق متاحة حاليًا باللغة الإنجليزية فقط.
Source code storage
Source code storage automatically saves snapshots of your application's code on every deploy. If someone else or a new AI session starts working on the application, they can download the latest version and continue from the same point — the code is not lost.
Documentation sections
- Automatic save on deploy — what goes into a snapshot automatically, the
sourceblock in the deploy response, deploying from a saved version - Snapshot before publishing — what is checked before publishing, the
409 SNAPSHOT_REQUIREDrefusal, publishing sources from a server - Save a snapshot —
POST /v1/apps/:id/sources, the metadata headers, deduplication - List versions — the application's version history and linked server versions
- Get version metadata — one version by its identifier
- Download the archive — a signed link to the version's archive
- Version tags and notes —
PATCHfor metadata and setting a tag - Delete a version — deleting one version
- Clear old versions — bulk cleanup
- Version lifetime and cleanup — retention policy, versions of a deleted server, objects in storage
- Server-keyed source endpoints — the same family keyed by the server
- Source registry and Bitrix24 account state —
GET /v1/me/sources, the page in your Vibecode account,capabilities.apps.sourceStorage
Why it matters
When you are refining an application, it is important not to lose the working version of the code. Source code storage does that automatically: on every successful deploy the platform saves a snapshot of the sources. If someone else or a new AI session starts working on the application later, they download the latest version and continue from the same point, without manually passing archives around.
A snapshot belongs to the application rather than to a particular developer: the code stays with the application even when the team changes.
How it differs from Git and GitHub
This is not a version control system and not a replacement for Git. Source code storage covers a narrower need — a safety net and project handoff.
| Source code storage | Git / GitHub | |
|---|---|---|
| What it stores | Source code storagewhole archive snapshots of the code | Git / GitHubchange history line by line |
| When it saves | Source code storageautomatically on every deploy | Git / GitHubmanually, on a developer's command |
| Git skills required | Source code storageno | Git / GitHubyes |
| Branches, merges, version comparison | Source code storageno | Git / GitHubyes |
If you need team development with branches and history, use Git. If you just need to avoid losing working code and to be able to return to a previous version, storage is enough.
How it works
- You refine the application and start a deploy.
- The platform saves a source snapshot on its own — the next version:
v1,v2,v3, … - At any time you can list the versions and download the one you need.
- Before the application is published, the platform checks that a snapshot has been saved.
edit code → deploy → snapshot vN saved automatically
↓
list versions → download any → continue work
Core concepts
- Snapshot — an archived copy of the application's source code at the moment of saving.
- Version
vN— the sequence number of a snapshot (v1,v2, …). The newest one is considered current. - Tag — a
manualorpublishedlabel: marks a version as important so automatic cleanup does not delete it. - Deduplication — if the code has not changed, no new snapshot is created and the existing version is returned. Applies within a single owner — a server or an application.
Access
Base URL: https://vibecode.bitrix24.com/v1
Authorization: the X-Api-Key header. Snapshots can be managed by the application authorization key (vibe_app_*), the application author's personal key (vibe_api_*), or a Bitrix24 account administrator.
Allowed archive formats: application/gzip, application/x-tar, application/zip, application/octet-stream.
Body limit: 500 MB per request.
Save contract
The body of POST …/sources is the raw archive bytes, not multipart/form-data. Metadata travels in headers, not as form fields and not as query parameters.
| Header | Required | Description |
|---|---|---|
HeaderContent-Type |
Requiredyes | DescriptionAn archive format from the list above. Any other value → 400 INVALID_CONTENT_TYPE |
HeaderContent-Length |
Requiredyes | DescriptionBody size in bytes. Without it (Transfer-Encoding: chunked) → 411 MISSING_CONTENT_LENGTH |
HeaderX-Filename |
Requiredno | DescriptionDisplay filename. If it is not provided, the name is derived from Content-Type. Characters outside a-zA-Z0-9._- → 400 INVALID_FILENAME |
HeaderX-Tags |
Requiredno | DescriptionComma-separated tags. manual and published are recognized — they protect the version from automatic cleanup |
HeaderX-Note |
Requiredno | DescriptionA note stored with the version record |
HeaderX-AI-Session-Id |
Requiredno | DescriptionAI session identifier — groups snapshots in the manifest |
curl -X POST https://vibecode.bitrix24.com/v1/apps/<APP_ID>/sources \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Content-Type: application/gzip" \
-H "X-Tags: manual" \
-H "X-Note: Added OAuth flow" \
--data-binary @app-sources.tar.gz
The code source for a deploy — the source field of POST /v1/infra/servers/:id/deploy accepts three mutually exclusive forms:
| Form | What it is |
|---|---|
Formsource.content |
What it isAn inline base64 archive — always works, including on a Galaxy app |
Formsource.url |
What it isA signed link from Vibecode storage. On a Galaxy app this must be enabled for you separately |
Formsource.versionId |
What it isAn already saved version of the form vN. On a Galaxy app this must be enabled for you separately |
The full walkthrough of saving — Save a snapshot. Auto-save and deploying from a version — Automatic save on deploy.
Quick start
Handing the project over to another developer or a new AI session takes three calls:
# 1. What is already saved for this application
curl -H "X-Api-Key: YOUR_API_KEY" \
https://vibecode.bitrix24.com/v1/apps/<APP_ID>/sources
# 2. A link to the archive of the version you need (valid for 30 minutes)
curl -H "X-Api-Key: YOUR_API_KEY" \
https://vibecode.bitrix24.com/v1/apps/<APP_ID>/sources/v1/download
# 3. Download the archive using that link — no additional headers
curl -o source-v1.tar.gz "<url from the response above>"
Full example
One continuous scenario: save a snapshot, list the versions, download the archive from its link and verify the checksum, then delete the version. The code runs in Node.js 18 or later: save it in an .mjs file, place the app-sources.tar.gz archive next to it, replace <APP_ID> with your application ID, and pass the key in the VIBE_KEY environment variable.
import { readFile } from 'node:fs/promises'
import { createHash } from 'node:crypto'
const VIBE_KEY = process.env.VIBE_KEY
const SOURCES = 'https://vibecode.bitrix24.com/v1/apps/<APP_ID>/sources'
async function api(method, path = '', init = {}) {
const res = await fetch(`${SOURCES}${path}`, {
...init,
method,
headers: { 'X-Api-Key': VIBE_KEY, ...init.headers },
})
const json = await res.json()
if (!json.success) {
throw new Error(`${method} ${path} → ${res.status} ${json.error.code}`)
}
return json.data
}
// 1. Save a snapshot: the body is the raw archive bytes,
// fetch sets the body length itself
const archive = await readFile(
new URL('./app-sources.tar.gz', import.meta.url),
)
const saved = await api('POST', '', {
headers: { 'Content-Type': 'application/gzip' },
body: archive,
})
if (saved.skipped) {
throw new Error(`Source storage is disabled: ${saved.reason}`)
}
console.log(
'Version:', saved.versionId,
'| deduplicated:', saved.deduplicated,
)
// 2. List the application's versions
const list = await api('GET')
console.log(
'Total versions:', list.totalVersions,
'| current:', list.currentVersionId,
)
// 3. Get a link to the archive and download it —
// the link is valid for 30 minutes and needs no key
const { url } = await api('GET', `/${saved.versionId}/download`)
const bytes = Buffer.from(await (await fetch(url)).arrayBuffer())
const sha256 = createHash('sha256').update(bytes).digest('hex')
console.log('Archive matches the saved one:', sha256 === saved.sha256)
// 4. Delete the version if this run created it. With deduplicated: true
// the save returned an existing version with the same bytes —
// the example leaves it alone
if (!saved.deduplicated) {
const deleted = await api('DELETE', `/${saved.versionId}`)
console.log('Deleted version:', deleted.versionId)
}
Endpoint reference
Application snapshots:
| Method | Path | Action |
|---|---|---|
MethodPOST |
Path/v1/apps/:id/sources |
ActionSave a snapshot |
MethodGET |
Path/v1/apps/:id/sources |
ActionList versions |
MethodGET |
Path/v1/apps/:id/sources/:versionId |
ActionGet version metadata |
MethodGET |
Path/v1/apps/:id/sources/:versionId/download |
ActionDownload the archive |
MethodPATCH |
Path/v1/apps/:id/sources/:versionId |
ActionUpdate version metadata |
MethodPOST |
Path/v1/apps/:id/sources/:versionId/tag |
ActionSet or remove a tag |
MethodDELETE |
Path/v1/apps/:id/sources/:versionId |
ActionDelete a version |
MethodPOST |
Path/v1/apps/:id/sources/cleanup |
ActionClear old versions |
Server snapshots — the same family keyed by the server. The differences and the full list of paths are on the Server-keyed source endpoints page.
Aggregated registry: GET /v1/me/sources — every snapshot owner the key can reach, see Source registry.
Error codes
Refusals specific to source storage:
| HTTP | Code | When returned |
|---|---|---|
| HTTP400 | CodeINVALID_CONTENT_TYPE |
When returnedContent-Type is not in the list of allowed archive formats |
| HTTP400 | CodeINVALID_SHA256 |
When returnedThe sha256 parameter is not exactly 64 hexadecimal characters |
| HTTP400 | CodeINVALID_VERSION_ID |
When returnedThe versionId format does not match v<non-negative integer> |
| HTTP400 | CodeINVALID_KEEP_LATEST |
When returnedThe keepLatest value is not a non-negative integer |
| HTTP400 | CodeSOURCE_VERSION_REQUIRES_APP |
When returnedDeploy by versionId onto a server owned by another key, and the server's owner is not bound to an application |
| HTTP403 | CodeNOT_AUTHORIZED |
When returnedThe key is neither an application key, the author's personal key, nor a Bitrix24 account administrator key |
| HTTP403 | CodePORTAL_KEY_REQUIRED |
When returnedThe key is not bound to a portal — the aggregated registry is unavailable to such a key |
| HTTP403 | CodeSOURCE_APP_ID_MISMATCH |
When returnedAn authorization key vibe_app_… targets snapshots of a different application |
| HTTP403 | CodeINFRA_FORBIDDEN_FOR_COWORK_KEY |
When returnedA save, a metadata edit, or a delete was made with a Cowork/Code key — Project key for deploy |
| HTTP403 | CodeEXTERNAL_COLLABORATOR_KEY_SERVER_MISMATCH |
When returnedThe call was made with an external-collaborator key, and the address names a server other than the one the key was issued for. Such a key is valid for exactly one server, and the response does not reveal whether the requested server exists. Working with another server requires the key issued for that external membership |
| HTTP403 | CodeEXTERNAL_COLLABORATOR_NOT_A_MEMBER |
When returnedAn external-collaborator key addresses its own server, but access is not granted right now: the membership was removed, it expired, or external development collaborators are switched off for the Bitrix24 account that owns the server. The code does not tell these reasons apart and reveals nothing about the server. Membership is re-read on every request, so revoked access stops working immediately |
| HTTP404 | CodeAPP_NOT_FOUND |
When returnedThe application does not exist, was deleted, or belongs to another portal |
| HTTP404 | CodeVERSION_NOT_FOUND |
When returnedNo version with that versionId exists, or it was deleted |
| HTTP404 | CodeSOURCE_VERSION_NOT_FOUND |
When returnedThe version was not found in either the server's context or the application's |
| HTTP409 | CodeSNAPSHOT_REQUIRED |
When returnedPublishing without a saved snapshot, or a deploy from an external URL |
| HTTP409 | CodePROTECTED_BY_TAG |
When returnedThe version is protected by the manual or published tag |
| HTTP410 | CodeSOURCE_VERSION_BYTES_PURGED |
When returnedThe version record still exists, but the bytes have already been purged from storage |
| HTTP411 | CodeMISSING_CONTENT_LENGTH |
When returnedThe save request arrived without Content-Length |
| HTTP415 | CodeUNSUPPORTED_ARCHIVE_FORMAT |
When returnedThe first bytes of the archive contradict the declared Content-Type |
| HTTP502 | CodeSOURCE_DOWNLOAD_URL_FAILED |
When returnedStorage is temporarily unavailable — retry the request |
The full reference of API error codes — Error codes.