Help us shape the future of Go! Take the 2026 Go Developer Survey

pricingspec

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 22, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package pricingspec is a machine-readable description of a product's pricing and packaging: the tiers of its ladder, the plans in them with their prices, the features and limits each plan sets, its one-time products, an optional marketplace fee, and the grants each tier gives an account.

A Spec is the source of truth. A pricing page, a limit check, a payment provider's prices and an account's entitlements are computed from it. The normative description is SPEC.md at the root of the repository; the types in this package are its Go form, and the JSON Schema in the schema package is generated from them.

Nothing here depends on a payment provider or an application framework.

Index

Constants

View Source
const FormatVersion = "1"

FormatVersion is the document format version this package reads and writes.

Variables

View Source
var ErrUnknownFormat = errors.New("pricingspec: unknown format version")

ErrUnknownFormat is returned for a document whose formatVersion this package does not read.

Functions

This section is empty.

Types

type Application

type Application struct {
	ID   string `json:"id" jsonschema:"pattern=^[a-z][a-z0-9_]*$"`
	Name string `json:"name"`
}

Application is an application an account can be granted access to.

type Change

type Change struct {
	Kind ChangeKind `json:"kind"`
	// Subject is what changed, for example "plan pro" or "grant free/reports".
	Subject string `json:"subject"`
	Detail  string `json:"detail"`
	// AffectsExisting is true when the change worsens the offer for accounts
	// already on it: a higher price, a lower allowance, a removed feature, a
	// removed grant, fewer seats, a lowered level, or a removed plan.
	AffectsExisting bool `json:"affectsExisting,omitempty"`
}

Change is one difference between two Specs.

func Diff

func Diff(oldSpec, newSpec *Spec) []Change

Diff compares two Specs and lists what differs, in a stable order. Additions and improvements are listed but do not set AffectsExisting.

func (Change) String

func (c Change) String() string

type ChangeKind

type ChangeKind string

ChangeKind says what happened to the thing that changed.

const (
	Added   ChangeKind = "added"
	Removed ChangeKind = "removed"
	Changed ChangeKind = "changed"
)

Change kinds.

type Decision

type Decision string

Decision is the answer to a limit check.

const (
	// Allowed means the action is within the allowance.
	Allowed Decision = "allowed"
	// Warn means the allowance is exceeded but marked fair use: allow the
	// action and flag the account for review.
	Warn Decision = "warn"
	// Refuse means the allowance is exceeded.
	Refuse Decision = "refuse"
)

Decisions.

type EntitlementMap

type EntitlementMap struct {
	Tiers []TierEntitlements `json:"tiers"`
}

EntitlementMap is what each tier grants, in tier rank order.

type Feature

type Feature struct {
	ID          string `json:"id" jsonschema:"pattern=^[a-z][a-z0-9_]*$"`
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	// Levels, when present, make the feature a ladder: at least two distinct
	// names, lowest first, each including the one below. Without levels the
	// feature is a switch.
	Levels []string `json:"levels,omitempty" jsonschema:"description=Ordered levels of a ladder feature; absent for a switch"`
}

Feature is something a plan switches on, or sets to a level.

type FeatureCell

type FeatureCell struct {
	Plan     string `json:"plan"`
	Included bool   `json:"included"`
	Level    string `json:"level,omitempty"`
}

FeatureCell is a plan's setting of a feature. Included is true for an enabled switch or a ladder at any level; Level is the ladder's level.

type FeatureRow

type FeatureRow struct {
	ID          string        `json:"id"`
	Name        string        `json:"name"`
	Description string        `json:"description,omitempty"`
	Levels      []string      `json:"levels,omitempty"`
	Cells       []FeatureCell `json:"cells"`
}

FeatureRow is one feature across the plans, in the same order as the plans.

type FeatureValue

type FeatureValue struct {
	Feature string `json:"feature"`
	// Enabled states a switch. It must be false for a ladder.
	Enabled bool `json:"enabled,omitempty"`
	// Level names one of a ladder's levels. It must be empty for a switch.
	Level string `json:"level,omitempty"`
}

FeatureValue sets one feature for a plan.

type Grant

type Grant struct {
	Application     string `json:"application"`
	ApplicationName string `json:"applicationName"`
	Seats           int    `json:"seats,omitempty"`
	UnlimitedSeats  bool   `json:"unlimitedSeats,omitempty"`
}

