Skip to main content

Pricing tier fields & guards reference

This page is a lookup for every field on a pricing tier, the rules that constrain relative tiers (chain depth, circular references, currency inheritance), and the guards that block a tier from being deleted while it's in use.

For the task of creating and editing tiers, see Manage pricing tiers. For the mental model behind relative tiers and how their prices are derived, see Relative pricing tiers. To apply a tier's price to a specific product, see Set a product's price.

Before you begin

Pricing tiers are an account-level catalog setting under Products → Pricing Tiers. Managing them requires the pricing-tier settings permission; see Product permissions reference.

Field reference

Every field below appears on the pricing-tier API resource. Numeric adjustment fields are stored and returned with 4 decimal places (decimal:4).

FieldTypeApplies toNotes
idintegerallRead-only identifier.
namestring, max 255allRequired and unique across pricing tiers. Also used as the import-mapping key (price.<name>.value), so renaming affects integration mappings.
pricing_typeenum absolute | relativeallDefaults to absolute when omitted on create. An absolute tier holds a price you set per product; a relative tier derives its price from a source.
relative_basisenum pricing_tier | supplier_pricing_tier | attributerelativeThe source a relative tier derives from. null for absolute tiers. Required when pricing_type is relative.
base_pricing_tier_idinteger, nullablerelative (pricing_tier basis)The tier this one derives from. Required when relative_basis is pricing_tier.
base_pricing_tier_namestringrelativeRead-only; included when the base tier is loaded.
base_supplier_pricing_tier_idinteger, nullablerelative (supplier_pricing_tier basis)The supplier pricing tier this one reads cost from (cost-plus).
base_supplier_pricing_tier_namestringrelativeRead-only; included when loaded.
base_attribute_idinteger, nullablerelative (attribute basis)The numeric/integer product attribute this tier derives from. Required when relative_basis is attribute. The attribute must be a numeric or integer type.
base_attribute_namestringrelativeRead-only; included when loaded.
attr_ratedecimal(4), -999999.9999999999.9999relative (attribute basis)Multiplier in the attribute formula. Required for the attribute basis.
attr_offsetdecimal(4), same rangerelative (attribute basis)Additive offset in the attribute formula.
adjustment_percentagedecimal(4), -99.9999999.9999relative (pricing_tier, supplier_pricing_tier)Percentage adjustment applied to the base price. Required for the pricing-tier and supplier bases.
adjustment_fixed_amountdecimal(4), -999999.9999999999.9999relativeFlat amount added after rounding.
rounding_valuedecimal(4), > 0, max 999999.9999relativeOptional. When set, the price is rounded to the nearest multiple of this value; when empty, the price is rounded to 2 decimals.
currency_codestring, must exist in currenciesallSet on create only; not editable on update for any tier. For pricing-tier and supplier basis relative tiers it's inherited from the source on save (see below); an attribute-basis tier keeps the currency you set on create.
is_defaultbooleanallMarks the account's default pricing tier. Setting a tier default clears the flag on all others. The default tier can't be relative, can't be archived, and can't be deleted.
chain_depthinteger (computed)all0 for absolute tiers; 13 for relative tiers, counting the hops back to the root absolute tier.
dependent_tier_countinteger (computed)allHow many tiers use this tier as their base; included when counted.
created_at / updated_atdatetimeallRead-only timestamps.
archived_atdatetime, nullableallSet when the tier is archived; archived tiers are excluded from lists by default.

How relative prices are calculated

The two relative formulas share a rounding-then-fixed-amount tail, and every result is floored at 0:

  • Pricing-tier / supplier basis: intermediate = basePrice × (1 + adjustment_percentage ÷ 100), then apply rounding, then add adjustment_fixed_amount.
  • Attribute basis: intermediate = attributeValue × attr_rate + attr_offset, then apply rounding, then add adjustment_fixed_amount.
  • Rounding step: when rounding_value is set and greater than 0, round(intermediate ÷ rounding_value) × rounding_value; otherwise round(intermediate, 2).

Relative chain depth & circular references

Relative tiers can point at other relative tiers, forming a chain that ends at a root absolute tier. Two rules keep those chains valid, enforced at validation time on create and update. Both checks apply only to the pricing_tier basis — supplier and attribute bases read from a fixed source and can't form a tier-to-tier cycle.

RuleBehaviorError
Self-referenceA tier can't set itself as its own base.A pricing tier cannot reference itself as a base tier.
Circular referenceSetting a base whose own chain leads back to this tier is rejected. The check walks up from the proposed base, tracking every tier visited.Cannot set this base tier: it would create a circular reference.
Maximum chain depthThe chain from a tier back to its root absolute tier may be at most 3 hops deep; a deeper chain is rejected.Maximum chain depth of 3 exceeded.
Default can't be relativeThe default tier can't be changed to relative.The default pricing tier cannot be set to relative.

A validation failure returns HTTP 422 with the message on the relevant field (base_pricing_tier_id for self/cycle/depth, pricing_type for the default-relative case).

The chain-walking helpers (resolveChain, getRootTier) also carry runtime loop-safety guards independent of validation: chain resolution stops after 10 hops, and root resolution stops if it revisits the starting tier. These guards protect the price calculation against a malformed chain that somehow bypassed validation, so a computed chain_depth never runs away.

Currency inheritance

currency_code is required when you create a tier, but a relative tier doesn't keep its own currency independent of its source — the currency is resolved automatically on save:

TierResulting currency
Absolute tierThe currency_code you set on create.
Relative, pricing_tier basisInherited from the root absolute tier of its chain (getRootTier()->currency_code).
Relative, supplier_pricing_tier basisInherited from the base supplier pricing tier's currency (falls back to the tier's own currency if the supplier tier has none).
Relative, attribute basisNot inherited — keeps the currency_code you set on create.
Any tier with an empty currency after the aboveFalls back to the account's default currency (Currency::default()->code).

currency_code is dropped from the update rules for every tier — you set it once on create. On each save, pricing_tier and supplier basis relative tiers re-resolve their currency from the source; absolute and attribute-basis tiers keep the value you set.

Delete guards

Deleting a pricing tier first checks whether it's in use. If any guard matches, the delete is blocked, the tier is left intact, and the API returns HTTP 400 with one error per matching reason (each keyed with a resource-linked code). If nothing matches, the tier's product pivots are detached and the tier is deleted.

GuardBlocked whenReason returned
Default tieris_default is trueYou can't delete the default product pricing tier '<name>'
In use by productsAny product has a price stored against this tier (product_prices_count > 0)Count of products currently using the tier.
Integration import mappingsAny data-import mapping references it via mapping->sku_field = price.<name>.valueCount of integration listing mappings using the tier.
Base for active tiersAny non-archived tier lists this one as its base (active dependent tiers)This tier is used as a base for: <names>

To delete a blocked tier, first clear what depends on it — remove the tier's price from the products using it (see Set a product's price), remove or repoint any dependent relative tiers, and remove any integration import mappings that target it. A default tier can never be deleted; assign the default flag to another tier first.

Archiving is a softer alternative but carries its own two guards, both returning HTTP 400: a tier that's the default can't be archived, and a tier that's a base for active dependent tiers can't be archived. Unlike delete, archiving doesn't check product usage or import mappings — an archived tier is simply hidden from lists by default while its historical prices remain. See Archive, unarchive & delete a product for the same pattern applied to products.

Next steps

Last verified: