How to Handle Amount, Scale, and Unscaled Values
Essential knowledge
Intended Audience:
Technical User
Author:
Fluent Commerce
Changed on:
17 Mar 2026
Overview
This article explains how to manage large monetary values accurately in Fluent OMS using`scale` and `unscaledValue`, rather than relying solely on a floating-point `amount`. Floating-point types (`Float`, `Double`) cannot accurately represent decimal currency values, leading to rounding errors and inconsistent financial results. Fluent OMS applies a consistent precision model across API, business logic, and storage to ensure deterministic, lossless monetary calculations.Key points
- Avoid floating-point inaccuracies by using
`scale`and`unscaledValue`for large amounts. - Treat
`unscaledValue`and`scale`as the source of truth for exact monetary values. - Adjust
`scale`to handle very large amounts while maintaining precision. - For display and reporting, always reconstruct amounts from
`unscaledValue`and`scale`. - Monetary values are stored and processed using deterministic decimal representations to avoid rounding loss.
- New development should use the precise representation model as the primary monetary format.
In Fluent OMS, monetary values are represented using three related fields:
- amount (Float): A floating-point representation of the monetary value.
- scale (Int): The number of decimal places that the unscaled value represents.
- unscaledValue (Int): The integer representation of the amount before decimal placement.
`BigDecimal` in Java or other languages, which stores values in a high-precision, scale-aware manner. The `amount` field alone is provided for convenience but is susceptible to floating-point inaccuracies, especially as the number of digits grows.- unscaledValue: This is the raw integer form of the monetary amount before considering the decimal point. For example, if you have 123.45:
`unscaledValue`might be`12345`.
- scale: This indicates how many decimal places are present. Using the above example:
`scale`would be`2`because we have two decimal places.
- amount: This is a floating-point number derived by applying the scale to the
`unscaledValue`:`amount = unscaledValue * 10^(-scale)`- Continuing the example,
`12345 * 10^(-2) = 123.45`.
Floating-point numbers (like
`Float` or `Double` in many programming languages) have limited precision. As the magnitude of the number grows, it becomes increasingly difficult to represent exact decimal values. This leads to rounding or representation errors. For currency values, even tiny inaccuracies can be problematic.Our OMS fields (`amount`, `scale`, `unscaledValue`) are designed so that `scale` and `unscaledValue` can be used to store and retrieve the exact monetary amount without precision loss, bypassing the limitations of floating-point arithmetic.Using Monetary Values Correctly
This section applies to APIs and integrations that use`amount`, `scale`, and `unscaledValue`. For the newer, precise monetary model based on `preciseAmount`, see the Payments Overview for a high-level description.For Data Input (Mutations)
- Option A (High Accuracy Preferred):
Always provide`scale`and`unscaledValue`fields when creating or updating monetary values. This ensures the OMS stores an exact decimal value.
1 mutation {
2
3 updateInvoice(input: {ref: "invoiceRef123",
4 totalAmount: {unscaledValue: 1234567878, scale: 2, amount: 12345678.78}}) {
5 ref
6 totalAmount {
7 amount
8 scale
9 unscaledValue
10 }
11
12 }
13
14}`unscaledValue`= 1234567878`scale`= 2- Thus, the exact monetary value is 12345678.78. Including the amount is optional if you are primarily relying on unscaled value and scale for precision, but it can be helpful for readability. The system will use the
`unscaledValue`and`scale`as the source of truth. - Option B (Display Only):
If you must use the`amount`alone, understand that it may not represent large values accurately. For very large values (generally 7+ digits before the decimal), floating-point inaccuracies are likely. Consider limiting the usage of`amount`alone to scenarios where perfect accuracy is not critical.
For Data Retrieval
- When reading values from the OMS, do not rely solely on the
`amount`if you need precision. - Use
`scale`and`unscaledValue`to reconstruct the exact amount:`precise_value = unscaledValue * 10^(-scale)` - For example, if
`unscaledValue = 100000087`and`scale = 2`, then:`precise_value = 100000087 * 10^(-2) = 1000000.87` - Display this calculated value in your UI or use it in downstream calculations for guaranteed accuracy.
Choosing the Right Scale
Select a`scale` that matches the smallest currency unit that you will handle. For most currencies, a scale of 2 (cents, pence) is common. If your currency requires more precision (e.g., 3 decimal places), adjust accordingly.For workflows that calculate proportions (e.g., allocating shipping fees, partial captures, splits), ensure scale is applied consistently, and rounding is explicit.UI Display Considerations:
- If the UI currently displays the
`amount`directly, you may see rounding issues with large amounts. - To ensure the UI displays exact values, transform
`unscaledValue`and`scale`it into a formatted string. This ensures that what the user sees matches the exact intended monetary value, regardless of the internal floating-point representation.
Example template code :`{{currency (divide unscaledValue ( pow 10 scale) _decimalPlaces=scale) currency}}`
Summary
- DO provide
`scale`and`unscaledValue`when accuracy matters—these are your source of truth. - DO use
`scale`and`unscaledValue`to reconstruct the precise monetary value for display and further calculations. - DON’T rely solely on the
`amount`for large or critical monetary values, as floating-point inaccuracies can cause rounding issues. - CHECK that your chosen
`scale`and`unscaledValue`fit within the integer range, and consider using different scales to handle very large values.