Quantity Pricing Rules
Set tiered and volume pricing by quantity
Medusa Quantity Pricing Rules
Medusa v2 plugin for quantity range pricing (volume / tiered / wholesale). Set unit prices by quantity with fixed prices, percentage discounts, or fixed amount-off tiers.
Watch demo: https://www.youtube.com/watch?v=CjBjc7j3H6g
Features
- PostgreSQL Copy to clipboard
quantity_pricestable (module + migrations) - Pricing types: Copy to clipboard
fixed, Copy to clipboardpercentage, Copy to clipboardfixed_discount - Admin API (CRUD + Zod validation) and Store API (list tiers, calculate price)
- Admin UI: Settings → Extensions → Quantity Pricing, per-product widget, store summary widget
- Workflows with compensation (create / update / delete)
- Auto cleanup on Copy to clipboard
product.deleted - Optional variant, region, and customer-group scoping
- Exported helpers: Copy to clipboard
resolveQuantityUnitPrice, catalog utilities, workflows
Requirements
Requirement Version Node.js 20+ Medusa v2.13+ (Copy to clipboard@medusajs/framework ^2.13)
Installation
1npm install @webbycrown/medusa-quantity-pricing-rules
Register in Copy to clipboardmedusa-config.ts:
12345678910import { defineConfig } from "@medusajs/framework/utils"export default defineConfig({plugins: [{resolve: "@webbycrown/medusa-quantity-pricing-rules",options: {},},],})
Registers the Copy to clipboardpricingEnginemodule automatically. Do not add a duplicate entry under Copy to clipboardmodules.
Run migrations and start Medusa:
12npx medusa db:migratenpm run dev
Open Admin → Settings → Extensions → Quantity Pricing to create tiers.
Admin UI
Location Purpose Settings → Extensions → Quantity Pricing List, create, edit, delete rules Products → [product] Tiers for that product (product ID pre-filled) Settings → Store Rule count + link to settings
Tier fields
Field Description Product ID Required (auto-filled on product page) Variant Optional — empty = all variants Min qty Minimum quantity (e.g. Copy to clipboard1) Max qty Upper bound; empty = open-ended (e.g. Copy to clipboard51+) Pricing type Copy to clipboardfixed, Copy to clipboardpercentage, or Copy to clipboardfixed_discount Discount / unit price See Pricing types Currency ISO 4217, e.g. Copy to clipboardinr, Copy to clipboardusd List price (reference) For discount tiers when catalog price is missing
Non-overlapping ranges per product + currency are recommended. When ranges overlap, the tier with the highest Copy to clipboardmin_qty that still fits the quantity wins.
Pricing types
Type Copy to clipboardprice means Resolved unit price Copy to clipboardfixed Tier unit price Copy to clipboardprice Copy to clipboardpercentage Percent off catalog (e.g. Copy to clipboard10 = 10% off) Copy to clipboardbase × (1 − price/100) Copy to clipboardfixed_discount Amount off per unit Copy to clipboardmax(base − price, 0)
Copy to clipboardbase is resolved in order:
- Copy to clipboard
base_unit_priceon Store API / Copy to clipboardresolveQuantityUnitPrice - Medusa variant catalog price for Copy to clipboard
currency_code - Copy to clipboard
reference_unit_priceon the rule
Store API
Copy to clipboardGET /store/quantity-pricing — requires a publishable API key.
Param Required Description Copy to clipboardproduct_id Yes Product to load tiers for Copy to clipboardvariant_id No Variant-specific rules + product-level fallback Copy to clipboardcurrency_code No Filter / calculation currency Copy to clipboardcustomer_group_id No B2B segment Copy to clipboardregion_id No Regional override Copy to clipboardquantity No When set, includes Copy to clipboardcalculated_price Copy to clipboardbase_unit_price No Catalog price for discount tiers
1GET /store/quantity-pricing?product_id=prod_01XXXX¤cy_code=inr&quantity=25
1234567891011{"quantity_prices": [],"calculated_price": {"unit_price": 90,"quantity": 25,"currency_code": "inr","rule_id": "qprice_02...","pricing_type": "fixed","line_total": 2250}}
Without Copy to clipboardvariant_id, only product-level tiers (Copy to clipboardvariant_id = null) are returned.
Admin API
Authenticated admin session or token.
Method Path Description Copy to clipboardGET Copy to clipboard/admin/quantity-pricing List rules Copy to clipboardPOST Copy to clipboard/admin/quantity-pricing Create rule Copy to clipboardGET Copy to clipboard/admin/quantity-pricing/:id Get rule Copy to clipboardPUT Copy to clipboard/admin/quantity-pricing/:id Update rule Copy to clipboardDELETE Copy to clipboard/admin/quantity-pricing/:id Delete rule Copy to clipboardGET Copy to clipboard/admin/quantity-pricing/catalog-prices Variant catalog prices
Create fixed tier:
12345678{"product_id": "prod_01XXXXXXXX","min_qty": 1,"max_qty": 10,"pricing_type": "fixed","price": 100,"currency_code": "inr"}
Open-ended tier (51+): set Copy to clipboard"max_qty": null.
Package exports
1234567891011121314151617181920import {PRICING_ENGINE_MODULE,resolveQuantityUnitPrice,fetchCatalogPricesForProducts,} from "@webbycrown/medusa-quantity-pricing-rules"const unitPrice = await resolveQuantityUnitPrice(container, {product_id: "prod_01...",variant_id: "variant_01...",quantity: 25,currency_code: "inr",rule_id: "qprice_02...", // optional — pin selected tier})const pricingEngine = container.resolve(PRICING_ENGINE_MODULE)const result = await pricingEngine.calculatePrice({product_id: "prod_01...",quantity: 25,currency_code: "inr",})
12345import {createQuantityPricingRuleWorkflow,updateQuantityPricingRuleWorkflow,deleteQuantityPricingRuleWorkflow,} from "@webbycrown/medusa-quantity-pricing-rules/workflows"
Export Purpose Copy to clipboardPRICING_ENGINE_MODULE Container key (Copy to clipboard"pricingEngine") Copy to clipboardpricingEngineModule Module definition Copy to clipboardPricingEngineService Service class Copy to clipboardresolveQuantityUnitPrice Resolve tier unit price (cart / checkout) Copy to clipboardfetchCatalogPricesForProducts Batch catalog prices Copy to clipboardgetBaseUnitPriceForRule Base price for a rule Types Copy to clipboardQuantityPriceRuleDTO, Copy to clipboardCalculatePriceInput, Copy to clipboardPricingType, … Copy to clipboard./workflows Create / update / delete workflows
The plugin does not modify cart line items automatically. Use Copy to clipboardresolveQuantityUnitPrice in your add-to-cart flow when a tier applies.
Tier matching
- Load rules for Copy to clipboard
product_id(+ optional filters). - Prefer variant-specific rules when Copy to clipboard
variant_idis set. - Match Copy to clipboard
min_qty ≤ quantityand (Copy to clipboardmax_qtyis null or Copy to clipboardquantity ≤ max_qty). - Highest matching Copy to clipboard
min_qtywins. - Resolve unit price from Copy to clipboard
pricing_typeand base price sources.
Database
Table Copy to clipboardquantity_prices: Copy to clipboardproduct_id, Copy to clipboardvariant_id, Copy to clipboardmin_qty, Copy to clipboardmax_qty, Copy to clipboardpricing_type, Copy to clipboardprice, Copy to clipboardcurrency_code, Copy to clipboardreference_unit_price, Copy to clipboardcustomer_group_id, Copy to clipboardregion_id.
After model changes in a fork:
12npx medusa db:generate pricingEnginenpx medusa db:migrate
Troubleshooting
Issue Check Admin page not found Rebuild plugin (Copy to clipboardnpm run build in package) and restart Medusa Empty Copy to clipboardquantity_prices on store Rules exist for Copy to clipboardproduct_id + Copy to clipboardcurrency_code; pass Copy to clipboardvariant_id if needed Wrong discount price Variant catalog price or Copy to clipboardreference_unit_price; pass Copy to clipboardbase_unit_price Wrong tier Overlapping ranges — highest Copy to clipboardmin_qty wins Module not found Plugin under Copy to clipboardplugins in Copy to clipboardmedusa-config.ts, not duplicated under Copy to clipboardmodules
Changelog
See CHANGELOG.md.
Author
WebbyCrown — info@webbycrown.com · webbycrown.com

