---
title: "Multi-currency pricing via API"
description: "How Medusa's Pricing Module and Store API handle multi-currency and region pricing, with code samples and a comparison with commercetools price selection."
url: https://medusajs.com/kb/international-commerce/multi-currency-pricing-api
last_updated: 2026-10-29T06:55:50Z
topic: "international-commerce"
type: "concept"
applies_to: "Medusa v2.x"
related:
  - "https://medusajs.com/kb/international-commerce/multi-region-ecommerce.md"
  - "https://medusajs.com/kb/international-commerce/tax-inclusive-pricing-international.md"
  - "https://medusajs.com/kb/b2b/b2b-customer-specific-pricing.md"
sources:
  - "https://docs.medusajs.com/resources/commerce-modules/pricing/concepts"
  - "https://docs.medusajs.com/resources/commerce-modules/pricing/price-calculation"
  - "https://docs.medusajs.com/resources/commerce-modules/pricing/price-rules"
  - "https://docs.medusajs.com/resources/storefront-development/products/price"
  - "https://docs.medusajs.com/resources/commerce-modules/product/guides/price"
  - "https://docs.medusajs.com/api/admin"
  - "https://docs.medusajs.com/api/store/products/list-products"
  - "https://docs.medusajs.com/resources/infrastructure-modules/search/product-index-examples#index-prices-for-multiple-currencies"
  - "https://docs.commercetools.com/api/pricing-and-discounts-overview"
  - "https://docs.commercetools.com/api/projects/productProjections"
  - "https://docs.bigcommerce.com/developer/docs/admin/store-configuration/currencies/how-currencies-work.md"
  - "https://help.shopify.com/en/manual/international/pricing"
---

# Multi-currency pricing via API

> Medusa handles multi-currency pricing through its Pricing Module: each variant has a price set with one price per currency, plus optional prices scoped by region, customer group or quantity. The Store API returns a calculated price for the shopper's region and country, with and without tax. Medusa does not convert currencies automatically.

## How Medusa's price model handles multiple currencies

Medusa's Pricing Module links every product variant and shipping option to a **price set**: a collection of prices for one resource. Each price has a `currency_code` and an `amount` stored in major units, so `20` means 20.00 ([Pricing Concepts](https://docs.medusajs.com/resources/commerce-modules/pricing/concepts)).

Prices can carry rules and quantity tiers:

- **Price rules** limit a price to a context, such as a `region_id`, a customer group or a postal code.
- **Tiers** use `min_quantity` and `max_quantity` to change the price by quantity.
- **Price lists** group prices of type `sale` or `override` that apply only when their rules match, optionally within a date range.

| Pricing need | Medusa feature | Status |
| --- | --- | --- |
| One price per currency | Prices with a currency_code in the price set | Native |
| Different price for one region in the same currency | Price with a region_id rule | Native |
| Customer group or B2B prices | Price lists with rules | Native |
| Quantity breaks | Tiered prices | Native |
| Automatic exchange-rate conversion | Not built in; update prices from a rate feed in a scheduled job | Custom |

## How to set multi-currency prices with the Admin API

