Separate provider-cost budgets from customer retail billing
Read the usage ledger and retail metering overview as different accounting systems with different scopes, prices and admission rules.
Convert a reviewed decimal amount to the API’s integer unit without floating-point rounding, locale ambiguity or accidental overage consent.
Lupin’s budget and retail settings APIs use integer micro-USD: one dollar equals one million micros. Invoice responses use the invoice currency’s minor units, which are cents for USD. A shared field called amount invites a hundredfold or millionfold conversion bug. Name the unit in variables, database columns and diagnostic output.
Treat the reviewed decimal input as text until it has been validated. Multiplying a binary floating-point number by one million can produce unexpected fractions near a boundary. Rounding that result may silently admit a different cap than the user entered. Parse the decimal digits directly instead.
For a USD-only form, a useful policy accepts a nonnegative whole number and up to six decimal places, using a dot as the decimal separator. Reject currency symbols, grouping separators, scientific notation and extra precision. If the interface accepts localized input, normalize it through a deliberately tested locale parser before this boundary.
Apply the endpoint’s range and positivity requirements after conversion. Budget creation requires a positive safe integer and currently rejects values above its documented implementation ceiling. Retail overage settings have their own validation. A reusable parser should return an exact quantity; an endpoint-specific validator decides whether that quantity is permitted.
Split the string into whole and fractional digits, pad the fraction to six places and calculate with integer arithmetic. Check that the result fits the safe integer range before converting to a JavaScript number for JSON. BigInt itself cannot be passed directly to JSON.stringify without a deliberate conversion.
The small example below illustrates the arithmetic boundary only. It does not create a budget or enable overages. The caller must still apply the correct endpoint policy and show the reviewed amount before making any consequential account change. Keeping parsing separate also makes its behavior easy to verify offline.
function usdMicros(text) {
if (!/^(0|[1-9][0-9]*)(\.[0-9]{1,6})?$/.test(text)) {
throw new Error("Use decimal USD with at most six fractional digits");
}
const [whole, fraction = ""] = text.split(".");
const value = BigInt(whole) * 1_000_000n + BigInt(fraction.padEnd(6, "0"));
if (value > BigInt(Number.MAX_SAFE_INTEGER)) throw new Error("Amount too large");
return Number(value);
}
console.assert(usdMicros("25.00") === 25_000_000);
console.assert(usdMicros("0.000001") === 1);A correctly parsed positive cap does not authorize paid overages. Lupin requires explicit acceptance of the relevant catalog and overage consent for an active paid account. A form should preserve those distinct decisions rather than treating the presence of a dollar amount as consent.
When saving settings, inspect the persisted response and updated overview. Do not show success merely because the client serialized the request or a payment page redirected back. A storage or subscription reconciliation failure can leave the prior settings active, so retain edits visibly and let the user understand the actual result.
Use local cases for zero, one microdollar, one dollar, six fractional digits, seven fractional digits, negative input and values beyond the safe integer range. Add locale-looking input such as a comma separator and scientific notation to ensure it is rejected under this grammar. None of these checks requires network access.
Format the resulting integer for display and verify that parsing the displayed precision returns the intended amount. Avoid discarding micros in a review screen when the API will preserve them. A user should approve the value that will be stored, with the unit and scope visible beside it.
Reviewed against the checked-in Lupin billing and budget implementation and official documentation on 2026-11-05. The local arithmetic example passed JavaScript syntax checking and twelve accepted/rejected-input checks; no API call, account setting or provider mutation was executed.
Prepared with AI assistance by Lupin editorial. How we research and maintain these guides.