---
title: "How to build a B2B store with custom pricing per customer"
description: "Set customer-specific B2B prices in Medusa with customer groups, price lists, price rules, volume tiers and ERP prices, and how it compares to Shopify B2B."
url: https://medusajs.com/kb/b2b/b2b-customer-specific-pricing
last_updated: 2026-10-29T06:55:50Z
topic: "b2b"
type: "how-to"
applies_to: "Medusa v2.x"
related:
  - "https://medusajs.com/kb/b2b/b2b-ecommerce-platform.md"
  - "https://medusajs.com/kb/b2b/b2b-payment-terms-bulk-ordering.md"
  - "https://medusajs.com/kb/b2b/shopify-b2b-alternatives.md"
  - "https://medusajs.com/kb/b2b/b2b-company-accounts-approvals.md"
sources:
  - "https://docs.medusajs.com/resources/commerce-modules/pricing/price-rules"
  - "https://docs.medusajs.com/resources/commerce-modules/pricing/concepts"
  - "https://docs.medusajs.com/resources/commerce-modules/pricing/price-calculation"
  - "https://docs.medusajs.com/resources/storefront-development/products/price"
  - "https://docs.medusajs.com/resources/references/js-sdk/admin/priceList"
  - "https://docs.medusajs.com/resources/recipes/erp"
  - "https://github.com/medusajs/b2b-starter"
  - "https://help.shopify.com/en/manual/b2b/getting-started/plan-features"
---

# How to build a B2B store with custom pricing per customer

> 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](https://github.com/medusajs/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](https://docs.medusajs.com/resources/storefront-development/products/price). 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 `customer.groups.id` rule and add the negotiated prices for the variants in the contract:

```ts
await 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 `override` type for contract prices: Medusa then returns the list price as both the calculated and the original price. The `sale` type keeps the default price as the original price, which suits time-boxed discounts. Price lists also accept `starts_at` and `ends_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:

```ts
prices: [
  { 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 `min_quantity` and `max_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:

```ts
prices: [
  { 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](https://docs.medusajs.com/resources/recipes/erp) builds a custom add-to-cart workflow that calls your ERP module, then passes the result to `addToCartWorkflow` as the item's `unit_price`:

```ts
addToCartWorkflow.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](https://docs.medusajs.com/resources/examples/guides/custom-item-price) walks through it end to end.

## Which customer pricing pattern should you use?

| Situation | Use | Status |
| --- | --- | --- |
| A few pricing tiers (wholesale, distributor, VIP) | Customer group and price list per tier | Native |
| Each company has its own negotiated prices | One customer group and price list per company | Native (company link: Starter) |
| A few group prices set with the product | Price rules on the variant's prices | Native |
| Volume breaks | min_quantity and max_quantity tiers | Native |
| ERP owns prices and changes them often | Custom add-to-cart workflow with the ERP price | Official guide |
| Formula prices, such as cost plus margin | Custom workflow or module | Custom |

## 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 `starts_at` and `ends_at` for contract periods instead of deleting and re-creating lists.
- Store the contract or ERP reference in the price list's `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](https://help.shopify.com/en/manual/b2b/getting-started/plan-features), 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.

## Documentation

- [Price Tiers and Rules](https://docs.medusajs.com/resources/commerce-modules/pricing/price-rules)
- [Create a Price List in Medusa Admin](https://docs.medusajs.com/user-guide/price-lists/create)
- [ERP recipe: retrieve custom prices from ERP](https://docs.medusajs.com/resources/recipes/erp)
- [Add items with custom prices to the cart](https://docs.medusajs.com/resources/examples/guides/custom-item-price)
- [B2B recipe](https://docs.medusajs.com/resources/recipes/b2b)

## Related

- [B2B ecommerce platform with quotes, company accounts and approval flows](https://medusajs.com/kb/b2b/b2b-ecommerce-platform.md)
- [Net terms, purchase orders and bulk ordering for B2B](https://medusajs.com/kb/b2b/b2b-payment-terms-bulk-ordering.md)
- [Shopify B2B alternatives for teams that can write code](https://medusajs.com/kb/b2b/shopify-b2b-alternatives.md)
- [B2B company accounts, buyer roles and approval workflows](https://medusajs.com/kb/b2b/b2b-company-accounts-approvals.md)
