Topolo Docs Topolo Platform
Open workspace

Restore and publish a saved version

Restore and publish a saved snapshot, replacing the current editable draft and creating a new immutable version.

Restore and publish a saved version

Every worked value below is SYNTHETIC / UNRUN; no action was called.

Restore one saved version and publish it, replacing what visitors currently see.

Request

  • Action: app_topolo_web.sites.versions.restore
  • Method and path: POST /api/studio/sites/{siteId}/versions/{versionId}/restore
  • Required permission: app_topolo_web.publish:write
  • Input: {"siteId":"site_synth_01","versionId":"version_synth_01"}
  • Additional input fields: false

How it behaves

State-changing compensating action. It creates and activates a new immutable version from the selected saved snapshot; older versions remain in history. Restore also replaces the current editable draft with a clone of the selected saved snapshot after stripping live draft state; review and preserve any current draft work before confirmation. The action requires publish:write. Resolve versionId from versions.list for the same site, inspect the snapshot and preflight before restoring. Success returns site, newly created version, qualityReport and URLs. The route also attempts placement reconciliation after success; that helper is best-effort and logs/swallow errors, so success is not proof of external placement synchronization.

Worked examples

SYNTHETIC / UNRUN — selected snapshot is publishable

HTTP 200; response body (synthetic/unrun):

