Emberstore logoEmberstore

Prices and currencies

Write prices once in your main currency, and bill gateways that use another currency with a fixed or converted price.

You write every price once, in your main currency. When a gateway bills in a different currency (Razorpay in rupees, for example), Emberstore uses a price you set for that currency, or converts your main price with an exchange rate. The player sees both amounts before paying.

The price steps in order: unit price times quantity, the best active sale, a code, rounding, conversion into the billing currency and the gateway minimum check, with two worked examples billing in INR.

Main currency and symbols

# Currency your item prices are written in
price-currency: "usd"

currencies:
  # Symbol shown for each currency code in prices. A code without an entry shows the code itself
  usd: "$"
  eur: "€"
  gbp: "£"
  inr: "₹"

Menus, lore, /store top and stats all show prices in price-currency. Prices are shown with the currency's own number of decimals, so $4.99, ₹399.00, or 500 JPY when there is no symbol for it.

Which price a gateway bills

Each gateway bills in its own currency (empty means price-currency). For each gateway, Emberstore picks the price in this order:

  1. The gateway bills in your main currency: the item's price.
  2. The item has a prices entry for that currency: that amount, exactly as written.
  3. Conversion is on and a usable rate exists: your main price, converted.
  4. None of these: that gateway is not offered for the item.
vip:
  price: 4.99
  # Optional prices in other currencies. A gateway billing in one of these uses that price
  prices:
    eur: 4.59
    inr: 399

Conversion settings

currency-conversion:
  enabled: true
  mode: live
  fixed-rates:
    inr: 88.0
  source-url: ""
  refresh-minutes: 60
  max-age-hours: 24
  max-deviation-percent: 10
  margin-percent: 0
  round-to: 1
  rounding: up
KeyDefaultWhat it does
enabledtrueConvert prices for gateways that bill in another currency, when the item has no price in it.
modelivelive fetches rates on a schedule. fixed only uses fixed-rates.
fixed-ratesinr: 88.0Units of each currency per 1 unit of price-currency. Used in fixed mode, and as the fallback in live mode. The shipped value is only an example, set your own.
source-url""Where live rates come from. Empty uses the built-in source (European Central Bank reference rates through frankfurter.dev, no key needed). Any address that answers {"rates": {"INR": 88.1}} works, with {base} and {symbols} filled in.
refresh-minutes60Minutes between live rate refreshes. Rates are never fetched during a checkout.
max-age-hours24How long a live rate may still be used after the last good refresh. After that the fixed rate takes over.
max-deviation-percent10A new live rate that moved more than this from the last one, or from the fixed rate, is ignored with a warning.
margin-percent0Percentage added on top of the rate to cover movement and fees.
round-to1Round converted prices to a multiple of this many whole units. 1 means whole rupees.
roundingupnearest, up or down. up makes sure you are never short.

The order of the maths

Always in this order:

  1. Unit price times quantity.
  2. The best active sale. Sales never stack, the one that saves the most wins.
  3. A promo or referral code, unless that sale has allow-codes: false.
  4. Round to the currency's smallest unit (cents, paise).
  5. For a converted price: times the rate, plus margin-percent, then rounded to round-to using rounding. Discounts are worked out in your main currency first and the result is converted once.
  6. Check the gateway's minimum charge. Below it, the player sees "This price is too low to pay with ..." in the dialog. Exactly zero is a free order: no gateway, the item is given straight away.

A fixed discount (type: fixed) is in your main currency. On an item with an explicit price in the billing currency, it is converted at the current rate, rounded down. Without a usable rate, a fixed code is not valid for that payment.

What the player sees

When the price was converted, the dialog shows a line such as:

Charged in INR: ₹1320.00 (about $14.99, 1 USD = 88 INR)

That line is dialog.checkout.converted-line in the language file.

The rate is locked on the order

The rate is read once, when the order is created, and stored with it. The amount sent to the gateway never changes afterwards, and a refund returns exactly what was charged. Stats and the dashboard keep revenue in the currency it was billed in, and convert to your main currency with each order's own stored rate, so old orders keep the rate they were really made at.

On this page