> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/medusajs/medusa/llms.txt
> Use this file to discover all available pages before exploring further.

# Pricing Module

> Learn about the Pricing Module and how to manage prices, price lists, and dynamic pricing rules in Medusa.

## Overview

The Pricing Module manages product pricing with support for multiple currencies, customer groups, regions, and dynamic pricing rules. It provides flexible price calculation based on context.

**Key Features:**

* Multi-currency pricing
* Price lists with rules
* Context-based price calculation
* Customer group pricing
* Region-specific prices
* Time-based pricing (sales, schedules)
* Bulk pricing rules
* Price preferences

## When to Use

Use the Pricing Module when you need to:

* Set prices in multiple currencies
* Create customer group discounts
* Implement region-specific pricing
* Run time-limited sales
* Calculate context-aware prices
* Support B2B and wholesale pricing
* Configure minimum/maximum quantities
* Handle complex pricing rules

## Data Models

### PriceSet

Groups prices for a product variant or other entity.

<ResponseField name="id" type="string" required>
  Unique price set identifier
</ResponseField>

<ResponseField name="prices" type="Price[]">
  Individual prices in this set
</ResponseField>

### Price

Represents a specific price with optional rules.

<ResponseField name="id" type="string" required>
  Unique price identifier
</ResponseField>

<ResponseField name="price_set_id" type="string" required>
  ID of the parent price set
</ResponseField>

<ResponseField name="amount" type="BigNumber" required>
  Price amount
</ResponseField>

<ResponseField name="currency_code" type="string" required>
  Three-letter ISO currency code
</ResponseField>

<ResponseField name="min_quantity" type="number">
  Minimum quantity for this price to apply
</ResponseField>

<ResponseField name="max_quantity" type="number">
  Maximum quantity for this price to apply
</ResponseField>

<ResponseField name="rules" type="PriceRule[]">
  Pricing rules (region, customer group, etc.)
</ResponseField>

### PriceRule

Defines conditions for price applicability.

<ResponseField name="id" type="string" required>
  Unique rule identifier
</ResponseField>

<ResponseField name="price_id" type="string" required>
  ID of the price
</ResponseField>

<ResponseField name="attribute" type="string" required>
  Rule attribute (e.g., "region\_id", "customer\_group\_id")
</ResponseField>

<ResponseField name="value" type="string" required>
  Rule value
</ResponseField>

<ResponseField name="priority" type="number">
  Rule priority for conflict resolution
</ResponseField>

### PriceList

Groups prices for sales, promotions, or special pricing.

<ResponseField name="id" type="string" required>
  Unique price list identifier
</ResponseField>

<ResponseField name="title" type="string" required>
  Price list title
</ResponseField>

<ResponseField name="description" type="string">
  Price list description
</ResponseField>

<ResponseField name="type" type="PriceListType" required>
  List type: `sale`, `override`
</ResponseField>

<ResponseField name="status" type="PriceListStatus" required>
  Status: `active`, `draft`
</ResponseField>

<ResponseField name="starts_at" type="DateTime">
  When price list becomes active
</ResponseField>

<ResponseField name="ends_at" type="DateTime">
  When price list expires
</ResponseField>

<ResponseField name="rules" type="PriceListRule[]">
  Rules defining when list applies
</ResponseField>

### PriceListRule

Defines conditions for price list applicability.

<ResponseField name="id" type="string" required>
  Unique rule identifier
</ResponseField>

<ResponseField name="price_list_id" type="string" required>
  ID of the price list
</ResponseField>

<ResponseField name="attribute" type="string" required>
  Rule attribute
</ResponseField>

<ResponseField name="value" type="string[]" required>
  Allowed values for the attribute
</ResponseField>

### PricePreference

Defines default pricing behavior.

<ResponseField name="id" type="string" required>
  Unique preference identifier
</ResponseField>

<ResponseField name="attribute" type="string">
  Preference attribute
</ResponseField>

<ResponseField name="value" type="string">
  Preference value
</ResponseField>

<ResponseField name="is_tax_inclusive" type="boolean">
  Whether prices include tax
</ResponseField>

## Service Interface

The Pricing Module service is available at `@medusajs/medusa/pricing`.

### Create Price Set

Create a price set for a product variant.

