Skip to main content

Overview

Canvas apps have built-in version control. Every time you publish config changes or deploy a new code bundle, an immutable version record is created with:
  • A content hash (SHA-256) — like a git commit SHA
  • A commit message (required) — describes what changed
  • A full config snapshot — serialized as diffable JSON files
  • Who published and when
You can list all versions, diff any two versions, download previous bundles, and restore (rollback) to any version instantly.

How versioning works

There are two ways a new version is created:
ActionWhat creates the versionWhat’s captured
Publish (POST /v1/apps/{id}/publish)Config snapshot (sections, meta, auth, theme, etc.)Content hash of config, message, config as JSON files
Deploy (POST /v1/apps/{id}/deploy)Code bundle upload (React/JS build)Asset manifest with file hashes, message, optional source files
Both paths create a VersionRecord in the app’s versions array. The version number auto-increments.

Content hashing

When you publish, Mixpeek generates a deterministic SHA-256 hash of your entire config snapshot. This hash changes only when the config actually changes — identical publishes produce the same hash.
v1  →  hash: d733b11021fa  →  "Initial release"
v2  →  hash: e186b986ff96  →  "feat: add custom HTML search interface"
v3  →  hash: d733b11021fa  →  "revert: back to original config"  (same hash as v1!)

Config as diffable files

Your app config is serialized into individual JSON files for each top-level key. This makes version diffs meaningful:
meta.json          →  {"title": "Product Search", "logo_url": "..."}
theme.json         →  {"colors": {"primary": "#FC5185"}}
sections.json      →  [{"type": "search", ...}]
auth_config.json   →  {"mode": "clerk", "clerk_allowed_providers": [...]}
custom_html.json   →  "<div id=\"app\">...</div>"

Listing versions

curl https://api.mixpeek.com/v1/apps/$APP_ID/versions \
  -H "Authorization: Bearer $API_KEY"
Response:
{
  "versions": [
    {
      "version": 2,
      "s3_version_id": "e186b986ff96",
      "message": "feat: add custom HTML search interface",
      "deployed_by": "int_40ed22c147907235",
      "deployed_at": "2026-03-27T13:10:00Z",
      "environment": "production"
    },
    {
      "version": 1,
      "s3_version_id": "d733b11021fa",
      "message": "Initial release",
      "deployed_by": "int_40ed22c147907235",
      "deployed_at": "2026-03-27T13:09:00Z",
      "environment": "production"
    }
  ],
  "total": 2
}

Viewing version details

Get full metadata for a specific version, including the source files snapshot and which environments it’s active in:
curl https://api.mixpeek.com/v1/apps/$APP_ID/versions/1 \
  -H "Authorization: Bearer $API_KEY"
Response:
{
  "version": 1,
  "s3_version_id": "d733b11021fa",
  "message": "Initial release",
  "deployed_by": "int_40ed22c147907235",
  "deployed_at": "2026-03-27T13:09:00Z",
  "environment": "production",
  "source_files": {
    "meta.json": "{\"title\": \"Product Search\"}",
    "theme.json": "{\"colors\": {\"primary\": \"#FC5185\"}}",
    "sections.json": "[]"
  },
  "is_active": {
    "staging": false,
    "production": true
  }
}

Diffing versions

Compare any two versions to see what changed — like git diff v1..v2:
curl https://api.mixpeek.com/v1/apps/$APP_ID/versions/1/diff/2 \
  -H "Authorization: Bearer $API_KEY"
Response:
{
  "app_id": "app_abc123",
  "from_version": 1,
  "to_version": 2,
  "summary": {
    "added": 1,
    "removed": 0,
    "modified": 0,
    "unchanged": 7
  },
  "source_diff": {
    "custom_html.json": "--- v1/custom_html.json\n+++ v2/custom_html.json\n@@ -0,0 +1 @@\n+\"<div><h1>Custom Search</h1></div>\""
  }
}
The summary counts file-level changes (based on content hashes). The source_diff provides unified diffs of the actual content — the same format as git diff.

Rollback

Quick rollback (one level)

Restore the previous published config instantly:
curl -X POST https://api.mixpeek.com/v1/apps/$APP_ID/rollback \
  -H "Authorization: Bearer $API_KEY"

Restore any version

For deploy-based versions (code bundles), restore any specific version to any environment:
curl -X POST https://api.mixpeek.com/v1/apps/$APP_ID/versions/3/restore \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"environment": "production"}'
This is instant — no rebuild required. The previous assets are always retained in S3.

Download a version’s bundle

Download the original zip bundle for any deployed version and work locally:
1

Download the bundle

curl https://api.mixpeek.com/v1/apps/$APP_ID/versions/2/download \
  -H "Authorization: Bearer $API_KEY"
Response:
{
  "download_url": "https://s3.amazonaws.com/...",
  "version": 2,
  "asset_prefix": "apps/my-app/dep_abc123",
  "expires_in": 3600
}
2

Download and extract

curl -o bundle.zip "$DOWNLOAD_URL"
unzip bundle.zip -d my-app/
3

Edit files locally

Make your changes to the extracted source.
4

Re-zip and deploy

cd my-app && zip -r ../updated.zip .
# Upload and deploy as usual (see Deploy from Code)

Git metadata

When deploying via CI/CD or the CLI, you can attach git metadata to each version for full traceability:
curl -X POST https://api.mixpeek.com/v1/apps/$APP_ID/deploy \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "cli_upload",
    "bundle_s3_key": "$BUNDLE_KEY",
    "message": "fix: search results pagination",
    "git_commit_sha": "a1b2c3d4e5f6",
    "git_commit_message": "fix: search results pagination",
    "git_author": "Jane Smith <jane@example.com>"
  }'
Git metadata appears in version detail responses and Studio’s version history panel.
If you connect a GitHub repository via POST /v1/apps/{id}/connect-repo, deploys are triggered automatically on push. Git metadata is captured from the webhook payload — no manual fields needed.

Version record fields

FieldTypeDescription
versionintAuto-incrementing version number
s3_version_idstringContent hash (publish) or S3 version ID (deploy)
asset_prefixstringS3 path prefix for deployed assets
asset_manifestobjectMap of {relative_path: {s3_key, hash, size}}
source_filesobjectMap of {path: content} for source-level diffs
deployed_bystringInternal ID of the user who published/deployed
deployed_atstringISO 8601 timestamp
environmentstring"staging" or "production"
messagestringCommit message (required)
build_duration_msintBuild time in milliseconds (deploy only)
git_commit_shastringGit SHA (if provided)
git_commit_messagestringGit commit message (if provided)
git_authorstringGit author (if provided)