Skip to content

Transaction velocity ​

Monitoring on facts that arrive after onboarding: payments are ingested as events, a workflow evaluates velocity rules over a subject's recent events and opens a high-priority case when the pattern looks wrong. Pack: examples/policies/transaction-velocity/.

A pattern for expressing a monitoring policy, not compliance guidance: the windows, thresholds and the choice of signals are placeholders; a real policy comes from the business's own loss data.

The decision it automates ​

Whether a subject's recent payment behaviour is fine, needs a person, or should be blocked, as of the moment the workflow runs. Today the run is started by the integrating system (for example after every batch of events, or on a schedule); events as workflow triggers are on the roadmap.

Data expected ​

  • A subject (any kind) and events for it ingested through POST /events: type payment, an amount and currency, an occurredAt, a caller-chosen idempotencyKey, the promoted cardFingerprint key when known, and attributes.status (approved, declined). See Events.
  • Nothing from subject.data.

Steps and rules ​

StepTypeWhy
rulesevaluate_rulesThe velocity_monitoring rule set; every rule aggregates the subject's events as of now.
routebranchrules.outcome == manual_review opens a case.
reviewcreate_casevelocity_review, priority high, 24-hour SLA: money may be moving.
decideemit_decisionFrom the rules, or the reviewer's decision.

The rule set velocity_monitoring (useCase: monitoring) sums weights into bands 0-40 approve, 40-90 manual_review, 90-100 reject:

RuleAggregateSeverity, weightFails when
velocity_payment_sum_24hsum of amount over 24 hours, type paymentwarn, 50more than 5 000
velocity_payment_count_1hcount over 1 hour, type paymentwarn, 405 or more
velocity_declined_count_24hcount over 24 hours, type payment, status: declinedblock, 1003 or more (card testing)
velocity_distinct_cards_24hdistinct_count of card_fingerprint over 24 hourswarn, 403 or more distinct cards

Volume alone (50) is a review; volume with a burst or many cards (90) rejects; repeated declines block on their own. Each result's details carries the computed value, the key and the window, so a reviewer sees the number, not only the verdict. Windows end at the evaluation time, which is what makes backtests reproduce live results.

What a reviewer sees ​

A velocity_review case with the four results and their values. The subject's timeline in the admin console lists the events behind them. The reviewer's reject becomes the decision; what the integrating system does with a rejected subject (hold payouts, close the account) is its call.

How to adapt it ​

Group by a promoted key instead of the subject (groupBy: ip with groupValuePath) to catch one device behind many accounts; add avg or max rules for unusually large single payments; use attributes filters for your own event vocabulary (channel, country). Dry-run a rule against a stored subject (POST /rule-definitions/:key/dry-run) and backtest a draft over recorded evaluations before publishing a new threshold.

Run it ​

bash
pnpm policy:import examples/policies/transaction-velocity --publish

The fixture (expect.json) ingests four payments of 1 500 over the last 90 minutes (two cards, one declined): the 24-hour sum of 6 000 fails, the burst, decline and card rules pass, the score of 50 opens a velocity_review case, the check rejects it and the run completes with a manual reject.

Released under the Apache-2.0 License.