Rules reference
A rule is a set of conditions and a set of actions. When every condition matches, every action is applied. Rules run after extraction and before the invoice reaches a human queue, so they decide what a reviewer or approver is handed rather than what happens afterwards.
This page is the exact vocabulary. If you want to write your first one instead, start with your first coding rule.
Condition fields and their operators
Each field understands only the operators listed against it. The builder offers no others, and a rule that names a pairing outside this table is refused when you save it rather than stored and quietly never fired.
| Field | Operators | Matches against |
|---|---|---|
| Source email | is, contains | The full sender address, for example invoices@theircompany.com |
| Vendor | is, contains, is not mapped | The vendor name read off the invoice |
| Amount | is, is greater than, is less than | The invoice total, compared as a number |
| Keyword in document | contains | The subject line the invoice arrived under |
| Property alias | is, contains | The property hint read off the invoice, or the subject |
| Intake mailbox | is, contains | The intake address the mail arrived at, for example lakeshore@yourcompany.inlet-ap.com |
Matching the intake mailbox
Intake mailbox is the receiving side of the conversation, where Source email is the sending side. It exists so that a mailbox you handed to one building's vendors can drive coding, and it is most useful with contains and the local part alone:
Intake mailbox contains "lakeshore@"
Written that way, the rule survives a change of intake subdomain, which writing out the full address does not.
You often do not need a rule at all. A mailbox created with a property already codes mail arriving there to that property when the invoice names nothing recognizable — see per-property mailboxes. Reach for a rule when the mailbox should also set a GL code, assign a reviewer, or apply to a subset of the mail arriving there.
Text comparisons are case-insensitive, so ACME Corp and acme corp are the same value. Surrounding whitespace is stripped from what you type in every case, and from the document's own value for Source email, Property alias and Intake mailbox. It is not stripped from the extracted Vendor name or the email subject, so prefer contains over is on those two.
Amount is compared as a number. A value that is not a number is refused on save, because a non-numeric amount compares as false against every operator — which produces a rule that looks correct in the list and never matches anything.
is not mapped takes no value. It is true when the invoice's vendor does not match a vendor in your workspace, which makes it the condition for "somebody new is billing us".
Why there is no domain field
To match a whole vendor domain, use Source email contains @theircompany.com.
Source email contains @theircompany.com
There is deliberately no separate domain field. The address already contains the domain, so a domain field would be a second field meaning almost the same thing, and every rule author would then have to guess which one they wanted. The leading @ is what makes the test exact: without it, theircompany.com would also match billing@nottheircompany.com.example.
The condition vocabulary is short on purpose. Every field and operator in the table above has a matching branch in the evaluator, and nothing has a branch in the evaluator that is not there. A dropdown offering an operator the evaluator cannot execute is worse than a missing feature, because the rule saves cleanly and then does nothing at all — which is why conditions are checked when you save. Actions are checked the same way, and against the same list the builder's own dropdown is built from, so an action the engine cannot carry out is refused at the moment you save it rather than discovered months later.
How conditions combine
All conditions must match. There is no OR, and there is no nesting. A rule with no conditions at all matches every document, so always give a rule at least one condition.
Where you want an OR, write two rules. This is more typing and it makes each rule readable on its own, which matters when somebody asks in six months why a particular invoice was coded the way it was.
Actions
| Action | What it does |
|---|---|
| Set coding | Writes a GL account onto the document, recorded as coming from a rule rather than from the page. An action with no account in it is ignored. |
| Assign reviewer | Assigns the document to a named member of your workspace. If the name matches nobody in the workspace, the document is left unassigned rather than handed to a stranger with a similar name. |
| Assign approver | Asks a named member of your workspace to approve the document, instead of leaving it for whoever picks it up. It takes effect when the document reaches ready for approval; a document the pipeline sends to review or quarantine instead is not given an approver, and the rule's intent is recorded in the audit trail either way. If the name matches nobody in the workspace, nobody is asked, for the same reason Assign reviewer refuses. |
| Auto-approve | Moves the document to ready for approval without waiting on the confidence threshold. Choose Yes or No. A property that still needs review overrides it. |
| Quarantine | Puts the document on a security hold and sends a notification naming the rule that did it. |
| Mark recoverable | Proposes that part of the invoice is owed back: you choose why (tenant damage, a tenant service call, a utility, an owner chargeback or other), who owes it (the resident or the unit owner) and, optionally, a percentage of each line (the whole line when left blank). For every printed line whose unit is known — from the line itself, from a Set coding unit, or from the one unit on that line's split — one recovery is proposed for that unit. A line with no known unit gets nothing and asks "Which unit?" on the invoice instead. Every recovery a rule makes is proposed; a person confirms or waives it, a rule never confirms one, and it never holds the invoice's approval. A recovery the invoice cannot carry (a unit owner on a building that is not Condo / HOA, more than the line cost) is skipped. See cost recovery. |
Auto-approval is opt-in and bounded by whatever conditions you set. A common first version is "a mapped vendor, under a small amount, from a known address" — narrow enough that you would have approved every one of them by hand anyway.
Every rule that fires is recorded in the audit trail against the document, together with the status the document ended in, and the GL code carries the id of the rule that wrote it — which is the part that makes auto-approval defensible rather than merely convenient.
Priority and ordering
Rules carry a priority number from 0 to 1000 and the engine runs them in ascending order, so a rule at 10 runs before a rule at 100. New rules start at 100, and you set it on the Rules screen. Rules that share a priority run oldest first.
Every rule that matches is applied, not only the first. Two rules that both set a GL account will both run and the one that runs last wins, so give the exception the higher number — a general rule at 100 and its exception at 200 — rather than relying on the order two rules happened to be written in.
One action stops the sequence: quarantine. When a quarantine rule matches, no further rule is evaluated for that document. A document being held for a security reason should not also be coded, assigned and auto-approved on its way into the hold.
Each rule keeps a count of how many documents it has matched. A rule with a match count of zero after a busy month is usually a rule whose conditions are narrower than its author believed.
Simulating a draft rule
Simulate, on the Rules screen, replays the rule you are editing over documents your workspace already holds and reports which of them it would match and what it would do to each. It answers "what would this rule do to the invoices we already have".
It writes nothing. No document is coded, assigned, held or exported; no audit entry is written; no rule is created; and no rule's match count moves. Running a simulation leaves the workspace exactly as it was.
The draft is evaluated inside the enabled rules, in priority order, rather than on its own. Simulating a rule you are editing takes the stored version out of the chain and puts the draft in its place, keeping that rule's position among rules of the same priority. A rule you have not saved yet is ordered last within its priority band, which is where saving it now would put it. A draft that could not be saved is refused rather than simulated, on the same three checks the save path applies: the condition grammar, the action vocabulary and the priority range.
Because quarantine stops the chain, a match is not always a rule that would fire. A matched document that an earlier enabled rule quarantines first is reported as never reached: the row names the rule that gets there first, and the summary counts how many of the matches it covers. A lower priority number moves your rule in front of the rule preempting it.
| Bound | What it is |
|---|---|
| Documents read | The most recent 200, newest first, ordered by when they reached inletAP |
| The most it ever reads | 500 in one run. The answer reports the bound it used and how many documents it actually read, and the screen prints both |
| Matched rows listed | 50, the most recent of them. The card says how many matches that list was cut from |
| Documents skipped | new, parsed, held_quota and filtered — the four statuses that sit before the rules engine. A document becomes eligible once extraction has finished with it |
| Property scope | The caller's own. A member scoped to certain buildings simulates over those buildings only, through the same filter the inbox uses |
| Who may run it | Admin, Controller Approver and AP Specialist. A Viewer is refused, as it is for everything else about rules |
| Plan | Paid, like the rest of the rules engine. On the Free plan the button is disabled and carries the reason |
| What it writes | Nothing |
For a draft with Mark recoverable, each matched invoice also lists the recoveries the rule would propose — the unit, the line and the amount — and the lines that would ask "Which unit?", plus any the invoice would refuse with the reason. The summary counts all three. Units and the tax setting are read as they are today, like everything else in a simulation, and nothing is proposed by simulating.
Everything older than that window is unexamined rather than unmatched, so a simulation is evidence about recent mail and not a census of your history. See invoice statuses for what the four skipped statuses mean.
Matching resolves vendor mappings and property aliases as they stand now, never as they stood when each invoice arrived. Vendor is not mapped is judged against today's vendor list, and a property alias you added this week applies to an invoice from last month. A simulation is a forecast about the documents it read, not a replay of what would have happened at the time.
Disabling rather than deleting
A rule can be switched off and left in place. The match count and the audit history survive, which is worth more than a tidy list when you are working out what changed.
Who may write rules
Reading rules — and simulating one — is open to the three internal roles: Admin, Controller Approver and AP Specialist. A specialist who cannot save a rule can still show an Admin or a Controller what the rule would do. Creating, editing and deleting rules is restricted to an Admin or a Controller Approver, and the API enforces that independently of what the interface shows. A Viewer reads none of this. See roles and permissions.
The rules engine is part of a paid plan. On the free plan the rest of the pipeline runs normally — intake, extraction, review, approval and export all work — and writing a new rule is the thing you upgrade for. Rules you wrote on a paid plan keep running if you move back to Free.
Where to go next
- Your first coding rule — a worked example from a real invoice.
- Coding invoices — what the fields a rule writes actually mean.
- Invoice statuses — where a quarantine or an auto-approval leaves a document.
- Roles and permissions — who is allowed to change any of this.