Rule language guide
Rules decide things in RefinePoint: which rows to leave out, what a value is worked out as, which reason code a break gets, when a journal is raised, when an account certifies itself. Every rule is written in the same language, a plain-English sentence that anyone can read back. It is modelled on the Natural Rule Language (NRL 1.4).
amount is greater than 500 and narration contains 'NEFT'You rarely type a rule. The rule builder writes it as you choose fields, comparisons and values, and shows it as a sentence. You can switch to the text at any time, and the AI rule builder can write one from a description.
Values
Section titled “Values”| Write | Means |
|---|---|
amount, party, invoice_date |
A field, by its name |
"Ref No" |
A name with spaces or symbols, in double quotes |
column "Narration" |
A column of the source file, by its heading (filters and preparation steps) |
source column "Ref No", target column "Voucher" |
A column of one side, when mapping two sides |
'NEFT' |
Text, in single quotes. Write a quote inside as two: 'O''Brien' |
500, 0.03, -75 |
A number |
'2026-04-01' |
A date, written year first |
today |
Today’s date |
true, false |
Yes and no |
The words the, its and their can be added anywhere for reading; they change nothing. Upper and lower case do not matter in words.
Comparisons
Section titled “Comparisons”| Write | Or | Means |
|---|---|---|
status is 'OPEN' |
status = 'OPEN', status is equal to 'OPEN', status equals 'OPEN' |
The same |
status is not 'OPEN' |
status <> 'OPEN', status != 'OPEN', status does not equal 'OPEN' |
Different |
amount is greater than 500 |
amount > 500, amount is more than 500, date is after '2026-04-01' |
More |
amount is at least 500 |
amount >= 500, amount is greater than or equal to 500, date is on or after ... |
At least |
amount is less than 500 |
amount < 500, date is before today |
Less |
amount is at most 500 |
amount <= 500, amount is less than or equal to 500, date is on or before ... |
At most |
status is one of 'OPEN', 'HELD' |
status is not one of ... |
In a list |
amount is between 100 and 500 |
amount is not between ... |
From the first to the second, both included |
reference is present |
reference is not present, reference is missing, reference is empty |
Has a value (not missing, not blank) |
narration contains 'NEFT' |
narration does not contain 'NEFT' |
Has it inside, ignoring case |
narration contains any of 'SMS', 'CHG' |
does not contain any of |
Has any of them inside |
reference starts with 'INV' |
does not start with |
Begins with, ignoring case |
account ends with '001' |
does not end with |
Ends with, ignoring case |
reference matches '^INV[0-9]+$' |
does not match |
A regular expression finds a match |
account is in BLOCKED_ACCOUNTS |
is not in |
The lookup table has it as a key |
date is a weekend |
is a business day, is a number, is a date, is a valid gstin |
Describes the value |
As in NRL, is can be left out: amount greater than 500.
How values compare. Text compares ignoring upper and lower case and spaces at either end: 'Tata Steel ' is
'TATA STEEL'. Numbers compare by value, so 500 is 500.00. Dates compare as dates. When one side is a number or a
date, the other side is read as one: a source column holding 1,250.50 is greater than 1000.
Missing values. NRL has no null; a value is either present or not. Blank text counts as missing. A missing value
is equal only to another missing value, and is neither greater nor less than anything, so amount is less than 0 is
false when there is no amount. Test for it with is present / is not present.
Combining conditions
Section titled “Combining conditions”| Write | Means |
|---|---|
a and b |
Both |
a or b |
Either |
not a |
The opposite |
( ... ) |
Group: work this out first |
and binds tighter than or: a or b and c is a or (b and c). Use brackets when you mean otherwise:
(side is 'B' or side is 'C') and amount is greater than 100000Calculations
Section titled “Calculations”| Write | Means |
|---|---|
igst + cgst + sgst |
Add. With text on both sides, + joins the text instead |
gross - tds |
Subtract |
quantity * rate |
Multiply (also times) |
amount / 100 |
Divide (also divided by); dividing by 0 gives no value |
day mod 7 |
The remainder |
-amount |
The negative |
invoice_date + 30 |
A date 30 days later; - 30 is 30 days earlier |
payment_date - invoice_date |
The days from one date to the other |
*, / and - read text as numbers, so column "Qty" * column "Rate" works on a file. To add two numbers held as
text, read one as a number: [number from] column "Debit" + column "Credit".
Choosing a value
Section titled “Choosing a value”if amount is greater than 0 then 'CR' else 'DR'if status is 'MATCHED' then 0 else if amount is less than 1000 then 1 else 2otherwise can be written for else. Without an else, the value is missing when the condition does not hold.
Functions
Section titled “Functions”A function is called the NRL way: its name in square brackets, then its values, joined by words that read naturally (to, with, and, of, from, by, as, using, at, or a comma):
[round] amount to 2[days between] invoice_date and payment_date[upper case] [trim] party[left] 4 of reference[join with] '/', branch, accountThe words between values are only for reading: values go in the order the function lists them. A function’s value
ends at + or -, so an addition as a value goes in brackets: [round] (igst + cgst) to 2; [round] amount * rate to 2
needs none. A function inside a calculation is put in brackets: ([round] amount to 2) * 3. The functions are listed at the end of this guide, and in
the rule builder under Function.
Your own functions
Section titled “Your own functions”A workspace can add functions of its own in Settings, Rule language, Your functions, without waiting for a release. Each has a name of a few words, parameters, and the rule it stands for, written with the parameters as fields:
| Name and parameters | Stands for | Then write |
|---|---|---|
net of amount and fee |
amount - fee |
[net of] debit and charges is greater than 0 |
clean ref ref |
[upper case] [remove spaces from] ref |
[clean ref] reference is [clean ref] invoice_no |
vendor group of party |
the group of party in VENDORS default 'OTHER' |
[vendor group of] party is 'METALS' |
They are used exactly like the built-in ones, everywhere rules are written, and run in SQL as well. A function of your own may use built-in functions and lookup tables, but not another of your own, and its name cannot be a built-in function’s. Changing its rule changes every rule that uses it.
Lookup tables
Section titled “Lookup tables”Lookup tables are set up in Settings, Lookup tables: vendor groups, GL account mappings, tax slabs, anything your rules need to look up.
| Write | Means |
|---|---|
the group of party in VENDORS |
The group column of the VENDORS row whose key is the party |
the group of party in VENDORS default 'OTHER' |
The same, or ‘OTHER’ when there is no such row |
the rate of (party, currency) in RATES |
A table keyed on two columns |
the rate for amount in TDS_SLABS |
A range table: the row whose range holds the amount |
account is in BLOCKED_ACCOUNTS |
Whether the table has the key |
Keys match ignoring case and spaces at either end, and numbers by value (100 and 100.00 are the same key).
Naming a part of a rule
Section titled “Naming a part of a rule”As in NRL, a value can be given a name before the rule and used in it. Names go in double quotes and end with a comma:
"net" represents amount - tds, "net" is greater than 0 and "net" is less than 50000What each place sees
Section titled “What each place sees”| Where | Fields | Also |
|---|---|---|
| A side’s filter | The reconciliation’s fields | column "..." for the side’s source columns |
| Preparation steps | The source columns, by heading (plain names, or column "...") |
|
| Field mapping | column "..." (two-sided: source column / target column) |
|
| Calculated fields | The other fields | column "..." |
| Reason codes | The record’s fields, side, status, cause |
column "..." |
| Checks over totals | A_amount (a total per side and field), A_count |
|
| Journal rules | The record’s fields, difference, absDifference, reasonCode |
|
| Workflow rules | The record’s fields, status, side, cause, reasonCode |
|
| Close certification | balance, prior, change, changePct, supporting, unexplained, items, risk |
The rule builder lists what is available where you are, and checks the rule as you write it: an unknown field, a table that does not exist or text compared with a number is pointed out with a suggestion.
Where rules run
Section titled “Where rules run”The same rule runs in two places with the same meaning:
- Whole datasets (preparation, mapping, calculated fields and filters during a run) are compiled to SQL and run in DuckDB, an analytical database inside the run service, so a run handles millions of rows. The design keeps the SQL engine replaceable: the same rules compile for Spark SQL.
- One record at a time (reason codes, journal and workflow rules, testing a rule on a screen) run in Java.
Examples
Section titled “Examples”| Rule | Reads |
|---|---|
narration contains any of 'SMS', 'CHG' and amount is less than 500 |
Bank charges |
[days between] invoice_date and payment_date is greater than 30 |
Paid late |
the group of party in VENDORS is 'BANK' |
A bank vendor |
column "Narration" starts with 'OPENING' or column "Amount" is not present |
An opening balance line or a row without an amount |
fee is present and fee is greater than amount * 0.03 |
Fee above 3% |
if currency is 'INR' then amount else amount * the rate of currency in FX_RATES |
Amount in rupees |
[similarity of] party and payee is at least 0.85 |
Names that nearly agree |
For every function with an example, see the function reference.