DEV Community

Jonas Hämmerle
Jonas Hämmerle

Posted on

ISO 4217 currency codes: the edge cases that break naive multi-currency forms

Most currency handling code assumes every currency has 2 decimal places and a straightforward numeric amount. Neither assumption holds universally, and both break in ways that are easy to miss until a real transaction hits the edge case.

Not every currency has 2 minor units. JPY has zero — ¥100 is a whole number, there's no ¥100.00. KWD (Kuwaiti Dinar) has three. If your form/database column hardcodes 2 decimal places "because that's how currency works," you'll either round JPY amounts into nonsense or truncate KWD precision.

const MINOR_UNITS = { JPY: 0, KWD: 3 /* ... */ }; // default 2 for anything not listed
function formatAmount(amount, code) {
  const digits = MINOR_UNITS[code] ?? 2;
  return amount.toFixed(digits);
}
Enter fullscreen mode Exit fullscreen mode

Currency codes aren't a stable, closed set forever — they get added, and in rare cases retired (old Eurozone currencies like DEM, FRF were withdrawn when the Euro launched). A hardcoded currency list baked into your app years ago can silently drift from reality. Pull the supported-currency list from a source that's actually kept current, rather than a list you typed once.

Symbol collisions are a UI bug waiting to happen. $ alone is ambiguous across USD, CAD, AUD, and several others — showing just the symbol without the ISO code next to it (or as a tooltip) is a real source of "wait, is that dollars or my dollars" confusion in any multi-currency UI.

Currency API's /v1/currencies endpoint always reflects the actual current supported set (ECB scope, ~30 major currencies) rather than a list that can go stale — check it instead of hardcoding one, especially if you're validating currency-code input from a form. Sibling API QR API is useful if that same form flow ever needs a QR code for a payment link, and Validate covers the rest of the form's IBAN/email/phone checks.

Top comments (0)