Grant is access to one application.

type Interval

type Interval string

Interval is a billing interval.

const (
	IntervalMonth Interval = "month"
	IntervalYear  Interval = "year"
)

Billing intervals.

type Issue

type Issue struct {
	Code     string   `json:"code"`
	Severity Severity `json:"severity"`
	// Path locates the finding, for example "plans[2].limits[0]".
	Path    string `json:"path"`
	Message string `json:"message"`
}

Issue is one finding about a Spec. Its Code is stable (E001 to E013 for errors, W001 to W006 for warnings) and documented in SPEC.md.

func (Issue) String

func (i Issue) String() string

type Limit

type Limit struct {
	ID          string `json:"id" jsonschema:"pattern=^[a-z][a-z0-9_]*$"`
	Name        string `json:"name"`
	Unit        string `json:"unit,omitempty"`
	Period      Period `json:"period" jsonschema:"enum=none,enum=day,enum=month"`
	Description string `json:"description,omitempty"`
}

Limit is something a plan caps.

type LimitCell

type LimitCell struct {
	Plan      string `json:"plan"`
	Max       int    `json:"max"`
	Unlimited bool   `json:"unlimited,omitempty"`
	FairUse   bool   `json:"fairUse,omitempty"`
}

LimitCell is a plan's allowance for a limit. Max is zero when the plan does not set it.

type LimitRow

type LimitRow struct {
	ID          string      `json:"id"`
	Name        string      `json:"name"`
	Unit        string      `json:"unit,omitempty"`
	Period      Period      `json:"period"`
	Description string      `json:"description,omitempty"`
	Cells       []LimitCell `json:"cells"`
}

LimitRow is one limit across the plans, in the same order as the plans.

type LimitValue

type LimitValue struct {
	Limit string `json:"limit"`
	// Max is the allowance; zero means zero. It must be zero when Unlimited.
	Max int `json:"max,omitempty" jsonschema:"minimum=0"`
	// Unlimited means no numeric limit.
	Unlimited bool `json:"unlimited,omitempty"`
	// FairUse: with Max, exceeding it warns and flags the account for review
	// instead of refusing; with Unlimited, the allowance is advertised as
	// unlimited and subject to the host's fair-use policy.
	FairUse bool `json:"fairUse,omitempty"`
}

LimitValue sets one limit for a plan.

type Marketplace

type Marketplace struct {
	// PlatformFeeBps is the share in basis points, 0 to 10000.
	PlatformFeeBps int `json:"platformFeeBps" jsonschema:"minimum=0,maximum=10000"`
}

Marketplace is the platform's share of sales by sellers.

type Period

type Period string

Period is how often a limit's usage resets.

const (
	PeriodNone  Period = "none"
	PeriodDay   Period = "day"
	PeriodMonth Period = "month"
)

Limit periods.

type Plan

type Plan struct {
	ID   string `json:"id" jsonschema:"pattern=^[a-z][a-z0-9_]*$"`
	Name string `json:"name"`
	// Tier is the plan's tier. Exactly one.
	Tier string `json:"tier"`
	// SelfServe means the plan can be bought through checkout; false means arranged.
	SelfServe bool `json:"selfServe"`
	// TrialDays is the length of a free trial. Only on a plan with prices.
	TrialDays int `json:"trialDays,omitempty" jsonschema:"minimum=0"`
	// Prices is empty for a free or arranged plan.
	Prices []Price `json:"prices,omitempty"`
	// Features are the features the plan sets; an unset feature is off.
	Features []FeatureValue `json:"features,omitempty"`
	// Limits are the limits the plan sets; an unset limit is zero.
	Limits []LimitValue `json:"limits,omitempty"`
	// PlatformFeeBps overrides the marketplace fee for sales by an account on this plan.
	PlatformFeeBps *int `json:"platformFeeBps,omitempty" jsonschema:"minimum=0,maximum=10000"`
}

Plan is what an account can be on.

func (Plan) Has

func (p Plan) Has(feature string) bool

Has reports whether the plan switches the feature on, or sets it to any level. It does not resolve an unknown plan; see Spec.Has.

type PlanColumn

type PlanColumn struct {
	ID        string  `json:"id"`
	Name      string  `json:"name"`
	Tier      string  `json:"tier"`
	TierName  string  `json:"tierName"`
	TierRank  int     `json:"tierRank"`
	SelfServe bool    `json:"selfServe"`
	Free      bool    `json:"free"`
	Default   bool    `json:"default"`
	TrialDays int     `json:"trialDays,omitempty"`
	Prices    []Price `json:"prices,omitempty"`
}

PlanColumn is one plan in a pricing view.

type Price

type Price struct {
	Interval Interval `json:"interval" jsonschema:"enum=month,enum=year"`
	// AmountCents is a positive integer in the currency's minor units.
	AmountCents int64 `json:"amountCents" jsonschema:"minimum=1"`
}

Price is a plan's price for one billing interval.

type PricingView

type PricingView struct {
	App      string       `json:"app"`
	Currency string       `json:"currency"`
	Plans    []PlanColumn `json:"plans"`
	Features []FeatureRow `json:"features"`
	Limits   []LimitRow   `json:"limits"`
	Products []Product    `json:"products,omitempty"`
}

PricingView is a Spec arranged for a page to render: plans in order, and a matrix of features and limits across them. It carries data, not display text.

type Product

type Product struct {
	ID   string `json:"id" jsonschema:"pattern=^[a-z][a-z0-9_]*$"`
	Name string `json:"name"`
	// AmountCents is the fixed price; zero when SellerSet.
	AmountCents int64 `json:"amountCents,omitempty" jsonschema:"minimum=0"`
	// SellerSet means the seller sets the price.
	SellerSet bool `json:"sellerSet,omitempty"`
	// MinAmountCents is the floor for a seller-set price.
	MinAmountCents int64 `json:"minAmountCents,omitempty" jsonschema:"minimum=0"`
}

Product is a one-time purchase.

type Severity

type Severity string

Severity says whether an Issue rejects a Spec.

const (
	SeverityError   Severity = "error"
	SeverityWarning Severity = "warning"
)

Severities.

type Spec

type Spec struct {
	// FormatVersion is "1". A reader rejects a version it does not know.
	FormatVersion string `json:"formatVersion" jsonschema:"description=The document format version,enum=1"`
	// App identifies the product; everything a billing system holds for it is tagged with it.
	App string `json:"app" jsonschema:"description=Identifies the product,pattern=^[a-z][a-z0-9-]*$"`
	// Currency is a lowercase ISO 4217 code. One currency per Spec.
	Currency string `json:"currency" jsonschema:"description=Lowercase ISO 4217 currency code,pattern=^[a-z]{3}$"`
	// DefaultPlan is the plan for any unrecognised plan value and for an account
	// when billing is not configured.
	DefaultPlan string `json:"defaultPlan" jsonschema:"description=Plan ID used for any unrecognised plan and when billing is not configured"`
	// Applications are the applications an account can be granted.
	Applications []Application `json:"applications" jsonschema:"description=The applications a tier can grant"`
	// Tiers are the product's ladder, lowest rank first.
	Tiers []Tier `json:"tiers" jsonschema:"description=The product's ladder"`
	// Features are what a plan can switch on or set to a level.
	Features []Feature `json:"features,omitempty" jsonschema:"description=What a plan can switch on or set to a level"`
	// Limits are what a plan can cap.
	Limits []Limit `json:"limits,omitempty" jsonschema:"description=What a plan can cap"`
	// Plans are what an account can be on.
	Plans []Plan `json:"plans" jsonschema:"description=What an account can be on"`
	// Products are one-time purchases.
	Products []Product `json:"products,omitempty" jsonschema:"description=One-time purchases"`
	// Marketplace is the platform's share of sales by sellers, when there are any.
	Marketplace *Marketplace `json:"marketplace,omitempty" jsonschema:"description=The platform's share of sales by sellers"`
	// Entitlements are what each tier grants an account.
	Entitlements []TierGrant `json:"entitlements" jsonschema:"description=What each tier grants an account"`
}

Spec describes a product's pricing and packaging.

func Load

func Load(r io.Reader) (*Spec, error)

Load reads a Spec from JSON, rejecting unknown fields, and validates it.

func Parse

func Parse(data []byte) (*Spec, error)

Parse decodes a Spec from JSON, rejecting unknown fields, and validates it. A Spec that breaks an error rule returns a *ValidationError.

