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

# Setting Conditions

> Write conditions in the Blnk Watch DSL: comparisons, logical operators, aggregates, and time-based checks.

<Note>Blnk Watch is currently in beta. [Send us a message](mailto:support@blnkfinance.com)</Note>

The `when` clause is used to describe a set of conditions that trigger a transaction in Watch.

Rules still evaluate **transactions only**. If you need extra context, include it in `meta_data` on the transaction first.

When setting conditions, you can only use the supported fields in the Watch transaction payload: `transaction_id`, `amount`, `reference`, `source`, `destination`, `description`, `created_at`, and `meta_data`.

***

## Basic conditions

Basic conditions compare transaction fields to literal values. You can compare numeric fields (e.g. `amount`), string fields (e.g. `currency`, `source`, `destination`), and metadata (e.g. `meta_data.kyc_tier`).

For example, this is a simple rule flagging amounts greater than 10,000:

```bash largeTransfer.ws {2} theme={"system"}
rule largeTransfer {
  when amount > 10000

  then review
    score 0.6
    reason "Transaction amount exceeds 10,000"
}
```

When directly comparing fields with values, Blnk supports the following operators:

| Operator    | Meaning                             | Example                                          |
| ----------- | ----------------------------------- | ------------------------------------------------ |
| `==`        | equal to                            | `currency == "USD"`                              |
| `!=`        | not equal to                        | `source != destination`                          |
| `>`         | greater than                        | `amount > 4000`                                  |
| `>=`        | greater than or equal to            | `amount >= 4000`                                 |
| `<`         | less than                           | `amount < 100`                                   |
| `<=`        | less than or equal to               | `amount <= 100`                                  |
| `in`        | value is in a list                  | `meta_data.channel in ("card", "bank_transfer")` |
| `regex`     | matches a regular expression        | `description regex "(?i)(gift.?card\|crypto)"`   |
| `not_regex` | does not match a regular expression | `description not_regex "(?i)test"`               |

***

## Combined conditions

To create conditions with two or more filters, Watch supports two logical operators:

* **and:** Every condition must be true.
* **or:** At least one of the conditions must be true.

For example, we could safeguard our earlier rule by specifying what currencies the transaction limit is for:

```bash highValueTransfer.ws {2,3} theme={"system"}
rule highValueTransfer {
  when amount > 4000 
    and currency in ("USD", "EUR")

  then review
    score 0.5
    reason "USD/EUR transaction exceeds 4,000"
}
```

With `or`, one of two conditions can trigger the same risk action. For example, in a cross-border app you might treat amounts over 10,000 as high-risk regardless of currency; but if the transaction is in PKR, IRR, or SYP, you treat it as high-risk regardless of amount.

```bash highRiskTransaction.ws {2,3} theme={"system"}
rule highRiskTransaction {
  when amount > 10000
    or currency in ("PKR", "IRR", "SYP")

  then review
    score 0.5
    reason "High-risk transaction detected"
}
```

> **Recommended:** If your `or` conditions start to get complex, you should consider using a separate rule for each condition. For example, a complex set of conditions like this …

```bash highRiskTransaction2.ws theme={"system"}
when (currency  == 'PKR' and amount > 1000) 
  or (currency == 'IRR' and amount > 8000) 
  or (currency == 'SYP' and amount > 5000)
```

> … is better written as three separate rules:

<CodeGroup>
  ```bash highRiskPKRTransaction.ws {2} theme={"system"}
  rule highRiskPKRTransaction {
    when currency == 'PKR' and amount > 1000

    then review
      score 0.5
      reason "High-risk PKR transaction detected"
  }
  ```

  ```bash highRiskIRRTransaction.ws {2} theme={"system"}
  rule highRiskIRRTransaction {
    when currency == 'IRR' and amount > 8000

    then review
      score 0.5
      reason "High-risk IRR transaction detected"
  }
  ```

  ```bash highRiskSYPTransaction.ws {2} theme={"system"}
  rule highRiskSYPTransaction {
    when currency == 'SYP' and amount > 5000

    then review
      score 0.5
      reason "High-risk SYP transaction detected"
  }
  ```
</CodeGroup>

> This makes your rule set easier to read, reason about, and change in your workflow.

***

## Metadata reference

When setting conditions on information that is not part of the top-level parameters, such as source country, destination country, customer KYC tier, or promo code, pass the value in `meta_data`.

You can then reference the value in your rule using dot notation. For example, here's a rule that flags when a customer has used at least one of the supported promo codes:

