> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kayanos.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Money helpers

> Every registered money helper, with signatures and examples for amounts in a currency, exact totals, rounding, allocation, and exchange rates.

## When to use these helpers

Use these helpers when a value is an amount in a currency. A MoneyValue keeps its currency, adds and compares exactly, and refuses to mix two currencies without a conversion. The arithmetic and comparison operators also understand MoneyValues; plain numbers behave exactly as before.

## Calling style

Call a helper as `roundMoney($.unit_price * $.quantity)`. Not every helper is available everywhere: validation, form, and document-template helpers have distinct context contracts. Editor suggestions are not proof that a helper is supported at runtime.

## Complete function reference

> **allocate**
>
> ### `allocate`
>
> Splits an amount by weights so the parts add up exactly to the total rounded to the currency’s decimals (2 decimals for a plain number). Leftover units go to the parts with the largest remainders, earlier parts first on a tie. Weights that are all zero give zero parts; weights that are not a list give an empty list. The parts carry no base.
>
> **Signature:** `allocate(value, weights)`
>
> **Example:**
>
> ```txt theme={null}
> allocate(money(100, "USD"), [1, 1, 1]) // [33.34, 33.33, 33.33] USD
> ```
>
> **Availability:** Shared builder expression runtime and document templates; function and transform forms are available. The organization’s currency decimals, rounding mode, base currency, and Money field values are in scope only in entity calculated fields evaluated on the server when a record is created or saved.
>
> **Note:** It can also be written as a transform when the first value is the input: `value | allocate(...)`.

> **base**
>
> ### `base`
>
> With a MoneyValue, returns its captured base-currency equivalent as a number, or null when none was captured. With no argument, returns the organization’s base currency code inside a calculated field and null elsewhere. Any other value gives null.
>
> **Signature:** `base(value?)`
>
> **Example:**
>
> ```txt theme={null}
> base($.contract_value) // captured base equivalent, or null
> base() // the organization’s base currency code, such as "SYP"
> ```
>
> **Availability:** Shared builder expression runtime and document templates; function and transform forms are available. The organization’s currency decimals, rounding mode, base currency, and Money field values are in scope only in entity calculated fields evaluated on the server when a record is created or saved.
>
> **Note:** It can also be written as a transform when the first value is the input: `value | base(...)`.

> **convert**
>
> ### `convert`
>
> Converts a MoneyValue to another currency at the organization’s rate (options.type and options.on as for rateOn) and rounds the result to the target currency’s decimals with the organization’s rounding mode. Returns the value unchanged when it is already in that currency, and null when the first argument is not a MoneyValue or to is not text. Stops with MONEY\_RATE\_MISSING when no rate qualifies. The result records the rate and rate type but has no base.
>
> **Signature:** `convert(value, to, options?)`
>
> **Example:**
>
> ```txt theme={null}
> convert($.contract_value, "USD", { on: $.invoice_date, type: "market" })
> ```
>
> **Availability:** Reads the organization’s exchange rates only in entity calculated fields evaluated on the server when a record is created or saved. Elsewhere rateOn and fx return null and convert stops with MONEY\_RATE\_MISSING. Function and transform forms are available.
>
> **Note:** It can also be written as a transform when the first value is the input: `value | convert(...)`.

> **currencyOf**
>
> ### `currencyOf`
>
> Returns the ISO currency code of a MoneyValue, or null for any other value.
>
> **Signature:** `currencyOf(value)`
>
> **Example:**
>
> ```txt theme={null}
> currencyOf(money(5, "EUR")) // "EUR"
> ```
>
> **Availability:** Shared builder expression runtime and document templates; function and transform forms are available. The organization’s currency decimals, rounding mode, base currency, and Money field values are in scope only in entity calculated fields evaluated on the server when a record is created or saved.
>
> **Note:** It can also be written as a transform when the first value is the input: `value | currencyOf(...)`.

> **fx**
>
> ### `fx`
>
> Short alias of rateOn with the same arguments, defaults, and result.
>
> **Signature:** `fx(currency, on?, type?, to?)`
>
> **Example:**
>
> ```txt theme={null}
> fx("EUR", $.invoice_date) // same as rateOn("EUR", $.invoice_date)
> ```
>
> **Availability:** Reads the organization’s exchange rates only in entity calculated fields evaluated on the server when a record is created or saved. Elsewhere rateOn and fx return null and convert stops with MONEY\_RATE\_MISSING. Function and transform forms are available.
>
> **Note:** It can also be written as a transform when the first value is the input: `value | fx(...)`.

> **isMoney**
>
> ### `isMoney`
>
> Checks whether a value is a MoneyValue. A Money field is a MoneyValue only where the organization’s Money-aware operators put one in the calculated-field context; otherwise it is a plain number.
>
> **Signature:** `isMoney(value)`
>
> **Example:**
>
> ```txt theme={null}
> isMoney(money(5, "EUR")) // true
> isMoney(5) // false
> ```
>
> **Availability:** Shared builder expression runtime and document templates; function and transform forms are available. The organization’s currency decimals, rounding mode, base currency, and Money field values are in scope only in entity calculated fields evaluated on the server when a record is created or saved.
>
> **Note:** It can also be written as a transform when the first value is the input: `value | isMoney(...)`.

