ShiftxPay
Core concepts

Money & currencies

Integer minor units, never floats.

Every monetary amount in ShiftxPay is an integer in the currency's minor units — never a float, never a decimal string. This is the single most important rule for handling money correctly, and it applies on the wire, in the gateway, and in the ledger.

Minor units

A minor unit is the smallest indivisible unit of a currency: cents for USD, pence for GBP, cents for EUR. Amounts are int64, so they comfortably cover any realistic transaction size.

Display amountCurrencyamount (minor units)
$12.34USD1234
$50.00USD5000
£9.99GBP999
€100.00EUR10000

To convert a major-unit price to minor units, multiply by the number of minor units in one major unit (100 for USD/GBP/EUR) and round to an integer before it ever enters the system. Do the conversion once, at the boundary.

Currency codes

Currency is a three-letter ISO 4217 code in uppercase: USD, GBP, EUR. Always send it uppercase; lowercase or non-ISO values are rejected by validation.

The number of minor units per major unit depends on the currency, so always pair an amount with its currency. Most currencies use two decimal places (factor 100), but not all — never assume 100.

Format only at the display layer

House style: store and compute money as integers everywhere, and format to a human-readable string only at the very last step, in the UI.

// amount in minor units, currency ISO 4217
function formatAmount(amount: number, currency: string): string {
  return new Intl.NumberFormat("en-US", {
    style: "currency",
    currency,
  }).format(amount / 100);
}

formatAmount(1234, "USD"); // "$12.34"

Doing arithmetic on the integer and converting only for display avoids the rounding errors that floats introduce. Never add, subtract, or split amounts as floating-point numbers.

On this page