Outcome
Publish a reviewed commercial revision or reconcile its retained attempt while distinguishing catalog receipts, financial effects and control finalization.
POST /api/developer-console/apps/{appId}/pricing/publish
Before you start
Use the original environment, organization, authorized app and platform-confirmed Developers workspace. Discover the current credential-scoped action and any separately required resource binding; never use fictional identifiers for a live operation.
These are confirmed mutations under the published apps:write permission. Target app edit access, developer-workspace status and runtime policy remain authoritative; a plan or GET canWrite flag is not a grant.
Every commercial write to topolo_first_party additionally requires the canonical platform-super-admin commercial predicate. A human must approve the actual commercial scope before a real write.
All examples are source-derived synthetic UNRUN carriers. No application, financial, billing, broker, provider or catalog operation ran. Source/declaration equality is not serving-runtime proof.
Request
Action: app_topolo_developers.apps.pricing.publish. Discover current context, validate/plan the exact payload and confirm its actual commercial effect before any live operation.
{
"appId": "app_docs_fixture",
"expectedRevision": 1
}
Input fields
| Field | Required | Meaning |
|---|---|---|
appId | Yes | Actual authorized app identity in the original organization/workspace. |
expectedRevision | Yes | Exact current revision; positive in the declared publish contract. |
resume | No | Explicit true for unfinished attempts; never authority to replay unknown financial work. |
Effects and state transitions
Shared context authenticates, resolves a platform-issued workspace and checks app access before authoring guards. It can initialize local developer/profile metadata before a later refusal; it does not create a canonical Auth workspace. Revoked and suspended developer access is refused for mutations.
Success uses {success:true,message,data:{appId,kind:"commercial",state}}. The OK display value is reused from the accepted source-qualified pricing.get precedent. Normal errorResponse refusals use an error object with message and optional code/details; raw publication-failure503 carriers instead have a string error and data.state.
The declared output is a permissive structural projection. State carries revision,draft,published,publication; readAppAuthoring validates only a nonnegative safe integer revision and otherwise returns stored metadata. Schema shape is not complete downstream validation.
Publication requires the actual expectedRevision and saved draft; the declared revision is positive and resume is optional. A stored published revision equal to current with status published returns a no-op before fresh eligibility, receipt or broker proof.
Publishing/failed attempts require explicit resume:true before reconciliation. Current registry eligibility must pass. The source computes SHA-256 of canonical JSON with sorted object keys; the retained publication revision must match the current saved revision. A truthy retained draftDigest must match the newly computed digest; a missing or empty retained draftDigest alone does not trigger this guard. If a durable receipt is found, its operation revision and draftDigest must still match.
A resumed call reads appId:commercial:attemptId durable catalog receipt before replaying service work. A matching operation revision/draftDigest is conditionally reconciled into published state. Uncertain reads return503; mismatches return409; an active publishing executionId without a found receipt returns409 instead of starting another execution.
A new allowed execution creates or retains an attempt ID, installs a new executionId/draftDigest/publication time and checkpoints outcomes through whole-state compare-and-swap. Lost ownership yields409. A failed status alone does not prove absence of external effects.
For non-external pricing, the first execution checkpoints commercial unknown before the Auth publish broker. Confirmed commercial.success:true is retained and skips later commercial work. Unresolved commercial outcomes without success are deliberately not replayed: the existing Auth recovery owner must reconcile the saved attempt, revision and immutable financial bindings. No opaque Auth broker carrier or provider outcome is invented here.
External mode skips the commercial publish broker branch. The catalog publisher can still activate permissions, sync first-party Auth projections where applicable, prepare/commit catalog records and emit developer events; a later error does not roll back earlier effects.
Receipts contain catalog_committed status,appId,operationId,generation,bindingDigest,manifestDigest,publishedAt and operation kind/revision/attemptId/draftDigest. The catalog commit guards generation and exact receipt bindings and preserves immutable revision facets. It is not one transaction across financial services, Auth, notifications and authoring control.
After confirmed catalog success the source finalizes authoring state. On exceptions it re-reads the receipt: catalog commit may advance state.published and publication.status even while HTTP503 is returned with string error and data.state. Control-finalization loss may likewise return candidate state after effects. Non-2xx does not always mean the prior published revision remains.
The synthetic receipt’s bindingDigest and manifestDigest are illustrative retained values, not reproduced hashes of a complete fictional app manifest. Its draftDigest is calculated from the exact shown draft. The success example reconciles an existing receipt; it is not a new financial or catalog execution capture.
Worked responses
Already completed publication is a no-op
Complete source-derived synthetic UNRUN HTTP 200. Stored published.revision==state.revision==1 and publication.status is published. The expected-revision check passes. All identifiers, times and receipt data are fictional. No API, billing, broker or provider operation ran.
Request:
{
"appId": "app_docs_fixture",
"expectedRevision": 1
}
Complete representative response:
{
"success": true,
"message": "OK",
"data": {
"appId": "app_docs_fixture",
"kind": "commercial",
"state": {
"revision": 1,
"draft": {
"appId": "app_docs_fixture",
"developerOrgId": "org_docs_fixture",
"mode": "external",
"label": "Publisher billing",
"url": "https://example.invalid/plans"
},
"published": {
"revision": 1,
"draft": {
"appId": "app_docs_fixture",
"developerOrgId": "org_docs_fixture",
"mode": "external",
"label": "Publisher billing",
"url": "https://example.invalid/plans"
},
"publishedAt": "2026-10-23T00:00:00.000Z"
},
"publication": {
"revision": 1,
"attemptId": "11111111-1111-4111-8111-111111111111",
"executionId": "22222222-2222-4222-8222-222222222222",
"draftDigest": "5e76bfe3955501184646ec4da74da5d2ec47f02fd2da4585f7998796ff201b44",
"publishedAt": "2026-10-23T00:00:00.000Z",
"status": "published",
"outcomes": {
"catalog": {
"success": true,
"receipt": {
"status": "catalog_committed",
"appId": "app_docs_fixture",
"operationId": "app_docs_fixture:commercial:11111111-1111-4111-8111-111111111111",
"generation": 1,
"bindingDigest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"manifestDigest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
"publishedAt": "2026-10-23T00:00:00.000Z",
"operation": {
"kind": "commercial",
"revision": 1,
"attemptId": "11111111-1111-4111-8111-111111111111",
"draftDigest": "5e76bfe3955501184646ec4da74da5d2ec47f02fd2da4585f7998796ff201b44"
}
}
}
}
}
}
}
}
This returns stored state before eligibility/receipt/broker work; it is not fresh financial or consumer-adoption proof.
Reconcile a retained durable catalog receipt
Complete source-derived synthetic UNRUN HTTP 200. Current revision1 has the shown draft and a publishing attempt with the shown executionId; outcomes.catalog is {status:unknown,operationId:app_docs_fixture:commercial:11111111-1111-4111-8111-111111111111}. The exact retained durable receipt matches saved revision/draftDigest. It is reconciled before execution-owner refusal or broker replay. All identifiers, times and receipt data are fictional. No API, billing, broker or provider operation ran.
Request:
{
"appId": "app_docs_fixture",
"expectedRevision": 1,
"resume": true
}
Complete representative response:
{
"success": true,
"message": "OK",
"data": {
"appId": "app_docs_fixture",
"kind": "commercial",
"state": {
"revision": 1,
"draft": {
"appId": "app_docs_fixture",
"developerOrgId": "org_docs_fixture",
"mode": "external",
"label": "Publisher billing",
"url": "https://example.invalid/plans"
},
"published": {
"revision": 1,
"draft": {
"appId": "app_docs_fixture",
"developerOrgId": "org_docs_fixture",
"mode": "external",
"label": "Publisher billing",
"url": "https://example.invalid/plans"
},
"publishedAt": "2026-10-23T00:00:00.000Z"
},
"publication": {
"revision": 1,
"attemptId": "11111111-1111-4111-8111-111111111111",
"executionId": "22222222-2222-4222-8222-222222222222",
"draftDigest": "5e76bfe3955501184646ec4da74da5d2ec47f02fd2da4585f7998796ff201b44",
"publishedAt": "2026-10-23T00:00:00.000Z",
"status": "published",
"outcomes": {
"catalog": {
"success": true,
"receipt": {
"status": "catalog_committed",
"appId": "app_docs_fixture",
"operationId": "app_docs_fixture:commercial:11111111-1111-4111-8111-111111111111",
"generation": 1,
"bindingDigest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"manifestDigest": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
"publishedAt": "2026-10-23T00:00:00.000Z",
"operation": {
"kind": "commercial",
"revision": 1,
"attemptId": "11111111-1111-4111-8111-111111111111",
"draftDigest": "5e76bfe3955501184646ec4da74da5d2ec47f02fd2da4585f7998796ff201b44"
}
}
}
}
}
}
}
}
Same attempt/execution identity and draft are retained; published.revision becomes1. This is catalog/control reconciliation, not financial-binding attestation.
Explicit resume is required
Complete source-derived synthetic UNRUN HTTP 409. Current publication is publishing or failed; resume:true is absent. All identifiers, times and receipt data are fictional. No API, billing, broker or provider operation ran.
Request:
{
"appId": "app_docs_fixture",
"expectedRevision": 1
}
Complete representative response:
{
"success": false,
"error": {
"message": "Read publication outcomes and explicitly resume this revision"
}
}
Inspect retained outcomes; a virtual published GET view may still need persisted control reconciliation.
Conflicting durable receipt is refused
Complete source-derived synthetic UNRUN HTTP 409. A retained receipt operation revision or draftDigest differs from the current saved revision. All identifiers, times and receipt data are fictional. No API, billing, broker or provider operation ran.
Request:
{
"appId": "app_docs_fixture",
"expectedRevision": 1,
"resume": true
}
Complete representative response:
{
"success": false,
"error": {
"message": "Catalog receipt does not match the saved revision"
}
}
Preserve both records for the owner; never alter the draft or receipt to force a match.
Catalog receipt read is uncertain
Complete source-derived synthetic UNRUN HTTP 503. An unresolved attempt is resumed and reading/parsing its durable receipt throws. All identifiers, times and receipt data are fictional. No API, billing, broker or provider operation ran.
Request:
{
"appId": "app_docs_fixture",
"expectedRevision": 1,
"resume": true
}
Complete representative response:
{
"success": false,
"error": {
"message": "Catalog outcome could not be read; preserve the attempt before retrying"
}
}
This is not no-commit proof; preserve the attempt. No commercial publish broker follows this branch.
Execution owner still holds the attempt
Complete source-derived synthetic UNRUN HTTP 409. The attempt is publishing with a nonempty executionId; this catalog read found no receipt. All identifiers, times and receipt data are fictional. No API, billing, broker or provider operation ran.
Request:
{
"appId": "app_docs_fixture",
"expectedRevision": 1,
"resume": true
}
Complete representative response:
{
"success": false,
"error": {
"message": "This publication still has an execution owner; inspect its outcomes before resuming"
}
}
Do not run another execution or parallel retry. This read is not global no-effects proof.
Saved draft is required
Complete source-derived synthetic UNRUN HTTP 409. Current revision matches1 but its saved draft is null. All identifiers, times and receipt data are fictional. No API, billing, broker or provider operation ran.
Request:
{
"appId": "app_docs_fixture",
"expectedRevision": 1
}
Complete representative response:
{
"success": false,
"error": {
"message": "Save a draft before publishing"
}
}
Read state and save a separately approved draft with proper authority before publication.
Exact current revision is required
Complete source-derived synthetic UNRUN HTTP 409. Actual current state remains revision1. All identifiers, times and receipt data are fictional. No API, billing, broker or provider operation ran.
Request:
{
"appId": "app_docs_fixture",
"expectedRevision": 2
}
Complete representative response:
{
"success": false,
"error": {
"message": "Read the current revision before saving or publishing"
}
}
Do not guess a later revision or replace an approved draft automatically.
Catalog eligibility is required
Complete source-derived synthetic UNRUN HTTP 409. A saved draft exists, the completed no-op does not apply, and current canPublishDeveloperApp returns false. All identifiers, times and receipt data are fictional. No API, billing, broker or provider operation ran.
Request:
{
"appId": "app_docs_fixture",
"expectedRevision": 1
}
Complete representative response:
{
"success": false,
"error": {
"message": "This app is not eligible for catalog publication"
}
}
Authoring state and a valid plan are not publication eligibility; follow current registry policy.
Verify and recover
-
Retain original app/workspace, actual revision, complete draft, attemptId,executionId,draftDigest and all service/catalog/control outcomes. GET may project published catalog state with control reconciliation_required without persisting finalization.
-
Compare receipt app/operation/revision/digest with the saved attempt. Catalog receipt or publication.status alone does not prove immutable financial binding, checkout, Auth/Notify delivery or consumer adoption.
-
Only use a separately reviewed same-revision resume after authoritative outcome inspection. Do not reset metadata, change the retained draft, delete receipts or run parallel retries. Current execution owners and unknown financial work require their existing recovery owner.
-
Any intentional reversal after confirmed publication is a new authorized draft/revision/publication with commercial review. No automatic cross-service rollback exists here; preserve actual request identity and refuse unsupported financial replay.
Source and limits
Frozen Developers source 7b89bd3b39092cdc29f87540847bf99a243f0a40 and retained exact declared schemas were reviewed. Locked @topolo-io/billing-manifest@2.0.0 integrity was compared as data only. No target module, validator, source test or app operation ran. Auth broker implementation and live provider/consumer outcomes remain unproven.
Change log
- 2026-10-23: Prepared source-derived publication and recovery guidance, strict inputs, complete synthetic unrun responses and financial/catalog/control evidence boundaries. No commercial operation executed.