> **money**
>
> ### `money`
>
> Creates a MoneyValue from an amount (a number or decimal text) and a three-letter uppercase ISO currency code. Returns null when the amount is not numeric or the code is not three uppercase letters. The optional denomination key is kept on the value.
>
> **Signature:** `money(amount, currency, denomination?)`
>
> **Example:**
>
> ```txt theme={null}
> money(1250.5, "USD") // 1250.5 USD
> ```
>
> **Availability:** Shared builder expression runtime and document templates; function and transform forms are available. The organization’s currency decimals, rounding mode, base currency, and Money field values are in scope only in entity calculated fields evaluated on the server when a record is created or saved.
>
> **Note:** It can also be written as a transform when the first value is the input: `value | money(...)`.

> **rateOn**
>
> ### `rateOn`
>
> Returns the exchange rate from a currency to a target currency (the organization’s base currency when to is omitted) as a number. on is a date text or Date and defaults to the moment of evaluation; type is a rate-type key and defaults to the organization’s default rate type. Returns 1 when the currency is the target and null when no rate qualifies. The lookup is asynchronous; the expression waits for it.
>
> **Signature:** `rateOn(currency, on?, type?, to?)`
>
> **Example:**
>
> ```txt theme={null}
> rateOn("USD", $.invoice_date, "market") // USD to the base currency on the invoice date, or null
> ```
>
> **Availability:** Reads the organization’s exchange rates only in entity calculated fields evaluated on the server when a record is created or saved. Elsewhere rateOn and fx return null and convert stops with MONEY\_RATE\_MISSING. Function and transform forms are available.
>
> **Note:** It can also be written as a transform when the first value is the input: `value | rateOn(...)`.

> **roundMoney**
>
> ### `roundMoney`
>
> Rounds a MoneyValue to its currency’s decimals, or a plain number to 2 decimals or to the decimals of the currency code you pass. A number as the second argument sets the decimals. The mode is half\_up, half\_even, half\_down, up, or down; without it the organization’s rounding mode applies. A rounded MoneyValue keeps its currency and base; a value that is not numeric is returned unchanged.
>
> **Signature:** `roundMoney(value, currencyOrDecimals?, mode?)`
>
> **Example:**
>
> ```txt theme={null}
> roundMoney(money(2.675, "USD"), 2, "half_even") // 2.68 USD
> roundMoney(12.3456, "KWD") // 12.346
> ```
>
> **Availability:** Shared builder expression runtime and document templates; function and transform forms are available. The organization’s currency decimals, rounding mode, base currency, and Money field values are in scope only in entity calculated fields evaluated on the server when a record is created or saved.
>
> **Note:** It can also be written as a transform when the first value is the input: `value | roundMoney(...)`.

> **sumBase**
>
> ### `sumBase`
>
> Totals the captured base-currency equivalents of the MoneyValues in a list, across currencies, and returns a plain number. MoneyValues without a base and plain numbers are skipped; an empty list or a value that is not a list gives 0.
>
> **Signature:** `sumBase(list)`
>
> **Example:**
>
> ```txt theme={null}
> sumBase([$.goods_total, $.freight_cost]) // total of both captured base equivalents
> ```
>
> **Availability:** Shared builder expression runtime and document templates; function and transform forms are available. The organization’s currency decimals, rounding mode, base currency, and Money field values are in scope only in entity calculated fields evaluated on the server when a record is created or saved.
>
> **Note:** It can also be written as a transform when the first value is the input: `value | sumBase(...)`.

> **sumMoney**
>
> ### `sumMoney`
>
> Totals a list exactly. MoneyValues must share one currency (MONEY\_CURRENCY\_MISMATCH otherwise) and give a MoneyValue; plain numbers in the list are added to that amount. A list of plain numbers gives a number, a list with nothing numeric gives 0, and a value that is not a list gives null. The total keeps a base only when every MoneyValue has one and the list has no plain numbers.
>
> **Signature:** `sumMoney(list)`
>
> **Example:**
>
> ```txt theme={null}
> sumMoney([money(100, "USD"), money(25.5, "USD")]) // 125.5 USD
> ```
>
> **Availability:** Shared builder expression runtime and document templates; function and transform forms are available. The organization’s currency decimals, rounding mode, base currency, and Money field values are in scope only in entity calculated fields evaluated on the server when a record is created or saved.
>
> **Note:** It can also be written as a transform when the first value is the input: `value | sumMoney(...)`.

## Runtime behavior and edge cases

### Money values and Money fields

A MoneyValue is an amount with a currency. Create one with `money(amount, currency)`. In an entity calculated field evaluated on the server, a Money field reads as a MoneyValue when the organization has turned on Money-aware operators; otherwise it stays a plain number, and the helpers treat it as one. A MoneyValue exposes these properties:

