Trigger condition
The pre-filter deciding which events the scenario runs on at all. If you only want to evaluate sales and cancellations, everything else is excluded here without writing a rule, and comes back asUnknown.
Rule = condition tree + score
Every rule is a condition tree: fields, comparisons, and nested AND/OR combinations of them. If the tree evaluates true, the rule’s score is added to the total.Operators
Text fields
Text fields
equal, notequal, contains, notcontains, startswith, endswith,
isempty, isnotempty, in (in list), notin, similarity.Numeric fields
Numeric fields
equal, notequal, lessthan, lessthanorequal, greaterthan,
greaterthanorequal, between, notbetween.Date fields
Date fields
Comparisons plus ready-made windows:
last24hours, lastnhours, last7days,
last90days, lastndays, thismonth, lastmonth and their forward-looking
counterparts.Pattern matching
Pattern matching
matchesregex, notmatchesregex — matching with a regular expression. For the
conditions contains cannot express: a card number shape, a disposable-mail domain
family, a phone prefix.Every match runs under a time limit; a pattern that exceeds it counts as not matching
and is recorded on a counter. Publishing checks that the pattern is valid.Comparing a field to another field
Comparing a field to another field
Instead of a value you can pick another field: billing country against shipping
country, cardholder name against account name, order total against line total.Toggled beside the value in the editor. If the referenced field is absent from the
payload the condition does not match — including for the negative operators, so a
rule does not fire precisely when the data needed to judge it is missing.
Derived signals
Derived signals
ipgeolocation, ipdatacenter, emaildisposable, emailfreeprovider,
emailnomx, phoneinvalid, phonecountry, phonelinetype, uabot,
uadevicetype, sslcertcheck, whoislookup, sanctionsmatch.More in Signals and Sanctions screening.Your own list entries
Your own list entries
in and notin ask whether a value is on a list, and compare exactly. That is the
right test for a card BIN, an IBAN, a device id.watchlistmatch is for names: it uses the same normalisation and the same similarity
measure sanctions screening uses, so “Muhammet Yilmaz” and “Muhammed Yılmaz” are one
person. It is offered only against lists marked as holding names of people or
companies.List weights
Membership answers one question well: is this value on the list. Risk is rarely a yes or no — gambling is worse than electronics, which is worse than groceries — and saying that with membership means one list per band; two of the three get updated and they drift apart. A list entry can carry an optional weight, and a condition can compare that weight instead of the value. The editor offers it from the same place as an aggregate, because it does the same kind of thing: it replaces what is on the left of the comparison, and the operator and value then work unchanged.An entry with no weight and an entry weighted zero are not the same thing. A value the list
does not weight is compared as zero — skipping it would make “weight below 10” miss every
unknown value, which is the population that rule is usually written to catch — and the
decision records which of the two it found.
value,weight lines. Lines with no comma are added as plain membership
entries, exactly as before.
Velocity rules and aggregates
A condition can look at history rather than at one event: how many accounts this device touched in the last 24 hours, how many different senders paid into this IBAN. Open it with the Aggregate selector beside the field; sub-filters decide which records count.Our own decision history
Every other aggregate reads what the customer sent us. The last two read what we did about it, and “we have sent this card to review four times this month” is a signal no amount of transaction data contains. They are two aggregates because they are two statements: a customer we have decided on twenty times is usually a frequent customer, and one we have sent to review four times is not. The count is keyed on the record’s pivot value — a decision is recorded against the entity it was about, and cases are grouped by it. On a table with no pivot the count is zero.The window is 30 days and cannot be changed in the rule. The decision being taken right now is
not counted: it has not been recorded yet, and counting it would fire the rule one transaction
earlier than its author meant.
The event being decided counts towards its own aggregate — but only where that can be done
exactly (
COUNT, SUM, MIN, MAX). So the answer does not depend on whether the caller
ingested the event before asking for the decision.Impossible travel
TIME_SINCE_LAST and DISTANCE_FROM_LAST in one scenario produce a signal no single
field can: a payment from somewhere the cardholder could not have reached in the time
available.
DISTANCE_FROM_LAST reads a text field shaped "41.0082,28.9784". The decimal separator
is a dot and does not depend on the server’s locale.
Scoring
Scores can be positive or negative. A negative score is the most direct way to cut false alarms: giving “customer with more than twelve successful transactions” a-20 stops
those customers from crossing a threshold on one weak signal.
Thresholds
Three thresholds, four outcomes. They must ascend — review ≤ block-and-review ≤ decline.Publishing a version
Rule changes accumulate in the draft; the live version is untouched. Publish makes the draft live and keeps the previous one on record. A draft affects no decision until you publish it — a half-built rule set never looks at live traffic.What publishing checks
Publish validates the scenario before it goes live and reports every problem at once:
All at once, because publishing one problem at a time is guess-and-retry against live
traffic.
A second approval before publishing
Turned on under Settings → Organization → Publishing rules. With it on, Publish does not publish — it records a request: the draft stays a draft and somebody else reviews it and publishes. Whoever asked cannot approve their own request. Retiring the request rather than refusing the edit is deliberate: a reviewer’s job is to find things that need changing, and a control that punishes them for finding one teaches everybody to approve without reading. Off by default. It is a cost as well as a control, and a two-person team cannot pay it.Comparing versions
Compare versions on the rules screen shows what was edited between two versions: rules added, removed and changed; the before and after of every field that moved; thresholds, schedule and the trigger condition. This is the other half of the question a shadow run answers. A shadow run measures how two versions behave on live traffic; this screen says what somebody changed. A change with no measurable effect is still one somebody has to account for. Rule conditions are shown as sentences rather than as JSON — two blocks of JSON side by side produce a comparison nobody actually performs; they approve it and move on.Rules are matched by name. Creating a draft copies every rule into a new row, so there is
no rule identity that survives a version. The cost is that renaming a rule shows up as a
removal and an addition, which the screen says outright. Guessing at a rename by matching
formulas would describe an edit nobody made.
A published version does not change
The version number is assigned at publish and that version can never be edited again. Editing always goes to the draft, which is opened as a copy of the live version if there is not one yet.Every decision records the version that produced it, and that version does not move. The
answer to “which rules decided this” is the same six months later — and rolling back is
publishing an earlier version rather than trying to remember what changed.