Skip to content

v0.1.0

Release Date: 2026-10-22

The first release: a Go-first, machine-readable description of a product's pricing and packaging. A Spec holds the tiers of a product's ladder, the plans in them with their prices, the features and limits each plan sets, one-time products, a marketplace fee, and the application access each tier grants. A pricing page, a limit check, a payment provider's prices and an account's entitlements are computed from it, so none of them is maintained beside it.

Highlights

  • One description of an offer. Tiers with an order; plans with monthly and yearly prices, trials, and free or arranged variants; features that are a switch or an ordered ladder of levels; limits with an optional period and a fair-use flag; fixed and seller-set one-time products; a marketplace fee with per-plan overrides. See Concepts.
  • Safe by construction. An unknown plan is the default plan, an unset feature is off, an unset limit is zero, and "unlimited" is its own field and never a zero or a missing value. The default plan must be free and its tier must grant something.
  • Validated with stable codes. A Spec that breaks an error rule (E001 to E013) is rejected with every error at once, each with a path. Lint warnings (W001 to W006) are for review and never reject.
  • Access is a grant; allowances are looked up. What an account may open and how many members it may have is its tier's grant and travels with its entitlement. Features and limits stay in the Spec and are read by the account's plan at the moment of a check.
  • Projections, not copies. A pricing view for a page to render, an entitlement map from tier to grants, and a diff between two Specs that marks what affects existing customers.
  • A generated JSON Schema from the Go types, linted with the family's schema tool with no findings.

What is in it

Part Contents
SPEC.md The normative description of the model, the validation and lint rules, resolution, and the mapping from a tier to account entitlements
pricingspec The types, Load and Parse, Validate and Lint, the plan, feature and limit helpers, PricingView, EntitlementMap and Diff
schema pricing.schema.json, generated and embedded
examples/ A subscription tool and a marketplace, both invented
docs/ A user guide: concepts, writing a spec, using a spec
spec, err := pricingspec.Load(f)            // strict decode, then validate
spec.Has(account.Plan, "audit_log")
spec.AtLeast(account.Plan, "support", "email")
spec.Check(account.Plan, "boards", boards+1) // Allowed, Warn or Refuse
view := spec.PricingView()
changes := pricingspec.Diff(oldSpec, newSpec)

Rules the model enforces

  • Amounts are integers in the currency's minor units, at most one price per interval.
  • A ladder's levels are ordered and distinct; levels are for ladders where each level includes the one below, and a set of independent options is several switches.
  • A limit is a number or explicitly unlimited. With a number, fair use makes exceeding it warn and flag the account for review; with unlimited, it records that the allowance is subject to the host's fair-use policy.
  • Seats live only in a tier's grants.
  • Every plan names a declared tier, every value a declared feature or limit, and every grant a declared tier and application.

Installation

go get github.com/plexusone/systemspec-pricingpackaging@v0.1.0

Requires Go 1.26. The package imports the standard library only; the schema generator and the tests use invopop/jsonschema and santhosh-tekuri/jsonschema.

Upgrade notes

None: this is the first release. formatVersion is "1"; a reader rejects any other version.

Known limitations

  • One currency per Spec. Prices in several currencies are not expressible.
  • No seat-based or metered prices, coupons, regional pricing or tax. A plan has a flat price per interval.
  • What a purchase issues, who may pay, and what payment may never buy are not in the model. They are policy that stays with the product that uses the Spec.
  • Usage is the host's. The Spec defines an allowance and the check; the host counts usage, including per day or month.
  • No command-line tool. Validation, lint, the pricing view and the diff are library functions.
  • Proven on invented offers and one draft of a real one. The model was checked against three product shapes and its examples, and a billing library that consumes it is being built; a production trial has not happened yet. The format may change before a 1.0 if that trial finds a gap.
  • Format version 1 is a promise only for additive changes: new optional fields do not bump it.

Dependencies

Module Use
github.com/invopop/jsonschema Generating the schema from the types
github.com/santhosh-tekuri/jsonschema/v6 Validating examples against the schema, in tests