<CodeGroup>
  ```typescript Example theme={null}
  import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
  import { IPricingModuleService } from "@medusajs/framework/types"
  import { Modules } from "@medusajs/framework/utils"

  export async function POST(
    req: MedusaRequest,
    res: MedusaResponse
  ) {
    const pricingModuleService: IPricingModuleService = req.scope.resolve(
      Modules.PRICING
    )

    const priceSet = await pricingModuleService.createPriceSets({
      prices: [
        {
          amount: 2000,
          currency_code: "usd",
          rules: {},
        },
        {
          amount: 1800,
          currency_code: "eur",
          rules: {},
        },
      ],
    })

    res.json({ price_set: priceSet })
  }
  ```
</CodeGroup>

<ParamField path="data" type="CreatePriceSetDTO | CreatePriceSetDTO[]" required>
  Price set data

  <ParamField path="prices" type="CreatePricesDTO[]">
    Prices to create in this set
  </ParamField>
</ParamField>

<ResponseField name="priceSet" type="PriceSetDTO | PriceSetDTO[]">
  The created price set(s)
</ResponseField>

### Add Prices

Add prices to an existing price set.

<CodeGroup>
  ```typescript Simple Price theme={null}
  await pricingModuleService.addPrices({
    priceSetId: "pset_123",
    prices: [
      {
        amount: 1500,
        currency_code: "gbp",
        rules: {},
      },
    ],
  })
  ```

  ```typescript With Rules theme={null}
  await pricingModuleService.addPrices({
    priceSetId: "pset_123",
    prices: [
      {
        amount: 1800,
        currency_code: "usd",
        rules: {
          region_id: "reg_us",
        },
      },
      {
        amount: 1600,
        currency_code: "usd",
        rules: {
          customer_group_id: "cgroup_vip",
        },
      },
    ],
  })
  ```

  ```typescript Quantity-Based theme={null}
  await pricingModuleService.addPrices({
    priceSetId: "pset_123",
    prices: [
      {
        amount: 2000,
        currency_code: "usd",
        min_quantity: 1,
        max_quantity: 9,
        rules: {},
      },
      {
        amount: 1800,
        currency_code: "usd",
        min_quantity: 10,
        max_quantity: 99,
        rules: {},
      },
      {
        amount: 1600,
        currency_code: "usd",
        min_quantity: 100,
        rules: {},
      },
    ],
  })
  ```
</CodeGroup>

<ParamField path="data" type="AddPricesDTO" required>
  Price data

  <ParamField path="priceSetId" type="string" required>
    ID of the price set
  </ParamField>

  <ParamField path="prices" type="CreatePricesDTO[]" required>
    Prices to add
  </ParamField>
</ParamField>

### Calculate Prices

Calculate prices based on context.

<CodeGroup>
  ```typescript Example theme={null}
  const calculatedPrices = await pricingModuleService.calculatePrices(
    { id: ["pset_123", "pset_456"] },
    {
      context: {
        currency_code: "usd",
        region_id: "reg_us",
        customer_group_id: "cgroup_vip",
      },
    }
  )

  for (const result of calculatedPrices) {
    console.log(result.id, result.calculated_amount)
  }
  ```
</CodeGroup>

<ParamField path="filters" type="PricingFilters" required>
  Filters to select price sets

  <ParamField path="id" type="string[]">
    Price set IDs to calculate
  </ParamField>
</ParamField>

<ParamField path="context" type="PricingContext" required>
  Pricing context

  <ParamField path="currency_code" type="string">
    Currency code for calculation
  </ParamField>

  <ParamField path="region_id" type="string">
    Region ID for region-specific pricing
  </ParamField>

  <ParamField path="customer_group_id" type="string">
    Customer group ID for group pricing
  </ParamField>

  <ParamField path="quantity" type="number">
    Quantity for quantity-based pricing
  </ParamField>
</ParamField>

<ResponseField name="calculatedPrices" type="CalculatedPriceSet[]">
  Array of calculated prices with `calculated_amount` field
</ResponseField>

### Create Price List

Create a price list for sales or special pricing.