```bash promoCodeReuse.ws {2} theme={"system"}
rule promoCodeReuse {
  when meta_data.promo_code in ('DISCOUNT10', 'WELCOME15', 'REFERRAL20')

  then review
    score 0.25
    reason "Current transaction has redeemed a supported promo code"
}
```

Now, you can use this flag to update the customer's account, e.g. to prevent them from using any of those promo codes again.

<Warning>
  **Always remember:** Watch does not automatically retrieve external data. Any value you want to reference in a rule must already exist in the transaction `meta_data` field.
</Warning>

<Tip>
  If you want to monitor fields such as destination country, KYC tier, or promo code, add them to the transaction `meta_data` in your application before sending the transaction to Blnk.
</Tip>

***

## Dynamic references

Dynamic references allow you to reuse values from the transaction being evaluated when defining a condition. This works with any field in the transaction payload, including values in `meta_data`.

Use dynamic references when the value you want to compare depends on the transaction being evaluated, rather than a fixed value.

To reference a value from the current transaction, use:

```text theme={"system"}
$current.<field>
```

For example, to flag transactions where the source and destination are the same:

```bash sameSourceAndDestination.ws {2} theme={"system"}
rule sameSourceAndDestination {
  when source == $current.destination

  then review
    score 0.45
    reason "Source and destination resolve to the same account"
}
```

Another common use case is mismatched countries.

For example, you may want to flag transactions where the customer's registered country is different from the country the transaction is coming from. This can indicate unusual activity or possible fraud:

```bash mismatchedCountries.ws {2} theme={"system"}
rule mismatchedCountries {
  when meta_data.registered_country != $current.destination_country

  then review
    score 0.45
    reason "Registered country does not match source country"
}
```

***

## Aggregate operators

Aggregate conditions evaluate groups of transactions over a defined time window rather than a single transaction. This makes it possible to detect patterns in activity.

Here are some examples of aggregate conditions in practice:

<CodeGroup>
  ```bash userSpendingLimit.ws {2,3} theme={"system"}
  rule userSpendingLimit {
    when sum(amount when source == $current.source, "PT24H") > 10000
      and meta_data.customer_tier != "premium"

    then review
      score 0.65
      reason "User spending exceeds 10,000 in 24 hours"
  }
  ```

  ```bash burstToSameDestination.ws {2} theme={"system"}
  rule burstToSameDestination {
    when count(when destination == $current.destination, "PT30M") >= 5

    then review
      score 0.65
      reason "Five or more transactions to the same destination in 30 minutes"
  }
  ```

  ```bash repeatedTransactions.ws {2,3} theme={"system"}
  rule repeatedTransactions {
    when count(when source == $current.source, "PT24H") >= 5
      and meta_data.kyc_tier == "basic"

    then review
      score 0.65
      reason "Five or more transactions from the same source in 24 hours"
  }
  ```
</CodeGroup>

You can use them to identify behaviors such as repeated transactions from the same source, burst activity to the same destination, or a user spending above a defined limit within a period, to name a few.

Instead of checking just the current transaction, aggregate conditions analyze related transactions that match a filter and calculate metrics such as count or sum within the specified time window. Rules can then trigger when those values cross a threshold defined in your condition.

To use an aggregate:

```text theme={"system"}
<aggregate>(when <filter>, "<window>")
```

* `aggregate` defines the metric to compute, e.g. `count` or `sum`.
* `when <filter>` selects the transactions to include in the calculation.
* `<window>` defines how far back to look from the current transaction.

Watch supports the following aggregate operators:

| Aggregate | Description                                              |
| --------- | -------------------------------------------------------- |
| `count`   | Number of matching transactions in the window            |
| `sum`     | Total of a numeric field (e.g. `amount`) over the window |
| `avg`     | Average value of a numeric field over the window         |
| `max`     | Largest value of a numeric field in the window           |
| `min`     | Smallest value of a numeric field in the window          |

The **time window** is written as an ISO 8601 duration string in quotes.

| Unit    | Example   | Meaning    |
| ------- | --------- | ---------- |
| Seconds | `"PT30S"` | 30 seconds |
| Minutes | `"PT30M"` | 30 minutes |
| Hours   | `"PT24H"` | 24 hours   |
| Days    | `"P7D"`   | 7 days     |

<Note>
  Use `PT` for time units (hours, minutes, seconds) and `P` for days. Weeks and months are not supported. Use days instead (for example `"P7D"` for one week or `"P30D"` for roughly a month).
</Note>

***

## Time-based functions

Time-based functions let you write rules that depend on when a transaction occurs.

For example, you might want to review large transactions late at night:

