Skip to content
Elara One docs

Money

How the API represents prices and totals as integer minor units, how to display them, and how tax-inclusive and tax-exclusive prices are labelled.

Every price, total and discount in the API is a money object with an integer amount in minor units. There are no floats and no decimal strings to parse. This page explains the shape, how to display it and how to send amounts back.

The money object

A money object
{ "amount": 8900, "currency": "GBP", "formatted": "£89.00" }
FieldTypeMeaning
amountintegerThe value in the currency's minor unit: pence for GBP, cents for EUR and USD. 8900 is £89.00.
currencystringThe ISO 4217 currency code, such as GBP.
formattedstringThe amount ready to show, formatted for the UK (£89.00).

The same shape is used everywhere: product prices, cart lines, shipping options, discounts, tax, order totals and search results. A money field that has no value is null, never 0 and never a missing object. For example, a variant has no price when the store has not set one in its currency, and cart totals are null until the cart has been calculated.

Merchant CRM money custom fields use the same idea without formatted: { "amount": 250000, "currency": "GBP" }.

Never use floats

Floating-point numbers cannot hold most decimal fractions exactly, so 0.1 + 0.2 is not 0.3. Keep amounts as integers from the moment they arrive until you display them.

  • Show formatted. It is correct for the currency and already rounded.
  • Do not add up totals yourself. Promotions, shipping discounts and tax all change the numbers. Read sub_total, discount_total, tax_total and total from the cart or order.
  • Compare and sort on amount, never on formatted.
  • Send integers back. Query parameters that take money, such as filter[price_min] and filter[price_max], take integer minor units. Send 2500 for £25.00, never 25 or 25.00.

Display amounts in another locale

If your shop shows prices in a format other than the UK one, format amount yourself. Divide by the currency's number of minor units, which Intl.NumberFormat already knows:

Format a money object for any locale
type Money = { amount: number; currency: string; formatted: string }

export function formatMoney(money: Money, locale = 'en-GB'): string {
  const formatter = new Intl.NumberFormat(locale, { style: 'currency', currency: money.currency })
  const digits = formatter.resolvedOptions().maximumFractionDigits ?? 2
  return formatter.format(money.amount / 10 ** digits)
}

formatMoney({ amount: 8900, currency: 'GBP', formatted: '£89.00' }, 'de-DE') // "89,00 £"

Division here is only for display. Never feed the result back into arithmetic or into a request.

Currency

Each store trades in its own currency. You can read it from:

  • currency on GET /v1/checkout/config;
  • currency on every money object;
  • meta.currency on search responses.

Do not assume GBP. Read the currency from the response and pass it to your formatter.

Percentages

Percentages that describe money are integers in basis points, so they never need floats either. percent_bp: 1250 is 12.5%. You will see them on a variant's pricing.saving and in a bulk-price table's rows.

Tax rates in a tax breakdown are the exception: percentage is a string, such as "20", meant for display.

Tax-inclusive and tax-exclusive prices

Stores set, per tax zone, whether prices are shown including or excluding tax. A cart tells you which applies through tax_zone:

tax_zone on a cart
{
  "tax_zone": {
    "id": 1,
    "name": "UK",
    "price_display": "tax_inclusive",
    "prices_include_tax": true
  }
}
FieldValues
price_displaytax_inclusive ("Including VAT") or tax_exclusive ("Excluding VAT")
prices_include_taxThe same, as a boolean

The zone is the shipping address's, or the store's default zone before an address is set. tax_zone is null when the store has no tax zone.

This setting is for labelling. The amounts are already correct either way: total is always what the shopper pays, tax_total is the tax within it, and tax_breakdown lists each rate:

tax_breakdown on a cart
[
  {
    "identifier": "vat-standard",
    "description": "VAT",
    "percentage": "20",
    "price": { "amount": 2050, "currency": "GBP", "formatted": "£20.50" }
  }
]

Use price_display to choose the label next to prices ("inc. VAT" or "ex. VAT"), and show tax_total as its own line when prices exclude tax.