> ## Documentation Index
> Fetch the complete documentation index at: https://docs.finwatch.finance/llms.txt
> Use this file to discover all available pages before exploring further.

# Rule Cookbook

A library of production-ready Watch Script rule patterns covering the most common fraud scenarios in fintech. Each recipe is a complete, copy-paste-ready `.ws` file with an explanation of why it works and how to customize it for your needs.

***

## How to Use This Cookbook

1. **Find a recipe** that matches the fraud pattern you want to detect.
2. **Copy the `.ws` file** into your `watch_scripts/` directory.
3. **Customize the thresholds** — adjust amounts, time windows, and scores to match your risk appetite.
4. **Test with sample transactions** — inject transactions that should and should not trigger the rule.
5. **Deploy** — commit to your Git repository and let FinWatch pick it up.

Every recipe includes:

* **The complete rule** — copy-paste ready.
* **Why this works** — the fraud pattern this rule targets.
* **How to customize** — which values to tune for your business.

***

## Threshold Checks

### High-Value Transaction Check

```go lines theme={null}
rule HighValueTransactionCheck {
    description "Monitors for unusually large transactions requiring review."

    when amount > 10000

    then review
         score   0.5
         reason  "Transaction amount exceeds 10,000 in any currency."
}
```

**Why this works:** The simplest and most important rule in any fraud detection system. Unusually large transactions are the most common vector for theft. This creates a baseline safety net that catches high-value transactions regardless of other factors.

**How to customize:**

* **Threshold:** Adjust `10000` based on your typical transaction sizes. A consumer payments platform might use `5000`; a B2B platform might use `100000`.
* **Score:** At `0.5`, this is moderate confidence. Increase to `0.7+` if high-value transactions are rare in your system.
* **Verdict:** `review` is appropriate for most cases. Use `block` only if your business requires pre-authorization holds on large amounts.

***

### Micro-Transaction Detection (Card Testing)

```go lines theme={null}
rule RapidSmallBurst {
    description "Multiple small transactions in quick succession."

    when amount < 500
     and count(when source == $current.source, "PT30M") >= 5

    then review
         score   0.65
         reason  "Rapid succession of small transactions"
}
```

**Why this works:** Card testing is a common fraud technique where stolen card numbers are validated with small purchases (often under \$1-5) before being used for larger fraudulent transactions. This rule detects the pattern: many small transactions from the same source in a short window.

**How to customize:**

* **Amount threshold:** Lower to `< 10` or even `< 1` for stricter card testing detection.
* **Count threshold:** `>= 5` in 30 minutes is aggressive. Relax to `>= 10` if your users legitimately make many small purchases (e.g., vending machines, transit systems).
* **Time window:** `"PT30M"` catches rapid bursts. Extend to `"PT1H"` for slower-paced testing.

***

### Cross-Border Transaction Flag

```go lines theme={null}
rule CrossBorderTransactionCheck {
    description "High-value transaction crossing international borders."

    when metadata.source_country != metadata.destination_country
     and amount > 1000

    then review
         score   0.5
         reason  "Large cross-border transaction requires review"
}
```

**Why this works:** Cross-border transactions carry inherent risk — different regulatory jurisdictions, currency exchange complexities, and difficulty in tracing funds. Many AML regulations require enhanced due diligence for international transfers.

**How to customize:**

* **Amount:** `1000` is a conservative threshold. Increase for high-volume cross-border businesses.
* **Metadata fields:** Ensure your application sends `source_country` and `destination_country` in the `meta_data` object.
* **Score:** Increase to `0.7+` if your business rarely processes international transactions.

***

## Velocity and Volume

### High-Frequency Transactions to Same Destination

```go lines theme={null}
rule HighFrequencyDestination {
    description "Unusually frequent payments to the same destination may require scrutiny."

    when count(when destination == $current.destination, "PT24H") > 10
     and amount > 100

    then review
         score   0.5
         reason  "High frequency of transactions to same destination in 24 hours"
}
```

**Why this works:** A single destination receiving many transactions is a hallmark of money mule accounts — intermediary accounts used to collect and redistribute stolen funds. Legitimate businesses rarely receive more than a handful of transactions from distinct sources in a day.

**How to customize:**

* **Count:** `> 10` is moderate. Lower to `> 5` for stricter monitoring; raise to `> 20` for high-volume merchant accounts.
* **Amount gate:** The `amount > 100` condition filters out micro-transactions, reducing false positives from legitimate high-frequency, low-value payments.

***

### Source Account High Outflow

```go lines theme={null}
rule SourceHighOutflow {
    description "Source account has high outflow volume in 24h."

    when sum(amount when source == $current.source, "PT24H") > 5000

    then review
         score   0.5
         reason  "High cumulative outflow from source in 24 hours"
}
```