{
  "site": {
    "id": "site_synth_01",
    "organizationId": "org_synth_01",
    "workspaceId": "workspace_synth_01",
    "slug": "northstar-studio",
    "name": "Northstar Studio",
    "status": "published",
    "brief": {
      "businessType": "service studio",
      "audience": "fictional launch teams",
      "offer": "launch planning",
      "tone": "clear"
    },
    "draftContent": {
      "intent": "business_site",
      "siteTitle": "Northstar Studio",
      "siteDescription": "A fictional service studio offering careful launch planning.",
      "contactEmail": "hello@example.invalid",
      "navigation": [],
      "footerNavigation": [],
      "menus": [],
      "styleClasses": [],
      "theme": {
        "primary": "#111111",
        "secondary": "#333333",
        "surface": "#ffffff",
        "ink": "#111111",
        "muted": "#444444",
        "accent": "#005fcc",
        "accentSoft": "#111111",
        "glow": "#111111",
        "headingFont": "Inter, system-ui, sans-serif",
        "bodyFont": "Inter, system-ui, sans-serif",
        "radius": "16px"
      },
      "document": {
        "version": 1,
        "pages": [
          {
            "id": "page-home",
            "kind": "page",
            "pageId": "page-home",
            "label": "Home",
            "path": [
              "page-home"
            ],
            "source": {
              "kind": "page",
              "id": "page-home"
            },
            "value": {
              "id": "page-home",
              "slug": "/",
              "title": "Northstar Studio",
              "description": "A fictional service studio offering careful launch planning."
            },
            "children": [
              {
                "kind": "slot",
                "slotKind": "page-body",
                "id": "page-home:body",
                "pageId": "page-home",
                "label": "Page body",
                "path": [
                  "page-home",
                  "slot:body"
                ],
                "parentNodeId": "page-home",
                "source": {
                  "kind": "page",
                  "id": "page-home"
                },
                "accepts": [
                  "layout",
                  "block"
                ],
                "children": [
                  {
                    "kind": "block",
                    "id": "hero-home",
                    "pageId": "page-home",
                    "label": "A clear service path",
                    "path": [
                      "page-home",
                      "slot:body",
                      "sections:0"
                    ],
                    "source": {
                      "kind": "section",
                      "id": "hero-home"
                    },
                    "blockKind": "hero",
                    "sectionKind": "hero",
                    "sectionId": "hero-home",
                    "value": {
                      "id": "hero-home",
                      "kind": "hero",
                      "title": "A clear service path",
                      "body": "A fictional team can plan a launch with careful review.",
                      "primaryAction": {
                        "label": "Contact Northstar",
                        "href": "mailto:hello@example.invalid",
                        "linkKind": "custom",
                        "targetBlank": false
                      }
                    },
                    "children": []
                  }
                ]
              }
            ]
          }
        ]
      },
      "collections": [],
      "codeSnippets": [],
      "seo": {
        "metaTitle": "Northstar Studio | Example",
        "metaDescription": "A fictional service studio for example.invalid readers."
      }
    },
    "draftPreviewToken": "draft-preview-synth-restore",
    "createdAt": "2026-10-20T10:00:00.000Z",
    "updatedAt": "2026-10-23T02:30:00.000Z",
    "currentVersionId": "version_synth_03"
  },
  "version": {
    "id": "version_synth_03",
    "organizationId": "org_synth_01",
    "workspaceId": "workspace_synth_01",
    "siteId": "site_synth_01",
    "versionNumber": 3,
    "label": "Rollback to v1: Initial publish",
    "snapshot": {
      "intent": "business_site",
      "siteTitle": "Northstar Studio",
      "siteDescription": "A fictional service studio offering careful launch planning.",
      "contactEmail": "hello@example.invalid",
      "navigation": [],
      "footerNavigation": [],
      "menus": [],
      "styleClasses": [],
      "theme": {
        "primary": "#111111",
        "secondary": "#333333",
        "surface": "#ffffff",
        "ink": "#111111",
        "muted": "#444444",
        "accent": "#005fcc",
        "accentSoft": "#111111",
        "glow": "#111111",
        "headingFont": "Inter, system-ui, sans-serif",
        "bodyFont": "Inter, system-ui, sans-serif",
        "radius": "16px"
      },
      "document": {
        "version": 1,
        "pages": [
          {
            "id": "page-home",
            "kind": "page",
            "pageId": "page-home",
            "label": "Home",
            "path": [
              "page-home"
            ],
            "source": {
              "kind": "page",
              "id": "page-home"
            },
            "value": {
              "id": "page-home",
              "slug": "/",
              "title": "Northstar Studio",
              "description": "A fictional service studio offering careful launch planning."
            },
            "children": [
              {
                "kind": "slot",
                "slotKind": "page-body",
                "id": "page-home:body",
                "pageId": "page-home",
                "label": "Page body",
                "path": [
                  "page-home",
                  "slot:body"
                ],
                "parentNodeId": "page-home",
                "source": {
                  "kind": "page",
                  "id": "page-home"
                },
                "accepts": [
                  "layout",
                  "block"
                ],
                "children": [
                  {
                    "kind": "block",
                    "id": "hero-home",
                    "pageId": "page-home",
                    "label": "A clear service path",
                    "path": [
                      "page-home",
                      "slot:body",
                      "sections:0"
                    ],
                    "source": {
                      "kind": "section",
                      "id": "hero-home"
                    },
                    "blockKind": "hero",
                    "sectionKind": "hero",
                    "sectionId": "hero-home",
                    "value": {
                      "id": "hero-home",
                      "kind": "hero",
                      "title": "A clear service path",
                      "body": "A fictional team can plan a launch with careful review.",
                      "primaryAction": {
                        "label": "Contact Northstar",
                        "href": "mailto:hello@example.invalid",
                        "linkKind": "custom",
                        "targetBlank": false
                      }
                    },
                    "children": []
                  }
                ]
              }
            ]
          }
        ]
      },
      "collections": [],
      "codeSnippets": [],
      "seo": {
        "metaTitle": "Northstar Studio | Example",
        "metaDescription": "A fictional service studio for example.invalid readers."
      }
    },
    "previewToken": "published-preview-synth-03",
    "publishedAt": "2026-10-23T02:30:00.000Z"
  },
  "qualityReport": {
    "generatedAt": "2026-10-23T02:30:00.000Z",
    "score": 92,
    "issues": [
      {
        "id": "asset_library_empty",
        "severity": "info",
        "title": "No assets in the library yet",
        "detail": "Load at least a logo or hero reference so the site can move beyond pure text-only scaffolding."
      },
      {
        "id": "no_form_signal",
        "severity": "info",
        "title": "No captured form submissions yet",
        "detail": "This is normal for a fresh site, but launch monitoring should confirm the lead path is working."
      }
    ]
  },
  "urls": {
    "previewUrl": "https://runtime.example.invalid/?preview=draft-preview-synth-restore",
    "publicUrl": "https://northstar.example.invalid"
  }
}

