A contract pricing engine for a Magento 2 B2B store
How we built a Magento 2 contract pricing engine with negotiated company prices, bulk price list imports, scheduled activation and fast, cache-safe price display.
Contract pricing, price list management, price visibility and caching
List price€100.00Few B2B customers pay this
Customer group price
Company discount
Contract price
Spreadsheets and ERP
The challenge
In B2B, few customers pay the list price
In B2B, few customers pay the list price. This client agreed prices per customer group, negotiated extra discounts with individual companies and kept long-term contract prices for key accounts. These prices lived in spreadsheets and the ERP, so customers often saw the wrong price online and the sales team corrected orders by hand.
Magento 2 supports customer group prices and tier prices out of the box, but not prices negotiated per company or contract, and not price lists that switch on automatically on a set date. Updating thousands of prices one product at a time in the admin was not workable.
The goal was a pricing engine that always shows each business customer their own agreed price, lets the team manage prices in bulk, and keeps the store fast.
Our solution
Five steps to the right price for every buyer
Maven Infotech built a custom pricing module on top of Magento’s native price logic, so the store keeps its standard pricing features and adds contract pricing where the business needs it. Read more about our Magento development services.
Part 1 of 5
Example productExample prices, list price €100.00
1Contract priceValid 1 Jan – 31 Dec€84.00WinsNot applicable
2Company negotiated priceAll buyers of the company€88.50WinsNot applicable
3Customer group priceNative group and tier price€92.00WinsNot applicable
The most specific valid price wins.
Product page
Category page
Search results
Cart
Checkout
Order
UploadCSV or Excel in the admin
ValidateError report before go-live
ScheduledWaits for its start date
LiveReindex and clear affected pages
RetiredAfter its end date
GuestNo prices / list prices onlyLog in or request an account
Unapproved accountNo prices / list prices onlyWaits for approval
Logged-in buyerOwn company’s pricesNever another customer’s price
price-list-2027.xlsx3 checks to fix
Unknown SKURow is skipped
Unknown companyRow is skipped
Invalid priceRow is skipped
Other rows validReady for the start date
01
A clear pricing architecture
We defined three price sources and a fixed order in which they apply:
1
Contract price
A price agreed in a customer contract, stored in a dedicated contract price table with start and end dates
2
Company negotiated price
A price agreed with one company, shared by all of its buyers
3
Customer group price
Magento’s native group and tier prices, used as the fallback
The most specific valid price wins: a contract price within its dates comes first, then the company’s negotiated price, then the customer group price. A price only counts as valid when its start date has passed and its end date has not.
Only if the client’s agreements say soIf a catalogue price rule or promotion would give a lower price, the buyer gets that lower price instead.Only if trueContract prices are synced from the client’s ERP through our ERP integration.
Example productExample prices, list price €100.00
1Contract priceValid 1 Jan – 31 Dec€84.00WinsNot applicable
2Company negotiated priceAll buyers of the company€88.50WinsNot applicable
3Customer group priceNative group and tier price€92.00WinsNot applicable
The most specific valid price wins.
02
Built into Magento’s price model
We added the contract pricing through a plugin on Magento’s price model and a custom price provider interface. Each price source is a separate provider, so the engine decides the final price in one place and new sources can be added later without touching core code.
Because the logic sits in the price model, the same price shows up everywhere: on product and category pages, in search results, in the cart, in the checkout and on the order.
Only if trueThe prices are also available through our REST / GraphQL APIs for the client’s mobile app / punch-out integration.
Product page
Category page
Search results
Cart
Checkout
Order
03
Bulk price lists and scheduled activation
The sales team can now upload price lists as CSV or Excel files from a custom screen in the Magento admin. Each upload is validated first, with a clear error report for unknown SKUs, companies or invalid prices, before anything goes live.
Every price list has a start date and an optional end date. A scheduled process makes each price list effective on its start date and retires it after its end date. When a price list changes status, the process reindexes the prices of the affected products and clears their cached pages, so the new prices show on the storefront, in the cart and at checkout at the same time. Annual price changes and temporary contract deals no longer need someone to update prices on the day.
The price engine also checks the dates itself whenever it calculates a price, so an expired contract price is never charged, even if a page is still waiting to be refreshed.
Only if trueEach activation run is logged, and the team gets an alert if a run fails.
UploadCSV or Excel in the admin
ValidateError report before go-live
ScheduledWaits for its start date
LiveReindex and clear affected pages
RetiredAfter its end date
04
Price visibility controls
Only include what was builtGuests and unapproved accounts see no prices / list prices only and are asked to log in or request an account. Specific products or categories can be hidden from the price display for certain customer groups.
Logged-in buyers only ever see their own company’s prices, never those of another customer.
GuestNo prices / list prices onlyLog in or request an account
Unapproved accountNo prices / list prices onlyWaits for approval
Logged-in buyerOwn company’s pricesNever another customer’s price
05
Fast pages with cache-safe prices
Customer-specific prices and full-page caching can easily conflict: a cached page must never show one company’s price to another. We solved this with:
Caching per customer group
Cached pages are shared only between customers in the same group. On its own this is not enough, because companies in the same group can have different negotiated prices.
Company-specific cache context
We added the company to Magento’s cache context, so buyers from different companies never share a cached page that contains prices.
Or, if built this wayCompany and contract prices are loaded as private, per-customer content after the cached page loads, so the page itself stays shared and fast.
Private content stays uncached
The cart, mini-cart, quotes and other customer-specific blocks are never served from the shared page cache.
Expiry and invalidation
When a price list is imported, activated or expired, only the cache entries of the affected products are cleared, instead of flushing the whole store.
Optional: We also tuned the Varnish configuration and the price indexer, so large price imports don’t slow down the live store. The setup is monitored as part of our Magento maintenance and support.
price-list-2027.xlsx3 checks to fix
Unknown SKURow is skipped
Unknown companyRow is skipped
Invalid priceRow is skipped
Other rows validReady for the start date
The impact
The numbers that matter
Keep only the lines you can back up with real measurements or client data. Delete the rest, and delete this whole section if none can be verified.
Price lists managedx price listscovering y contract prices
Price update timex days → y minutesfor a full price list update
Order corrections for wrong pricesx → y per monthmeasured over period
Category page TTFBx s → y sbefore and after contract pricing went live
Online B2B ordersx% → y%of all B2B orders
Technology and expertise
The stack behind the pricing engine
Magento 2 Open Source / Adobe Commerce
PHP and custom Magento modules
Plugins on the Magento price model and a custom price provider interface
Customer group and tier prices
CSV and Excel price list import with validation
Cron-based scheduled price activation
Full-page cache, Varnish and cache tag invalidation
ERP price sync
The outcome
Their own agreed price, the moment they log in
Business customers now see their own agreed prices the moment they log in, and the sales team manages thousands of prices with a single upload instead of manual edits. Caching respects each company’s prices, and only the affected products are refreshed when prices change. Add the single most important verified number here.