<CodeGroup>
  ```typescript Example theme={null}
  const priceList = await pricingModuleService.createPriceLists({
    title: "Summer Sale 2024",
    description: "20% off summer items",
    type: "sale",
    status: "active",
    starts_at: new Date("2024-06-01"),
    ends_at: new Date("2024-08-31"),
    rules: [
      {
        attribute: "region_id",
        value: ["reg_us", "reg_eu"],
      },
    ],
  })
  ```
</CodeGroup>

<ParamField path="data" type="CreatePriceListDTO | CreatePriceListDTO[]" required>
  Price list data

  <ParamField path="title" type="string" required>
    Price list title
  </ParamField>

  <ParamField path="description" type="string">
    Price list description
  </ParamField>

  <ParamField path="type" type="PriceListType" required>
    List type: `sale`, `override`
  </ParamField>

  <ParamField path="status" type="PriceListStatus">
    Status: `active`, `draft`
  </ParamField>

  <ParamField path="starts_at" type="Date">
    When list becomes active
  </ParamField>

  <ParamField path="ends_at" type="Date">
    When list expires
  </ParamField>

  <ParamField path="rules" type="CreatePriceListRuleDTO[]">
    Applicability rules
  </ParamField>
</ParamField>

### Set Price List Prices

Add prices to a price list.

<CodeGroup>
  ```typescript Example theme={null}
  await pricingModuleService.setPriceListPrices([
    {
      price_list_id: "plist_123",
      price_set_id: "pset_456",
      amount: 1600, // Discounted price
      currency_code: "usd",
    },
  ])
  ```
</CodeGroup>

### Remove Price List Prices

Remove prices from a price list.

<CodeGroup>
  ```typescript Example theme={null}
  await pricingModuleService.removePriceListPrices([
    "plist_123_pset_456",
  ])
  ```
</CodeGroup>

## Integration Examples

### With Product Module

Create prices for product variants.

<CodeGroup>
  ```typescript Example theme={null}
  import { Modules } from "@medusajs/framework/utils"

  const productModule = container.resolve(Modules.PRODUCT)
  const pricingModule = container.resolve(Modules.PRICING)

  // Create product
  const product = await productModule.createProducts({
    title: "T-Shirt",
    variants: [
      { title: "Small", sku: "TSHIRT-S" },
    ],
  })

  const variant = product.variants[0]

  // Create price set
  const priceSet = await pricingModule.createPriceSets({
    prices: [
      { amount: 2000, currency_code: "usd", rules: {} },
      { amount: 1800, currency_code: "eur", rules: {} },
    ],
  })

  // Link price set to variant (via workflows)
  ```
</CodeGroup>

### With Cart Module

Calculate prices for cart items.

<CodeGroup>
  ```typescript Example theme={null}
  import { Modules } from "@medusajs/framework/utils"

  const cartModule = container.resolve(Modules.CART)
  const pricingModule = container.resolve(Modules.PRICING)

  // Get cart
  const cart = await cartModule.retrieveCart("cart_123", {
    relations: ["items"],
  })

  // Calculate prices for all items
  const priceSetIds = cart.items.map(item => item.variant.price_set_id)

  const prices = await pricingModule.calculatePrices(
    { id: priceSetIds },
    {
      context: {
        currency_code: cart.currency_code,
        region_id: cart.region_id,
        customer_group_id: cart.customer?.group_id,
      },
    }
  )

  // Update cart items with calculated prices
  for (let i = 0; i < cart.items.length; i++) {
    await cartModule.updateLineItems(cart.items[i].id, {
      unit_price: prices[i].calculated_amount,
    })
  }
  ```
</CodeGroup>

### With Customer Module

Customer group pricing.

<CodeGroup>
  ```typescript Example theme={null}
  import { Modules } from "@medusajs/framework/utils"

  const customerModule = container.resolve(Modules.CUSTOMER)
  const pricingModule = container.resolve(Modules.PRICING)

  // Get customer with groups
  const customer = await customerModule.retrieveCustomer("cus_123", {
    relations: ["groups"],
  })

  const customerGroupId = customer.groups[0]?.id

  // Calculate prices for customer group
  const prices = await pricingModule.calculatePrices(
    { id: ["pset_123"] },
    {
      context: {
        currency_code: "usd",
        customer_group_id: customerGroupId,
      },
    }
  )
  ```