**Why this works:** Account draining — where a compromised account is quickly emptied through many transfers — is one of the most damaging fraud patterns. This rule detects it by monitoring total outflow, not individual transaction amounts.

**How to customize:**

* **Sum threshold:** `5000` is conservative. Set based on your typical user's daily spending. A fintech serving gig workers might use `2000`; a corporate treasury platform might use `500000`.
* **Time window:** `"PT24H"` is standard for daily limits. Use `"PT1H"` for near-real-time draining detection.

***

### High-Value Velocity from Single Source

```go lines theme={null}
rule HighAmountVelocitySource {
    description "Monitors for rapid high-value spending from a single source in the last hour."

    when sum(amount when source == $current.source, "PT1H") > 3000

    then review
         score   0.7
         reason  "Source account shows high-velocity spending pattern"
}
```

**Why this works:** A tighter version of the high outflow rule with a 1-hour window and higher score. Detects rapid account draining in near-real-time rather than over a full day.

***

### Repeated Identical Amounts

```go lines theme={null}
rule RepeatedIdenticalAmount {
    description "Multiple transactions with identical amounts may indicate structuring."

    when count(when amount == $current.amount, "PT1H") > 2

    then review
         score   0.6
         reason  "Multiple identical amount transactions in a short time period"
}
```

**Why this works:** Structuring (smurfing) often involves multiple transactions of the same amount to stay under reporting thresholds. Legitimate users rarely make multiple transactions for exactly the same amount in a short period.

**How to customize:**

* **Count:** `> 2` means 3+ identical amounts in an hour triggers the rule. Adjust based on your business — some retail scenarios legitimately have repeated amounts.
* **Time window:** `"PT1H"` is tight. Extend to `"PT24H"` to catch slower structuring patterns.

***

## Behavioral Anomalies

### Dormant Account Reactivation

```go lines theme={null}
rule DormantAccountActivity {
    description "Unusual activity after long period of account dormancy."

    when metadata.days_since_last_transaction > 90
     and amount > 1000

    then review
         score   0.7
         reason  "High-value transaction after extended account inactivity"
}
```

**Why this works:** When an account that's been dormant for 90+ days suddenly makes a large transaction, it's a strong signal of account takeover. The legitimate owner likely isn't using the account; someone else gained access.

**How to customize:**

* **Dormancy period:** `90` days is standard. Lower to `30` for more aggressive detection.
* **Amount:** `1000` filters out small reactivation transactions (e.g., checking if the account still works).
* **Metadata requirement:** Your application must include `days_since_last_transaction` in the transaction's `meta_data`.

***

### New Account First-Day Activity

```go lines theme={null}
rule NewAccountFirstDay {
    description "High-volume activity on first day of account creation."

    when metadata.account_age_days < 1
     and amount > 1000

    then review
         score   0.6
         reason  "Large transaction from newly created account"
}
```

**Why this works:** Fraudulently created accounts are typically used within the first few hours. A legitimate user might fund their account with a small test deposit; a fraudster goes straight for a large transaction.

**How to customize:**

* **Account age:** `< 1` day catches same-day activity. Extend to `< 7` for the critical first-week period.
* **Amount:** Lower to `500` for consumer platforms; raise for B2B.
* **Combine with velocity:** Add `and count(when source == $current.source, "PT1H") > 3` to catch rapid activity from new accounts.

***

### Unusual Transaction Time

```go lines theme={null}
rule UnusualTransactionTime {
    description "Large transactions during unusual hours receive extra scrutiny."

    when hour_of_day(timestamp) >= 1
     and hour_of_day(timestamp) < 5
     and amount > 1000

    then review
         score   0.6
         reason  "Large transaction during unusual hours (1 AM - 5 AM)"
}
```

**Why this works:** Most legitimate financial activity happens during waking hours. Transactions between 1 AM and 5 AM (UTC) are statistically more likely to be fraudulent — especially large ones.

**How to customize:**

* **Time range:** Adjust for your users' time zones. See the [Time-Based Rules Guide](time-functions-guide.md) for UTC offset considerations.
* **Amount:** Lower the threshold for higher sensitivity.

***

### Late Night Transactions

```go lines theme={null}
rule LateNightTransactions {
    description "Detects transactions made late at night."

    when hour_of_day(timestamp) >= 23
      or hour_of_day(timestamp) <= 3

    then review
         score   0.4
         reason  "Transaction occurred during late night hours"
}
```

**Why this works:** A broader version of the unusual time rule. Catches any transaction between 11 PM and 3 AM, regardless of amount. Lower score because late-night activity alone isn't highly suspicious.

***

### Weekend Transaction on Business Account

```go lines theme={null}
rule WeekendTransactionCheck {
    description "Flags high-value transactions on weekends for business accounts."

    when day_of_week(timestamp) == 0
      or day_of_week(timestamp) == 6

    then review
         score   0.4
         reason  "Transaction on a weekend"
}
```