SYNTHETIC / UNRUN — restored snapshot is blocked by launch quality

HTTP 422; response body (synthetic/unrun):

{
  "error": "Resolve launch-blocking quality issues before publishing.",
  "qualityReport": {
    "generatedAt": "2026-10-23T02:30:00.000Z",
    "score": 72,
    "issues": [
      {
        "id": "hero_action_missing",
        "severity": "error",
        "title": "Hero section has no primary action",
        "detail": "The landing experience should expose one clear next step from the first screen."
      },
      {
        "id": "asset_library_empty",
        "severity": "info",
        "title": "No assets in the library yet",
        "detail": "Load at least a logo or hero reference so the site can move beyond pure text-only scaffolding."
      },
      {
        "id": "no_form_signal",
        "severity": "info",
        "title": "No captured form submissions yet",
        "detail": "This is normal for a fresh site, but launch monitoring should confirm the lead path is working."
      }
    ]
  }
}

SYNTHETIC / UNRUN — version does not belong to this site or scope

HTTP 404; response body (synthetic/unrun):

{
  "error": "Version not found"
}

Errors and recovery

The declared agent contract calls the not-found code version_not_found. The pinned route returns 404 via localized versionNotFound text (default English: Version not found), and returns 422 {error, qualityReport} when the selected snapshot fails publish quality; this source-backed 422 is absent from descriptor agentContract.errors. Preflight checks the current editable draft and does not certify the historical snapshot chosen for restore. A saved snapshot is immutable: if restore returns 422, choose another saved version or use the separately authorized normal draft-update and publish workflow for corrected content. Before confirmation, preserve current draft work you may need. Because the route has no idempotency key or expected-current-version guard and persistence precedes cache publication, an error or lost response does not prove no change. Read back sites.get and sites.versions.list and compare the currentVersionId and new version records before any retry; do not retry blindly. If the outcome remains unclear, stop and reconcile. A successful restore can be compensated by restoring the previously active version, which creates yet another version and does not erase history. Placement reconciliation is attempted after the restore result, but errors are logged and swallowed; provider effects and completion remain UNKNOWN.

Who should use this guide

For authorized site publishers handling rollback/recovery. Typed guide should be used by callers that need to branch on 200, 404 and source-backed 422; include explicit confirmation before execution.

Provenance and change log

Pinned d9 source d9c75819abedaf71f9436a1d200015883a291072 (tree 186133adb5823723307184dcbd77acb1814317a1) plus the exact saved action descriptor in the current detailed catalog. The action metadata in the saved detailed catalog is bound by SHA-256 0d37dbcd6b71ee45f4e09d2a34dcb8331676dd2c0ea2184460400ec1abe688fc. Relevant implementation paths at revision d9c75819abedaf71f9436a1d200015883a291072: apps/api/src/repositories/store/sites.ts:955-996, apps/api/src/repositories/store/sites.ts:1011-1022, apps/api/src/routes/studio.ts:761-774, apps/api/src/routes/studio.ts:166-172. Current-source freshness beyond the saved d9/release association is UNKNOWN; this is not fresh production action readback.

Change log — 2026-10-23 — source-derived guide content: aligned method/path/permission and input to the saved current descriptor; added synthetic/unrun branch examples; documented source behavior and recovery; left missing/ambiguous envelopes and output schema gaps explicit.

Correction change log — 2026-10-23: documented draft replacement and preservation, selected-snapshot quality checks versus current-draft preflight, immutable history, absent idempotency/current-version guards, persist-before-cache ordering, and read-back before retry after an unknown response. The source-backed 422 and placement UNKNOWN remain explicit.

Unresolved: The route-localized not-found text and provider-side reconciliation effects/completion are not verified by execution. Exact auth error envelopes are not claimed.