Direct answer: customer-specific B2B pricing should not be modelled by cloning the product catalogue or stacking discounts until the desired number appears. A robust model separates four decisions: who is buying (account, company or location), what they may buy (catalogue and assortment), which contractual price applies (currency, unit, validity and tiers), and which rule wins when several conditions match. The same precedence must be used on the product page, in the basket, at checkout, in the order and in the ERP.
If a price is correct on screen but changes when the order reaches the ERP, the business does not have one pricing model. It has competing interpretations. The operational goal is simple: the same account, SKU, quantity, date, market, currency and selling unit must always produce the same explainable result.
Do not confuse catalogue, price list and discount
In B2B commerce, a catalogue answers “may this customer see and purchase this product?”. A price list answers “what authorised base price applies to this account?”. A discount answers “which additional adjustment is allowed for this transaction?”. Combining those concepts creates exceptions that are hard to audit: duplicate products, promotions overriding contracts, public values exposed to private accounts, and different totals in commerce and ERP.
A maintainable architecture keeps one stable product identifier and relates that SKU to access and pricing rules. Duplicate a product only when its commercial or logistical identity is genuinely different, not as a way to represent every contract.
Define the minimum pricing key
Before choosing a platform or data model, specify the inputs that identify a pricing decision. At minimum, include:
- account_id or company_location_id: the contractual buying entity, not merely the signed-in user;
- sku or variant_id: the exact commercial item;
- quantity: expressed in the unit against which the agreement was negotiated;
- unit_of_measure: each, case, pallet, metre or kilogram, including an authorised conversion factor;
- currency and market: the monetary and geographic or tax context;
- effective_at: the date and time at which the contract must be valid;
- channel: ecommerce, sales desk, EDI or portal when authorised terms differ.
A user is a credential; the account or company location is the commercial counterparty. When one person may buy for several companies, require an explicit active account and recalculate catalogue, credit, tax treatment and prices after every switch. Silently inheriting the last selected account is a common cause of incorrectly priced orders.
Write an explainable price hierarchy
There is no universal hierarchy, but there is one universal requirement: the rule must be written, versioned and tested. One workable order is:
- Account + SKU contract price, valid for the requested currency and selling unit.
- Account-group + SKU contract price, when no account exception exists.
- Assigned catalogue price for the company or company location.
- Market-wide B2B price, only where the contract permits a fallback.
- No sellable price: request a quote or block the purchase explicitly.
Once the winning level is selected, quantity tiers and permitted adjustments are applied in a defined order. Do not assume that “lowest price wins” is always commercially correct. It can breach an agreement, erase margin or combine incentives that were meant to be exclusive. Some platforms select the lowest value across eligible catalogues; others resolve prices through scoped precedence. The business rule must therefore be intentional, not an accidental side effect of the commerce engine.
Worked resolution example
| Input | Value | Decision |
|---|---|---|
| Account | ACME Barcelona | Contract C-2026-041 |
| SKU / unit | VAL-80 / case of 10 | Do not derive it from an each price without an authorised conversion |
| Date | 15 October 2026 | Contract version effective from 1 October 2026 |
| Quantity | 20 cases | 20–49 tier |
| Resolved price | EUR 184.00 per case | Account contract; general promotion excluded |
A pricing service should return more than 184.00. Its response should include currency, selling unit, net or gross treatment, rule identifier and version, validity dates and the reason for selection. Without that explanation, customer service cannot reconstruct a dispute.
Contracts, volume and promotions: decide what can stack
Every pricing rule needs a compatibility policy. For each contract, state whether its price is:
- net and final: promotions and coupons are excluded;
- a negotiated base: only named downstream discounts may apply;
- volume-based: a unit price replaces the base price at a qualifying tier;
- retrospective: a rebate or credit is settled outside the order;
- quotable: approval is required before it becomes an order.
Minimums, maximums and purchase increments must use the same variant and unit as volume tiers. If a product is sold in cases of ten, a 100-each threshold means ten cases only where that conversion is governed and does not vary by market or packaging. Shopify’s B2B documentation, for example, specifies quantity rules at variant level and requires price-break quantities to respect minimums and increments. That is a useful design constraint even when another platform is used.
Give every data element one owner
| Data | Typical system of record | Commerce responsibility |
|---|---|---|
| SKU, unit and conversion | ERP or PIM | Validate that the purchased variant matches |
| Account, group and location | ERP or CRM | Resolve the active buying identity |
| Contract and validity | ERP or CPQ | Consume a published, traceable version |
| Visible assortment | PIM or commerce | Apply catalogue access by account or location |
| Displayed price | Pricing service | Do not recalculate it through divergent logic |
| Accepted order price | Commerce with ERP validation | Store rule, version and breakdown |
Avoid giving ERP and ecommerce independent editing rights over the same rule. A stable pattern is to publish an immutable price-list version, activate it at a controlled time and retain the previous version for audit. A correction creates a new version; it does not silently overwrite the data that valued existing orders.
Synchronise and reconcile with the ERP
A price import is not complete because a file upload or API request returned “success”. Reconciliation should:
- count received, accepted, rejected and expired rules;
- validate currency, unit, SKU, account, overlapping dates and tiers;
- compare a deterministic sample of source and destination prices;
- activate the version only when agreed thresholds pass;
- alert on rejected identifiers with an actionable reason;
- revalue the order in ERP and stop confirmation if the difference exceeds an authorised tolerance.
Commerce should send the resolved price, rule identifier and rule version to the ERP. If the ERP returns a different amount, do not replace it silently. Tell the buyer whether the order is being held, needs approval or must be recalculated.
Cache and privacy: a private price must never cross accounts
A cached page or API response must vary, at minimum, by effective account or catalogue, market, currency, unit and authentication state. Caching HTML by URL alone can show one customer another customer’s contract price. Separate cacheable public content from the private price component; for APIs, use explicit keys and prevent personalised responses from entering shared network caches.
Contract prices should not appear in public structured data, open feeds, anonymous internal search or server-rendered fragments before the account is resolved. When a user signs out or switches company, invalidate the basket, pricing context and permissions inherited from the previous identity.
Decide what happens when a price is missing
Zero, the public price or the last cached value are not safe defaults. Define one permitted outcome per contract: block purchase with a clear explanation, allow a request for quotation, fetch the value in real time, or use an explicitly authorised general price. Record the reason and alert when the rate of unpriced products increases.
During an ERP outage, continuity may use the latest published version only while it remains valid. Do not serve an expired version without an explicit business decision and visible operational alert. Set a maximum degraded-service window and define which orders require later review.
Tests to run before release
A minimum end-to-end suite includes:
- two users in the same account receive the same result;
- a user with two companies can switch context without carrying prices or basket data across;
- two accounts buying the same SKU receive their correct individual terms;
- the exact first and last second of validity selects the expected version;
- minimum, increment and every volume boundary are tested below, at and above the threshold;
- currency, market and selling unit change without implicit conversions;
- an exclusive contract price cannot stack with a promotion or coupon;
- missing price, expired price list and account without a catalogue fail explicitly;
- product page, basket, checkout, order, email and ERP show the same breakdown;
- cold cache, warm cache, sign-out and account switching do not leak a price.
Metrics that reveal real degradation
Track the proportion of unpriced lines, ecommerce-to-ERP differences, orders held for revaluation, pricing-service latency, rejected import rules and pricing disputes. Segment by account, market, catalogue and version. A healthy global average can hide a broken contract affecting one strategically important customer.
Frequently asked questions
Should every customer have a separate price list?
Only where the terms are genuinely individual. If hundreds of accounts share the same conditions, use a common group or catalogue and add account-level exceptions. This reduces duplicate rules without sacrificing contractual accuracy.
Should prices appear before sign-in?
That depends on commercial policy. A public price may be shown to visitors, but it must never be confused with the contractual price. Where all pricing is private, show an account-access or enquiry route and keep those values out of public HTML, feeds and structured data.
What if two contracts match?
Reject the overlap during import or resolve it through an approved priority rule. Selecting the lowest price or the last imported row without a governed rule makes the result unpredictable.
Where should tax be calculated?
The price model must state whether values are net or gross and which service determines tax treatment. Tax may depend on address, customer status and product classification; it should not be embedded ambiguously in a contract price.
Primary documentation
- Shopify: B2B catalogues and pricing, covering catalogue assignment to companies and locations.
- Shopify: quantity rules and volume pricing, covering minimums, increments and variant-level price breaks.
- commercetools: pricing and discounts overview, covering scoped prices, customer groups and selection precedence.
- Adobe Commerce: shared catalogues, covering custom pricing and company assignment.
Next step
Before migrating price lists or adding another discount layer, build a decision table from ten real orders and require business, ecommerce and ERP teams to explain the same result. If you need to review the architecture, precedence and test cases for your implementation, explore the CODE B2B resources.