OpenPricing Data Specification
Version: draft-01 Status: Draft Date: 2026-06-17
Abstract
OpenPricing defines a provider-independent format for representing the pricing and packaging of a
service: its features, the meters that measure usage, the packages (plans) it offers, the rate cards
that price each feature within a package, and the add-ons, discounts, credit grants, and qualifying
conditions that apply. A document in this format — the OpenPricing object — represents one
provider's pricing model using a fixed, vendor-neutral vocabulary, so that pricing models from
different providers share a common representation.
A document MAY be produced by any means, including manual authoring and extraction from a published pricing page. The format does not depend on how a document is produced.
This specification is the normative contract for the document. It is intended for:
- Producers that emit documents in this format, by any means.
- Consumers that read documents in this format.
- Validators that check a candidate document for conformance.
The contract is expressed as a JSON Schema ($id
https://openpricing.io/draft-01/schema.json, drafted against JSON Schema 2020-12). This
document defines the data model that the JSON Schema encodes: the meaning, value format, nullability, and
cross-field requirements of every field. The JSON Schema constrains the shape of each field; this
specification additionally states the referential and cross-field requirements that a conformant
document MUST satisfy and that validation of fields in isolation does not capture. Both are
normative.
Status of This Document
This is a draft specification. The specification identity is draft-01:
| Identifier | Value |
|---|---|
| Specification version | draft-01 |
JSON Schema $id |
https://openpricing.io/draft-01/schema.json |
| JSON Schema meta | https://json-schema.org/draft/2020-12/schema |
While the specification is in draft, fields, defaults, and constraints MAY change between revisions without a formal deprecation cycle, and backward compatibility of documents is not guaranteed between draft revisions. The Migration and Versioning section describes the policy that applies once the specification stabilizes.
This document and the JSON Schema artifact describe one contract. A disagreement between them is a defect to be reconciled; neither takes precedence over the other. Any change to a field, default, value format, allowed value, or requirement is a change to this specification.
Scope
This specification covers the structure, field semantics, value formats, and conformance rules of a
single OpenPricing document.
In scope:
- The structure and meaning of every object, field, enumeration, and primitive in the document.
- The required-field and default-value conventions.
- The value formats for keys, numerics, currencies, durations, dates, and URLs.
- The referential-integrity and cross-field requirements a conformant document must satisfy.
- Versioning of the specification.
Explicitly out of scope:
- Hidden or contractual pricing logic. A document describes a provider's published pricing and packaging model, not privately negotiated terms, internal rate sheets, or undisclosed billing-engine behavior.
- Runtime billing computation. The document describes how a feature is priced; it does not specify how a billing system meters events, rates usage, applies proration, or settles invoices.
- Storage, transport, and provenance. How a document is serialized to a file, persisted, diffed, scraped, or extracted is not constrained by this specification. A conformant document is valid regardless of how it is produced or stored.
- Companion documents. Any provider metadata or change-history documents that an implementation may keep alongside a catalog have their own schemas and are not part of this specification.
Design Goals and Principles
- Provider independence. A fixed, vendor-neutral vocabulary (service categories, meter aggregations, price types, entitlement types, condition operators) represents the pricing of any service in a single model, independent of how a given provider presents it. Documents from different providers share one representation and are interoperable without per-provider adapters.
- One contract. A single data model governs all producers and consumers. The JSON Schema artifact and this specification describe that model and are kept in agreement.
- Conformance as an invariant. A conformant document satisfies the full contract — both the per-field constraints and the cross-field requirements. A producer that cannot satisfy the contract does not emit a partial document.
- Explicit over implicit. Every field is required. A field with a documented default is emitted
with that default value (
null,"",[]) rather than omitted, so that an absent field and a field set to its default are never ambiguous. See Normative Language and the required-field convention. - Stated values only. A document represents the pricing model as the provider states it. Where
a fact is not stated, the corresponding field carries its documented
nullor empty default; a producer does not infer or invent a value. - Extension through
attributes. Provider-specific data that has no first-class field is carried asattributeskey-value pairs rather than dropped, and does not occupy a typed field. - Alignment with metering and billing systems. Metering and pricing concepts (meters, aggregations, entitlements, graduated/volume tiers, credit grants) correspond to the primitives of usage-metering and billing engines, so a document maps onto such a system without re-modeling, yet the model is not specific to any one of them.
Terminology
| Term | Definition |
|---|---|
| Catalog | A single OpenPricing document describing one provider's pricing. |
| Provider | The service whose pricing the catalog describes. The root OpenPricing object carries the provider's identity. |
| Feature | A distinct capability or billable dimension offered by the provider, defined once and referenced by key from rate cards. |
| Meter | A definition of how raw usage events are aggregated into a billable quantity. Features reference meters to connect pricing to measured usage. |
| Package | A bundle of rate cards with a shared currency and billing cadence. Corresponds to what a pricing page usually calls a "plan" or "tier". Commercial variants (monthly vs annual) are separate packages. |
| Rate card | The pricing-and-entitlement entry for one feature within one package or add-on. Typically corresponds to a single cell in a pricing table. |
| Price | How each unit of a feature is billed (free, flat, unit, graduated, volume, or custom). A discriminated union. |
| Entitlement | What the customer receives for a feature (included access, a quantified limit, or structured configuration). Orthogonal to price. |
| Add-on | An optional, on-demand purchasable extension to a package, referenced by key from the packages where it is available. |
| Credit grant | A prepaid value pool (credits, points) bundled with a package or granted by an add-on purchase. |
| Condition | A structured qualifier (region, deployment model, audience) that narrows when a package, add-on, or rate card applies. |
| Key | A snake_case identifier used for cross-resource references within a catalog. |
| Custom currency | A provider-specific currency (credits, points) declared once and referenced by code where any currency is accepted. |
| Containment | Where an object appears in the document structure and what one instance of it represents. |
Normative Language
The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL in this document are to be interpreted as described in RFC 2119 and RFC 8174 when, and only when, they appear in all capitals.
Normative and informative content
Unless explicitly marked as non-normative, this specification is normative. Examples, JSON snippets, and explanatory text introduced with "For example" are informative: they illustrate the normative requirements and do not create conformance requirements beyond the stated MUST, SHOULD, and MAY statements. Where an example and a normative requirement appear to conflict, the requirement governs.
Required-field convention
Every field on every object is REQUIRED, including fields that have a documented default. A producer MUST emit each field explicitly rather than omitting it:
- A nullable field MUST carry JSON
nullwhen no value is stated. The key MUST NOT be dropped. - A field MUST NOT use the JSON string
"null"in place of the JSON literalnull. - A string field whose default is
""MUST carry""when no value is stated. A producer MUST NOT invent text to fill it. - An array field whose default is
[]MUST carry[]when no entries are stated.
This format favors canonical, validator-friendly documents over sparse, source-preserving ones. A
fully-populated document has a fixed shape: a consumer reads any field without testing for its
presence, and "absent" never has to be distinguished from "set to its default". A producer that
extracts from a pricing page MUST normalize an unstated value to the field's documented default
(null, "", or []) rather than omit the field. Documents therefore carry explicit null, "",
and [] for facts the source does not state; this is intended, not a defect.
Throughout this document, the Requirement column and the per-field Requirements sections use
"REQUIRED" to mean "the key MUST be present"; nullability is stated separately. A field may be both
REQUIRED (present) and nullable (its value MAY be null).
Feature levels
Each field and rule carries a feature level that maps to the normative keywords above:
| Feature level | Meaning |
|---|---|
| Mandatory | Stated with MUST, unconditionally. |
| Conditional | Stated with MUST, applicable only when a stated condition holds (for example, a feature MUST set meter_key only when it is priced by usage). |
| Recommended | Stated with SHOULD. |
| Optional | Stated with MAY. |
Every field is REQUIRED to be present, so the presence obligation is Mandatory for all fields. The
distinctions among fields are therefore expressed through nullability (whether the value MAY be
null) and the conditional cross-field rules in Document Requirements.
Conformance
A document is conformant with this specification when it satisfies, together:
- Field requirements — every field is present, correctly typed, within its value format and length bounds, draws from its allowed values, and respects its nullability, as defined in Value Formats and each field's table and Requirements.
- Document requirements — the referential-integrity and cross-field rules in Document Requirements (R1–R16) hold across the whole document.
Both sets of requirements are normative. A document that satisfies the per-field rules but violates
a document requirement (for example, a rate card that references a feature key absent from
features) is not conformant.
Conforming actors
| Actor | Conformance obligation |
|---|---|
| Producer | MUST emit only documents that satisfy the field requirements and the document requirements. MUST NOT emit a partial document. |
| Consumer | MUST accept any conformant document. SHOULD NOT fail on a document that violates a document requirement, and SHOULD instead surface the violation. MUST ignore attributes keys it does not recognize rather than reject the document. |
| Validator | SHOULD check both the field requirements and the document requirements, and SHOULD report each violation with the JSON path of the offending value. |
Document Requirements
These requirements constrain relationships across fields and objects — references that must resolve, keys that must be unique, and fields whose obligation depends on another field's value. They cannot be expressed by validating one field in isolation, so they are stated here as document-level rules. Each rule carries a feature level: Mandatory and Conditional rules are MUST-level (Conditional meaning the MUST applies only when the stated condition holds), and Recommended rules are SHOULD-level.
| # | Level | Requirement |
|---|---|---|
| R1 | Mandatory | The document's key MUST be a resolved provider key (not empty and not the placeholder "pending"), and name MUST be a resolved provider name (not empty and not "pending", compared case-insensitively). |
| R2 | Mandatory | features MUST contain at least one feature, and packages MUST contain at least one package. |
| R3 | Mandatory | The key of each feature MUST be unique within features; likewise each meter key within meters, each package key within packages, and each add-on key within addons. (The Key value format constrains shape only, not uniqueness; a duplicate defining key makes references ambiguous.) |
| R4 | Mandatory | Each package MUST contain at least one rate card. |
| R5 | Mandatory | Every rate card's feature MUST reference a feature key present in the top-level features. |
| R6 | Mandatory | Every feature in features MUST be referenced by at least one rate card. A feature referenced by no rate card is an orphan. |
| R7 | Conditional | A feature whose rate card has a usage-based price (unit, graduated, or volume) or a numeric limit entitlement MUST set meter_key (it MUST NOT be null). |
| R8 | Conditional | When a feature sets meter_key, that key MUST reference a meter key present in the top-level meters. |
| R9 | Mandatory | Every key in a package's available_addons MUST reference an add-on key present in the top-level addons. |
| R10 | Mandatory | Every currency code used anywhere in the document that is not a three-letter ISO 4217 fiat code (any currency field, a credit grant's unit) MUST be declared in the top-level custom_currencies. |
| R11 | Conditional | In a graduated or volume price, tiers MUST be ordered from lowest to highest quantity; the final tier MUST be open-ended (up_to_amount = null) and no other tier may be; and each tier MUST carry flat_price, unit_price, or both. |
| R12 | Conditional | When a rate card's billing_cadence is non-null and differs from its package's billing_cadence, the pair MUST be one of the allowed cadence relationships. |
| R13 | Conditional | When service_subcategory is non-null, the segment before its . MUST equal service_category. |
| R14 | Conditional | A condition's value MUST be a single string when its operator is eq, and an array of strings when its operator is in. |
| R15 | Conditional | Every key in a credit grant's feature_scope MUST reference a feature key present in the top-level features. |
| R16 | Mandatory | Each add-on MUST contain at least one rate card or a non-null credit_grant. An add-on with neither has no effect. |
Rules R15 and R16, and the enumerated form of R12, are introduced in draft-01 by this
specification. They constrain a conformant document beyond what the per-field JSON Schema
expresses; a producer MUST satisfy them, and a document that violates them is non-conformant whether
or not a given validator checks them.
A consumer SHOULD treat a document that satisfies every field requirement but violates a document requirement as structurally readable yet not catalog-complete, and SHOULD surface the violation rather than acting on the affected portion.
Rate-card cadence relationships
R12 governs a rate card whose billing_cadence differs from its package's. The divisor relationship
applies only when both the package cadence and the rate-card cadence are ISO 8601 Durations;
the BillingCadence values "one_time" and "negotiated", on either side, are
non-recurring or custom terms and never participate in R12. Usage measured on the rate card's cadence
aggregates up into the package's billing period, so the rate-card Duration cadence MUST be a
sub-period that composes a whole number of times into the package period. To keep this check
mechanical and free of calendar arithmetic, the allowed (package cadence → rate-card cadence) pairs
are enumerated rather than derived by dividing one ISO 8601 duration by another:
Package billing_cadence |
Allowed rate-card billing_cadence |
|---|---|
P1Y (annual) |
P1M, P1D, PT1H |
P3M (quarterly) |
P1M, P1D, PT1H |
P1M (monthly) |
P1D, PT1H |
P1W (weekly) |
P1D, PT1H |
P1D (daily) |
PT1H |
A rate-card cadence equal to the package cadence is always allowed; it is expressed as null. A pair
not listed above is non-conformant. For example, a package cadence of P1M with a rate-card cadence
of P1W is non-conformant, because a week does not compose a whole number of times into a calendar
month. A package or rate-card cadence outside this enumeration is not defined for cross-cadence rate
cards in draft-01; a rate card whose cadence is outside the enumeration MUST equal its package
cadence.
Companion taxonomy overrides
An implementation MAY annotate a catalog (in a companion metadata document, outside this
specification) with overrides to its assigned service_category / service_subcategory. Where such
an override mechanism exists, each override MUST name a value drawn from the
ServiceCategory or
ServiceSubcategory vocabulary defined here and MUST carry a
non-empty human-readable reason. The override document's own structure is out of scope.
Data Model
An OpenPricing document is a single nested JSON object. Its structure is:
OpenPricing (root)
├── service_category / service_subcategory (taxonomy enums)
├── features[] Feature ── meter_key ─────────┐
├── meters[] Meter ◄─────────────────────┘
├── custom_currencies[] CustomCurrency
├── packages[] Package
│ ├── rate_cards[] RateCard ── feature ──► Feature.key
│ │ ├── price Price (one of: free|flat|unit|graduated|volume|custom)
│ │ ├── entitlement Entitlement (one of: included|limit|configuration)
│ │ ├── discount Discount? (one of: percentage|usage)
│ │ ├── unit_config UnitConfig?
│ │ ├── commitments SpendCommitments?
│ │ └── conditions Conditions
│ ├── credit_grants[] CreditGrant
│ ├── available_addons[] ── key ──► Addon.key
│ └── conditions Conditions
└── addons[] Addon
├── rate_cards[] RateCard
└── credit_grant CreditGrant?
Shared identity fields. The root object and each named, referenceable object — OpenPricing,
Feature, Meter, Package, and Addon — carry the same four identity fields: key, name,
description, and attributes. They are defined once as the Resource fields and
are not repeated in each object's field table.
Cross-references. All references are by Key string, never by embedding the referenced object:
- a feature's
meter_key→ a meter'skey - a rate card's
feature→ a feature'skey - a package's
available_addons[]→ an add-on'skey - a credit grant's
feature_scope[]→ a feature'skey - any custom
currency/ credit grantunitcode → a custom currency'scode
Every cross-reference MUST resolve; see Document Requirements.
Orthogonality of price and entitlement. On every rate card, price specifies how each unit is
billed and entitlement specifies what the customer receives. Both are REQUIRED and independent;
their valid combinations are described under RateCard.
Array order. Array order is not semantically meaningful except for the arrays named below. Only these carry order meaning:
packages, and a package's or add-on'srate_cards, preserve the provider's presentation order (for example, free before pro before enterprise). A consumer MAY render them in document order.- A graduated or volume price's
tiersare order-sensitive and MUST be ordered byup_to_amountper R11.
For every other array in the document, order is not meaningful: a consumer MUST NOT assign meaning to
it, and a producer MAY emit it in any order, including sorted by key (or, for entries without a
key, by serialized value).
The rest of this specification defines each object and its fields. Each object section opens with a Containment line stating where instances appear and what one instance represents.
Value Formats
These formal definitions are referenced by the per-field tables. Where a field's type is one of
these, the format rule below applies in full. Each value-format rule carries a stable identifier
(VF-…) so that a validator can report a violation by rule ID; the identifiers do not change between
specification revisions once assigned.
Key
Rule ID: VF-KEY-001
A cross-resource identifier.
| Property | Value |
|---|---|
| JSON type | string |
| Pattern | ^[a-z0-9]+(?:_[a-z0-9]+)*$ |
| Length | 1–64 characters |
| Style | Descriptive snake_case, spelled in full |
| Example | monthly_active_users, gigabytes_stored |
Lowercase letters, digits, and single underscores between segments. Producers SHOULD prefer full,
human-readable names over abbreviations (monthly_active_users, not mau). Uniqueness of a key
within its collection is a document requirement (R3), not a value-format
rule.
Numeric
Rule ID: VF-NUM-001
An arbitrary-precision number encoded as a string.
| Property | Value |
|---|---|
| JSON type | string |
| Pattern | ^-?[0-9]+(\.[0-9]+)?$ |
| Example | "0.029", "100", "-5.5" |
All monetary amounts, tier bounds, percentages, conversion factors, limits, and credit amounts are
Numeric. They MUST be encoded as JSON strings, never JSON numbers, to preserve precision. A
producer MUST NOT emit 0.029; it MUST emit "0.029".
URL
Rule ID: VF-URL-001
| Property | Value |
|---|---|
| JSON type | string |
| Format | absolute URI (uri) |
| Example | https://example.com/pricing |
An absolute HTTP or HTTPS URL.
DateTime
Rule ID: VF-DTM-001
| Property | Value |
|---|---|
| JSON type | string |
| Format | RFC 3339 date-time, UTC |
| Example | 2023-01-01T01:01:01.001Z |
Duration
Rule ID: VF-DUR-001
| Property | Value |
|---|---|
| JSON type | string |
| Format | ISO 8601 duration |
| Pattern | ^P(?:\d+(?:\.\d+)?Y)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?W)?(?:\d+(?:\.\d+)?D)?(?:T(?:\d+(?:\.\d+)?H)?(?:\d+(?:\.\d+)?M)?(?:\d+(?:\.\d+)?S)?)?$ |
| Examples | P1M (monthly), P1Y (annual), P7D (7 days), P1D, PT1H (hourly) |
BillingCadence
The billing cadence shared by Package.billing_cadence and RateCard.billing_cadence. A union of a
Duration and two string literals, plus null:
| Value | Meaning |
|---|---|
Duration |
The charge recurs on that ISO 8601 period (P1M, P1Y, PT1H). |
"one_time" |
A single purchase with no recurrence: a setup or implementation fee, a prepaid unit bundle, a lifetime pool. |
"negotiated" |
The page explicitly states custom or contact-us billing terms. |
null |
The page does not state a cadence. Unstated only, never a positive commercial claim. |
"negotiated" is an extractable fact (the page says terms are custom), distinct from null
(silence). A producer MUST NOT use null to mean "negotiated". CreditGrant.cadence uses the
subset Duration | "one_time" | null: a grant is never "negotiated".
CurrencyCode
Rule ID: VF-CUR-001
A union of two string subtypes:
| Subtype | Pattern | Length | Meaning | Example |
|---|---|---|---|---|
CurrencyCodeFiat |
^[A-Z]{3}$ |
3 | An ISO 4217 fiat currency code. | USD |
CurrencyCodeCustom |
^[A-Z]{4,24}$ |
4–24 | A provider-specific code declared in custom_currencies. |
CREDITS |
The 3-character versus 4-or-more-character length distinguishes a fiat code (USD, as in "$10 in credits") from a custom code (CREDITS, as in "300 provider credits"). A custom code used
anywhere MUST be declared in top-level custom_currencies (R10).
Attributes
Rule ID: VF-ATTR-001
A flexible list of string key-value pairs for metadata that does not fit a first-class field.
| Property | Value |
|---|---|
| JSON type | array of { "key": string, "value": string } |
| Default | [] |
Producers MUST prefer typed fields over attributes and MUST NOT use attributes to carry
commercial logic that belongs in a typed field. Consumers MUST ignore unrecognized attributes
keys. This is the format's extension mechanism.
Within a single array of this Attributes format — any attributes field, and
EntitlementConfiguration.values — key values MUST be unique. A consumer MAY therefore treat one
such array as a string-to-string map.
Condition and Conditions
A Condition is a structured qualifier; Conditions is an array of conditions combined with logical
AND.
Condition fields:
| Column ID | Type | Requirement | Nullable | Description |
|---|---|---|---|---|
key |
Key | REQUIRED | No | Semantic condition key, e.g. region, deployment_model, audience. |
operator |
ConditionOperator | REQUIRED | No | eq or in. Default in. |
value |
string | string[] | REQUIRED | No | A single string for eq; an array of strings for in (requirement R14). |
ConditionOperator allowed values:
| Value | Description |
|---|---|
eq |
Equal — operand is a single string. |
in |
Membership — operand is a string[]. |
Use conditions for region, deployment model, audience, model, or quantity qualifiers rather than
encoding those rules in attributes. Examples:
region in ["us", "eu"]deployment_model in ["cloud", "self_hosted"]model eq "gpt-5.5"
Objects
Each subsection below defines one object. The Containment line states where instances appear and
what one instance represents. Field tables use these columns: Column ID (the JSON field name),
Type, Requirement (REQUIRED — the key MUST be present), Nullable (whether the value MAY
be null), Default, and Description.
Resource fields
Description
The four common identity fields shared by the root object and by each named, referenceable object —
OpenPricing, Feature, Meter, Package, and Addon. These fields appear inline on each such
object; "Resource fields" is a naming shorthand, not a separate object in the document.
Containment
Present on the root object and on every Feature, Meter, Package, and Addon.
Fields
| Column ID | Type | Requirement | Nullable | Default | Description |
|---|---|---|---|---|---|
key |
Key | REQUIRED | No | — | Object-level unique key identifier. MUST be unique within its collection (R3). |
name |
string | REQUIRED | No | — | Display name. Length 1–256. |
description |
string | REQUIRED | No | "" |
Description. Length 0–1024. Emit "" when the page has none. |
attributes |
Attributes | REQUIRED | No | [] |
Extension metadata. MUST NOT carry commercial logic that belongs elsewhere. |
OpenPricing (root object)
Description
The root object. It carries provider identity (the shared identity fields), service taxonomy, the provider and pricing-page URLs, and the five top-level collections that the rest of the catalog references: features, meters, custom currencies, packages, and add-ons.
Containment
The single root object. One instance per provider catalog.
Fields
| Column ID | Type | Requirement | Nullable | Default | Description |
|---|---|---|---|---|---|
key |
Key | REQUIRED | No | — | Provider key (identity field). MUST be a resolved provider key, not empty or "pending" (R1). |
name |
string | REQUIRED | No | — | Provider display name (identity field). MUST be resolved, not empty or "pending" (R1). |
description |
string | REQUIRED | No | "" |
Identity field. Length 0–1024. |
attributes |
Attributes | REQUIRED | No | [] |
Identity field. |
service_category |
ServiceCategory | REQUIRED | No | other |
Highest-level classification of the service. |
service_subcategory |
ServiceSubcategory | REQUIRED | Yes | null |
Secondary classification; when non-null, its parent prefix MUST equal service_category (R13). null if none fits or the provider spans several. |
provider_url |
URL | REQUIRED | No | — | The provider's website URL. |
pricing_page_url |
URL | REQUIRED | No | — | The provider's pricing-page URL. |
features |
Feature[] | REQUIRED | No | [] |
Distinct features and billable dimensions. A feature appearing in multiple packages is defined once. |
meters |
Meter[] | REQUIRED | No | [] |
Usage-event aggregation definitions, referenced by features via meter_key. |
custom_currencies |
CustomCurrency[] | REQUIRED | No | [] |
Provider-specific currencies. Empty when everything is priced in fiat. |
packages |
Package[] | REQUIRED | No | [] |
Bundles of rate cards. Commercial variants are separate packages. |
addons |
Addon[] | REQUIRED | No | [] |
Add-ons referenced by key from packages. |
last_updated |
DateTime | REQUIRED | Yes | null |
When the catalog was last updated. null if unknown. |
Notes
- A document with empty
featuresorpackagesmay satisfy every per-field rule, but it is not conformant: R2 requires at least one of each. - Packages encode commercial variants (monthly vs annual, region-specific, enterprise) as separate
package objects connected by shared feature keys, with a naming convention such as
pro_monthly/pro_annual. A single offering uses the bare name (pro).
Allowed Values — ServiceCategory
The highest-level classification. Exactly one value per catalog.
| Value | Description |
|---|---|
ai_and_machine_learning |
Artificial Intelligence and Machine Learning related technologies. |
analytics |
Data processing, analytics, and visualization capabilities. |
business_applications |
Business and productivity applications and services. |
compute |
Virtual, containerized, serverless, or high-performance computing infrastructure and services. |
databases |
Database platforms and services for storage and querying of data. |
developer_tools |
Software development and delivery tools and services. |
multicloud |
Interworking of multiple cloud and/or on-premises environments. |
identity |
Identity and access management services. |
integration |
Services that allow applications to interact with one another. |
internet_of_things |
Development and management of IoT devices and networks. |
management_and_governance |
Management, logging, and observability of cloud usage. |
media |
Media and entertainment streaming and processing services. |
migration |
Moving applications and data to the cloud. |
mobile |
Services enabling cloud applications to interact via mobile technologies. |
networking |
Network connectivity and management. |
security |
Security monitoring and compliance services. |
storage |
Storage services for structured or unstructured data. |
web |
Services enabling cloud applications to interact via the Internet. |
other |
New or emerging services that do not align with an existing category. |
Allowed Values — ServiceSubcategory
A secondary classification namespaced as <category>.<subcategory>, so each value's parent is
unambiguous. The chosen value's parent prefix MUST match service_category (R13). Use the
<category>.other member when no specific subcategory fits within the chosen category, and the
top-level other.other when the category itself is other. The complete enumeration, grouped by
parent service_category:
ai_and_machine_learning
| Value | Description |
|---|---|
ai_and_machine_learning.ai_platforms |
Unified solution that combines artificial intelligence and machine learning technologies. |
ai_and_machine_learning.bots |
Automated performance of tasks such as customer service, data collection, and content moderation. |
ai_and_machine_learning.generative_ai |
Creation of content like text, images, and music by learning patterns from existing data. |
ai_and_machine_learning.machine_learning |
Creation, training, and deployment of statistical algorithms that learn from and perform tasks based on data. |
ai_and_machine_learning.natural_language_processing |
Generation of human language, handling tasks like translation, sentiment analysis, and text summarization. |
ai_and_machine_learning.other |
AI and Machine Learning services that do not fall into one of the defined subcategories. |
analytics
| Value | Description |
|---|---|
analytics.analytics_platforms |
Unified solution that combines technologies across the entire analytics lifecycle. |
analytics.business_intelligence |
Semantic models, dashboards, reports, and data visualizations to track performance and identify trends. |
analytics.data_processing |
Integration and transformation tasks to prepare data for analysis. |
analytics.search |
Discovery of information by indexing and retrieving data from various sources. |
analytics.streaming_analytics |
Real-time data stream processes to detect patterns, trends, and anomalies as they occur. |
analytics.other |
Analytics services that do not fall into one of the defined subcategories. |
business_applications
| Value | Description |
|---|---|
business_applications.productivity_and_collaboration |
Tools that facilitate individuals managing tasks and working together. |
business_applications.other |
Business Applications services that do not fall into one of the defined subcategories. |
compute
| Value | Description |
|---|---|
compute.containers |
Management and orchestration of containerized compute platforms. |
compute.end_user_computing |
Virtualized desktop infrastructure and device or endpoint management. |
compute.quantum_compute |
Resources and simulators that leverage the principles of quantum mechanics. |
compute.serverless_compute |
Enablement of compute capabilities without provisioning or managing servers. |
compute.virtual_machines |
Computing environments ranging from hosts with abstracted operating systems to bare-metal servers. |
compute.other |
Compute services that do not fall into one of the defined subcategories. |
databases
| Value | Description |
|---|---|
databases.caching |
Low-latency and high-throughput access to frequently accessed data. |
databases.data_warehouses |
Big data storage and querying capabilities. |
databases.ledger_databases |
Immutable and transparent databases to record tamper-proof and cryptographically secure transactions. |
databases.nosql_databases |
Unstructured or semi-structured data storage and querying capabilities. |
databases.relational_databases |
Structured data storage and querying capabilities. |
databases.time_series_databases |
Time-stamped data storage and querying capabilities. |
databases.other |
Database services that do not fall into one of the defined subcategories. |
developer_tools
| Value | Description |
|---|---|
developer_tools.developer_platforms |
Unified solution that combines technologies across multiple areas of the software development lifecycle. |
developer_tools.continuous_integration_and_deployment |
CI/CD tools and services that support building and deploying code for software and systems. |
developer_tools.development_environments |
Tools and services that support authoring code for software and systems. |
developer_tools.source_code_management |
Tools and services that support version control of code for software and systems. |
developer_tools.quality_assurance |
Tools and services that support testing code for software and systems. |
developer_tools.other |
Developer Tools services that do not fall into one of the defined subcategories. |
identity
| Value | Description |
|---|---|
identity.identity_and_access_management |
Technologies that ensure users have appropriate access to resources. |
identity.other |
Identity services that do not fall into one of the defined subcategories. |
integration
| Value | Description |
|---|---|
integration.api_management |
Creation, publishing, and management of application programming interfaces. |
integration.messaging |
Asynchronous communication between distributed applications. |
integration.workflow_orchestration |
Design, execution, and management of business processes and workflows. |
integration.other |
Integration services that do not fall into one of the defined subcategories. |
internet_of_things
| Value | Description |
|---|---|
internet_of_things.iot_analytics |
Examination of data collected from IoT devices. |
internet_of_things.iot_platforms |
Unified solution that combines IoT data collection, processing, visualization, and device management. |
internet_of_things.other |
Internet of Things services that do not fall into one of the defined subcategories. |
management_and_governance
| Value | Description |
|---|---|
management_and_governance.architecture |
Planning, design, and construction of software systems. |
management_and_governance.compliance |
Adherence to regulatory standards and industry best practices. |
management_and_governance.cost_management |
Monitoring and controlling expenses of systems and services. |
management_and_governance.data_governance |
Management of the availability, usability, integrity, and security of data. |
management_and_governance.disaster_recovery |
Plans and procedures that ensure systems and services can recover from disruptions. |
management_and_governance.endpoint_management |
Tools that configure and secure access to devices. |
management_and_governance.observability |
Monitoring, logging, and tracing of data to track the performance and health of systems. |
management_and_governance.support |
Assistance and expertise supplied by service providers. |
management_and_governance.other |
Management and Governance services that do not fall into one of the defined subcategories. |
media
| Value | Description |
|---|---|
media.content_creation |
Production of media content. |
media.gaming |
Development and delivery of gaming services. |
media.media_streaming |
Multimedia delivered and rendered in real-time on devices. |
media.mixed_reality |
Technologies that blend real-world and computer-generated environments. |
media.other |
Media services that do not fall into one of the defined subcategories. |
migration
| Value | Description |
|---|---|
migration.data_migration |
Movement of stored data from one location to another. |
migration.resource_migration |
Movement of resources from one location to another. |
migration.other |
Migration services that do not fall into one of the defined subcategories. |
mobile
| Value | Description |
|---|---|
mobile.other |
All Mobile services. |
multicloud
| Value | Description |
|---|---|
multicloud.multicloud_integration |
Environments that facilitate consumption of services from multiple cloud service providers. |
multicloud.other |
Multicloud services that do not fall into one of the defined subcategories. |
networking
| Value | Description |
|---|---|
networking.application_networking |
Distribution of incoming network traffic across application-based workloads. |
networking.content_delivery |
Distribution of digital content using a network of servers (CDNs). |
networking.network_connectivity |
Facilitates communication between networks or network segments. |
networking.network_infrastructure |
Configuration, monitoring, and troubleshooting of network devices. |
networking.network_routing |
Services that select paths for traffic within or across networks. |
networking.network_security |
Protection from unauthorized network access and cyber threats using firewalls and anti-malware tools. |
networking.other |
Networking services that do not fall into one of the defined subcategories. |
security
| Value | Description |
|---|---|
security.secret_management |
Information used to authenticate users and systems, including secrets, certificates, tokens, and other keys. |
security.security_posture_management |
Tools that help organizations configure, monitor, and improve system security. |
security.threat_detection_and_response |
Collect and analyze security data to identify and respond to potential security threats and vulnerabilities. |
security.other |
Security services that do not fall into one of the defined subcategories. |
storage
| Value | Description |
|---|---|
storage.backup_storage |
Secondary storage to protect against data loss. |
storage.block_storage |
High performance, low latency storage that provides random access. |
storage.file_storage |
Scalable, sharable storage for file-based data. |
storage.object_storage |
Highly available, durable storage for unstructured data. |
storage.storage_platforms |
Unified solution that supports multiple storage types. |
storage.other |
Storage services that do not fall into one of the defined subcategories. |
web
| Value | Description |
|---|---|
web.application_platforms |
Integrated environments that run web applications. |
web.other |
Web services that do not fall into one of the defined subcategories. |
other
| Value | Description |
|---|---|
other.other |
Services that do not fall into one of the defined categories. |
Feature
Description
A distinct capability or billable dimension. Features are defined once in the top-level features
collection and referenced by rate cards via the feature key. A metered (usage-based) feature also
references a meter and may narrow it to a specific slice with conditions.
Containment
OpenPricing.features[]. One instance per distinct billable capability across the whole catalog.
Fields
| Column ID | Type | Requirement | Nullable | Default | Description |
|---|---|---|---|---|---|
| (identity) | — | REQUIRED | — | — | key, name, description, attributes per Resource fields. |
meter_key |
Key | REQUIRED | Yes | null |
Key of the meter measuring this feature. Set only for metered features; null otherwise. When set, the meter MUST exist in top-level meters (R8). A usage-priced or numeric-limit feature MUST set it (R7). |
meter_conditions |
Conditions | REQUIRED | No | [] |
Conditions narrowing the meter to this feature's slice. Meaningful only when meter_key is set. Each condition key SHOULD name one of the referenced meter's dimensions. |
Notes
For example, the meter_conditions for a "GPT-5.5 input tokens" feature on a tokens meter are
[{key:"model",operator:"eq",value:"gpt-5.5"},{key:"type",operator:"eq",value:"input"}].
Meter
Description
Defines how raw usage events are aggregated into a billable quantity. One meter can be shared by several features that filter on different dimensions.
Containment
OpenPricing.meters[]. One instance per usage-event aggregation definition.
Fields
| Column ID | Type | Requirement | Nullable | Default | Description |
|---|---|---|---|---|---|
| (identity) | — | REQUIRED | — | — | key, name, description, attributes per Resource fields. |
event_type |
string | REQUIRED | No | — | The type of event aggregated, e.g. api_request, token_usage, storage_read. |
value_property |
string | REQUIRED | Yes | null |
Event property holding the value to aggregate. REQUIRED (non-null) for all aggregations except count. |
aggregation |
MeterAggregation | REQUIRED | No | — | The aggregation function. |
dimensions |
string[] | REQUIRED | No | [] |
Dimension names available for filtering/grouping. Features narrow on these via meter_conditions. |
Allowed Values — MeterAggregation
| Value | Description | Requires value_property |
|---|---|---|
sum |
Sum of all value_property values. |
Yes |
count |
Count of events. | No |
unique_count |
Number of distinct value_property values. |
Yes |
avg |
Arithmetic mean of value_property values. |
Yes |
min |
Minimum value_property value observed. |
Yes |
max |
Maximum value_property value observed. |
Yes |
latest |
Most recently reported value_property value. |
Yes |
A meter SHOULD set value_property for every aggregation except count, which operates on the
event itself. The "requires value_property" column above states this expectation; count is the
sole aggregation for which value_property MAY be null.
CustomCurrency
Description
Declaration of a provider-specific currency (credits, points). Declared once here and referenced by
code wherever a CurrencyCode is accepted.
Containment
OpenPricing.custom_currencies[]. One instance per proprietary currency.
Fields
| Column ID | Type | Requirement | Nullable | Default | Description |
|---|---|---|---|---|---|
code |
CurrencyCodeCustom | REQUIRED | No | — | Unique uppercase code (4–24 chars). MUST NOT conflict with an ISO 4217 code. |
name |
string | REQUIRED | No | — | Human-readable name as stated, e.g. "Netlify credits". Length 1–256. |
description |
string | REQUIRED | No | "" |
Description. Length 0–1024. |
Package
Description
A bundle of rate cards with a single currency and billing cadence, plus optional trial, bundled
credit grants, available add-ons, and applicability conditions. A package corresponds to what a
pricing page usually labels a "plan" or "tier"; this format uses the name Package.
Containment
OpenPricing.packages[]. One instance per commercial package variant, such as a monthly Pro plan or
an annual Pro plan; monthly and annual are separate packages.
Fields
| Column ID | Type | Requirement | Nullable | Default | Description |
|---|---|---|---|---|---|
| (identity) | — | REQUIRED | — | — | key, name, description, attributes per Resource fields. |
currency |
CurrencyCode | REQUIRED | No | — | Currency applying to all rate-card prices unless a rate card overrides it. |
billing_cadence |
BillingCadence | REQUIRED | Yes | null |
Billing cadence: a Duration (P1M, P1Y), "one_time", "negotiated", or null (unstated). |
trial_period |
Duration | REQUIRED | Yes | null |
Optional trial before billing; all rate cards are free during it. null for no trial. |
variant_of |
Key | REQUIRED | Yes | null |
Shared plan-group key carried by every commercial variant of one plan (e.g. pro_monthly and pro_annual both set pro). null when the package is not a variant. |
rate_cards |
RateCard[] | REQUIRED | No | [] |
Feature-level pricing/entitlement entries. A conformant package has ≥1 (R4). |
credit_grants |
CreditGrant[] | REQUIRED | No | [] |
Credit pools bundled into the package. Empty when none. |
available_addons |
Key[] | REQUIRED | No | [] |
Add-on keys purchasable with this package. Each MUST resolve to a top-level add-on (R9). |
conditions |
Conditions | REQUIRED | No | [] |
Structured qualifiers for when the package applies. |
currencyhas no schema-level default and MUST be emitted explicitly.billing_cadence,trial_period, andvariant_ofdefault tonullbut, like every field, MUST still be present.
Addon
Description
An optional, on-demand purchasable extension to a package — extra features or capacity. Add-ons are
defined once in top-level addons and referenced from packages via available_addons.
Containment
OpenPricing.addons[]. One instance per purchasable extension.
Fields
| Column ID | Type | Requirement | Nullable | Default | Description |
|---|---|---|---|---|---|
| (identity) | — | REQUIRED | — | — | key, name, description, attributes per Resource fields. |
max_quantity |
integer | REQUIRED | Yes | null |
Maximum purchasable quantity, ≥ 1. null means unlimited. 1 = single-instance add-on. |
currency |
CurrencyCode | REQUIRED | No | — | Currency applying to all the add-on's rate-card prices. |
rate_cards |
RateCard[] | REQUIRED | No | [] |
Feature-level pricing/entitlement entries for the add-on. An add-on MUST have ≥1 rate card or a non-null credit_grant (R16). |
credit_grant |
CreditGrant | REQUIRED | Yes | null |
Credits granted by purchasing the add-on (the rate cards price the purchase). null if none. |
currencyhas no schema-level default and MUST be emitted explicitly.max_quantitydefaults tonull(unlimited) but, like every field, MUST still be present — as an integer ≥ 1 ornull.
A single-instance add-on (max_quantity = 1) — e.g. "Enterprise support" — may be added once; a
multi-instance add-on (max_quantity > 1 or null) — e.g. additional seats or custom domains — may
be added repeatedly to raise an entitlement limit.
RateCard
Description
The pricing-and-entitlement entry for one feature within one package or add-on, typically
corresponding to a single cell in a pricing table. price and entitlement are orthogonal and both
REQUIRED: price specifies how each unit is billed; entitlement specifies what the customer
receives.
Containment
Package.rate_cards[] and Addon.rate_cards[]. One instance per priced feature within one package
or add-on, qualified by its conditions. The same feature MAY appear in more than one rate card of
the same package when each instance carries different conditions (for example one rate card for
region=us and another for region=eu). A consumer resolving the price of a feature in a package
MUST use the rate cards' conditions to select the applicable instance.
Fields
| Column ID | Type | Requirement | Nullable | Default | Description |
|---|---|---|---|---|---|
feature |
Key | REQUIRED | No | — | Key of the feature this rate card prices. MUST resolve to a top-level feature (R5). |
price |
Price | REQUIRED | No | — | How each unit is billed. Discriminated union, see Price. |
entitlement |
Entitlement | REQUIRED | No | — | What the customer gets. Discriminated union, see Entitlement. |
unit_config |
UnitConfig | REQUIRED | Yes | null |
Unit conversion applied before pricing/entitlement comparison. null when commercial unit = natural unit. |
billing_cadence |
BillingCadence | REQUIRED | Yes | null |
Per-rate-card cadence override. null inherits the package cadence. When both are Durations, MUST divide the package cadence (R12); "one_time"/"negotiated" do not participate. |
currency |
CurrencyCode | REQUIRED | Yes | null |
Per-rate-card currency override. null inherits the package/add-on currency. |
conditions |
Conditions | REQUIRED | No | [] |
Structured qualifiers for when the rate card applies. |
discount |
Discount | REQUIRED | Yes | null |
A percentage or usage discount. null when none. See Discount. |
commitments |
SpendCommitments | REQUIRED | Yes | null |
Minimum spend / spend cap. null when the page states neither. |
payment_term |
PaymentTerm | REQUIRED | Yes | null |
Billing timing. null when not stated — a producer MUST NOT infer it. See allowed values below. |
attributes |
Attributes | REQUIRED | No | [] |
Metadata. Prefer typed fields first. E.g. {key:"sku_id",value:"compute-vm-d2s-v5"}. |
Allowed Values — PaymentTerm
| Value | Description |
|---|---|
in_advance |
The charge is billed at the start of the period (prepaid). |
in_arrears |
The charge is billed at the end of the period (postpaid). |
payment_term is nullable: when the source does not state the billing timing, it is null, and a
producer MUST NOT default it to either value.
Price × Entitlement combinations
Both are required and independent. Common combinations:
| Commercial situation | price |
entitlement |
|---|---|---|
| Capability included ("SSO included") | PriceFree |
EntitlementIncluded |
| Hard cap, no overage ("100 GB, no overage") | PriceFree |
EntitlementLimit { value:"100" } |
| Hard cap with paid overage ("100 GB, then $0.10/GB") | PriceUnit { amount:"0.10" } + DiscountUsage { units:"100" } |
as appropriate |
| Per-seat charge ("$10/seat/mo") | PriceUnit { amount:"10" } |
EntitlementLimit { value:"1" } |
| Structured non-numeric ("99.95% SLA", "Premium support") | any price | EntitlementConfiguration |
| Quote-only ("Contact sales") | PriceCustom |
best-fit entitlement |
No percentage price. Take rates, revenue share, and cost-plus margins are a
unitprice over a currency-denominated meter: the meter reports the base value (payment volume, net license fees, upstream cost) and the unitamountis the multiplier —"0.029"for a 2.9% take rate,"0.30"for a 30% revenue share,"1.1"for a 10% cost-plus margin. A separate discount percentage (theDiscountPercentagemodel) is unrelated and concerns price reductions, not this multiplier.
Effective currency
A rate card has an effective currency, resolved as:
rate_card.currency, when non-null;- otherwise the
currencyof the containing package or add-on.
The containing package or add-on currency is non-nullable, so the effective currency is always
defined. Every currency-denominated Numeric amount within the rate card is interpreted in the
effective currency: the amount of a flat or unit price, the flat_price and unit_price
amounts of graduated and volume tiers, PriceCustom.estimated_amount, and
commitments.minimum_amount / commitments.maximum_amount. A tier's up_to_amount is a quantity
bound, not a monetary amount, and is not interpreted in any currency.
The effective currency does not apply to amounts that carry their own denomination or are not
monetary: a credit grant's amount and max_balance are denominated in the grant's own unit;
DiscountPercentage.percent is a ratio; and DiscountUsage.units is a quantity of usage units, not
a monetary amount.
Discriminated Unions
Price, Entitlement, and Discount are discriminated unions. The discriminator is an inline
type property on the object — the variant is not wrapped in a named envelope. A unit price is
serialized as:
{ "type": "unit", "amount": "0.20" }
It is NOT wrapped as { "unit": { "amount": "0.20" } }. A consumer MUST select the variant by
reading the type property.
Price
Discriminator: type (PriceType). Variants:
type |
Variant | Additional fields |
|---|---|---|
free |
PriceFree | (none) — an included feature with no additional charge. |
flat |
PriceFlat | amount: Numeric — a fixed price. |
unit |
PriceUnit | amount: Numeric — price per unit of a metered feature. |
graduated |
PriceGraduated | tiers: PriceTier[] — marginal tiered pricing. MUST contain at least one tier. |
volume |
PriceVolume | tiers: PriceTier[] — total-quantity-selected tiered pricing. MUST contain at least one tier. |
custom |
PriceCustom | qualifier: string, estimated_amount: Numeric | null — non-public/negotiated. |
PriceCustom. qualifier is a short commercial-posture label (contact_sales, negotiated,
contract_required, quote_only). estimated_amount carries an indicative starting price when the
page shows one, else null.
Choosing how to represent an unclear or non-standard price. A price is always present and
typed; the representation depends on what the source states:
| The source states… | Representation |
|---|---|
| A concrete price (free, flat, per-unit, or tiered) | The matching price variant (free, flat, unit, graduated, volume). |
| That pricing is negotiated, quote-only, or "contact sales" | PriceCustom, with qualifier naming the posture and estimated_amount set if a starting figure is shown. |
| A price whose model none of the variants captures | PriceCustom, with the closest qualifier, and the structural detail recorded in the rate card's attributes. |
| Nothing about how the line is priced, on a rate card that nonetheless exists | The variant that best fits the surrounding context; a rate card cannot omit price. When the line is included at no stated charge, use PriceFree. |
A null value is used for an unstated optional field (for example payment_term or a rate-card
currency override), not in place of a price. attributes records non-commercial annotation and
structural detail that no typed field captures; it does not substitute for a price type.
Graduated vs Volume.
- Graduated — each tier's rate applies only to units within that tier's range (marginal). "First 10k at X, next 40k at Y."
- Volume — the total quantity selects a single tier whose rate applies to all units. "Once usage reaches this tier, that rate applies to every unit."
PriceTier
Used by graduated and volume prices.
| Column ID | Type | Requirement | Nullable | Default | Description |
|---|---|---|---|---|---|
up_to_amount |
Numeric | REQUIRED | Yes | null |
Inclusive upper quantity bound. null marks the open-ended final tier; the last tier MUST be open-ended and no other tier may be. |
flat_price |
PriceFlat | REQUIRED | Yes | null |
Flat component of the tier. |
unit_price |
PriceUnit | REQUIRED | Yes | null |
Per-unit component of the tier. |
Tier-structure rules (R11): a graduated or volume price MUST contain at
least one tier; tiers MUST be ordered lowest→highest; the final tier MUST have up_to_amount = null
and no other tier may; each tier MUST carry flat_price, unit_price,
or both.
Entitlement
Discriminator: type (EntitlementType). Variants:
type |
Variant | Additional fields |
|---|---|---|
included |
EntitlementIncluded | (none) — access granted without an explicit cap (unlimited access, or a capability available in the plan). |
limit |
EntitlementLimit | value: Numeric, usage_period: Duration | null, scope: string | null — a usage cap or fixed allowance. |
configuration |
EntitlementConfiguration | values: Attributes — structured non-numeric metadata (SLA, support tier, residency). |
EntitlementLimit. Use for a fixed included allowance or a usage cap. A soft threshold that
continues with paid overage is modeled as a PriceUnit rate card with a DiscountUsage, not as this
entitlement. usage_period is the allowance reset cadence when it differs from the billing cadence
(P1D for "100 generations per day" on a monthly plan); null inherits the rate-card or package
cadence. A rate limit needs no extra field: value plus usage_period (PT1M) already expresses
"100 requests per minute".
scope names what the cap applies to when it is not organization-wide, e.g. "project" for Neon's
"100 CU-hours per project". null reads as organization-wide (the default reading of an unscoped
limit). It is an open string, not a closed enum, because providers scope caps unpredictably;
recommended values are project, user, workspace, database.
Discount
Discriminator: type (DiscountType). At most one discount per rate card. Variants:
type |
Variant | Additional fields |
|---|---|---|
percentage |
DiscountPercentage | percent: Numeric — percentage off the price, 0–100 (e.g. "25"). |
usage |
DiscountUsage | units: Numeric — free usage units granted before billing starts. |
DiscountUsage is meaningful only for usage-based features and is the canonical way to encode an
"included allowance, then paid overage" pattern alongside a PriceUnit.
DiscountUsage.units is expressed in the rate card's billing units: the unit the price operates on,
after any unit_config conversion. When the rate card has a unit_config, the free allowance is
counted in converted units, not raw quantity. units and the price amount are therefore stated in
the same unit. For example, on a rate card priced per million tokens (unit_config divide by
1000000, display_unit "M"), a free allowance of five million tokens is DiscountUsage { units: "5" }, not units: "5000000".
Supporting Models
UnitConfig
Description
Unit conversion applied before pricing and entitlement comparison, letting a rate card bill in a transformed unit (per GB, per million invocations) while the feature is described in its natural unit (bytes, raw invocations).
Containment
RateCard.unit_config (nullable).
Fields
| Column ID | Type | Requirement | Nullable | Default | Description |
|---|---|---|---|---|---|
operation |
UnitConfigOperation | REQUIRED | No | — | divide or multiply. |
conversion_factor |
Numeric | REQUIRED | No | — | Positive non-zero factor. E.g. 1000000000 (bytes→GB), 3600 (seconds→hours). |
rounding |
UnitConfigRoundingMode | REQUIRED | No | none |
Rounding mode applied after conversion. |
precision |
integer | REQUIRED | Yes | null |
Decimal precision retained after rounding. Only matters when rounding ≠ none. null if unstated. |
display_unit |
string | REQUIRED | Yes | null |
Human-readable converted unit label (GB, hours, million requests). null if no stable label. |
Computation: for divide, billed = raw / conversion_factor; for multiply, billed = raw * conversion_factor.
Allowed Values — UnitConfigOperation
| Value | Description |
|---|---|
divide |
Divide raw quantity by the factor (e.g. 2.5M tokens / 1M = 2.5 units). |
multiply |
Multiply raw quantity by the factor (e.g. 100 × 1.2 = 120 units). |
Allowed Values — UnitConfigRoundingMode
| Value | Description |
|---|---|
ceiling |
Round up to the next whole/configured increment. Typical for "per started GB / hour" billing. |
floor |
Round down after conversion. Rare; use only when the provider clearly states it. |
half_up |
Round to nearest, midpoints up. Use only for stated standard commercial rounding. |
none |
Do not round. The default; used when no rounding rule is stated. |
SpendCommitments
Description
Published commitments for a rate card: spend floors and caps in the rate card's effective currency,
plus the one quantity floor (minimum_quantity).
Containment
RateCard.commitments (nullable).
Fields
| Column ID | Type | Requirement | Nullable | Default | Description |
|---|---|---|---|---|---|
minimum_amount |
Numeric | REQUIRED | Yes | null |
Published minimum spend. null when none stated. |
maximum_amount |
Numeric | REQUIRED | Yes | null |
Published spend cap. null when none stated. |
minimum_quantity |
Numeric | REQUIRED | Yes | null |
Smallest purchasable quantity of the rate card's unit (e.g. "minimum 3 seats"). null when none stated. |
The floor applies per rate card. When both are stated, the smallest bill is max(minimum_amount, minimum_quantity × unit price), and the two floors compose (a plan can carry both a platform fee and
a seat minimum). Encode a stated quantity minimum as minimum_quantity, never as a derived
minimum_amount.
CreditGrant
Description
A prepaid value pool bundled with a package or granted by an add-on purchase. Emit a credit grant
only when the page names a credit-like currency (credits, points, tokens) that one or more
features draw from. A single feature's included quota is an EntitlementLimit or DiscountUsage,
not a credit grant.
Containment
Package.credit_grants[] and Addon.credit_grant (nullable).
Fields
| Column ID | Type | Requirement | Nullable | Default | Description |
|---|---|---|---|---|---|
unit |
CurrencyCode | REQUIRED | No | — | Grant denomination: a fiat code (USD for "$10 in credits") or a declared custom code. |
amount |
Numeric | REQUIRED | No | — | Amount of credit granted, in unit. |
cadence |
Duration | "one_time" |
REQUIRED | Yes | null |
How often the grant recurs (P1M, P1D), "one_time" for a single non-recurring grant, or null when unstated. Never "negotiated". |
expires_after |
Duration | REQUIRED | Yes | null |
How long granted credits stay valid (P1M, P2Y). null when credits never expire / unstated. |
max_balance |
Numeric | REQUIRED | Yes | null |
Cap on accumulated unused credits, in unit. null when uncapped/unstated. |
per_unit_cost_basis |
Numeric | REQUIRED | Yes | null |
Published monetary value of one credit, in the effective fiat currency: its purchase price ("$30 per 1M points" → 0.00003) or, for a bundled grant, its stated worth. null when the page publishes no per-credit rate. |
feature_scope |
Key[] | REQUIRED | No | [] |
Feature keys the credits apply to. Empty means all features. Each listed key MUST resolve to a top-level feature (R15). |
Common patterns: "resets monthly, no rollover" → cadence P1M, expires_after P1M; "150 credits
daily" on a monthly plan → cadence P1D; "credits roll over, valid two years" → expires_after P2Y;
"500 signup credits, one-time" → cadence "one_time".
Common Attributes
Rules that apply uniformly across many fields:
- Strings. UTF-8.
namefields are 1–256 chars;descriptionfields are 0–1024 chars with a""default. Producers MUST NOT invent text for an empty description. - Decimals / numerics. All numeric quantities are
Numericstrings. ANumericfield MUST NOT be a JSON number. The two integer fields (Addon.max_quantity,UnitConfig.precision) are JSON integers within the IEEE-754 safe-integer range. - Dates / times.
DateTimeis RFC 3339 in UTC. - Durations.
Durationis ISO 8601 (P…). - Currencies.
CurrencyCode; custom codes MUST be declared (R10). - Nulls.
nulldenotes "not stated". The string"null"is not a valid substitute. A nullable field MUST be present with valuenull, not omitted. - Arrays / objects. Empty collections are emitted as
[], present and explicit. - Attributes.
Attributesis[{key,value}]with both values string-typed, used for extension data only.
Extensions
The object shapes are closed: a conformant document MUST NOT add keys that this specification
does not define to any object. Provider-specific data that has no first-class field is carried in the
attributes array ([{key,value}]) present on every object that has the shared identity fields and
on RateCard.
Rules for extension data:
- Producers MUST place provider-specific qualifiers in
attributes, not in an undefined field. - Producers MUST NOT use
attributesfor commercial logic that a typed field already models (price,entitlement,discount,unit_config,conditions,commitments). - Consumers MUST ignore
attributeskeys they do not recognize and MUST NOT reject a document for carrying unfamiliar attribute keys. - New first-class vocabulary (a new enum member, a new field) is a change to this specification,
released through versioning, not carried in
attributes.
Validation Rules
A validator checks a candidate document against this specification and classifies each violation. The two classes of rule are independent; a validator SHOULD check both and SHOULD report each violation with the JSON path of the offending value.
| Class | What is checked | On violation |
|---|---|---|
| Field violation | A field is absent, mistyped, outside its value format or length bound, not among its allowed values, or null where non-null is required. |
The document is non-conformant. A validator MUST report it. |
| Document violation | A document requirement R1–R16 fails (a broken reference, a duplicate key, a conditional field obligation not met). | The document is non-conformant. A validator SHOULD report it, naming the requirement. |
A field violation can be detected by inspecting a single value against its definition. A document
violation requires looking at more than one field or object at once (a reference and its target, a
key and its siblings, a price type and a feature's meter_key). Both render a document
non-conformant; the distinction is informational, to help a validator locate and explain the
failure. Conformance does not depend on any particular validator implementation.
Validator profiles
A tool that validates OpenPricing documents conforms to one of two profiles. A tool MUST state which profile it implements.
| Profile | Checks | Catches |
|---|---|---|
| Schema validator | Field requirements only, via the JSON Schema. | Field violations. |
| Conforming OpenPricing validator | Field requirements and document requirements R1–R16. | Field violations and document violations. |
The JSON Schema (drafted against JSON Schema 2020-12) expresses the field requirements but cannot express the referential-integrity and cross-field requirements R1–R16. A schema validator therefore accepts documents that a conforming OpenPricing validator rejects. A tool that checks only the JSON Schema MUST NOT describe its result as full OpenPricing conformance.
Examples
Minimal conformant catalog
A flat-priced single plan with one included feature:
{
"key": "acme",
"name": "Acme",
"description": "",
"attributes": [],
"service_category": "developer_tools",
"service_subcategory": null,
"provider_url": "https://acme.example",
"pricing_page_url": "https://acme.example/pricing",
"features": [
{
"key": "core_platform",
"name": "Core platform",
"description": "",
"attributes": [],
"meter_key": null,
"meter_conditions": []
}
],
"meters": [],
"custom_currencies": [],
"packages": [
{
"key": "pro",
"name": "Pro",
"description": "",
"attributes": [],
"currency": "USD",
"billing_cadence": "P1M",
"trial_period": null,
"rate_cards": [
{
"feature": "core_platform",
"price": { "type": "flat", "amount": "20" },
"entitlement": { "type": "included" },
"unit_config": null,
"billing_cadence": null,
"currency": null,
"conditions": [],
"discount": null,
"commitments": null,
"payment_term": "in_advance",
"attributes": []
}
],
"credit_grants": [],
"available_addons": [],
"conditions": []
}
],
"addons": [],
"last_updated": null
}
Metered feature with a graduated price
The fragments below show a metered token feature and a graduated unit-priced rate card. The meter
aggregates a tokens property by sum; the feature narrows it to a model+direction slice; the rate
card prices it per million tokens via unit_config.
{
"meters": [
{
"key": "tokens",
"name": "Tokens",
"description": "",
"attributes": [],
"event_type": "token_usage",
"value_property": "tokens",
"aggregation": "sum",
"dimensions": ["model", "type"]
}
],
"features": [
{
"key": "gpt_5_5_input_tokens",
"name": "GPT-5.5 input tokens",
"description": "",
"attributes": [],
"meter_key": "tokens",
"meter_conditions": [
{ "key": "model", "operator": "eq", "value": "gpt-5.5" },
{ "key": "type", "operator": "eq", "value": "input" }
]
}
]
}
A graduated rate card for that feature, billed per million tokens:
{
"feature": "gpt_5_5_input_tokens",
"price": {
"type": "graduated",
"tiers": [
{ "up_to_amount": "10", "flat_price": null, "unit_price": { "type": "unit", "amount": "1.25" } },
{ "up_to_amount": null, "flat_price": null, "unit_price": { "type": "unit", "amount": "1.00" } }
]
},
"entitlement": { "type": "included" },
"unit_config": {
"operation": "divide",
"conversion_factor": "1000000",
"rounding": "none",
"precision": null,
"display_unit": "M"
},
"billing_cadence": null,
"currency": null,
"conditions": [],
"discount": null,
"commitments": null,
"payment_term": "in_arrears",
"attributes": [{ "key": "model_id", "value": "gpt_5_5" }]
}
Take rate (no percentage price type)
A 2.9% payment-processing take rate, modeled as a unit price over a currency-denominated meter
(payment_volume in USD), the unit amount being the multiplier:
{
"feature": "payment_processing",
"price": { "type": "unit", "amount": "0.029" },
"entitlement": { "type": "included" },
"unit_config": null,
"billing_cadence": null,
"currency": null,
"conditions": [],
"discount": null,
"commitments": null,
"payment_term": "in_arrears",
"attributes": []
}
Schema Artifact
This specification is accompanied by a machine-readable JSON Schema that encodes the per-field portion of the contract — the field set, types, value formats, length bounds, allowed values, and nullability defined above. It is identified by:
| Property | Value |
|---|---|
$id |
https://openpricing.io/draft-01/schema.json |
$schema |
https://json-schema.org/draft/2020-12/schema |
| Root | the OpenPricing object |
Validating a document against the JSON Schema checks the field requirements. It does not check the document requirements (R1–R16), which constrain relationships across fields and objects; those are checked separately. A document is conformant only when it satisfies both. The JSON Schema and this document describe one contract; a divergence between them is a defect to be reconciled.
Canonical Encodings
One blessed encoding per otherwise-ambiguous construct, so two producers do not legitimately diverge:
| Construct | Canonical encoding |
|---|---|
| Percentage price (take rate, revenue share, cost-plus margin) | A unit price over a currency-denominated meter; the amount is the multiplier (see Price × Entitlement). |
| Minimum-usage plan ("$5/month minimum, includes $5 of usage") | A flat base fee plus a matching monthly CreditGrant, never a bare commitments.minimum_amount. |
| Cap-unlock fee ("$250 for unlimited overrides") | A graduated price whose final tier carries a flat_price. |
| Hourly-prorated monthly rate | The stated amount with the hours-per-period convention in unit_config (720 for a 30-day month). |
| Setup / implementation fee | An add-on (or rate card) with billing_cadence: "one_time" and a flat price. |
| Prepaid unit bundle | A one-time add-on whose rate card carries the bundle price and an EntitlementLimit for the included units. |
| Purchasable credit pack | A one-time add-on with a credit_grant, linked to the pool it tops up by the shared custom currency code. |
| Quantity minimum ("minimum 3 seats") | commitments.minimum_quantity: "3" on the seat rate card, list price unchanged. |
Migration and Versioning
- Identity. The specification's identity is the JSON Schema
$id,https://openpricing.io/draft-01/schema.json. The version segment (draft-01) advances when the contract changes incompatibly. - During draft. While the version is
draft-01, the contract MAY change without a deprecation cycle, and documents are not guaranteed to remain valid across draft revisions. A producer re-emits a document against the current revision rather than relying on in-place migration. - Field lifecycle. Adding a new enum member or a new union variant is additive for existing documents. Because every field is REQUIRED, adding a field is not backward compatible for producers (they must now emit it) even though consumers tolerate it; such changes are batched into a version bump.
- Stabilization. When the specification leaves draft, a stable
$idversion (e.g.v1) is assigned, introduced and deprecated fields carry an "Introduced In" marker, and a defined compatibility and deprecation policy replaces the re-emit approach described above. - Introduced In. Every field and enum member in this specification was introduced in
draft-01.
Changelog
| Version | Date | Changes |
|---|---|---|
draft-01 |
2026-06-17 | Initial draft of the OpenPricing data specification. |
draft-01 |
2026-07-07 | v1.0 finalization: BillingCadence union (one_time/negotiated) on Package/RateCard; CreditGrant.cadence gains "one_time"; SpendCommitments.minimum_quantity; EntitlementLimit.scope; Package.variant_of. Added the canonical-encoding section. |