func (*Spec) Allowance

func (s *Spec) Allowance(planID, limit string) (max int, unlimited, fairUse bool)

Allowance returns the plan's allowance for a limit. A limit the plan does not set has a maximum of zero. unlimited is true when the plan sets it unlimited, and fairUse when it is marked fair use.

func (*Spec) AtLeast

func (s *Spec) AtLeast(planID, feature, level string) bool

AtLeast reports whether the plan sets a ladder feature at or above level. It is false for an unset ladder, a switch, an unknown feature or an unknown level.

func (*Spec) Check

func (s *Spec) Check(planID, limit string, after int) Decision

Check answers whether an action may proceed. after is the usage after the action: a plan with a maximum of 3 and 2 items in use checks adding a third as 3. The result is Allowed when the limit is unlimited or after is within the maximum; over the maximum it is Warn for a fair-use limit and Refuse otherwise. A limit the plan does not set has a maximum of zero. An unlimited fair-use limit is always Allowed: the Spec sets no threshold and the host applies its own policy.

func (*Spec) EntitlementMap

func (s *Spec) EntitlementMap() EntitlementMap

EntitlementMap returns what each tier grants. Tiers with no grant are listed with an empty Grants.

func (*Spec) GrantsFor

func (s *Spec) GrantsFor(planID string) []TierGrant

GrantsFor returns what the plan's tier grants an account, in the Spec's order. An unknown plan resolves to the default plan.

func (*Spec) Has

func (s *Spec) Has(planID, feature string) bool

Has reports whether the plan (or the default plan, for an unknown ID) has the feature on, or at any level.

func (*Spec) Level

func (s *Spec) Level(planID, feature string) string

Level returns the level the plan sets for a ladder feature, or "" when the plan does not set it, or the feature is a switch or unknown.

func (*Spec) Lint

func (s *Spec) Lint() []Issue

Lint returns the warnings (W001 to W006) for a Spec. Warnings are for review and never reject a Spec. Call Validate first: Lint assumes references resolve.

func (*Spec) Plan

func (s *Spec) Plan(id string) (Plan, bool)

Plan returns the plan with the given ID.

func (*Spec) PlanOrDefault

func (s *Spec) PlanOrDefault(id string) Plan

PlanOrDefault returns the plan with the given ID, or the default plan when the ID is not a plan, so an unrecognised value never grants more. It returns the zero Plan only for a Spec with no default plan, which Validate rejects.

func (*Spec) PricingView

func (s *Spec) PricingView() PricingView

PricingView arranges the Spec for display. Plans are ordered by tier rank, then by monthly price (plans without one first), then by their order in the Spec.

func (*Spec) TierRank

func (s *Spec) TierRank(tier string) int

TierRank returns the rank of a tier, or zero when it is not declared.

func (*Spec) Validate

func (s *Spec) Validate() []Issue

Validate returns every error-level finding (E001 to E013). A Spec with none is valid. It does not report warnings; see Lint.

type Tier

type Tier struct {
	ID   string `json:"id" jsonschema:"pattern=^[a-z][a-z0-9_]*$"`
	Name string `json:"name"`
	// Rank is a positive integer, unique within the Spec, lowest first. Ranks
	// of different products are not comparable.
	Rank int `json:"rank" jsonschema:"minimum=1"`
}

Tier is a position on the product's ladder.

type TierEntitlements

type TierEntitlements struct {
	Tier   string  `json:"tier"`
	Name   string  `json:"name"`
	Rank   int     `json:"rank"`
	Grants []Grant `json:"grants"`
}

TierEntitlements is one tier's grants.

type TierGrant

type TierGrant struct {
	Tier        string `json:"tier"`
	Application string `json:"application"`
	// Seats is the number of members, at least 1, unless UnlimitedSeats.
	Seats          int  `json:"seats,omitempty" jsonschema:"minimum=0"`
	UnlimitedSeats bool `json:"unlimitedSeats,omitempty"`
}

TierGrant is what a tier gives an account for one application.

type ValidationError

type ValidationError struct {
	Issues []Issue
}

ValidationError is returned by Load and Parse for a Spec that breaks an error rule. It carries every error found, not only the first.

func (*ValidationError) Error

func (e *ValidationError) Error() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL