13 Oct 2026 · 5 min read
Tier pricing, customer groups, and B2B price resolution
How Magento resolves tier, group and B2B shared-catalog prices in order, and where catalog_product_index_price stores the final number
Part 3 of the Catalog at Scale series — the final price is a resolution order, not a field.
Shoppers see one price. Behind it, Magento evaluates a stack: base price, special price, tier prices, group prices, catalog rule prices, and on B2B installations shared-catalog pricing, then writes the winner into catalog_product_index_price per website and customer group. When B2B buyers report "wrong price," the bug is almost never the number typed in the admin. It is the resolution order nobody wrote down.
The layers in evaluation order
For a given product, website, and customer group, Magento resolves prices roughly in this sequence. Each layer can only lower or replace what the previous layer produced, and the price index records the outcome:
- Base price from
catalog_product_entity_decimalfor thepriceattribute, scoped per website. - Special price with its date window, when active, replaces the base for the displayed regular price.
- Tier prices from
catalog_product_entity_tier_price: quantity thresholds per website, group, and quantity. The applicable tier for the cart quantity wins when it is lower. - Group price / customer group price: a fixed price for a specific customer group, evaluated alongside tiers. Historically stored with tier records; conceptually a quantity-one override for that group.
- Catalog rule price from
catalogrule_product_price: the rule engine output for this product, website, and group. - B2B shared catalog pricing on Commerce/Adobe Commerce: the assigned shared catalog and its tier structure override the standard stack for company-associated customers.
The storefront never evaluates this stack live per request at scale. The price indexer computes the minimum applicable combination and stores it in catalog_product_index_price with min_price, max_price, and tier_price columns per group and website. That table is the storefront truth. Debugging price means reading that row first, then walking the stack backwards to find which layer produced it.
Tier prices: quantities, groups, and websites
Tier records carry four coordinates: product, website, customer group (all groups or a specific group), and minimum quantity. A common B2B shape is three tiers for retailers at quantities 10, 50, and 200, plus a separate set for distributors. The indexer picks the best tier at or below the quote quantity for the buyer's group.
Three mistakes dominate large catalogs. First, tiers defined for all groups that undercut a negotiated group price, because all groups applies to everyone including groups that have their own fixed price. Second, duplicate tier quantities across websites where only one website was intended, doubling import rows and indexer input. Third, tier prices above the base price left over from a bulk import, which the indexer silently ignores but which confuse every merchant who reads the admin grid.
Imports deserve care: tier prices import per website and group, and a feed that omits the group column can assign every row to all groups. Validate group codes and website codes before the feed runs, not after buyers see the wrong number.
Customer groups as a pricing axis
Customer groups (customer_group table, referenced as customer_group_id across pricing tables) are the axis the whole stack pivots on. Guest and general groups see list prices; trade groups see negotiated prices; tax classes and catalog rule scoping also key off the group. A new group is therefore a pricing event: every catalog rule must declare whether it applies to the group, every shared catalog must assign the group, and the price index must be rebuilt for the group's rows.
Keep the group list short. Five to eight groups cover most B2B operations. Twenty groups with three active buyers each means every pricing table carries dead combinations that the indexer still computes. Name groups by commercial meaning, retailer, distributor, partner, not by campaign, because campaigns expire and group IDs do not clean themselves up.
The NOT LOGGED IN group deserves explicit review. Catalog rules and tiers scoped to all groups include guests, which is how a trade discount leaks to the public storefront. When a price looks wrong for guests, check all groups rows before anything else.
B2B: shared catalogs sit on top
On Commerce with B2B, shared catalogs add a final override layer. A company is assigned to a shared catalog, and that catalog carries its own product prices and tier structures. For company buyers, shared catalog pricing replaces the standard tier and group resolution for assigned products. Products not assigned to the shared catalog fall back to the standard stack, which is exactly how mixed catalogs produce "some products discounted, some not" reports that look like bugs but are assignment gaps.
Debugging order for a B2B price complaint: confirm the buyer's company and its assigned shared catalog, confirm the product is assigned to that catalog with a price, then read catalog_product_index_price for the product, website, and the buyer's group. If the index row matches the shared catalog price, the engine worked and the assignment is the question. If it does not, check whether the price index has been rebuilt since the assignment changed.
Reading the final number
catalog_product_index_price stores the computed outcome per product, website, and group: price as the regular resolved price, final_price as the selling price after rules and specials, min_price and max_price for configurable ranges, and tier_price as the best available tier. Queries filtered by product, website ID, and group ID answer "what does this buyer see" without rendering a page.
When the row is wrong, walk backwards: is there a shared catalog override, which catalog rule rows exist in catalogrule_product_price for this product and group, which tier rows exist at or below the quantity, is a special price window active. Log each layer's candidate in order and the winner becomes obvious. Most B2B pricing tickets resolve at step one or two once the stack is written down per store.
Operational rules for B2B pricing at scale
- One owner for the resolution order document: which layers the business uses and which always win.
- No
all groupstiers or rules without a recorded reason; default to named groups. - Tier imports validated against website and group codes before execution.
- Shared catalog assignments reviewed when companies or products change, with a price reindex gated on completion.
- A reference matrix of test buyers, one per group and shared catalog, with expected prices for a fixed basket, checked after every pricing deploy.
Price resolution rewards explicitness. The next post leaves pricing for time: how to publish future content and price changes on schedule without Commerce staging.
Next in this series:
Continue with magento2-catalog-scheduled-updates for scheduled content updates without Commerce staging.