Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.launchmystore.io/llms.txt

Use this file to discover all available pages before exploring further.

App Versioning & Rollback

LaunchMyStore tracks every release of your app as an immutable version record. Merchants install a version, not just an app — which means a bad release can be rolled back per-merchant without you re-publishing fixed code, and merchants can choose between auto-update (always run the latest) or pinning (stay on a known-good version). This page walks through the full lifecycle: create → publish → deprecate → rollback.

Why Versioning Matters

Safe rollouts

Publish a version. If reports come in, deprecate it — auto-update merchants stay where they are; new installs get the previous version.

Per-merchant rollback

A single merchant hitting an edge case can pin themselves to v1.4.2 while the rest of the world runs v1.5.0.

Audit trail

Every publish, deprecate, and rollback is recorded with actor + timestamp in the version changelog.

Predictable behavior

Once a version is published, its extensions, functions, and wasmPaths are frozen. Editing them creates a new version.

Version Lifecycle

   ┌─────────┐   publish    ┌────────────┐   deprecate   ┌─────────────┐
   │  draft  │ ───────────▶ │ published  │ ────────────▶ │ deprecated  │
   └─────────┘              └────────────┘               └─────────────┘
        ▲                         │
        │                         │  (auto when newer version published)
        └─────────────────────────┘
StatusMeaningInstallable?Visible in Marketplace?
draftCreated but not yet releasedNoNo
publishedCurrent live versionYes (default for new installs)Yes
deprecatedPreviously published, supersededYes (rollback target)No (existing installs only)
A version can never go backwards in the lifecycle — once deprecated, it cannot become published again. Cut a new version instead.

Semver Requirements

Every version string must be valid semver:
  • 1.0.0
  • 2.3.1-beta.4
  • 1.0 ❌ (missing patch)
  • v1.0.0 ❌ (no leading v)
The new version must be strictly greater than the latest published version. This is enforced server-side via semver.gt().
Latest published: 1.4.2
✅ Allowed: 1.4.3, 1.5.0, 2.0.0
❌ Rejected: 1.4.2, 1.4.1, 1.0.0
Pre-release tags (-beta, -rc.1) are allowed and follow standard semver precedence: 1.5.0-beta.1 < 1.5.0-rc.1 < 1.5.0.

Create a Draft Version

POST /apps/developer/:appId/versions
Authorization: Bearer <developer-jwt>
{
  "version": "1.5.0",
  "releaseNotes": "Adds dark mode + Czech translations.",
  "extensions": { /* extension manifest snapshot — optional */ },
  "functions":  { /* function manifest snapshot — optional */ }
}
If extensions / functions are omitted, the API snapshots the app’s current values. The snapshot is immutable — re-installing the app will not push fresh extension code into a published version. Cut a new version instead. Response (201):
{
  "id": "ver_01HZ...",
  "appId": "app_01H...",
  "version": "1.5.0",
  "status": "draft",
  "releaseNotes": "Adds dark mode + Czech translations.",
  "createdAt": "2026-05-06T12:00:00.000Z",
  "createdBy": "dev_01H..."
}

Publish a Version

POST /apps/developer/:appId/versions/:version/publish
Authorization: Bearer <developer-jwt>
What happens server-side:
  1. Validates the target version exists and is in draft status
  2. Marks the previous published version as deprecated (deprecated_at = now)
  3. Marks the target version published (published_at = now)
  4. Updates the parent app’s version column to the new version string
  5. Cascades to installations: every app_installation row with auto_update = true gets installed_version updated to the new version
  6. Writes a row to app_version_changelog with action = 'published'
Installations with auto_update = false (pinned) are left untouched.
Publishing is not reversible. If you publish a broken version, you cannot un-publish it — the only path forward is to publish a new version that fixes the bug, or deprecate it (which removes it from new installs but keeps existing installs running it).

Deprecate a Version

POST /apps/developer/:appId/versions/:version/deprecate
Authorization: Bearer <developer-jwt>
Sets the version to deprecated and stamps deprecated_at. Existing installations are not migrated — merchants pinned to it stay there. New installs and auto-update merchants will fall back to the most recent non-deprecated version. Use this when:
  • A version has a critical bug and you’ve already published a fix
  • You want to remove a version from the marketplace listing without forcing migrations

List Versions

GET /apps/developer/:appId/versions
Authorization: Bearer <developer-jwt>
Returns all versions (drafts + published + deprecated), newest first.

Version Stats

GET /apps/developer/:appId/versions/stats
Authorization: Bearer <developer-jwt>
Returns install-count breakdown per version — useful for deciding when it’s safe to deprecate an older version.
[
  { "version": "1.5.0", "status": "published",  "publishedAt": "...", "installCount": 1240 },
  { "version": "1.4.2", "status": "deprecated", "publishedAt": "...", "installCount": 86 },
  { "version": "1.4.1", "status": "deprecated", "publishedAt": "...", "installCount": 3 }
]

Per-Installation Rollback (Merchant Side)

A merchant who hits a bug in 1.5.0 can roll their store back to 1.4.2 without affecting any other merchant.
POST /apps/store/installations/:installationId/rollback
Authorization: Bearer <merchant-jwt>
{ "targetVersion": "1.4.2" }
What happens:
  1. Verifies the target version exists and is published or deprecated (cannot rollback to draft)
  2. Updates app_installation:
    • installed_version = '1.4.2'
    • pinned_version = '1.4.2'
    • auto_update = false ← key side effect
The merchant is now pinned: future publishes will not touch them.

Resume Auto-Update

When the merchant is ready to re-join the auto-update channel:
POST /apps/store/installations/:installationId/resume-auto-update
Authorization: Bearer <merchant-jwt>
This:
  • Sets auto_update = true
  • Clears pinned_version
  • Updates installed_version to the current published version

Auto-Update vs Pinned

SettingWhen publishes happenUse case
auto_update = true (default)Installation jumps to new version immediatelyMost merchants — they want bug fixes & features
auto_update = false (pinned)Installation stays on pinned_version until manually changedEnterprise merchants on a change-control schedule, or merchants who hit a regression
Pinning is always a per-installation decision — there is no app-wide “freeze auto-updates” setting.

Snapshotting What Goes In a Version

A version captures three things at publish time:
  1. extensions — JSON manifest of every block, snippet, checkout extension, post-purchase extension, and admin extension shipped by the app
  2. functions — JSON manifest of every function (cart_transform, shipping_rate, etc.), including their input schema and target
  3. wasmPaths — R2 storage paths for compiled WASM modules
Once published, these are read-only. The renderer and function-runner load extension/WASM bytes by version — meaning two merchants on different versions of the same app run different code paths simultaneously.

Breaking Changes & Migrations

If a new version requires merchants to do something (re-grant scopes, configure new settings, etc.):
  1. Bump the major version (1.x.x2.0.0) so the change is visible
  2. Document the breaking change in releaseNotes
  3. Consider keeping the previous major version published for 30+ days so merchants have time to migrate
  4. Use the app/scopes_update webhook (sent on every publish) to notify yourself when an installation actually picks up the new version

CLI Workflow

The lms CLI wraps the version endpoints. Run any of these from inside an app project — --app is inferred from .lmsrc.json and only needs to be passed explicitly when you’re outside the project directory.
lms app version create --version 1.5.0 --notes "Adds dark mode"
lms app version publish 1.5.0

Merchant-side rollback

These commands act on a specific installation (a merchant’s install of your app), not on the app itself. Use them when a merchant reports a regression or wants to opt back into auto-updates.
# Pin installation `inst_01HZ...` to v1.4.2.
# Side effect: sets auto_update = false on that installation.
lms app rollback inst_01HZ... 1.4.2
lms app rollback calls POST /apps/store/installations/:id/rollback and lms app resume-auto-update calls POST /apps/store/installations/:id/resume-auto-update — see Per-Installation Rollback above for the server-side behavior.

Best Practices

Drafts in CustomerLMS are records, not installable artifacts — the install path requires a published or deprecated version, so there’s no “install this draft on a test store” shortcut. Instead, test before you bump the version:
  • Iterate locally with lms app dev (live-reloads extensions into a dev store) and lms function test (runs declarative functions against fixture inputs).
  • Install your app on a developer-owned test store from a previous published version, then point that install at your in-progress code via the dev tunnel.
  • Only run lms app deploy (or version create + version publish) once the change is green on the test store.
A published version is permanent — you cannot un-publish, only deprecate or supersede.
Don’t deprecate the previous version the same minute you publish a new one. Wait 24-48 hours so any auto-update merchants who hit a bug have a known-good rollback target.
PATCH (1.4.2 → 1.4.3) for bug fixes. MINOR (1.4.0 → 1.5.0) for backwards-compatible features. MAJOR (1.x.x → 2.0.0) for breaking changes that need merchant action.
releaseNotes is shown to merchants in the dashboard before they auto-update. “Fixed bug in cart” is useless. “Fixed: cart total was off by $0.01 when discount + tax both applied” is useful.
Treat the version snapshot as a build artifact. Your source-of-truth is your git repo + CI pipeline that calls lms app version create on every release tag.
  • App Lifecycle — install/uninstall webhooks fire on every version change
  • CLI Setuplms app version * commands
  • Webhooksapp/scopes_update notifies you when a merchant picks up a new version