Skip to main content

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.

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:
largeTransfer.ws
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:
OperatorMeaningExample
==equal tocurrency == "USD"
!=not equal tosource != destination
>greater thanamount > 4000
>=greater than or equal toamount >= 4000
<less thanamount < 100
<=less than or equal toamount <= 100
invalue is in a listmeta_data.channel in ("card", "bank_transfer")
regexmatches a regular expressiondescription regex "(?i)(gift.?card|crypto)"
not_regexdoes not match a regular expressiondescription 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:
highValueTransfer.ws
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.
highRiskTransaction.ws
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 …
highRiskTransaction2.ws
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:
rule highRiskPKRTransaction {
  when currency == 'PKR' and amount > 1000

  then review
    score 0.5
    reason "High-risk PKR transaction detected"
}
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:
promoCodeReuse.ws
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.
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.
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.

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:
$current.<field>
For example, to flag transactions where the source and destination are the same:
sameSourceAndDestination.ws
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:
mismatchedCountries.ws
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:
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"
}
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:
<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:
AggregateDescription
countNumber of matching transactions in the window
sumTotal of a numeric field (e.g. amount) over the window
avgAverage value of a numeric field over the window
maxLargest value of a numeric field in the window
minSmallest value of a numeric field in the window
The time window is written as an ISO 8601 duration string in quotes.
UnitExampleMeaning
Seconds"PT30S"30 seconds
Minutes"PT30M"30 minutes
Hours"PT24H"24 hours
Days"P7D"7 days
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).

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:
lateNightLargeTransfer.ws
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.
When transactions are injected through the API, this is typically the created_at value.
You can write time-based conditions using helper functions that extract parts of the timestamp.
FunctionDescriptionExample
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 namesday_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:
weekendHighValueTransactions.ws
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:
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:
blockIfPreviousFailed.ws
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:
burstToSameDestination.ws
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.