Money
Every monetary value in the SDK is a `Money`: a branded string at runtime, a distinct type at compile time. Strings keep decimal precision intact across JSON, databases, and currency boundaries.
Why a string
IEEE-754 doubles can't represent 0.1 exactly. Multiplying tax rates, summing order lines, comparing prices: all of these silently round when carried as number. The wire format settles it: backend serializes amounts to two-decimal strings, the SDK preserves them, and you parse only at the moment you need to do math or render to a user.
import type { Money } from "@cimplify/sdk";
const price: Money = "29.99" as Money;
// Compile-time: plain string is not a Money
const wrong: Money = "29.99"; // type error: must use money() or come from the SDKThe helpers
import { money, parsePrice, formatPrice } from "@cimplify/sdk/utils";
const price = money("29.99"); // Money, validated at construction
const cents = parsePrice(price); // 29.99 number, for math only
const display = formatPrice(29.99, "GHS"); // "GH₵29.99" for UI| Helper | In | Out | Use for |
|---|---|---|---|
money(s) | string | Money | Constructing Money from a literal |
parsePrice(m) | Money | string | number | Math, comparisons, totals |
formatPrice(n, ccy) | number, string | string | Locale-aware UI rendering |
The trap: comparing strings to numbers
JSON delivers Money as strings. JavaScript's coercion rules will happily compare "0.00" to 0 and tell you they're different. Always parse before you compare.
const cart = await client.cart.get();
if (!cart.ok) return;
// "0.00" !== 0 → true. Always.
if (cart.value.pricing.subtotal !== 0) {
showCheckoutButton();
}import { parsePrice } from "@cimplify/sdk/utils";
const cart = await client.cart.get();
if (!cart.ok) return;
if (parsePrice(cart.value.pricing.subtotal) !== 0) {
showCheckoutButton();
}Summing line items
import { parsePrice, formatPrice } from "@cimplify/sdk/utils";
const cart = await client.cart.get();
if (!cart.ok) throw cart.error;
const total = cart.value.items
.map((item) => parsePrice(item.price) * item.quantity)
.reduce((a, b) => a + b, 0);
return formatPrice(total, cart.value.currency); // "GH₵149.94"Currency lives next to the amount
Money values do not embed their currency. Carts, orders, and products carry a separate currency field (ISO 4217). Always format with that explicit currency; never hardcode "USD" in templates that may serve a Ghanaian or Kenyan merchant.
import { formatPrice } from "@cimplify/sdk/utils";
const order = (await client.orders.get(orderId)).value;
const display = formatPrice(parsePrice(order.total), order.currency);Next
Environments
Cimplify runs in two modes. **Test mode** is either the in-process mock that ships with the SDK, or a sandbox business at `api.cimplify.io` using `pk_test_…` keys. **Live mode** is your real business, real catalogue, real money, gated by `pk_live_…` keys.
Result
Every SDK method returns `Result<T, CimplifyError>` and never throws. You narrow on `.ok`, and TypeScript gives you either `value` or `error` on the other branch.