Skip to main content

Screening alerts in monitoring scenarios

Monitoring scenarios can access the screening alerts associated with the current transaction directly in their queries, using the $transaction.alerts computed parameter.

This makes it possible to write scenarios that are aware of screening outcomes — for example, skipping auto-reject logic when a transaction is already under manual screening review, or firing only when both a behavioural signal and a screening hit are present at the same time.


The $transaction.alerts parameter

$transaction.alerts is a jsonb array. Each element represents one screening alert on the current transaction and contains the following fields:

Field

Type

Description

status

string

Current status of the alert, as its code value

flowHandle

string

Handle of the screening flow that created the alert. You can find the handle on the Screening flows page — copy it using the icon next to the flow ID.

createdTime

timestamp

When the alert was first created

statusUpdatedTime

timestamp

When the alert status was last updated

Example value of $transaction.alerts:

[
{
"status": "CLOSED_AS_TRUE_POSITIVE",
"flowHandle": "d7708a04-6528-45a7-b709-f0545a039c04",
"createdTime": "2026-01-05T10:15:30.00Z",
"statusUpdatedTime": "2026-01-05T10:15:30.00Z"
},
{
"status": "CLOSED_AS_FALSE_POSITIVE",
"flowHandle": "d7708a04-6528-45a7-b709-f0545a039c04",
"createdTime": "2026-01-05T10:15:30.00Z",
"statusUpdatedTime": "2026-01-05T10:15:30.00Z"
},
{
"status": "CLOSED_AS_TRUE_POSITIVE",
"flowHandle": "d7708a04-6528-45a7-b709-f0545a039c04",
"createdTime": "2026-01-05T10:15:30.00Z",
"statusUpdatedTime": "2026-01-05T10:15:30.00Z"
}
]

The status field contains the code of the alert status as configured in your organisation's settings. To find the correct code values to use in your queries, navigate to Configuration → General → Alert Statuses and refer to the code field for each status. See Alert statuses for more details. Note: FILTERED alerts are not included.


Using $transaction.alerts in scenarios

Because $transaction.alerts is a standard jsonb array, you can use any PostgreSQL jsonb functionality with it. The examples below show the most common patterns.

Use with real-time scenarios

$transaction.alerts can only be used with real-time and post-event scenarios, it is not available in periodic scenarios. Real-time is recommended: you control the order of API calls and can ensure screening runs before monitoring by making the screening-checks API call first. Post-event scenarios start running automatically when a transaction is created, and since we don't guarantee screening checks will have completed by that point, $transaction.alerts may be empty or incomplete when the scenario executes.

Example 1: Trigger if at least one alert is a true positive from a specific screening flow

This query unnests the alerts array and filters for alerts from a particular screening flow that have been closed as true positives. If any such alert exists for the current transaction, the scenario triggers.

select sa ->> 'flowHandle' = 'a1b0b0fe-b6b5-4094-896a-aee5effaac68', $transaction.attributes.amount
from jsonb_array_elements($transaction.alerts) as sa
where sa ->> 'status' = 'CLOSED_AS_TRUE_POSITIVE'

Example 2: Trigger if more than 2 alerts are in NEW status

This query counts the number of unresolved alerts for the current transaction. The scenario triggers when there are more than 2 alerts with a NEW status code.

select count(*) > 2, $transaction.attributes.amount
from jsonb_array_elements($transaction.alerts) as sa
where sa ->> 'status' = 'NEW'

Example 3: Trigger if at least one alert is a true positive (using jsonpath)

This is a more concise alternative to Example 1 using the jsonpath @? operator. It returns true if any element in the alerts array has a status of CLOSED_AS_TRUE_POSITIVE.

select $transaction.alerts @? '$.status[*] ? (@ == "CLOSED_AS_TRUE_POSITIVE")', $transaction.attributes.amount

Example 4: Combine screening alert status with transaction history

This query combines alert data with historical transaction behaviour. It triggers if the current transaction has at least one true positive alert and the associated person has had more than 5 incoming transactions in the last 30 days.

select count(past.id) > 5 and sa ->> 'status' = 'CLOSED_AS_TRUE_POSITIVE', $transaction.attributes.amount
from transaction past
cross join jsonb_array_elements($transaction.alerts) as sa
where past.person_id = $person.id
and past.direction = 'INCOMING'
and past.timestamp >= $transaction.timestamp - interval '30 days'

