Price selection

Predict which Price commercetools selects for a buyer, and diagnose the most common B2B pricing failures with a structured checklist.

Ask about this Page
Copy for LLM
View as Markdown

After completing this page, you should be able to:

  • Trace the price-selection fallback to predict which Price the platform selects.

  • Explain how currency and validity act as hard filters before specificity is scored.

  • Diagnose a B2B pricing failure using a structured debugging checklist.

The single most common B2B implementation issue is not "the wrong price showed"; it is "no price showed at all," or "a price showed that nobody can explain." Both come from the same source: a Price exists, but it does not match the buyer's context, or a more specific Price won. The Price and discount your products path introduced price selection and its fallback order; this page focuses on tracing it in a multi-buyer B2B project and on debugging it when a price goes missing.

What price selection actually does

When a Cart resolves a Line Item Price, the platform does not start by picking the cheapest or newest Price. It filters the candidate Prices for the SKU by context, then walks a fixed fallback order from most specific to least specific and uses the first fallback level that contains an eligible Price. Two of those context dimensions behave as hard filters, meaning that if they do not match, the Price is never a candidate:
  • Currency must match the Cart's currency exactly.
  • Validity period: a Price is only eligible when the request time falls within its validFrom and validUntil window. Prices with a current validity window are preferred over Prices with no dates.

The remaining dimensions (Customer Group, Channel, and country) are scored by specificity.

The fallback order

For a given currency, commercetools applies the canonical price-selection fallback logic: Customer Group is evaluated before Channel, and Channel before country. Use that order when tracing the worked example below. The important B2B design point is not to memorize every fallback combination, but to know which pricing dimension wins when more than one matches.
When the walk completes without finding any matching fallback level (most commonly because no Currency-matching Price exists, or because the buyer's Store has no distribution Channel attached), the product has no selected price. In storefronts this outcome is typically surfaced as "price on request": the product is visible but cannot be added to a Cart at a resolved price, and the buyer must contact the seller directly. Treat this as a diagnostic signal: if a buyer sees "price on request" for a product that should be priced, price selection terminated without a match, and the debugging checklist below will identify why.
The ordering tells you something important for B2B design: Customer Group outranks Channel, which outranks country. A Customer-Group-scoped Price will beat a Channel-scoped Price when both match at different fallback levels. If multiple eligible Prices match the same fallback level, the cheapest eligible Price is selected before Cart Discounts. This matters most when a Customer or Business Unit has multiple Customer Group assignments. For the Channel-on-Store pattern from the previous page, where buyers are not assigned Customer Groups for pricing, the Channel-specific fallback levels resolve the negotiated rate.

Resolving prices for B2B catalogs

When a buyer browses, you need prices resolved in the catalog response, not just on the Cart. Use the price-selection parameters on the Product Projection and Product Search APIs (priceCurrency, priceChannel, priceCustomerGroup, and priceCountry) scoped to the buyer's context. Setting priceChannel to the buyer's distribution Channel returns the negotiated Price alongside each Product. When the buyer adds a Product to the Cart, pass the same Channel as the Line Item distributionChannel so Cart price selection uses the same commercial context.
To fetch product data alongside search results, the recommended integration path is the GraphQL productsSearch query, which lets you request only the fields you need. The older productProjectionParameters data-integration field on Product Search was deprecated in December 2025. Search and faceting for B2B are covered in the previous module, Product Search for B2B catalogs.

Worked example: an Atlas Corporate APAC buyer

Atlas Corporate Solutions has an APAC division buying in AUD through its atlas-apac-pricing distribution Channel. Trace the selection for SKU ZET-MONITOR-27, given these candidate Standalone Prices:
PriceCurrencyChannelCountryvalidFrom / validUntilValue
P1AUDatlas-apac-pricingAUcurrent64900
P2AUDatlas-apac-pricing(any)none67900
P3AUD(any)(any)current79900
P4USDatlas-apac-pricingAUcurrent49900
For a Cart in AUD with country AU and the atlas-apac-pricing Channel:
  • P4 is filtered out immediately: its currency is USD, which does not match the Cart. The lowest number on the list is never even a candidate.
  • P1, P2, P3 remain. The walk starts with Customer Group combinations. There is no Customer Group in context, so those levels find nothing. The first Channel-and-country level matches P1 (atlas-apac-pricing, AU, currently valid).
  • The first matching fallback level contains P1, AUD 649.00. P2 and P3 are never reached, even though later fallback levels would have matched them.

The lesson for tracing: read top-down, stop at the first matching fallback level, and remember that currency and validity gate the list before specificity is ever scored.

The pricing debugging checklist

When a buyer reports a missing or wrong price, work this checklist in order. It mirrors the fallback order, so the first failing check is usually the cause. Keep it to hand during implementation as a diagnostic for the most common B2B pricing failures.

  1. Currency: does a Price exist for the exact Cart currency? A price in the "wrong" currency is invisible, not a fallback.
  2. Validity window: is the request time inside the Price's validFrom / validUntil? An expired or not-yet-valid Price is filtered out.
  3. Channel ↔ Store link: is the buyer's distribution Channel actually attached to the Store the Business Unit resolves to? A Channel-scoped Price with no Channel on the Store never matches.
  4. Customer Group: if you scope prices by Customer Group, is the expected group resolved on the Cart or Customer? A Customer Group match also outranks a Channel match, so check it is not selecting an unexpected Price.
  5. Product Selection / availability: is the SKU actually available to the buyer through an active Product Selection (from the previous module)? A buyer cannot be priced for a Product they cannot see.
  6. Precision and rounding: are amounts the precision you expect, and is the Cart's rounding mode the one your invoicing requires? Covered in high-precision pricing.
  7. API surface: are you reading the Price from a price-aware response (a Cart Line Item with distributionChannel set, or a Product Search/Projection with price-selection parameters set) rather than a raw Product that performs no price selection?

Key takeaways

  • Currency and validity period are hard filters; non-matching Prices are removed before specificity is scored.
  • The fallback order is Customer Group, then Channel, then country, using the first matching fallback level from most specific to least specific.
  • If multiple eligible Prices match the same fallback level, the cheapest eligible Price is selected before Cart Discounts.
  • A Customer-Group-scoped Price outranks a Channel-scoped Price when both match, which matters when mixing the two scopes.
  • For Channel-on-Store B2B pricing, the Channel-and-country or Channel-only fallback level resolves the negotiated rate.
  • A missing price is almost always one of seven things; work the debugging checklist in waterfall order to find the first failing check.

Test your knowledge