**Why this works:** Business accounts typically don't process payments on weekends. Weekend activity from a corporate account could indicate unauthorized access.

**How to customize:**

* Add `and metadata.account_type == "business"` to target only business accounts.
* Add `and amount > 5000` to focus on significant transactions.

***

## Identity and KYC

### Low KYC Daily Limits

```go lines theme={null}
rule LowKycDailyTotal {
    description "Low-tier KYC total spend in 24h above threshold."

    when metadata.kyc_tier == 1
     and sum(amount when source == $current.source, "PT24H") > 5000

    then review
         score   0.5
         reason  "Total transacted amount exceeds tier-1 limit"
}
```

**Why this works:** KYC tiering is standard in fintech. Users with basic verification (tier 1) should have lower daily limits. This rule enforces that limit by monitoring cumulative daily spending.

**How to customize:**

* **KYC tier:** Adjust for your tier system. Create separate rules for each tier with different thresholds.
* **Daily limit:** `5000` is illustrative. Set based on your regulatory requirements.

***

### Low KYC High-Risk Activity

```go lines theme={null}
rule LowKycHighRisk {
    description "Low-tier KYC customer engaging in high-risk activity."

    when metadata.kyc_tier == 1
     and metadata.merchant_category in ("gambling", "cryptocurrency", "adult", "high_value_goods")
     and amount > 500

    then review
         score   0.8
         reason  "Low-KYC account engaging in high-risk category transaction"
}
```

**Why this works:** Low-KYC users transacting in high-risk categories (gambling, crypto, etc.) represent elevated risk. The combination of weak identity verification and risky transaction categories is a common fraud vector.

**How to customize:**

* **Categories:** Adjust the list based on your risk assessment. Replace with MCC codes if you have them.
* **Score:** `0.8` is high. This is appropriate because the combination of low KYC and high-risk category is a strong signal.

***

### Self-Transfer Detection

```go lines theme={null}
rule SelfTransferCheck {
    description "Detects when the source and destination of a transaction are the same."

    when source == $current.destination

    then review
         score   0.5
         reason  "Self-transfer detected — source and destination are identical"
}
```

**Why this works:** Sending money to yourself is a common technique in money laundering — the funds appear to have moved through the system, but they're actually staying with the same entity. It can also indicate a configuration error.

***

## Sanctions and Compliance

### Sanctioned Country Check

```go lines theme={null}
rule SanctionedCountryCheck {
    description "Blocks transactions to sanctioned countries per OFAC/international sanctions."

    when metadata.destination_country in $sanctioned_countries

    then block
         score   1.0
         reason  "Destination country is on global sanctions list"
}
```

**Why this works:** This is a **mandatory** rule for any regulated financial institution. Transactions to sanctioned countries must be blocked outright. Using a variable (`$sanctioned_countries`) means the list can be updated without modifying the rule.

**How to customize:**

* **Variable:** Maintain `$sanctioned_countries` externally. Update it whenever OFAC, EU, or UN sanctions lists change.
* **Verdict:** `block` is non-negotiable for sanctions compliance.
* **Score:** `1.0` — maximum confidence.

***

### High-Risk Destination Country

```go lines theme={null}
rule HighRiskDestinationCountry {
    description "Destination country on high-risk list."

    when metadata.destination_country in $high_risk_countries

    then block
         score   0.5
         reason  "Destination country classified as high risk"
}
```

**Why this works:** Distinct from sanctioned countries, high-risk countries may not require an outright block but warrant enhanced due diligence. Common high-risk lists include FATF grey/black lists.

**How to customize:**

* Consider using `review` instead of `block` for high-risk (non-sanctioned) countries.
* The `$high_risk_countries` variable can include FATF-listed jurisdictions.

***

### Suspicious Description Patterns

```go lines theme={null}
rule SuspiciousDescriptionCheck {
    description "Detects suspicious keywords or patterns in transaction descriptions."

    when description regex "(?i)(btc|bitcoin|crypto|wallet|transfer|gift.?card|western.?union)"
     and amount > 1000

    then review
         score   0.2
         reason  "Suspicious description pattern."
}
```

**Why this works:** Transaction descriptions containing cryptocurrency keywords, gift card references, or money transfer service names are common in scam-related payments (romance scams, tech support scams, etc.).

**How to customize:**

* **Pattern:** Extend with additional keywords relevant to your market. Be careful not to make the pattern too broad — you don't want to flag legitimate crypto exchanges.
* **Amount gate:** `1000` filters noise. Lower for higher sensitivity.
* **Score:** `0.2` is low because description matching alone has high false-positive rates. Layer with other conditions for higher confidence.

***

### Known Fraud Entity Check

