Outcome
Publish a draft as the immutable version consumers resolve.
Before you start
- Verify whoami and the pinned credential context, then inspect the exact discovered action before preparing input.
- Discover a granted Brand workspace. Pass its resourceType/workspace identifier separately from input; a copied fixture identifier grants no access.
- The declared permission is brand:publish. The active credential, application scope, resource binding and runtime authority must all authorize the request.
- Review the exact mutation and recovery, including destructive scope, and execute only after the intended effect is authorized.
Discover the target
topolo whoami --json
topolo actions get app_topolo_brand.brand_kit_versions.publish --detail --json
topolo resources topolo-brand --json
topolo workspaces list topolo-brand --json
Request
POST /api/brand-kits/{brandKitId}/versions/{versionId}/publish
Resource context is the selected Brand workspace. CLI/SDK action input includes path identifiers; direct HTTP JSON bodies exclude path parameters. Read the reviewed plan for the exact request.
Input fields
| Field | Required | Meaning |
|---|---|---|
brandKitId | Yes | Brand kit identifier in the verified Brand workspace. Read brand_kits.list before selecting it. |
versionId | Yes | Exact version identifier from brand_kit_versions.list for brandKitId; not the numeric version. |
Exact published input schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"brandKitId": {
"type": "string",
"minLength": 1,
"description": "Brand kit identifier in the verified Brand workspace. Read brand_kits.list before selecting it."
},
"versionId": {
"type": "string",
"minLength": 1,
"description": "Exact version identifier from brand_kit_versions.list for brandKitId; not the numeric version."
}
},
"required": [
"brandKitId",
"versionId"
],
"additionalProperties": false
}
Effects
Requires an active kit, a draft version and passing snapshot governance. Publishes the draft, retires the former published version, records a lifecycle audit and attempts frozen copies of referenced hosted assets.
Interpret the response
version.status is published. Governance refusal is HTTP 422 with issues. SQL publication can succeed even when an initial frozen-object copy fails; the first public asset read can repair the frozen copy from the original. This is not cross-store atomicity, and repeated publication of the same version returns 404.
Response identifier contract:
{
"kind": "brand_kit_version",
"identifierSource": "response",
"idPath": "$.version.id"
}
Worked examples
These complete synthetic responses were captured from the local worker over canonical SQL migrations. Auth and R2 dependencies are simulated; notification delivery is not exercised. Set BRAND_WORKSPACE_ID from granted workspace discovery. Save reviewed input as payload.json, validate and inspect the unchanged plan. The final mutation command and MCP confirm flag assume the intended effect has already been authorized.
Minimal example
Input · payload.json:
{
"brandKitId": "brand_c794be50-0306-4933-8de8-5609340bed9e",
"versionId": "brand_version_5d0eb310-87f0-4a81-9f27-11240da457e6"
}
CLI:
topolo actions validate app_topolo_brand.brand_kit_versions.publish --data @payload.json --json
topolo actions plan app_topolo_brand.brand_kit_versions.publish --resource-type workspace --resource-id "$BRAND_WORKSPACE_ID" --data @payload.json --json
topolo actions call app_topolo_brand.brand_kit_versions.publish --resource-type workspace --resource-id "$BRAND_WORKSPACE_ID" --data @payload.json --confirm --json
MCP tool and arguments:
{
"tool": "topolo_call_action",
"arguments": {
"actionId": "app_topolo_brand.brand_kit_versions.publish",
"input": {
"brandKitId": "brand_c794be50-0306-4933-8de8-5609340bed9e",
"versionId": "brand_version_5d0eb310-87f0-4a81-9f27-11240da457e6"
},
"resourceType": "workspace",
"resourceId": "<identifier returned by resource discovery>",
"confirm": true
}
}
Captured local response · HTTP 200:
{
"version": {
"id": "brand_version_5d0eb310-87f0-4a81-9f27-11240da457e6",
"brandKitId": "brand_c794be50-0306-4933-8de8-5609340bed9e",
"version": 1,
"status": "published",
"snapshot": {
"identity": {
"displayName": "Fixture identity",
"shortDescription": "The next generation of software.",
"domains": [
"topolo.io"
],
"locales": [
"en"
]
},
"visual": {
"logos": {
"primaryAssetId": "brand_asset_dd192c95-76da-4c2e-a61c-8b164686806b"
},
"palette": {
"primary": "#111827",
"secondary": "#E5E7EB",
"accent": "#F97316",
"background": "#FFFFFF",
"foreground": "#111827",
"semantic": {}
},
"typography": {
"heading": {
"family": "Inter",
"weights": [
700
],
"fallback": [
"sans-serif"
]
},
"body": {
"family": "Inter",
"weights": [
400,
600
],
"fallback": [
"sans-serif"
]
}
},
"layout": {
"radius": 16,
"spacingScale": [
4,
8,
16
],
"logoPlacement": "top-left"
},
"imagery": {
"direction": "Bold, graphic, product-led.",
"avoid": [
"generic stock photography"
]
}
},
"verbal": {
"positioning": "Enterprise-grade software without enterprise-era waste.",
"audiences": [
"small businesses"
],
"valuePropositions": [
"One connected software ecosystem"
],
"tone": [
"bold",
"direct"
],
"do": [
"Use specific proof"
],
"dont": [
"Use unsupported superlatives"
],
"bannedTerms": [
"guaranteed riches"
]
},
"claims": [],
"ctas": [],
"assets": [
{
"id": "brand_asset_dd192c95-76da-4c2e-a61c-8b164686806b",
"kind": "logo",
"name": "Fixture logo",
"url": "/api/brand-assets/brand_asset_dd192c95-76da-4c2e-a61c-8b164686806b/content",
"mimeType": "image/svg+xml"
}
],
"accessibility": {
"minimumContrast": 4.5,
"requireAltText": true,
"reducedMotion": true
},
"legal": {
"requiredDisclosures": [],
"prohibitedTopics": []
}
},
"changeNote": "Ready for review",
"createdAt": "2026-10-03T11:23:59.072Z",
"updatedAt": "2026-10-03T11:23:59.081Z",
"publishedAt": "2026-10-03T11:23:59.081Z"
}
}
version.status is published. Governance refusal is HTTP 422 with issues. SQL publication can succeed even when an initial frozen-object copy fails; the first public asset read can repair the frozen copy from the original. This is not cross-store atomicity, and repeated publication of the same version returns 404.
Workflow example
Input · payload.json:
{
"brandKitId": "brand_55886012-13a4-4e95-ad31-3fe2b52cdf20",
"versionId": "brand_version_d00e1d23-0626-418b-ba5c-e9c02b746293"
}
CLI:
topolo actions validate app_topolo_brand.brand_kit_versions.publish --data @payload.json --json
topolo actions plan app_topolo_brand.brand_kit_versions.publish --resource-type workspace --resource-id "$BRAND_WORKSPACE_ID" --data @payload.json --json
topolo actions call app_topolo_brand.brand_kit_versions.publish --resource-type workspace --resource-id "$BRAND_WORKSPACE_ID" --data @payload.json --confirm --json
MCP tool and arguments:
{
"tool": "topolo_call_action",
"arguments": {
"actionId": "app_topolo_brand.brand_kit_versions.publish",
"input": {
"brandKitId": "brand_55886012-13a4-4e95-ad31-3fe2b52cdf20",
"versionId": "brand_version_d00e1d23-0626-418b-ba5c-e9c02b746293"
},
"resourceType": "workspace",
"resourceId": "<identifier returned by resource discovery>",
"confirm": true
}
}
Captured local response · HTTP 200:
{
"version": {
"id": "brand_version_d00e1d23-0626-418b-ba5c-e9c02b746293",
"brandKitId": "brand_55886012-13a4-4e95-ad31-3fe2b52cdf20",
"version": 1,
"status": "published",
"snapshot": {
"identity": {
"displayName": "Fixture identity",
"shortDescription": "The next generation of software.",
"domains": [
"topolo.io"
],
"locales": [
"en"
]
},
"visual": {
"logos": {
"primaryAssetId": "brand_asset_87bffee4-7249-419b-b4c1-8edeeb732d55"
},
"palette": {
"primary": "#111827",
"secondary": "#E5E7EB",
"accent": "#F97316",
"background": "#FFFFFF",
"foreground": "#111827",
"semantic": {}
},
"typography": {
"heading": {
"family": "Inter",
"weights": [
700
],
"fallback": [
"sans-serif"
]
},
"body": {
"family": "Inter",
"weights": [
400,
600
],
"fallback": [
"sans-serif"
]
}
},
"layout": {
"radius": 16,
"spacingScale": [
4,
8,
16
],
"logoPlacement": "top-left"
},
"imagery": {
"direction": "Bold, graphic, product-led.",
"avoid": [
"generic stock photography"
]
}
},
"verbal": {
"positioning": "Enterprise-grade software without enterprise-era waste.",
"audiences": [
"small businesses"
],
"valuePropositions": [
"One connected software ecosystem"
],
"tone": [
"bold",
"direct"
],
"do": [
"Use specific proof"
],
"dont": [
"Use unsupported superlatives"
],
"bannedTerms": [
"guaranteed riches"
]
},
"claims": [],
"ctas": [],
"assets": [
{
"id": "brand_asset_87bffee4-7249-419b-b4c1-8edeeb732d55",
"kind": "logo",
"name": "Fixture logo",
"url": "/api/brand-assets/brand_asset_87bffee4-7249-419b-b4c1-8edeeb732d55/content",
"mimeType": "image/svg+xml"
},
{
"id": "brand_asset_dce3c24f-65dd-4579-913f-9ffbf74619c9",
"kind": "logo",
"name": "Fixture email logo",
"url": "/api/brand-assets/brand_asset_dce3c24f-65dd-4579-913f-9ffbf74619c9/content",
"mimeType": "image/png",
"altText": "Fixture email identity"
}
],
"accessibility": {
"minimumContrast": 4.5,
"requireAltText": true,
"reducedMotion": true
},
"legal": {
"requiredDisclosures": [],
"prohibitedTopics": []
},
"communications": {
"emailLogoAssetId": "brand_asset_dce3c24f-65dd-4579-913f-9ffbf74619c9",
"senderDisplayName": "Fixture identity",
"replyToAddress": "reply@example.invalid",
"supportAddress": "support@example.invalid",
"legalFooter": {
"entityName": "Fixture identity Ltd",
"registeredAddress": "1 Fixture Street, Example City",
"companyNumber": "FIXTURE-001"
},
"unsubscribeText": "Manage your message preferences.",
"footerText": "Synthetic documentation example."
}
},
"changeNote": "Ready for review",
"createdAt": "2026-10-03T11:23:59.115Z",
"updatedAt": "2026-10-03T11:23:59.118Z",
"publishedAt": "2026-10-03T11:23:59.118Z"
}
}
version.status is published. Governance refusal is HTTP 422 with issues. SQL publication can succeed even when an initial frozen-object copy fails; the first public asset read can repair the frozen copy from the original. This is not cross-store atomicity, and repeated publication of the same version returns 404.
readiness corrected example
Input · payload.json:
{
"brandKitId": "brand_5b9a9c07-74db-48cd-85fe-b6cda159a7f7",
"versionId": "brand_version_99d46a87-cdd3-47a8-bb44-7a45c648cb9d"
}
CLI:
topolo actions validate app_topolo_brand.brand_kit_versions.publish --data @payload.json --json
topolo actions plan app_topolo_brand.brand_kit_versions.publish --resource-type workspace --resource-id "$BRAND_WORKSPACE_ID" --data @payload.json --json
topolo actions call app_topolo_brand.brand_kit_versions.publish --resource-type workspace --resource-id "$BRAND_WORKSPACE_ID" --data @payload.json --confirm --json
MCP tool and arguments:
{
"tool": "topolo_call_action",
"arguments": {
"actionId": "app_topolo_brand.brand_kit_versions.publish",
"input": {
"brandKitId": "brand_5b9a9c07-74db-48cd-85fe-b6cda159a7f7",
"versionId": "brand_version_99d46a87-cdd3-47a8-bb44-7a45c648cb9d"
},
"resourceType": "workspace",
"resourceId": "<identifier returned by resource discovery>",
"confirm": true
}
}
Captured local response · HTTP 200:
{
"version": {
"id": "brand_version_99d46a87-cdd3-47a8-bb44-7a45c648cb9d",
"brandKitId": "brand_5b9a9c07-74db-48cd-85fe-b6cda159a7f7",
"version": 1,
"status": "published",
"snapshot": {
"identity": {
"displayName": "Topolo",
"shortDescription": "The next generation of software.",
"domains": [
"topolo.io"
],
"locales": [
"en"
]
},
"visual": {
"logos": {
"primaryAssetId": "external-logo-fixture"
},
"palette": {
"primary": "#111827",
"secondary": "#E5E7EB",
"accent": "#F97316",
"background": "#FFFFFF",
"foreground": "#111827",
"semantic": {}
},
"typography": {
"heading": {
"family": "Inter",
"weights": [
700
],
"fallback": [
"sans-serif"
]
},
"body": {
"family": "Inter",
"weights": [
400,
600
],
"fallback": [
"sans-serif"
]
}
},
"layout": {
"radius": 16,
"spacingScale": [
4,
8,
16
],
"logoPlacement": "top-left"
},
"imagery": {
"direction": "Bold, graphic, product-led.",
"avoid": [
"generic stock photography"
]
}
},
"verbal": {
"positioning": "Enterprise-grade software without enterprise-era waste.",
"audiences": [
"small businesses"
],
"valuePropositions": [
"One connected software ecosystem"
],
"tone": [
"bold",
"direct"
],
"do": [
"Use specific proof"
],
"dont": [
"Use unsupported superlatives"
],
"bannedTerms": [
"guaranteed riches"
]
},
"claims": [],
"ctas": [],
"assets": [
{
"id": "external-logo-fixture",
"kind": "logo",
"name": "External fixture logo",
"url": "https://assets.example.invalid/fixture.svg"
}
],
"accessibility": {
"minimumContrast": 4.5,
"requireAltText": true,
"reducedMotion": true
},
"legal": {
"requiredDisclosures": [],
"prohibitedTopics": []
}
},
"changeNote": "",
"createdAt": "2026-10-03T11:23:59.142Z",
"updatedAt": "2026-10-03T11:23:59.146Z",
"publishedAt": "2026-10-03T11:23:59.146Z"
}
}
version.status is published. Governance refusal is HTTP 422 with issues. SQL publication can succeed even when an initial frozen-object copy fails; the first public asset read can repair the frozen copy from the original. This is not cross-store atomicity, and repeated publication of the same version returns 404.
frozen copy failed example
Input · payload.json:
{
"brandKitId": "brand_1f849ab3-dd0b-42f0-8362-4ca55b07c221",
"versionId": "brand_version_98b79ce8-872e-4e64-a928-6d4615df9e17"
}
CLI:
topolo actions validate app_topolo_brand.brand_kit_versions.publish --data @payload.json --json
topolo actions plan app_topolo_brand.brand_kit_versions.publish --resource-type workspace --resource-id "$BRAND_WORKSPACE_ID" --data @payload.json --json
topolo actions call app_topolo_brand.brand_kit_versions.publish --resource-type workspace --resource-id "$BRAND_WORKSPACE_ID" --data @payload.json --confirm --json
MCP tool and arguments:
{
"tool": "topolo_call_action",
"arguments": {
"actionId": "app_topolo_brand.brand_kit_versions.publish",
"input": {
"brandKitId": "brand_1f849ab3-dd0b-42f0-8362-4ca55b07c221",
"versionId": "brand_version_98b79ce8-872e-4e64-a928-6d4615df9e17"
},
"resourceType": "workspace",
"resourceId": "<identifier returned by resource discovery>",
"confirm": true
}
}
Captured local response · HTTP 200:
{
"version": {
"id": "brand_version_98b79ce8-872e-4e64-a928-6d4615df9e17",
"brandKitId": "brand_1f849ab3-dd0b-42f0-8362-4ca55b07c221",
"version": 1,
"status": "published",
"snapshot": {
"identity": {
"displayName": "Topolo",
"shortDescription": "The next generation of software.",
"domains": [
"topolo.io"
],
"locales": [
"en"
]
},
"visual": {
"logos": {
"primaryAssetId": "brand_asset_d73b3539-66b6-4923-9b0e-bcea5cccb8e8"
},
"palette": {
"primary": "#111827",
"secondary": "#E5E7EB",
"accent": "#F97316",
"background": "#FFFFFF",
"foreground": "#111827",
"semantic": {}
},
"typography": {
"heading": {
"family": "Inter",
"weights": [
700
],
"fallback": [
"sans-serif"
]
},
"body": {
"family": "Inter",
"weights": [
400,
600
],
"fallback": [
"sans-serif"
]
}
},
"layout": {
"radius": 16,
"spacingScale": [
4,
8,
16
],
"logoPlacement": "top-left"
},
"imagery": {
"direction": "Bold, graphic, product-led.",
"avoid": [
"generic stock photography"
]
}
},
"verbal": {
"positioning": "Enterprise-grade software without enterprise-era waste.",
"audiences": [
"small businesses"
],
"valuePropositions": [
"One connected software ecosystem"
],
"tone": [
"bold",
"direct"
],
"do": [
"Use specific proof"
],
"dont": [
"Use unsupported superlatives"
],
"bannedTerms": [
"guaranteed riches"
]
},
"claims": [],
"ctas": [],
"assets": [
{
"id": "brand_asset_d73b3539-66b6-4923-9b0e-bcea5cccb8e8",
"kind": "logo",
"name": "Fixture logo",
"url": "/api/brand-assets/brand_asset_d73b3539-66b6-4923-9b0e-bcea5cccb8e8/content"
}
],
"accessibility": {
"minimumContrast": 4.5,
"requireAltText": true,
"reducedMotion": true
},
"legal": {
"requiredDisclosures": [],
"prohibitedTopics": []
}
},
"changeNote": "",
"createdAt": "2026-10-03T11:23:59.151Z",
"updatedAt": "2026-10-03T11:23:59.152Z",
"publishedAt": "2026-10-03T11:23:59.152Z"
}
}
version.status is published. Governance refusal is HTTP 422 with issues. SQL publication can succeed even when an initial frozen-object copy fails; the first public asset read can repair the frozen copy from the original. This is not cross-store atomicity, and repeated publication of the same version returns 404.
Public asset recovery readback
The following separate anonymous read demonstrates recovery after an initial frozen-copy failure. It is not a second published action.
{
"evidenceForActionId": "app_topolo_brand.brand_kit_versions.publish",
"variant": "public-asset-read-repairs-deferred-freeze",
"method": "GET",
"path": "/api/public/brand-versions/brand_version_98b79ce8-872e-4e64-a928-6d4615df9e17/assets/brand_asset_d73b3539-66b6-4923-9b0e-bcea5cccb8e8",
"status": 200,
"response": {
"contentType": "image/svg+xml",
"contentLength": 6,
"contentBase64": "PHN2Zy8+"
},
"frozenCopyPresentAfterRead": true
}
Verify the result
Read the exact version, kit currentVersionId and intended consumer resolution. Fetch returned public asset URLs anonymously when public availability matters; preserve the publication result before retrying an unknown outcome.
Errors and recovery
refused · HTTP 404
{
"input": {
"brandKitId": "missing-fixture",
"versionId": "missing-version"
},
"response": {
"error": "version_not_found"
}
}
not publishable · HTTP 422
{
"input": {
"brandKitId": "brand_5b9a9c07-74db-48cd-85fe-b6cda159a7f7",
"versionId": "brand_version_99d46a87-cdd3-47a8-bb44-7a45c648cb9d"
},
"response": {
"error": "brand_version_not_publishable",
"valid": false,
"errors": 1,
"warnings": 0,
"issues": [
{
"code": "primary_logo_required",
"severity": "error",
"message": "Select a primary logo before publishing this version.",
"path": "visual.logos.primaryAssetId"
}
]
}
}
retry after partial failure · HTTP 404
{
"input": {
"brandKitId": "brand_1f849ab3-dd0b-42f0-8362-4ca55b07c221",
"versionId": "brand_version_98b79ce8-872e-4e64-a928-6d4615df9e17"
},
"response": {
"error": "version_not_found"
}
}
-
auth_error(HTTP 401): CLI/SDK authentication classification when Auth returns a non-code message: restore the authorized credential, then verify whoami and context. Preserve the exact service message. -
permission_denied(HTTP 403): Use the exact permission and granted resource required by the reviewed action; organization membership alone is insufficient. -
workspace_required(HTTP 400): Discover and select a granted Brand workspace before preparing the request. -
brand_storage_unavailable(HTTP 503): The Brand storage bindings are unavailable. Preserve the request identifier and report the service fault; do not retry an unverified mutation. -
version_not_found(HTTP 404): Discover the exact parent/resource again and inspect its lifecycle status. Missing, inaccessible or immutable resources can share this refusal. -
brand_version_not_publishable(HTTP 422): Inspect the governance issues, update the still-editable draft and validate before a separately approved publication.
Recovery boundary
Published snapshots cannot be edited or unpublished. Restore an earlier snapshot into the working draft, review it and publish a new version.
Related actions
app_topolo_brand.brand_kit_versions.get: Read an exact Brand version and its rendering presentation.app_topolo_brand.brand_kits.resolve_context: Resolve the first eligible brand for a consumer context.
Evidence
Four real local SQLite stores use all canonical migrations; Auth identity/grants and archival plus R2 object storage are explicitly simulated. Notifications are disabled in fixtures. No notification delivery, live mutation, gateway credential parity or deployed environment proof is claimed. Fixture identifiers and timestamps are synthetic and must be replaced by exact authorized resource discovery.