Topolo Docs Topolo Platform
Open workspace

Read an app’s commercial authoring state

Read saved pricing drafts and publication outcomes while distinguishing catalog reconciliation, write eligibility and executable commercial configuration.

Outcome

Inspect an app’s saved commercial draft and publication state. Distinguish that metadata from executable billing configuration and unresolved financial outcomes.

GET /api/developer-console/apps/{appId}/pricing

Before you start

Use the original authenticated organization and published Developers apps:read permission. Discover the accessible canonical app and Developers workspace and bind workspace separately; appId input is not a grant.

The route permits suspended profile reads but refuses revoked access and requires app.canRead after a workspace match. It does not require completed onboarding for this GET. Ordinary same-organization workspace selection is Auth-verified; the existing privileged cross-organization platform context uses its seeded profile workspace without honoring a requested header.

This reads commercial authoring metadata. It does not establish effective checkout prices, billing configuration, financial receipt identity, financial publication success or live catalog adoption. Discover separate current mutation authority before changing or publishing pricing.

The response can include an executable field from a downstream commercial read only when no draft is saved. That downstream field is passed through, not normalized by this route. Its full Auth commercial carrier has not been source-qualified here; do not manufacture its schema or an example.

Shared workspace/profile initialization can write before the read or a later refusal. No canonical Auth workspace is created by that initialization.

All examples below are complete source-derived synthetic UNRUN carriers with fictional app and organization identifiers. No app, billing broker, checkout, catalog publication, private authoring or payment operation was called. Immutable source/declaration equality does not prove serving runtime.

Request

Action: app_topolo_developers.apps.pricing.get. Discover the actual app and canonical Developers workspace, bind the workspace separately and validate/plan the current read contract.

{"appId":"app_docs_fixture"}

Interpret the response

The normal saved-draft branch returns HTTP200 {success:true,message,data:{appId,kind:"commercial",state,canWrite}}. Read the nested data carrier. The catalog output schema is a permissive structural projection, not a complete behavioral specification.

The saved state is metadata.appAuthoring.commercial. Missing authoring defaults to revision0,draft:null,published:null,publication:null, but this GET then calls the Auth commercial read broker; it does not simply return that empty state as a successful complete pricing read. A broker result is accepted only when response.ok and data.success===true. A failed broker result becomes HTTP503 Commercial configuration could not be read completely. Transport/JSON exceptions reach the outer console error boundary.

When a draft exists, this GET does not call the commercial read broker and does not validate or apply the saved draft. readAppAuthoring validates only a nonnegative safe-integer revision before returning the stored state; draft/publication details remain saved metadata. Invalid stored revision throws. Saved pricing is not evidence of current financial execution.

canWrite initially requires app.canEdit and a non-read-only developer context. A first-party app additionally requires platform commercial authority (hasPlatformSuperAdminAccess). The flag does not independently grant a future workspace write, current action permission, source/custody or expected-revision authority; the later action must check these itself. A suspended profile can read with canWrite:false.

For a publishing/failed attempt with a saved draft and matching publication.revision/state.revision, the GET tries the durable catalog receipt for that app, commercial kind and retained attempt. A matching operation.draftDigest returns a virtual published snapshot and status:published with catalog.success/receipt and control.status:reconciliation_required. No authoring-control row is persisted by this GET. This is catalog reconciliation, not proof of the financial broker attempt.

A thrown catalog receipt read/digest operation makes canWrite:false and returns a publication view with catalogReadback.status:unknown. Preserve the saved attempt/outcomes; this is not a rollback, absence proof or replay clearance. When state.draft is null, the no-draft broker branch returns the original state variable, not that virtual visibleState variable.

Successful downstream commercial configuration can be returned as data.executable only in the no-draft branch. It is a raw service carrier; this guide intentionally does not invent its nested financial bindings, revisions or recovery receipt schema. Follow the current separately published Auth commercial contract and its owner when exact financial evidence is needed.

The handler does not save a draft, publish prices, call the commercial publish broker, create payment objects or change checkout state. Context initialization is the separate possible local write. Do not use the catalog’s generic restore_previous instruction as a rollback for this read; saving/publishing a prior draft is a distinct authorized mutation with financial effects.

Worked responses

Saved external-pricing draft

Complete source-derived synthetic UNRUN HTTP200. Accessible developer-owned app; editable app and non-suspended profile. A non-null saved draft selects the no-commercial-read-broker branch. Fictional identifiers and example.invalid confer no access; no draft was saved or published.

{
  "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": "Contact the publisher",
        "url": "https://example.invalid/pricing"
      },
      "published": null,
      "publication": null
    },
    "canWrite": true
  }
}

Retain the actual revision and full draft/publication state. canWrite is a projection, not a grant or financial execution proof.

Viewer reads the saved draft

Complete source-derived synthetic UNRUN HTTP200. Same saved non-null draft; an authorized app viewer has app.canEdit:false. The false flag here is not a receipt-failure diagnosis. Fictional identifiers and example.invalid confer no access; no draft was saved or published.

{
  "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": "Contact the publisher",
        "url": "https://example.invalid/pricing"
      },
      "published": null,
      "publication": null
    },
    "canWrite": false
  }
}

Retain the actual revision and full draft/publication state. canWrite is a projection, not a grant or financial execution proof.

Commercial broker read refused with no saved draft

Complete source-derived synthetic UNRUN HTTP503. The app is accessible and commercial state has draft:null; the downstream result did not satisfy response.ok and success:true. No private broker response is fabricated. This is not a financial-publish call or a receipt-reconciliation failure.

{
  "success": false,
  "error": {
    "message": "Commercial configuration could not be read completely"
  }
}

Preserve refusal and request identity; do not substitute empty pricing, publish/reset a draft or infer no financial configuration exists.

App absent or inaccessible

Complete synthetic UNRUN HTTP404 for missing app or selected-workspace/actor mismatch after shared context. It does not imply global nonexistence or prove no initialization happened.

{
  "success": false,
  "error": {
    "message": "Developer app not found"
  }
}

Retain actual original context/refusal/request id; no alternate organization, guessed id or state reset as recovery.

Verify and recover

  1. Compare data.appId and kind:commercial with the originally authorized app/workspace. Retain the actual complete state.revision, saved draft, published snapshot and publication attempt/outcomes.

  2. Distinguish a saved draft branch from the no-draft downstream executable branch, suspended/viewer/first-party-authority canWrite restrictions, and a virtual catalog reconciliation. A returned published view can still require control reconciliation.

  3. Preserve catalogReadback:unknown or a refused/incomplete broker read. Catalog receipts do not establish immutable financial price bindings or safe commercial replay. Escalate unresolved financial outcomes to the existing Auth commercial owner.

  4. For a later change, discover and plan the separate current save/publish action with actual current expectedRevision and concrete authority. No synthetic example, canWrite flag or generic read rollback authorizes that mutation.

Change log

  • 2026-10-23: Documented commercial authoring read branches, coarse write eligibility, virtual catalog reconciliation, downstream carrier limits and complete synthetic unrun responses. No pricing or financial operation was executed.