```go lines theme={null}
rule KnownFraudEntityCheck {
    description "Automatically blocks transactions with entities on fraud list."

    when destination in $known_fraud_entities

    then block
         score   1.0
         reason  "Destination is on known fraud entities list"
}
```

**Why this works:** If you maintain a list of known fraudulent accounts (from previous investigations, shared intelligence, or fraud databases), this rule provides an automatic hard block.

**How to customize:**

* Use a variable (`$known_fraud_entities`) rather than an inline list. This list changes frequently as new fraud accounts are identified.
* Consider also checking `source in $known_fraud_entities` for inbound fraud detection.

***

### Cryptocurrency Category Check

```go lines theme={null}
rule CategoryBTCCheck {
    description "Cryptocurrency transaction requires manual verification."

    when metadata.category == "cryptocurrency"

    then review
         score   0.6
         reason  "Cryptocurrency transaction requires verification"
}
```

**Why this works:** Cryptocurrency transactions carry elevated risk due to the irreversible nature of blockchain transfers and the pseudonymous nature of crypto wallets. Many compliance frameworks require additional verification.

***

### Foreign Currency Transaction

```go lines theme={null}
rule ForeignCurrencyTx {
    description "Transaction occurs in currency different from account's base currency."

    when currency != metadata.account_base_currency
     and amount > 1000

    then review
         score   0.4
         reason  "Large transaction in foreign currency"
}
```

**Why this works:** When an account normally transacts in one currency but suddenly uses a different one, it could indicate the account is being used from a different country — potentially by someone other than the legitimate owner.

***

## Sequential Patterns

### Block After Previous Failure

```go lines theme={null}
rule BlockIfPreviousFailed {
    description "Block when previous transaction failed for same source."

    when previous_transaction(
        within: "PT1H",
        match: {
            status: "failed",
            source: "$current.source"
        }
    )
    and amount > 700000

    then block
         score   1.0
         reason  "High-value transaction after recent failure from same source"
}
```

**Why this works:** A failed transaction followed by a large retry is a classic account takeover signal. The initial failure might have been due to the fraudster hitting an incorrect limit, after which they adjust and try again with a larger amount.

**How to customize:**

* **Time window:** `"PT1H"` is tight. Extend to `"PT2H"` or `"PT4H"` for broader coverage.
* **Amount:** `700000` is very high. Lower based on your typical transaction sizes.
* **Failed status:** Ensure your system records failed transactions with `status: "failed"`.

***

### Merchant-Issuer Country Mismatch

```go lines theme={null}
rule MerchantIssuerMismatch {
    description "Card issuer country does not match merchant country."

    when metadata.merchant_country != metadata.card_issuer_country

    then review
         score   0.4
         reason  "Card issuer country does not match merchant country"
}
```

**Why this works:** When a card issued in one country is used at a merchant in a different country, it's a geographical anomaly that could indicate the card data was stolen and used remotely.

**How to customize:**

* Add `and amount > 500` to filter out small international purchases (common for online shopping).
* Combine with `and metadata.is_card_present == false` to focus on card-not-present (CNP) fraud.

***

## Combining Recipes

The most effective fraud detection comes from layering multiple rules. Here's a recommended starter set for a typical fintech platform:

| Priority | Rule                       | Verdict  | Why                     |
| -------- | -------------------------- | -------- | ----------------------- |
| 1        | SanctionedCountryCheck     | `block`  | Regulatory requirement  |
| 2        | KnownFraudEntityCheck      | `block`  | Known bad actors        |
| 3        | BlockIfPreviousFailed      | `block`  | Account takeover signal |
| 4        | HighValueTransactionCheck  | `review` | High-value safety net   |
| 5        | SourceHighOutflow          | `review` | Account draining        |
| 6        | RapidSmallBurst            | `review` | Card testing            |
| 7        | DormantAccountActivity     | `review` | Account takeover        |
| 8        | LowKycDailyTotal           | `review` | KYC compliance          |
| 9        | SuspiciousDescriptionCheck | `review` | Scam detection          |
| 10       | LateNightTransactions      | `alert`  | Monitoring baseline     |

Start with this set, monitor the verdicts for a week, tune the thresholds based on your false-positive and false-negative rates, and then add more specialized rules.

***

## Next Steps

* [**Writing Your First Rule**](writing-your-first-rule.md) — Learn the rule authoring workflow from scratch.
* [**Conditions Deep Dive**](conditions-deep-dive.md) — Master every operator and condition type.
* [**Aggregate Functions Guide**](aggregate-functions-guide.md) — Deep dive into velocity and volume detection.
* [**GitOps Rule Management**](gitops-rule-management.md) — Deploy these recipes through your Git workflow.
* [**DSL Reference**](../DSL_REFERENCE.md) — Complete language specification.
