Spree’s pricing system supports both simple single-currency pricing and advanced multi-currency, rule-based pricing through Price Lists. Every Variant can have multiple prices — a base price per currency, plus additional prices from Price Lists that apply conditionally based on rules like geography, customer segment, or quantity.
Each variant has one or more Price records — one per currency. The API automatically returns the correct price based on the current currency and Market context. See monetary amounts for how money fields (decimal, cents, and display string) are formatted across the API.
Attribute
Description
Example
amount
Current selling price
"99.90"
compare_at_amount
Original/compare price for strikethrough display
"129.90"
currency
ISO 4217 currency code
USD
If a product doesn’t have a price in the selected currency, it won’t appear in Store API responses by default.
Base prices are set per variant per currency. Use the Admin API — via the Admin SDK — to set them individually or in bulk (bulk_upsert matches on variant + currency):
import { createAdminClient } from '@spree/admin-sdk'const client = createAdminClient({ baseUrl: 'https://store.example.com', secretKey: 'sk_xxx',})// Set / change one variant's price in a currencyawait client.prices.create({ variant_id: 'variant_xxx', currency: 'USD', amount: '15.99' })// Upsert many at onceawait client.prices.bulkUpsert({ prices: [ { variant_id: 'variant_xxx', currency: 'USD', amount: '15.99' }, { variant_id: 'variant_xxx', currency: 'EUR', amount: '14.99' }, ],})
The recommended approach for regional pricing when using Markets. Applies the Price List when the customer is in one of the specified markets.Example: Price a product at $29.99 in North America and €24.99 in Europe, rather than relying on exchange rate conversion.
The Store API automatically builds this context from the request headers (X-Spree-Currency, X-Spree-Country) and authentication state. You don’t need to construct it manually — just make API requests and the correct price is resolved.
Price resolution runs per request — there is no in-process caching of resolved prices. The Store API instead relies on HTTP/CDN caching, with Vary headers keyed on the X-Spree-Currency and X-Spree-Locale request headers so each currency/locale combination is cached separately at the edge.
Price Lists support scheduling through starts_at and ends_at attributes. Scheduled Price Lists automatically become applicable when the current time falls within their date range — no manual activation needed.Example: A Black Friday sale Price List with starts_at: 2025-11-28 00:00 and ends_at: 2025-11-28 23:59 will automatically activate and deactivate.
Price Lists are managed in the Admin Panel under Products → Price Lists, or via the Admin API.Each Price List contains prices for specific variants and currencies. Products can be added to a Price List, and individual variant prices set within it.
Spree automatically records price changes for EU Omnibus Directive compliance. When a product goes on sale, EU regulations require displaying the lowest price in the preceding 30 days alongside the discounted price.
Every time a base price amount changes, a PriceHistory record is created automatically. Price list prices are not tracked — only the base price visible to all customers.