Making the API calls

To use $transaction.alerts effectively, the screening and monitoring calls must be made in the right order. The parameter reflects the state of screening alerts at the moment the monitoring call is made, so screening must run first.

Call sequence

1. Create the transaction

POST /v1/persons/{personId}/transactions

2. Screen the transaction

POST /v1/transactions/{transactionId}/screening-checks

If the transaction matches anything on your configured screening flows, the response will contain a matches array and a screening alert will be created (find an example here). If there are no matches, the response is { "matches": [] } and no screening alert is created.

⚠️ Screening alert creation is not guaranteed to complete before the monitoring call is processed. If your scenario relies on $transaction.alerts being populated, wait until screening checks response is returned before making the monitoring checks call.

3. Run monitoring checks

POST /v1/transactions/{transactionId}/monitoring-checks

Once you have the screening checks response, run monitoring checks. Monitoring runs all configured real-time scenarios against the transaction. If a scenario triggers, an alert is created and the response contains a results array ((find an example here). If no scenarios trigger, the response is { "results": [] }.


End-to-end example: auto-reject when no screening alerts exist

This example shows how to fully automate a reject decision for transactions that hit a high-risk monitoring scenario — but only when screening has not flagged them. If screening has flagged the transaction, it goes to manual review instead.

1. Configure the scenario

Create a monitoring scenario with jsonb_array_length($transaction.alerts) = 0 as part of the condition. Give the scenario a name (reason) that clearly identifies it — in this example, the reason includes the word "reject" so it is easy to identify in the API response.

select count(past.id) > 5
and jsonb_array_length($transaction.alerts) = 0,
$transaction.attributes.amount
from transaction past
where past.person_id = $person.id
and past.direction = 'INCOMING'
and past.timestamp >= $transaction.timestamp - interval '30 days'

Configure a dedicated alert status for automatic rejections — for example, one named Auto-rejected with its code set to AUTO_REJECTED. In Configuration → General → Alert Statuses. Additionally, have a decision rule enabled on this status so that when an alert is set to AUTO_REJECTED, Salv fires a decision webhook to your core banking system.

2. Make the API calls

Call screening first, then monitoring:

POST /v1/persons/{personId}/transactions
POST /v1/transactions/{transactionId}/screening-checks
POST /v1/transactions/{transactionId}/monitoring-checks

3. Check the monitoring response

In your backend, inspect the monitoring response. If results is non-empty and contains a result whose reason identifies the auto-reject scenario, extract the alertId:

{
"results": [
{
"reason": "Auto-reject: high incoming velocity, no screening alerts",
"details": "Sum >= 5 000? (Sum: 19 694.05) in last 30 days",
"score": 100,
"weight": 1,
"scenarioType": "ONLINE",
"alertId": 321,
"scenarioHandle": "3871753a-75d7-4b15-80d0-8f9f523611e2",
"relatedTransactions": [
321
],
"includeRelatedTransactions": true
}
]
}

If results is empty, no scenario fired — process the payment normally.

4. Update the alert status

Call the alert status update endpoint with the alertId from the monitoring response and set the status to your configured auto-reject status code:

PUT /v1/alerts/status
{
"alertType": "MONITORING",
"alertId": 1234567,
"status": "AUTO_REJECTED",
"note": "Automatically rejected"
}

5. Decision webhook fires

Because the AUTO_REJECTED status is configured with a decision rule, Salv automatically fires a decision webhook to your configured endpoint:

{
"action": "TRANSACTION_REJECTED",
"createdTime": "2026-01-05T10:15:32.00Z",
"metadata": {
"transactionId": "txn-000123"
}
}

The action field contains the name of the decision rule you configured — in this case instructing your core banking system to reject the payment.

What happens when screening does flag the transaction

If the screening call returns matches, $transaction.alerts will be non-empty by the time the monitoring call runs. The scenario condition jsonb_array_length($transaction.alerts) = 0 evaluates to false — the scenario does not trigger, no monitoring alert is created, and the transaction is held for manual screening review. Your backend receives empty monitoring results and takes no automated action.

Did this answer your question?