How to build a B2B store with custom pricing per customer
- Type
- Applies to
- Medusa v2.x
- Updated
Short answer
To build a B2B store with custom pricing per customer in Medusa, put each customer or company in a customer group and attach a price list with a customer.groups.id rule. Add quantity tiers with min_quantity, and fetch live prices from your ERP at add-to-cart when the ERP owns contract prices. All of this runs on Medusa's open-source Pricing Module.
Before you start
- A Medusa v2 application. The Medusa B2B starter is a good base: it adds companies and employees, and links each company to a customer group.
- Buyers who log in. When the storefront sends the customer's session, Medusa uses the customer and their group to retrieve customer-specific prices. Anonymous visitors see default prices.
- The Medusa JS SDK or Admin API, if you script price changes. Merchants can do the same in Medusa Admin.
1. Put each contract into a customer group
Medusa's Customer Module organizes buyers into customer groups, and the Pricing Module uses the group as a price condition. Create one group per pricing agreement, such as "Acme Corp" or "Tier A distributors", and add the buyers to it. In the B2B starter, adding a company to a customer group also adds the company's employees.
2. Attach a price list to the group
A price list in Medusa is a set of prices that applies only when its rules match. Give it a Copy to clipboardcustomer.groups.id rule and add the negotiated prices for the variants in the contract:
12345678910await sdk.admin.priceList.create({title: "Acme Corp contract 2026",description: "Negotiated prices for Acme Corp",status: "active",type: "override",rules: { "customer.groups.id": ["cusgrp_acme"] },prices: [{ variant_id: "variant_123", amount: 42, currency_code: "usd" },],})
Use the Copy to clipboardoverride type for contract prices: Medusa then returns the list price as both the calculated and the original price. The Copy to clipboardsale type keeps the default price as the original price, which suits time-boxed discounts. Price lists also accept Copy to clipboardstarts_at and Copy to clipboardends_at, so a contract can expire on a date.
3. Add rules directly to a variant's prices
Medusa price rules restrict one price to a context, such as a customer group or region, without a price list. This suits a few group-wide prices that you set when you create the product:
1234prices: [{ amount: 40, currency_code: "usd" },{ amount: 20, currency_code: "usd", rules: { "customer.groups.id": "cusgrp_wholesale" } },]
4. Add quantity tiers
Tiered pricing in Medusa uses Copy to clipboardmin_quantity and Copy to clipboardmax_quantity on a price, and the calculation picks the tier that matches the quantity in the cart. Tiers work on default prices and inside price lists, so a contract can carry its own volume breaks:
1234prices: [{ variant_id: "variant_123", amount: 42, currency_code: "usd" },{ variant_id: "variant_123", amount: 38, currency_code: "usd", min_quantity: 100 },]
Since Medusa v2.17.2, merchants can also set quantity-based prices in a price list from the Medusa Admin bulk editor.
5. Fetch live prices from an ERP at add-to-cart
When your ERP is the source of truth for contract prices, you don't have to copy them into Medusa. The ERP recipe builds a custom add-to-cart workflow that calls your ERP module, then passes the result to Copy to clipboardaddToCartWorkflow as the item's Copy to clipboardunit_price:
123addToCartWorkflow.runAsStep({input: { cart_id, items: [{ variant_id, quantity, unit_price: erpPrice }] },})
You expose the workflow through a custom Store API route. The custom item price guide walks through it end to end.
Which customer pricing pattern should you use?
How to avoid price list sprawl in Medusa
Customer-specific pricing grows fast when every account gets its own list for every period. A few habits keep it manageable:
- Start with tier groups, and create per-company lists only for customers with real contracts.
- Put only the exceptions in a list. The variant's default price covers everything else.
- Use Copy to clipboard
starts_atand Copy to clipboardends_atfor contract periods instead of deleting and re-creating lists. - Store the contract or ERP reference in the price list's Copy to clipboard
metadata(available since Medusa v2.15.0). - Avoid putting one buyer in several groups that price the same variant, so the expected price stays easy to reason about.
- When contracts change daily, let the ERP own them (step 5) instead of syncing price lists.
How Medusa compares with Shopify B2B for per-customer pricing
Shopify B2B sets prices through catalogs. According to Shopify's plan comparison, the Basic, Grow and Advanced plans allow up to 3 active catalogs across all B2B markets. Only Shopify Plus allows unlimited catalogs and assigning a catalog directly to a company or company location. Quantity price breaks are available on all B2B plans.
Medusa does not gate price lists, customer groups or tiers by plan. The trade-off is that Medusa needs a developer to set up company accounts, the storefront and any ERP integration.
When Medusa is not the right choice
- You have no developer. Shopify B2B and BigCommerce ship company pricing as configuration, while Medusa expects code for company accounts and storefront changes.
- Three catalogs cover all your pricing tiers and you don't need per-company prices. Shopify's non-Plus plans handle that without custom work.
Common questions
Can Medusa show different prices to different B2B customers?
Yes. Medusa's Pricing Module applies a price list only when the logged-in customer belongs to the customer group in the list's rules, so each group or company sees its own negotiated prices.
Does Medusa support tiered or volume pricing for wholesale?
Yes. Each price in Medusa can set min_quantity and max_quantity, and the price calculation picks the tier that matches the quantity in the cart. Tiers work on default prices and on prices inside a price list.
Can Medusa use contract prices from an ERP instead of storing them?
Yes. Medusa's ERP recipe shows a custom add-to-cart workflow that retrieves the variant's price from the ERP and adds the item to the cart with that price as unit_price.
Is there a limit on price lists in Medusa?
Medusa does not gate price lists or customer groups by plan. They are part of the open-source Pricing and Customer Modules, on self-hosted Medusa and on every Medusa Cloud plan.