Tacnode™
Glossary
Decisioning

What Are Velocity Checks?

Velocity checks are fraud and risk rules that measure how often, or how much, something happens per key within a time window, and act when a threshold is crossed. The key is an identifier such as a card, device, IP address, email or account; the measure is a count, a sum of amounts or a count of distinct values; and the action is to decline, send to review or ask for step-up authentication. For example, a rule might decline a card after five authorization attempts in ten minutes. A velocity check is only as accurate as the count it reads at the moment the transaction is evaluated.

Updated

What are velocity checks?

Velocity rules are a basic fraud defense because many attacks are fast and repetitive. Card testing runs many small authorizations to find which stolen card numbers work. Account takeover often shows up as a burst of logins or password resets. Money mules move funds through an account faster than its history predicts.

Payment platforms expose velocity as rule attributes. Stripe's Radar rules reference calls attributes like total_charges_per_email_daily "velocity rules" and notes: "A common use case for these attributes is to reduce card testing or enumeration attack scenarios." Its supported attributes include authorized_charges_per_card_number_hourly and authorized_charges_per_ip_address_daily. The rules reference also documents two details worth copying: counts over time windows exclude "the payment that you're currently processing," and windows are built from buckets, so "an hourly attribute interval might be 3900 seconds."

How velocity checks work

Each rule is a key, a window, a measure and a threshold. Computed on demand, it is a range query over recent events:

sql
-- Attempts and amount on this card in the past 10 minutes, at decision time.
-- Needs an index on (card_id, attempted_at).
SELECT count(*)                 AS attempts_10m,
       coalesce(sum(amount), 0) AS amount_10m
FROM   auth_attempts
WHERE  card_id = $1
  AND  attempted_at > now() - interval '10 minutes';

At higher volume, teams often precompute instead: a counter in a cache, or a stream job that writes windowed counts to a key-value store. Each read gets cheap, but a count updated by an asynchronous pipeline lags the events it should include.

A worked failure, with illustrative numbers. The rule declines at five prior attempts in ten minutes. The count comes from a stream pipeline that lands each attempt four seconds after it happens, and an attempt counts from the instant it lands. A card-testing script sends three attempts per second.

AttemptTime (s)Attempts already madeCount the rule readsVerdict
10.0000Approve
61.6750Approve; a current count declines here
134.00121Approve
165.00154Approve
175.33165Decline

The rule meant to stop the card after five attempts approves sixteen. Concurrency adds a second problem: two attempts evaluated at the same moment read the same count, even when it is current. In PostgreSQL's default Read Committed level, a query "never sees either uncommitted data or changes committed by concurrent transactions during the query's execution," per the PostgreSQL docs. A hard per-card limit needs those checks serialized, for example by locking a per-card row with SELECT ... FOR UPDATE before counting, which makes a concurrent check on the same card wait until the first transaction ends.

Why velocity checks matter in real-time systems

A velocity check is derived context: a count computed from transactions. When a pipeline prepares it, it lags the transactions that should update it, and a burst attack fits inside that lag. Bursts are when the rule matters most.

The fix is to compute counts that must reflect the latest transaction on demand, against committed data, and precompute only long windows. In Tacnode, short-window counts can run on demand against the attempts and transactions ingested from the systems you run, in the same snapshot as the account, device and risk data the rule reads. Longer windows can be incremental views, refreshed incrementally on a schedule you set in SQL, typically every few seconds. Tacnode gives the check accurate context; enforcement stays in your authorization service. Where the attempt records or holds are written to Tacnode itself, the writes are transactional, so concurrent checks against the same limit are serialized. More on where fraud architectures break is in real-time fraud detection architecture.

FAQ

Related terms

Further reading