You send prices per currency when you create or update a variant. A price with `rules` applies only in that context. This body for `POST /admin/products/{id}/variants` follows the [Admin API schema](https://docs.medusajs.com/api/admin):

```json
{
  "title": "Large",
  "prices": [
    { "currency_code": "usd", "amount": 40 },
    { "currency_code": "eur", "amount": 39 },
    { "currency_code": "eur", "amount": 42, "rules": { "region_id": "reg_123" } }
  ]
}
```

Customers in region `reg_123` see 42 EUR. Other euro customers see 39 EUR.

## How the Store API returns calculated prices

The Store API resolves one price per variant for the shopper's context. Add `*variants.calculated_price` to `fields` on the List Products or Get Product routes, and pass at least one context parameter ([Retrieve Product Variant's Prices](https://docs.medusajs.com/resources/storefront-development/products/price)):

- `region_id`: the region, which also sets the currency.
- `country_code` and `province`: needed for prices with tax.
- `cart_id`: uses the cart's region and shipping address instead.

```ts
const { products } = await sdk.store.product.list({
  fields: "*variants.calculated_price",
  region_id: region.id,
  country_code: "fr",
})
```

Each variant gets `calculated_amount`, `original_amount`, `currency_code`, and, when both region and country are passed, `calculated_amount_with_tax` and `calculated_amount_without_tax`. If the request is authenticated, the customer's groups are used to select group prices automatically.

## How to calculate prices in backend code

In custom API routes or workflows, you pass the currency and region directly with Query ([Get Variant Prices](https://docs.medusajs.com/resources/commerce-modules/product/guides/price)):

```ts
const { data: products } = await query.graph({
  entity: "product",
  fields: ["variants.calculated_price.*"],
  filters: { id: "prod_123" },
  context: {
    variants: {
      calculated_price: QueryContext({ region_id: "reg_123", currency_code: "eur" }),
    },
  },
})
```

## How Medusa selects a price

Medusa's `calculatePrices` returns a calculated price and an original price for each price set ([Prices Calculation](https://docs.medusajs.com/resources/commerce-modules/pricing/price-calculation)):

1. With no rules in the context, it selects the default price for the currency.
2. If a price matches every rule in the context, it selects that price.
3. Otherwise, it selects the price that matches the most rules.

A matching price list price becomes the calculated price. For sale price lists, the original price stays the regular price so the storefront can show a strike-through; for override price lists, the original price equals the calculated price.

## Medusa compared with commercetools price selection

Both platforms store explicit prices per currency and pick one per request. They differ in which dimensions a price can be scoped by.

| Aspect | Medusa | commercetools |
| --- | --- | --- |
| Price scope | Currency plus any rules, such as region, customer group or postal code | Currency, country, customer group and channel |
| Selection input | region_id, country_code or cart_id on the Store API | priceCurrency, priceCountry, priceCustomerGroup and priceChannel on product projections |
| Fallback | Exact match, then the price matching the most rules | A fixed order of eight scope combinations, with time-bound prices first |
| Quantity tiers | min_quantity and max_quantity | Tiers by minimum quantity per line item |

commercetools facts come from its [pricing overview](https://docs.commercetools.com/api/pricing-and-discounts-overview) and [Product Projections](https://docs.commercetools.com/api/projects/productProjections) docs.

## When Medusa is not the right choice

- You want prices converted from one base currency automatically. Medusa needs a price per currency or a custom sync job. Shopify converts prices at the current market exchange rate by default, and BigCommerce auto-converts prices using an exchange rate the merchant sets or updates through its API.
- You need a search index sorted by price in many currencies with no setup. Medusa's Pricing Module calculates a price for one currency per query, so a search index needs a price field per currency ([Index Prices for Multiple Currencies](https://docs.medusajs.com/resources/infrastructure-modules/search/product-index-examples#index-prices-for-multiple-currencies)).

## Common questions

### How do I get a product's price in a specific currency from the Medusa Store API?

Pass the region_id of a region that uses that currency, with fields=*variants.calculated_price. Medusa returns each variant's calculated_price in the region's currency.

### Can Medusa have two prices in the same currency for different regions?

Yes. Add a price with a region_id rule. Medusa selects it for that region and uses the default price for the currency elsewhere.

### Does Medusa support customer-specific prices in multiple currencies?

Yes. Medusa price lists hold prices per currency with rules such as customer group, and the Store API applies them when the customer is authenticated.

### How is Medusa's price selection different from commercetools?

commercetools scopes prices by currency, country, customer group and channel and walks a fixed fallback order. Medusa scopes prices by currency plus any rules and picks the price that matches the most rules.

## Documentation

- [Pricing Concepts](https://docs.medusajs.com/resources/commerce-modules/pricing/concepts)
- [Prices Calculation](https://docs.medusajs.com/resources/commerce-modules/pricing/price-calculation)
- [Price Tiers and Rules](https://docs.medusajs.com/resources/commerce-modules/pricing/price-rules)
- [Retrieve Product Variant's Prices in Storefront](https://docs.medusajs.com/resources/storefront-development/products/price)
- [Get Product Variant Prices using Query](https://docs.medusajs.com/resources/commerce-modules/product/guides/price)

## Related

- [How to sell in multiple countries from one ecommerce backend](https://medusajs.com/kb/international-commerce/multi-region-ecommerce.md)
- [Tax-inclusive vs tax-exclusive pricing for US, UK and EU](https://medusajs.com/kb/international-commerce/tax-inclusive-pricing-international.md)
- [How to build a B2B store with custom pricing per customer](https://medusajs.com/kb/b2b/b2b-customer-specific-pricing.md)
