Money and prices

Minor units, currencies, price lists and pack sizes.

Amounts are minor units

Every amount is a whole number in the currency's smallest unit: pesewas for Ghana cedis. 1200 is GH₵ 12.00, 9000 is GH₵ 90.00. There are never decimals, so nothing is lost to rounding.

The shop's currency is in GET /shop as currency (GHS, NGN, KES, ZAR, USD, EUR or GBP):

Showing an amount
const money = (amount, currency) =>
  new Intl.NumberFormat(undefined, { style: 'currency', currency }).format(
    amount / 100,
  );

money(1200, 'GHS'); // "GH₵12.00"

Where prices live

A product has one or more versions (sizes, colours: a variant each). Each version has:

  • sellingPrice: its price for one unit, at the shop's first price type.
  • prices: its price at each price type the shop shows online.
  • sellingUnits: the packs it also sells in (a carton of 24), each with its own sellingPrice and prices.
{
  "priceTypes": [
    { "id": null, "name": "Retail" },
    { "id": "9badb858-…", "name": "Wholesale" }
  ],
  "versions": [
    {
      "variantId": "1db29704-…",
      "sellingPrice": 1200,
      "prices": [
        { "priceListId": null, "sellingPrice": 1200 },
        { "priceListId": "9badb858-…", "sellingPrice": 1000 }
      ],
      "sellingUnits": [
        {
          "id": "c22d51bf-…",
          "name": "Pack of 10",
          "sellingPrice": 12000,
          "prices": [{ "priceListId": null, "sellingPrice": 12000 }]
        }
      ]
    }
  ]
}

Price types

Shops sell at more than one price: retail and wholesale, adult and kids. priceTypes lists those the shop offers online; id: null is Retail. Let customers pick one and send its id as priceListId on each order line. Leave it out for Retail.

Taxes and delivery

The order's total includes the shop's taxes and any delivery fee, worked out by Cashiar. Show the line prices while the customer shops, and the total the order answers with at checkout.

Delivery fees are in GET /shop: delivery.fee is the usual fee, and delivery.zones lists places with their own fee. Send the zone's name as deliveryZone to charge it.

On this page