```bash lateNightLargeTransfer.ws {2-4} theme={"system"}
rule lateNightLargeTransfer {
  when hour_of_day(timestamp) >= 22 
    and amount > 3000

  then review
    score 0.6
    reason "Large USD transaction during late-night hours"
}
```

In this rule, Watch checks the transaction timestamp and evaluates whether it occurred after 10 PM.

Watch evaluates time using the timestamp provided with the transaction event. In practice this is the event time you send to Watch.

<Info>When transactions are injected through the API, this is typically the `created_at` value.</Info>

You can write time-based conditions using helper functions that extract parts of the timestamp.

| Function                   | Description                                                         | Example                                                                                  |
| -------------------------- | ------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `hour_of_day(timestamp)`   | Hour of day (0-23)                                                  | `hour_of_day(timestamp) >= 22`                                                           |
| `day_of_week(timestamp)`   | Weekday: 0 = Sunday, 6 = Saturday. With `in`, you can use day names | `day_of_week(timestamp) in (0, 6)` or `day_of_week(timestamp) in ("Saturday", "Sunday")` |
| `day_of_month(timestamp)`  | Day of month (1-31)                                                 | `day_of_month(timestamp) == 17`                                                          |
| `day_of_year(timestamp)`   | Day of year (1-366)                                                 | `day_of_year(timestamp) <= 31`                                                           |
| `month_of_year(timestamp)` | Month (1-12)                                                        | `month_of_year(timestamp) == 3`                                                          |
| `week_of_year(timestamp)`  | ISO week number (1-53)                                              | `week_of_year(timestamp) == 12`                                                          |
| `year(timestamp)`          | Year (e.g. 2026)                                                    | `year(timestamp) == 2026`                                                                |

> **Also note:** Time-based conditions support standard comparison operators: `==`, `!=`, `>`, `>=`, `<`, `<=`, `in`.

> For `day_of_week`, when using the `in` operator, you can use day names instead of numbers. So `day_of_week(timestamp) in ("Saturday", "Sunday")` is equivalent to `day_of_week(timestamp) in (0, 6)`.

For example, to flag high value transactions that occur on a weekend:

```bash weekendHighValueTransactions.ws {2-4} theme={"system"}
rule weekendHighValueTransactions {
  when day_of_week(timestamp) in ("Saturday", "Sunday")
    and amount > 10000
    and currency == "USD"

  then review
    score 0.45
    reason "Transaction occurred on a weekend"
}
```

***

## "Previous transaction" function

`previous_transaction` checks if any transaction in a past time window matches specific criteria. It returns `true` if at least one matching transaction exists, otherwise `false`.

Use it to detect patterns like:

* This source had a failed transaction recently
* This destination already received a transaction in the last hour

To use this function:

```text theme={"system"}
previous_transaction(within: "<duration>", match: { <field>: <value>, ... })
```

* **within** — How far back to look. Uses ISO 8601 duration strings, e.g. `"PT1H"` (1 hour), `"P1D"` (1 day).

* **match** — A set of fields that must all match for a transaction to count. You can use literal values, e.g. `meta_data.status: "failed"` or dynamic references, `source: $current.source`.

For example, to flag and block when the same source has had a failed transaction in the last hour:

```bash blockIfPreviousFailed.ws {2-6} theme={"system"}
rule blockIfPreviousFailed {
  when previous_transaction(
      within: "PT1H",
      match: { source: "$current.source", status: "failed" }
    )
    and amount > 700000

  then block
    score 1.0
    reason "Previous transaction from this source failed; blocking high amount"
}
```

Here's another example that checks if a transaction has received at least one transaction in the last 30 minutes:

```bash burstToSameDestination.ws {2-5} theme={"system"}
rule burstToSameDestination {
  when previous_transaction(
      within: "PT30M",
      match: { destination: "$current.destination" }
    )

  then review
    score 0.5
    reason "Another transaction to this destination in the last 30 minutes"
}
```

> **Note:**
>
> * This is a boolean check, not a count. It only answers: “Did at least one matching transaction occur?”
> * Uses the same transaction store and time window format as aggregate conditions.

***

## Need help?

We are very happy to help you make the most of Blnk, regardless of whether it is your first time or you are switching from another tool.

To ask questions or discuss issues, please [contact us](mailto:support@blnkfinance.com) or [join our Discord community](https://discord.gg/7WNv94zPpx).

**Connect your ledger to Blnk Cloud**

Sign up and manage your ledger with our back-office dashboard. You can invite teammates to collaborate and manage your ledger operations directly from the dashboard.