</CodeGroup>

### With Region Module

Region-based pricing.

<CodeGroup>
  ```typescript Example theme={null}
  import { Modules } from "@medusajs/framework/utils"

  const regionModule = container.resolve(Modules.REGION)
  const pricingModule = container.resolve(Modules.PRICING)

  // Get region
  const region = await regionModule.retrieveRegion("reg_us")

  // Add region-specific price
  await pricingModule.addPrices({
    priceSetId: "pset_123",
    prices: [
      {
        amount: 2000,
        currency_code: region.currency_code,
        rules: {
          region_id: region.id,
        },
      },
    ],
  })
  ```
</CodeGroup>

## Pricing Strategies

### Multi-Currency

<CodeGroup>
  ```typescript Example theme={null}
  // Add prices in multiple currencies
  await pricingModule.addPrices({
    priceSetId: "pset_123",
    prices: [
      { amount: 2000, currency_code: "usd", rules: {} },
      { amount: 1800, currency_code: "eur", rules: {} },
      { amount: 1500, currency_code: "gbp", rules: {} },
      { amount: 170000, currency_code: "jpy", rules: {} },
    ],
  })
  ```
</CodeGroup>

### Tiered Pricing (Quantity Discounts)

<CodeGroup>
  ```typescript Example theme={null}
  // Volume discounts
  await pricingModule.addPrices({
    priceSetId: "pset_123",
    prices: [
      {
        amount: 2000,
        currency_code: "usd",
        min_quantity: 1,
        max_quantity: 9,
        rules: {},
      },
      {
        amount: 1800,
        currency_code: "usd",
        min_quantity: 10,
        max_quantity: 49,
        rules: {},
      },
      {
        amount: 1600,
        currency_code: "usd",
        min_quantity: 50,
        rules: {},
      },
    ],
  })
  ```
</CodeGroup>

### Customer Group Pricing (B2B)

<CodeGroup>
  ```typescript Example theme={null}
  // Wholesale pricing
  await pricingModule.addPrices({
    priceSetId: "pset_123",
    prices: [
      {
        amount: 2000,
        currency_code: "usd",
        rules: {}, // Retail price
      },
      {
        amount: 1400,
        currency_code: "usd",
        rules: {
          customer_group_id: "cgroup_wholesale",
        },
      },
      {
        amount: 1200,
        currency_code: "usd",
        rules: {
          customer_group_id: "cgroup_distributor",
        },
      },
    ],
  })
  ```
</CodeGroup>

### Flash Sales

<CodeGroup>
  ```typescript Example theme={null}
  // Time-limited sale
  const flashSale = await pricingModule.createPriceLists({
    title: "24-Hour Flash Sale",
    type: "sale",
    status: "active",
    starts_at: new Date(),
    ends_at: new Date(Date.now() + 24 * 60 * 60 * 1000), // 24 hours
    rules: [],
  })

  // Add discounted prices
  await pricingModule.setPriceListPrices([
    {
      price_list_id: flashSale.id,
      price_set_id: "pset_123",
      amount: 1500, // 25% off from $20
      currency_code: "usd",
    },
  ])
  ```
</CodeGroup>

## Best Practices

1. **Rule Priority**: When multiple prices match the context, the module selects based on rule specificity. More specific rules (with more conditions) take precedence.

2. **Currency Codes**: Always use lowercase three-letter ISO currency codes ("usd", not "USD").

3. **Quantity Ranges**: Use `min_quantity` and `max_quantity` for tiered pricing. Ensure ranges don't overlap.

4. **Price List Types**:
   * `sale`: Reduces prices (used for promotions)
   * `override`: Replaces prices entirely

5. **Context Calculation**: Include all relevant context when calculating prices (currency, region, customer group, quantity) for accurate results.

6. **Tax Inclusion**: Use `PricePreference.is_tax_inclusive` to indicate if prices include tax. This affects tax calculations in other modules.

## Related Modules

* [Product Module](/modules/product) - Link prices to product variants
* [Cart Module](/modules/cart) - Calculate cart item prices
* [Customer Module](/modules/customer) - Customer group pricing
* [Region Module](/modules/region) - Region-based pricing
* [Promotion Module](/modules/promotion) - Apply promotional discounts
