Medusa v2 plugin: quantity range pricing engine with admin UI, store API, and PostgreSQL-backed tiers
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
| Requirement | Version |
|---|---|
| Node.js | 20+ |
| Medusa | v2.13+ ( ^2.13) |
npm install @webbycrown/medusa-quantity-pricing-rules
Register in :
1import { defineConfig } from "@medusajs/framework/utils"23export default defineConfig({4 plugins: [5 {6 resolve: "@webbycrown/medusa-quantity-pricing-rules",7 options: {},8 },9 ],10})
Registers the module automatically. Do not add a duplicate entry under .
Run migrations and start Medusa:
1npx medusa db:migrate2npm run dev
Open Admin → Settings → Extensions → Quantity Pricing to create tiers.
| 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 |
| Field | Description |
|---|---|
| Product ID | Required (auto-filled on product page) |
| Variant | Optional — empty = all variants |
| Min qty | Minimum quantity (e.g. ) |
| Max qty | Upper bound; empty = open-ended (e.g. ) |
| Pricing type | , , or |
| Discount / unit price | See Pricing types |
| Currency | ISO 4217, e.g. , |
| 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 that still fits the quantity wins.
| Type | means | Resolved unit price |
|---|---|---|
| Tier unit price | ||
| Percent off catalog (e.g. = 10% off) | ||
| Amount off per unit |
is resolved in order:
— requires a publishable API key.
| Param | Required | Description |
|---|---|---|
| Yes | Product to load tiers for | |
| No | Variant-specific rules + product-level fallback | |
| No | Filter / calculation currency | |
| No | B2B segment | |
| No | Regional override | |
| No | When set, includes | |
| No | Catalog price for discount tiers |
GET /store/quantity-pricing?product_id=prod_01XXXX¤cy_code=inr&quantity=25
1{2 "quantity_prices": [],3 "calculated_price": {4 "unit_price": 90,5 "quantity": 25,6 "currency_code": "inr",7 "rule_id": "qprice_02...",8 "pricing_type": "fixed",9 "line_total": 225010 }11}
Without , only product-level tiers () are returned.
Authenticated admin session or token.
| Method | Path | Description |
|---|---|---|
| List rules | ||
| Create rule | ||
| Get rule | ||
| Update rule | ||
| Delete rule | ||
| Variant catalog prices |
Create fixed tier:
1{2 "product_id": "prod_01XXXXXXXX",3 "min_qty": 1,4 "max_qty": 10,5 "pricing_type": "fixed",6 "price": 100,7 "currency_code": "inr"8}
Open-ended tier (51+): set .
1import {2 PRICING_ENGINE_MODULE,3 resolveQuantityUnitPrice,4 fetchCatalogPricesForProducts,5} from "@webbycrown/medusa-quantity-pricing-rules"67const unitPrice = await resolveQuantityUnitPrice(container, {8 product_id: "prod_01...",9 variant_id: "variant_01...",10 quantity: 25,11 currency_code: "inr",12 rule_id: "qprice_02...", // optional — pin selected tier13})1415const pricingEngine = container.resolve(PRICING_ENGINE_MODULE)16const result = await pricingEngine.calculatePrice({17 product_id: "prod_01...",18 quantity: 25,19 currency_code: "inr",20})
1import {2 createQuantityPricingRuleWorkflow,3 updateQuantityPricingRuleWorkflow,4 deleteQuantityPricingRuleWorkflow,5} from "@webbycrown/medusa-quantity-pricing-rules/workflows"
| Export | Purpose |
|---|---|
| Container key () | |
| Module definition | |
| Service class | |
| Resolve tier unit price (cart / checkout) | |
| Batch catalog prices | |
| Base price for a rule | |
| Types | , , , … |
| Create / update / delete workflows |
The plugin does not modify cart line items automatically. Use in your add-to-cart flow when a tier applies.
Table : , , , , , , , , , .
After model changes in a fork:
1npx medusa db:generate pricingEngine2npx medusa db:migrate
| Issue | Check |
|---|---|
| Admin page not found | Rebuild plugin ( in package) and restart Medusa |
| Empty on store | Rules exist for + ; pass if needed |
| Wrong discount price | Variant catalog price or ; pass |
| Wrong tier | Overlapping ranges — highest wins |
| Module not found | Plugin under in , not duplicated under |
See CHANGELOG.md.
WebbyCrown — info@webbycrown.com · webbycrown.com