Skip to main content

Operate the product catalog

This guide documents operational rules for product and price catalog operations.

It focuses on behavior and constraints. For endpoint request/response shapes, use API reference.

Prereqs

API surfaces

Management (write/read):

  • /mgt/v1/ops/catalog/products*
  • /mgt/v1/ops/catalog/prices*

Public catalog read:

  • /api/v1/catalog/products
  • /api/v1/catalog/prices

Authoritative schema:

Product lifecycle behavior

  • Create accepts draft, active, archived.
  • Delete is soft archive (status = archived), not hard delete.
  • Patch with no effective fields returns current record unchanged.
  • presentation_config must be a JSON object (array is invalid).

Price lifecycle behavior

  • Create defaults status to active when omitted.
  • Delete is soft archive (status = archived), not hard delete.
  • Patch with no effective fields returns current record unchanged.
  • Price must belong to an existing product in the same realm.

Recurring and subscription-group rules

Recurring shape rules:

  • recurring_interval and recurring_count must be provided together.
  • If recurring is set, subscription_group_id is required.

Group pairing rules:

  • subscription_group_id and subscription_group_key must be provided together.
  • Group id must reference an existing subscription group.

Deterministic ordering and default selection

Price ordering is deterministic:

  1. display_priority ascending
  2. unit_amount ascending
  3. deterministic final tiebreaker

Implications:

  • Public catalog APIs return prices in this order.
  • Default price selection follows this order after filters.
  • In product detail reads, if a price exists in default_currency, it is preferred as default; otherwise the first ordered price is used.

Validation and uniqueness rules

  • product_code is unique.
  • (provider, provider_product_id) is unique.
  • price_code is unique.
  • provider_price_id is unique.
  • default_currency and currency must be 3-letter uppercase.
  • unit_amount >= 0.
  • recurring_count > 0 when recurring is set.

Conflicting writes against these rules are rejected; retries with the same invalid input do not succeed.

Metadata keys that drive system behavior

Product metadata

  • billing_plan_code
  • grants[]

Price metadata

  • billing_plan_code
  • grants[]
  • gating.bundle

Rules and precedence

  • metadata.grants must not contain duplicate grant program codes within the same metadata object.
  • Grant binding merge reads product + price grants:
    • same program code on both levels: price-level values override product-level values.
  • Billing plan mapping prefers price-level billing_plan_code; falls back to product-level when price-level is absent.
  • Gate bundle projection reads metadata.gating.bundle from price metadata.

Public catalog read semantics

  • Public /catalog/products and /catalog/prices return only active products and active prices.
  • /catalog/prices requires product_id.
  • Optional expansions enrich products/prices with:
    • subscription-state hints
    • feature-family projections

This makes catalog usable as a storefront index while keeping write operations on the management surface.

Operational workflow recommendation

  1. Create products in draft.
  2. Attach prices and validate recurring/group constraints.
  3. Verify metadata wiring (billing_plan_code, grants, gating.bundle).
  4. Promote to active.
  5. Archive old products/prices instead of deleting history.

Verify

  • Create/update/delete operations satisfy recurring/group pairing rules.
  • No duplicate program codes exist inside each metadata.grants.
  • Public catalog returns expected active products/prices and order.
  • Checkout/subscription flows resolve expected plan/grant/gate outcomes from metadata.

Next