# Automatic save on deploy

The platform saves a source snapshot by itself, on every successful deployment. This page covers what goes into a snapshot automatically, how to read the outcome in the deploy response, when saving is skipped, and the three cases where a snapshot is still saved by hand.

Storage overview and the endpoint reference — [Source code storage](/docs/source-storage).

## Saving sources

Since the 2026-05-23 release the platform **automatically** saves the source bytes to storage on every successful deployment. This applies to:

- `POST /v1/infra/servers/:id/deploy { source: { content: <base64> } }` — the inline bytes are saved as a new version
- `POST /v1/infra/servers/:id/deploy { source: { url: <signed URL from storage> } }` — the existing version is linked to the deployment identifier
- `POST /v1/infra/servers/:id/deploy { source: { versionId: 'vN' } }` — the same

**For a Galaxy app, deploying from a link or a saved version must be enabled for you separately.** On standalone virtual machines (`kind` is `STANDALONE`) every variant from the list above works. For a Galaxy app (`kind` is `GALAXY_APP`) the inline `source.content` always works, while `source.url` and `source.versionId` work where the platform has enabled link deploys for you; otherwise the request is rejected with `400 GALAXY_DEPLOY_CONTENT_ONLY`. On a Galaxy app the link itself must point at this storage — an outside address is rejected with `400 GALAXY_SOURCE_URL_NOT_ALLOWED`. See [Galaxy app](/docs/infra/galaxy) for details.

**Exception**: deployment with an external URL (not from Vibecode storage) returns **409 SNAPSHOT_REQUIRED**. To work around it — either first upload an archive via `POST /v1/apps/:id/sources` and deploy via `{source: {versionId: 'vN'}}`, or pass the `X-Skip-Source-Snapshot: <reason>` header to explicitly opt out.

### Deploy response: the `source` block

The `POST /v1/infra/servers/:id/deploy` response includes a `data.source` block — the auto-save outcome. An AI agent or client reads it to tell whether the code reached storage:

```json
{
  "success": true,
  "data": {
    "status": "running",
    "appUrl": "https://app-b7c1e2a4.vibecode.bitrix24.com",
    "source": {
      "autoSaved": true,
      "savedVersionId": "v4",
      "sha256": "a3f5d8b2c1e9f4...",
      "linkedDeployId": "deploy:2026-05-21T10:15:30.000Z",
      "skippedReason": null
    }
  }
}
```

| Field | Type | Description |
|------|-----|----------|
| `source.autoSaved` | boolean | `true` — snapshot saved; `false` — skipped (reason in `skippedReason`) |
| `source.savedVersionId` | string \| absent | Identifier of the created version (`vN`) when `autoSaved: true` |
| `source.sha256` | string \| absent | SHA-256 of the saved archive |
| `source.linkedDeployId` | string \| absent | Identifier of the deployment the snapshot is linked to |
| `source.skippedReason` | string \| null | `null` on success; otherwise the skip reason (see below) |

The deployment completes successfully (`200`) regardless of the `source` block — auto-save is best-effort and never fails the deployment. Values of `skippedReason`:

| `skippedReason` | When |
|-----------------|-------|
| `feature-disabled-platform` | Source deposit is disabled at the platform level |
| `feature-disabled-portal` | The Bitrix24 account owner disabled source deposit for their account |
| `external-url-or-toggles-off` | The source is an external URL (not from Vibecode storage) |
| `save-failed` | Transient storage error — retry the deploy or save manually via `POST /v1/apps/:id/sources` |
| `<header value>` | `X-Skip-Source-Snapshot: <reason>` was passed — the snapshot was skipped intentionally |

To confirm the code was deposited, check `data.source.autoSaved === true` and store `savedVersionId` for later rollback or handoff.

### When a snapshot is not created

If source saving is disabled for the Bitrix24 account or the source is an external URL (not Vibecode storage), no snapshot is created and the deployment completes normally. To save a version explicitly, upload an archive via `POST /v1/apps/:id/sources`.

### When `POST /sources` is still needed explicitly

Only three scenarios:

1. **Mark a version** — set a `manual` or `published` tag so the version is stored indefinitely.
2. **Save without deploying** — record an intermediate result for handoff to another developer.
3. **Prepare for a rollback** — a snapshot of the initial state before a risky change.

## When to call

Typical scenario for an AI agent (since 2026-05-23 an explicit `POST /sources` call before deploy is not required — the platform saves automatically):

1. Change the code → `POST /v1/infra/servers/:id/deploy` — sources are saved automatically.
2. `POST /v1/apps/:id/publish` — publishes the application to the Bitrix24 catalog. The `published` tag is added to the snapshot automatically.
3. Repeat the cycle on the next change.

Scenario for handing the project to a new developer or a new AI session:

1. `GET /v1/apps/:id/sources` — list of available versions.
2. `GET /v1/apps/:id/sources/:versionId/download` — signed link to the archive.
3. Download the archive, unpack it, and continue work.

For MCP clients: the `save_sources` tool packs the file tree into tar.gz on the client side and sends it in a single request. The `load_sources` tool downloads the latest version and unpacks it back into a file tree. A direct HTTP endpoint call is available for clients that pack the archive themselves.

## Deploy from a snapshot

`POST /v1/infra/servers/:id/deploy` accepts the `source.versionId` field — an alternative to `source.url` and `source.content`. It lets you deploy the exact version saved via `save_sources` to the server, without a separate file upload.

```json
{
  "source": {
    "versionId": "v3"
  },
  "start": "node server.js"
}
```

The server resolves `versionId` into a signed link to the archive and performs the deploy. After a successful or failed deploy, the snapshot's `linkedDeployId` field is updated automatically.

**On a Galaxy app, this must be enabled for you separately.** Deploy by `source.versionId` works on servers whose `kind` is `STANDALONE`. A Galaxy app (`kind` is `GALAXY_APP`) accepts `source.versionId` and `source.url` where the platform has enabled link deploys for you; otherwise the request is rejected with `400 GALAXY_DEPLOY_CONTENT_ONLY` and only the inline `source.content` remains. On a Galaxy app the link must point at this storage — an outside address is rejected with `400 GALAXY_SOURCE_URL_NOT_ALLOWED`. See [Galaxy app](/docs/infra/galaxy) for details.

**How the version is resolved.** When the server belongs to the same key that makes the call, the version is looked up in that server's context — this is what makes the "save through `POST /v1/infra/servers/:id/sources`, then deploy by `versionId`" pair work, including on a personal key (`vibe_api_*`). If the server holds no such version and the owning key is bound to an application, the lookup is repeated in the application's context — that is what deploys a version saved before the server was replaced. Not found in either context — `404 SOURCE_VERSION_NOT_FOUND`.

**Restriction:** it has narrowed and now applies only when the server belongs to a key other than the calling one — a management key, or access through an application card. There the version is still looked up in the application's context only, and when the server's owning key is not bound to an application, `400 SOURCE_VERSION_REQUIRES_APP` is returned.

## Behavior for AI models

The `save_sources` MCP tool wraps `POST /v1/apps/:id/sources`. The `load_sources` tool downloads and unpacks the latest snapshot into a file tree.

Since 2026-05-23 an explicit `save_sources` call before deployment is not required — the platform saves the bytes automatically. `save_sources` is still needed only for the three explicit scenarios (the "Saving sources" section above).

Channels through which the model learns about source saving:

- The descriptions of the `save_sources` and `load_sources` MCP tools — visible on first use.
- The hint in the `409 SNAPSHOT_REQUIRED` response (deployment with an external URL) — suggests uploading via `POST /sources` or passing `X-Skip-Source-Snapshot`.
- The hint in the `409 SNAPSHOT_REQUIRED` response (publishing without a saved snapshot) — guides the model into the `publish → save_sources → publish` cycle (relevant if the source is an external URL and auto-saving was skipped).
- The `capabilities.apps.sourceStorage` block in the `GET /v1/me` response — a programmatic state check.

## See also

- [Source code storage](/docs/source-storage)
- [Save a snapshot](/docs/source-storage/save)
- [Snapshot before publishing](/docs/source-storage/publish)
- [Version list and download](/docs/source-storage/versions)
- [Deploy API](/docs/infra/deploy)
- [MCP for AI](/docs/mcp)