| Property | Meaning |
| - | - |
| `.amount` | The amount as a number. |
| `.currency` | The ISO currency code, such as `USD`. |
| `.base` | The equivalent in the organization’s base currency captured when the record was saved, or `null`. |
| `.rate` | The exchange rate the value was captured at, or `null`. |

`.rateDate` and `.rateType` give the date and type of that rate. When a calculated field’s result is a MoneyValue, the field stores its amount.

### Operators with MoneyValues

| Expression | Result |
| - | - |
| Money `+` or `-` Money | Money, only when both have the same currency |
| Money `+` or `-` number | Money in the same currency |
| Money `*` number | Money in the same currency |
| Money `*` Money | A plain number |
| Money `/` Money | A plain ratio, only when both have the same currency |
| Money `/` number | Money in the same currency |
| `==` `!=` `<` `<=` `>` `>=` | Compares Money with Money of the same currency, or Money with a number |

Unary minus negates a MoneyValue. Dividing by zero gives `Infinity`, as it does for plain numbers. Comparing a MoneyValue with a value that is not numeric, such as `null`, is false for `==` and the ordering operators and true for `!=`. When neither side is a MoneyValue, every operator behaves exactly as before.

### One currency at a time

Adding, subtracting, dividing, or comparing two MoneyValues in different currencies stops the expression with `MONEY_CURRENCY_MISMATCH` (“Cannot add USD and EUR: convert one of them first.”). `sumMoney` applies the same rule. Convert one side first:

```txt theme={null}
$.goods_total + convert($.freight_cost, currencyOf($.goods_total), { on: $.invoice_date })
```

When a calculated field’s expression stops with an error, the field keeps its previously stored value.

### Exact decimal arithmetic

Money arithmetic works on exact decimals rather than floating-point numbers, so amounts do not drift:

```txt theme={null}
money(0.1, "USD") + money(0.2, "USD") // exactly 0.3 USD
0.1 + 0.2 // 0.30000000000000004 with plain numbers, as before
```

Results are not rounded automatically: `money(10, "USD") / 3` keeps up to 18 decimal places, and a Money-to-Money ratio keeps up to 10. Only `convert` and `allocate` round for you. Round with `round(m)` or `roundMoney` before you show, compare, or store an amount that must match the currency’s precision.

### Rounding

`round(m)` and `roundMoney(m)` round a MoneyValue to its currency’s decimals; `round(number, decimals)` on a plain number is unchanged. In a calculated field evaluated on the server, the decimals come from the organization’s currency list and the mode from the organization’s rounding setting. Elsewhere KayanOS uses built-in decimals (3 for KWD, JOD, BHD, OMR, TND, LYD, and IQD; 0 for JPY, KRW, CLP, VND, and ISK; 2 otherwise) and `half_up`. When a Money field uses a fixed number of decimals that differs from its currency, pass that number: `roundMoney($.unit_price * $.quantity, 4)`. Pass a mode only when a rule requires one, for example `roundMoney(m, 2, "half_even")`.

### Exchange rates

`rateOn`, `fx`, and `convert` read the organization’s exchange rates only in an entity calculated field evaluated on the server. The lookup uses:

* **Rate type**: the type you pass, otherwise the organization’s default rate type.
* **Date**: the `on` date you pass, otherwise the moment the expression runs. The helpers do not read the record’s document date by themselves; pass it, as in `convert(m, "USD", { on: $.invoice_date })`.
* **Missing-rate policy**: the rate type’s policy decides how old a rate may be. Under a same-day policy only a rate for that day qualifies; under a latest-earlier policy the most recent earlier rate within the allowed number of days qualifies. A monthly rate type’s rate covers its whole month, and the type’s fallback rate types are tried in order.

When no rate qualifies, `rateOn` and `fx` return `null` and `convert` stops with `MONEY_RATE_MISSING`. Each record evaluation makes at most 200 distinct rate lookups; further lookups find no rate. Outside a calculated field evaluated on the server, such as in rules, document templates, and background recalculation, there are no rates: `rateOn` returns `null` and `convert` stops with `MONEY_RATE_MISSING` unless the value is already in the target currency.

### When `.base` is null

The base-currency equivalent is captured when a record is saved with an exchange rate. `.base` and `base(m)` are `null` when no rate was captured for that value, and for MoneyValues created inside the expression: `money()`, `convert()`, `allocate()`, and Money plus or minus a plain number. Multiplying or dividing by a number scales the base; adding two MoneyValues keeps a base only when both have one. `sumBase` skips values without a base, so a total can be understated; test `base(m) == null` before you rely on it.

## Before you publish

* Start with a known value and confirm the expected result.
* Handle null, empty text, and empty lists deliberately.
* Do not place secrets, access tokens, or sensitive personal data in an expression.
* Read [expression contexts and availability](https://docs.kayanos.com/reference/expressions/contexts.md) before copying an expression between features.

![Money helpers in KayanOS](https://kayanos.app/docs-images/en/reference/expressions-helpers-math.png)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.