Contextual Rule Features
Enrich authorization rules with card and account behavioral history to detect anomalies, flag first-time activity, and tailor fraud logic per cardholder.
Contextual Rule Features is a premium capability of the Lithic Fraud Command suite. To enable Fraud Command, contact your Customer Success Manager.
Overview
Standard authorization rules apply the same thresholds to every card. A spend limit that catches fraud on low-activity cards will block legitimate purchases on high-spend cards. Contextual Rule Features solve this by evaluating each transaction relative to the specific card's or account's own history.
Contextual Rule Features give your authorization rules access to historical behavior data for the card or account being evaluated. Instead of acting only on properties of the current transaction (amount, MCC, country, etc.), you can write rules that factor in the full transaction history: average spend amounts, countries visited, time since last activity, and more.
A single program-wide rule using Contextual Rule Features automatically tailors itself to each card and cardholder. For example, a rule that challenges transactions with a z-score above 3 will flag a $200 charge on a card that typically spends $20, while allowing the same $200 charge on a card that regularly spends $500.
Contextual Rule Features are available in both CONDITIONAL_ACTION rules (as condition attributes) and TYPESCRIPT_CODE rules (via the TRANSACTION_HISTORY_SIGNALS and CONSECUTIVE_DECLINES feature inputs). They are evaluated on the AUTHORIZATION event stream only.
How It Works
Lithic automatically tracks transaction history for every card and account. When a rule references a contextual feature, the relevant history is evaluated at authorization time alongside the current transaction. For example, is_new_country checks whether the current merchant country has appeared in any previous approved transaction on the card.
Feature freshness depends on the category:
| Category | Examples | Update Frequency |
|---|---|---|
| Behavioral signals | Is New Country, Consecutive Declines, Is First Transaction | Within seconds of each transaction |
| Statistical aggregates | Average, Standard Deviation, Z-Score | Recomputed hourly |
Contextual Rule Features only add latency to authorizations when at least one active rule references them. Programs without contextual rules are unaffected.
Contextual Rule Features use a fail-open design. If feature data is temporarily unavailable, all features return null and rules evaluate as if the features are absent. Unavailable feature data never blocks authorizations.
Available Features
Lithic regularly adds new contextual features. This guide covers the current set, but may not be exhaustive. See the Auth Rules API specification for the most up-to-date list of available attributes.
Anomaly Detection
Z-score measures how far the current transaction amount deviates from the card's or account's historical average, expressed in standard deviations. A z-score of 3 means the transaction amount is 3 standard deviations above the average: a strong outlier signal.
| Feature | Type | Description |
|---|---|---|
| Amount Z-Score | numeric | How many standard deviations the current transaction amount is from the historical mean |
| Avg Transaction Amount | numeric (cents) | Mean amount of approved transactions |
| Stdev Transaction Amount | numeric (cents) | Standard deviation of approved transaction amounts |
Each of these features is available over the entity's (card, account, or business account) full lifetime and in 7-day, 30-day, and 90-day trailing windows. See Time Windows.
Z-score and standard deviation require at least 30 approved transactions before returning a value. Average transaction amount requires at least 5. For programs with low per-card transaction volume, consider using account-level scope (which aggregates across all cards) to reach these thresholds faster, or use the boolean pattern features (Is New Country, Is New MCC) which have no minimum threshold.
Geographic and Spending Patterns
| Feature | Type | Description |
|---|---|---|
| Is New Country | boolean | Whether the merchant country has never appeared in the entity's transaction history |
| Is New MCC | boolean | Whether the merchant category code has never appeared in the entity's transaction history |
| Distinct Country Count | integer | Number of unique merchant countries seen |
These features are computed over the entity's full lifetime.
Activity Signals
| Feature | Type | Description |
|---|---|---|
| Is First Transaction | boolean | Whether this is the very first transaction attempt on the entity |
| Time Since Last Transaction | numeric (days) | Elapsed days since the most recent approved transaction |
| Consecutive Declines | integer | Count of consecutive declined transactions, reset to 0 on any approval |
Decline Velocity
| Feature | Type | Description |
|---|---|---|
| Decline Count (15m, 1h, 24h) | integer | Number of declined transactions in the trailing window (card scope only) |
3DS Authentication
| Feature | Type | Description |
|---|---|---|
| 3DS Success Rate | integer (0 to 100) | Percentage of successful 3DS authentications over the card's lifetime (card scope only) |
Feature Scopes
Contextual Rule Features are computed at three scope levels. The scope determines which entity's transaction history the feature draws from:
| Scope | Value | Description |
|---|---|---|
| Card | CARD | History of transactions on a single card |
| Account | ACCOUNT | History across all cards belonging to the account |
| Business Account | BUSINESS_ACCOUNT | History across all accounts under the business account |
Account and business account scopes are useful for detecting patterns that span multiple cards. Consider an account takeover where an attacker opens new cards on a compromised account. A rule that evaluates IS_NEW_COUNTRY at the ACCOUNT scope flags activity in a country that no card under the account has ever transacted in, even if the specific card being used is new.
Not all features are available at every scope:
| Feature | Card | Account | Business Account |
|---|---|---|---|
| Z-Score, Avg, Stdev | Yes | Yes | Yes |
| Is New Country / MCC | Yes | Yes | Yes |
| Is First Transaction | Yes | Yes | Yes |
| Time Since Last Transaction | Yes | Yes | Yes |
| Distinct Country Count | Yes | Yes | Yes |
| Consecutive Declines | Yes | Yes | No |
| 3DS Success Rate | Yes | No | No |
| Decline Count (15m, 1h, 24h) | Yes | No | No |
Time Windows
Statistical features (z-score, average, standard deviation) are available over multiple time windows:
| Window | Value | Description |
|---|---|---|
| Lifetime | LIFETIME | Full history of the entity |
| 90 days | 90D | Trailing 90-day window |
| 30 days | 30D | Trailing 30-day window |
| 7 days | 7D | Trailing 7-day window |
Shorter windows capture recent behavioral shifts. A card that typically spends $50 per transaction but shifted to $200 over the past week would show a low lifetime z-score but a high 7-day z-score. Combining windows lets you distinguish between a genuine spending change and an anomalous burst.
See How It Works for feature freshness by category.
Using Contextual Rule Features in Rules
Conditional Action Rules
In CONDITIONAL_ACTION rules, reference contextual features as condition attributes. Most contextual attributes are parameterized: the attribute identifies the feature, and a parameters object specifies the scope and (for statistical features) the time window.
See the following examples:
- Anomalous Spend - challenge transactions where the card's 30-day z-score exceeds 3
- New Country - decline transactions in countries the card has never visited, skipping the card's very first transaction (where every country is inherently new)
- Card Testing - challenge after 5 consecutive declines so the real cardholder can verify and reset the counter
{
"type": "CONDITIONAL_ACTION",
"parameters": {
"event_stream": "AUTHORIZATION",
"conditions": [
{
"attribute": "AMOUNT_Z_SCORE",
"parameters": {
"scope": "CARD",
"interval": "30D"
},
"operation": "IS_GREATER_THAN",
"value": 3
}
],
"actions": [
{
"type": "CHALLENGE"
}
]
}
}{
"type": "CONDITIONAL_ACTION",
"parameters": {
"event_stream": "AUTHORIZATION",
"conditions": [
{
"attribute": "IS_NEW_COUNTRY",
"parameters": { "scope": "CARD" },
"operation": "IS_ONE_OF",
"value": ["TRUE"]
},
{
"attribute": "IS_FIRST_TRANSACTION",
"parameters": { "scope": "CARD" },
"operation": "IS_ONE_OF",
"value": ["FALSE"]
}
],
"actions": [
{
"type": "DECLINE",
"decline_code": "UNAUTHORIZED"
}
]
}
}{
"type": "CONDITIONAL_ACTION",
"parameters": {
"event_stream": "AUTHORIZATION",
"conditions": [
{
"attribute": "CONSECUTIVE_DECLINES",
"parameters": { "scope": "CARD" },
"operation": "IS_GREATER_THAN",
"value": 5
}
],
"actions": [
{
"type": "CHALLENGE"
}
]
}
}Boolean contextual features use
IS_ONE_OFwith string values["TRUE"]or["FALSE"]. TheCONDITIONAL_ACTIONrule schema represents all condition values as strings or string arrays, so boolean checks follow the same pattern as other enum attributes. Thedecline_codespecifies the reason code returned to the network. See the Auth Rules API specification for valid codes and the full list of supported operations.
Conditions within a single rule are joined with AND logic. To express OR logic across different features, create separate rules. See Authorization Rules for details on rule structure and the full rule lifecycle.
Attribute Reference
Each attribute below lists the accepted parameters object alongside the attribute name. Statistical attributes accept both scope and interval; most behavioral attributes accept only scope; a few attributes take no parameters at all.
| Attribute | Parameters | Type | Compatible Operations |
|---|---|---|---|
AMOUNT_Z_SCORE | scope, interval | numeric | IS_GREATER_THAN, IS_LESS_THAN, and other numeric comparisons |
AVG_TRANSACTION_AMOUNT | scope, interval | numeric (cents) | Same as above |
STDEV_TRANSACTION_AMOUNT | scope, interval | numeric (cents) | Same as above |
IS_NEW_COUNTRY | scope | boolean | IS_ONE_OF with ["TRUE"] or ["FALSE"] |
IS_NEW_MCC | scope | boolean | IS_ONE_OF with ["TRUE"] or ["FALSE"] |
IS_FIRST_TRANSACTION | scope | boolean | IS_ONE_OF with ["TRUE"] or ["FALSE"] |
TIME_SINCE_LAST_TRANSACTION | scope | numeric (days) | IS_GREATER_THAN, IS_LESS_THAN, and other numeric comparisons |
DISTINCT_COUNTRY_COUNT | scope | integer | Same as above |
CONSECUTIVE_DECLINES | scope (CARD or ACCOUNT) | integer | Same as above |
THREE_DS_SUCCESS_RATE | (none, card-only) | integer (0 to 100) | Same as above |
CARD_DECLINE_COUNT_15M | (none, card-only) | integer | Same as above |
CARD_DECLINE_COUNT_1H | (none, card-only) | integer | Same as above |
CARD_DECLINE_COUNT_24H | (none, card-only) | integer | Same as above |
Valid scope values are CARD, ACCOUNT, and BUSINESS_ACCOUNT (except where noted). Valid interval values are LIFETIME, 7D, 30D, and 90D.
Thresholds may be integers or decimals (e.g.,
"value": 2.5). Use whichever precision best fits the rule.
Custom Code Rules
In TYPESCRIPT_CODE rules, the statistical and behavioral signals are exposed as a TRANSACTION_HISTORY_SIGNALS feature, and consecutive decline counts are exposed as a separate CONSECUTIVE_DECLINES feature. Declare each feature with the desired scope. Each feature is passed to your rule() function as a typed input.
import {
Authorization,
TransactionHistorySignals,
ConsecutiveDeclines,
AuthorizationAction as Action,
} from './types';
function rule(
authorization: Authorization,
card_signals: TransactionHistorySignals,
account_signals: TransactionHistorySignals,
card_declines: ConsecutiveDeclines,
): Action[] {
// Challenge if the card's 30-day z-score exceeds 3
if (
card_signals.amount_z_score_30d !== null &&
card_signals.amount_z_score_30d > 3
) {
return [
Action.Challenge(
`Z-score ${card_signals.amount_z_score_30d.toFixed(1)} exceeds threshold`
),
];
}
// Decline if a new country appears at the account level (cross-card ATO signal)
if (
account_signals.is_new_country === true &&
authorization.amount > 100_00
) {
return [
Action.Decline(
'UNAUTHORIZED',
'New country on account with high-value transaction'
),
];
}
// Challenge after 5 consecutive declines on the card
if (card_declines.count > 5) {
return [Action.Challenge('Consecutive decline threshold exceeded')];
}
return [];
}When creating the rule via the API, declare each feature with its scope:
{
"type": "TYPESCRIPT_CODE",
"parameters": {
"event_stream": "AUTHORIZATION",
"features": [
{ "name": "authorization", "type": "AUTHORIZATION" },
{ "name": "card_signals", "type": "TRANSACTION_HISTORY_SIGNALS", "scope": "CARD" },
{ "name": "account_signals", "type": "TRANSACTION_HISTORY_SIGNALS", "scope": "ACCOUNT" },
{ "name": "card_declines", "type": "CONSECUTIVE_DECLINES", "scope": "CARD" }
],
"code": "..."
}
}The TransactionHistorySignals type exposes all the features listed in Available Features (except consecutive declines), plus additional properties for advanced use cases such as the raw sets of observed countries and MCCs (seen_countries, seen_mccs), approved transaction counts, Welford m2 values for custom variance calculations, and 3DS authentication counts. All properties are nullable. The ConsecutiveDeclines type exposes a single count property and supports only the CARD and ACCOUNT scopes. See the auto-generated type definitions in ./types for the full interface.
For details on the Custom Code Rules execution environment, compilation, and constraints, see Custom Code Rules.
Inspecting Feature State
Use the Signals API to view the current feature state for a card or account outside of a rule evaluation. This is useful for debugging rules, building dashboards, or feeding contextual data into your own systems.
- Get Card Signals:
GET /v2/card_signals/{card_token} - Get Account Signals:
GET /v2/account_signals/{account_token}
The response includes current values for statistical and behavioral features, the sets of countries and MCCs the entity has transacted in, the most recent card-present transaction location, and raw Welford m2 values for custom variance calculations.
The Signals API returns features that can be computed without a transaction (averages, counts, sets, etc.). Features that require a current transaction for comparison (z-score, is_new_country, is_new_mcc) are computed at authorization time during rule evaluation. Consecutive decline counts are not exposed via this API; inspect them through rule evaluation reports instead.
Null Handling
Statistical features return null when insufficient data is available to produce a meaningful value. Null values are handled safely by default:
| Feature | Null When |
|---|---|
| Avg Transaction Amount | Fewer than 5 approved transactions recorded |
| Stdev Transaction Amount | Fewer than 30 approved transactions recorded |
| Z-Score | Fewer than 30 approved transactions recorded |
| 3DS Success Rate | No 3DS authentication attempts recorded |
| Time Since Last Transaction | No prior approved transaction exists |
In conditional action rules, a null value causes any comparison to evaluate to false. A rule that declines when AMOUNT_Z_SCORE > 3 at the card scope will not decline a card with no transaction history, because the null z-score produces a false comparison. Missing features never trigger a decline.
In custom code rules, null values appear as null in the TypeScript type. Always check for null before using a value:
if (
signals.amount_z_score_30d !== null &&
signals.amount_z_score_30d > 3
) {
// Only fires when enough history exists AND the z-score exceeds the threshold
}When no feature state exists at all (the entity has never transacted), behavioral features return sensible defaults rather than null: is_first_transaction returns true, is_new_country and is_new_mcc return true (any value is inherently new), distinct_country_count returns 0, and consecutive_declines.count returns 0. All statistical features return null.
Limitations
- Authorization stream only: Contextual Rule Features are available on the
AUTHORIZATIONevent stream. - Statistical feature freshness: Statistical features (average, standard deviation, z-score) are recomputed hourly and may lag real-time activity by up to one hour. Behavioral signals (is_new_country, consecutive_declines, etc.) update within seconds.
- Minimum transaction thresholds: Z-score and standard deviation require at least 30 approved transactions before returning a value. Average transaction amount requires at least 5. Entities with limited history will have null values for these features.
- Pattern features are lifetime-scoped: Is New Country, Is New MCC, and Distinct Country Count are computed over the entity's full lifetime.
- Backtesting coverage: Contextual feature values are recorded alongside rule evaluations from the moment Fraud Command is enabled. We recommend enabling Fraud Command early, even before deploying contextual rules, to build backtesting history.
- Consecutive declines scope: Consecutive Declines is available at the
CARDandACCOUNTscopes only. - Decline count scope: Decline Count (15m, 1h, 24h) and 3DS Success Rate are available at the card scope only.
- Signals API scope: The Signals API exposes feature state at the card and account scopes. Business account scope state is available only through rule evaluation.
Next Steps
Rules using Contextual Rule Features support the same draft, shadow, and promotion lifecycle as all authorization rules, including instant deactivation. Use this lifecycle to safely test and deploy contextual rules.
- Review Authorization Rules for the full rule lifecycle: drafting, shadow mode, performance reports, and promotion
- See Custom Code Rules to write TypeScript rules with full access to contextual signals
- Use Backtesting to validate contextual rules against historical transactions before going live
- Pair contextual detection with SMS step-up via Authorization Challenges
- Consult the Auth Rules API specification for complete endpoint and parameter documentation
Updated about 3 hours ago
