Concepts
Amounts and time
Money is exact and time is simple: decimal strings and Unix seconds, everywhere.
Money
Every amount in a response is a plain decimal string: no exponent, no trailing zeros,
"0" for zero, null when absent. Parse it with a decimal type, and never compare
amounts as strings or as floats. Amounts you send use the same format, and may not have
more decimals than the currency's theoretical precision.
Parsing amounts
A float turns 0.1 + 0.2 into 0.30000000000000004, which is how a fully paid order reads as short. Compare amounts as decimals, or as whole units of the currency's smallest denomination.
from decimal import Decimal
def paid_in_full(payment: dict) -> bool:
return Decimal(payment["paid"]) >= Decimal(payment["topay"])// Whole minor units: "0.00021" with 8 decimals is 21000n.
function toUnits(amount, decimals) {
const [whole, fraction = ""] = amount.split(".");
return BigInt(whole + fraction.padEnd(decimals, "0").slice(0, decimals));
}
function paidInFull(payment, decimals) {
return toUnits(payment.paid, decimals) >= toUnits(payment.topay, decimals);
}// bcmath compares decimal strings exactly.
function paidInFull(array $payment, int $decimals): bool
{
return bccomp($payment["paid"], $payment["topay"], $decimals) >= 0;
}
Each currency's precision is on Payment methods and in the currency registry.
Time
Every timestamp is an integer number of seconds since the Unix epoch, in UTC.