Cloud commerce onboarding
Before a market can sell a paid plan, the Cloud operator publishes the commercial catalogue and releases the market. Everything happens in Operator console → Commerce catalogue, in five numbered steps. Each write asks for a recent password confirmation and is recorded in the audit trail.
The Readiness panel at the top of the section names every precondition for a seller, market and currency and shows which ones are still missing. When all of them are green, customers of that market can buy through Subscription.
Keep one market per currency for a seller. A customer never chooses a market: their acceptance of the terms is recorded for the one market that sells in their account’s currency. With two markets open in the same currency that market is ambiguous, no acceptance is recorded and new customers cannot buy; the readiness panel names the other market so you can close it.
Who does what
| Role | Appointed by | Publishes |
|---|---|---|
| Platform admin | promoted through the operator CLI | appoints the two roles below |
| Finance approver | platform admin | legal seller, public prices, finance approval of a market release |
| Privacy counsel | platform admin | market policy (tax and fiscalisation), counsel approval of a market release |
A platform admin cannot appoint themselves. A market release needs both approvals from two different people.
Step 1 — Appoint the approvers
Enter the user’s e-mail, pick the role and press Appoint. The user must already have a verified Cloud account and operator access. An account without operator access is refused with target_not_operator; promote it first. Revoke removes the role; anything published earlier stays.
Step 2 — Publish the legal seller
Seller code (for example mockarty), country, legal name and status. Publishing the same code again changes its status; a seller is never deleted.
Step 3 — Publish the market policy
A privacy counsel publishes the policy for a seller and market: VAT rate, fiscalisation and the review date. Every publication is a new revision; the previous approved revision retires automatically, so a market always has exactly one current policy.
Step 4 — Publish public prices
A finance approver publishes one price per plan, market and currency, with the billing period and the start date. A newer price closes the previous one at its start, so prices never overlap.
Infrastructure Units need one more step. Publish the top-up price for the plan wallet-topup-infra with the billing period One-time, then, in the Infrastructure Unit rate form under the price form, pick that price and set the price of one unit and our cost of one unit. The form offers only top-up prices that do not have a rate yet. Until a rate exists the top-up shelf does not sell Infrastructure Units, and customers who switched on paying for runner minutes past the plan keep the hard stop.
Step 5 — Release the market
The evidence bundle pins the current terms version, the market policy, the price of the chosen plan and the current versions of the payment and fiscal connectors. Configure those connectors first in Platform connectors (see Cloud platform connectors) with the seller code, market and mode that match the release scope: sandbox uses connectors in test mode, production uses live mode.
- Press Show state — the panel lists what the bundle would pin and what is missing.
- Press Create bundle and gate in your role.
- Approve the gate in your role, then ask the second person to approve in theirs.
When both approvals are in, the gate shows Released and the readiness panel turns green. Any later change to the pinned artifacts — a new price, policy or connector version — needs a new release.
What the customer sees
The buyer accepts the current terms at sign-in; that acceptance becomes the contract evidence for the sale, so there is no second consent at checkout. Subscription creates an order and invoice. Provider checkout redirects to the provider; checkout paid entirely from the promotional balance settles without a redirect. In either case, the invoice becomes paid and the plan is active only after settlement. The cabinet has no refund action: a canceled plan runs to the end of its paid period, and a mistaken charge goes to support. If a stored invoice cannot be read, the cabinet reports a temporary error rather than claiming that it does not exist.
Publish each new terms document under a new numeric version, for example v2 after v1. Reusing the same number under a different label (such as v1b or v01) is rejected: customers must be asked to accept a genuinely new version when the document changes.
The first sale needs one clear selling market. If more than one market fits a new billing account, checkout stops instead of choosing a legal region for the buyer. Support must resolve this before purchase; accepting the terms again does not fix an ambiguous market.
Deployment setting
Paid checkout is enabled with CLOUD_API_BILLING_MODE=provider on the Cloud API. The default free keeps the catalogue editable but refuses paid checkout.
Selecting provider does not, on its own, let the deployment take money. A real charge additionally requires CLOUD_API_ENV=prod and CLOUD_API_LIVE_PAYMENTS=true; with either missing, checkout stays in test mode and the customer is told the market has no approved sandbox release. This is deliberate: an acquirer that is still being contracted must not be charged against because an environment variable was changed for another reason. Balances topped up with a promo code and every deduction path are unaffected — they never touch this contour.
Retail accounting on a new deployment
Allowances are counted from the first request of a deployment; there is nothing to reconcile or switch on. Each Shared runtime replica needs the internal Cloud API addresses for its four authorities — SAAS_RUNTIME_CLOUD_FLOW_GRANT_URLS (monthly requests, runner minutes and egress), SAAS_RUNTIME_CLOUD_MOCK_STOCK_URLS (the account’s mock allowance), SAAS_RUNTIME_CLOUD_SYNC_STORAGE_URLS (Team retained sync storage) and SAAS_RUNTIME_CLOUD_PROVIDER_CLAIM_URLS (the current entitlement of work handed to shared providers) — plus its existing service authentication. In Helm these are runtime.cloudFlowGrantURLs, runtime.cloudMockStockURLs, runtime.cloudSyncStorageURLs and runtime.cloudProviderClaimURLs; the chart refuses to render and the runtime refuses to start without them.
- A new mock is admitted against its host billing account’s allowance; deleting a mock or a mock folder frees the room, and restoring from the recycle bin needs free room again.
- Every protected runtime request obtains its monthly allowance from Cloud. The Usage page labels these figures as reserved allowance: a grant may reserve a small block before every unit in it is used, so the figure is deliberately conservative.
- If Cloud or one of these authorities is unavailable, new protected work is refused until it recovers; the allowance is never reset by changing Spaces or replicas.
- A job held for provider authorization can be delivered only within 15 seconds of its local reservation. After that it is cancelled during recovery or expiry cleanup, which releases its provider slot. Cancelling a held job does not itself promise or trigger a financial refund.
API
All endpoints require an operator session and, for writes, a step-up confirmation and an Idempotency-Key header.
| Method | Path | Role checked by the server |
|---|---|---|
GET |
/api/v1/cloud/operator/commerce/catalogue |
any operator |
GET |
/api/v1/cloud/operator/commerce/readiness?seller=…&market=…¤cy=…&mode=test |
any operator |
PUT |
/api/v1/cloud/operator/commerce/authority-roles |
platform admin |
PUT |
/api/v1/cloud/operator/commerce/sellers |
finance approver |
POST |
/api/v1/cloud/operator/commerce/policies |
privacy counsel |
POST |
/api/v1/cloud/operator/commerce/prices |
finance approver |
POST |
/api/v1/cloud/operator/commerce/team-packages |
finance approver |
POST |
/api/v1/cloud/operator/commerce/infrastructure-rates |
finance approver |
GET |
/api/v1/cloud/operator/commerce/market-release?seller=…&market=…&scope=sandbox&plan=team |
any operator |
POST |
/api/v1/cloud/operator/commerce/market-release/bundles |
privacy counsel or finance approver |
POST |
/api/v1/cloud/operator/commerce/market-release/gates |
privacy counsel or finance approver |
POST |
/api/v1/cloud/operator/commerce/market-release/gates/{gate_id}/approve |
the role named in the request |
A Team package is a 5, 10 or 20 Seat price derived from a published Pro base price and a discount, in its own immutable price lane: publishing a new Pro price later never moves an existing package. In the cabinet the finance approver publishes it from the Team package form under the price form (the form lists the published Pro prices to pick from); over the API the body names the base price version, the same market, currency and billing period, seats (5, 10 or 20), discount_bps (0–9999) and effective_from, with an Idempotency-Key header. A seat count outside the three packages answers 400 bad_request; a base price that is not a public Pro price for that market, currency and period answers 409 commerce_catalogue_conflict.
An Infrastructure Unit rate names commerce_price_version_id (an open wallet-topup-infra price), customer_rate_minor (the price of one unit in minor currency units, above zero), provider_cogs_minor (our cost of one unit, zero or more) and optionally rounding_mode (ceil, floor or half_up; ceil when omitted). A price of another product, or a price that already has a rate, answers 409 commerce_catalogue_conflict. The published rates are listed under infrastructure_rates in the catalogue.
A write by a user without the role answers 403 authority_role_required. A publication that references a missing seller, plan or user answers 409 commerce_catalogue_conflict; a bundle with missing inputs answers 409 market_release_inputs_missing with the list of gaps.
If the catalogue reports 503 commerce_catalogue_unavailable, keep the request ID. A temporary outage may clear on retry; an unexpected publication failure needs support to check the catalogue configuration. The cabinet shows that guidance in the selected language.