Alerts and cases
Rules produce hits. People work cases. Between the two sits the alert, which turns a stream of hits into a queue you can work. This page explains each step, what SpeculaPro does automatically, and what each person can do.
rule hit ─▶ suppression check ─▶ alert ─┬─▶ dismissed (false positive, no action, duplicate) │ └─▶ case ─▶ work ─▶ escalate? ─▶ close ─▶ second approval? │ └─▶ STR drafted from the case ─▶ approved ─▶ filed with the FICA hit is one rule version matching one transaction. On its own it is just a fact: “rule D1 v3 matched on Ama’s transaction at 18:02”. Hits are never queued for analysts one by one; there would be far too many.
Every hit is stored, with everything needed to explain it later:
| Recorded | Example |
|---|---|
| The rule and the exact version | core.fan_in, version 3 |
| The subject | The customer, account or counterparty the rule is about |
| The transaction | Which one, and when it happened |
| Severity and score | From the rule version |
| The feature values the rule saw | senders_7d = 21 |
| The parameters it used | min_senders = 15 |
| The explanation | “21 different senders paid this account in 7 days.” |
| Shadow or live | Whether it came from a shadow version |
| Suppression | Which suppression covered it, if any |
A transaction can only produce one hit per rule version, even if it is processed twice.
Hits that don’t raise alerts
Section titled “Hits that don’t raise alerts”Some hits are stored as evidence but never reach the alert queue:
- Shadow hits, from a version deployed in the shadow slot to be compared with the live one. See Shadow mode.
- Suppressed hits, covered by an approved, unexpired suppression. The hit records which suppression covered it, so an auditor can see what was suppressed and why. A suppression still waiting for approval has no effect.
- Hits from rules whose action only records. A rule version’s action decides what a hit
does.
alert,review,blockandstep_upraise alerts.tag,score_onlyandallowonly record the hit. See Rules and versions.
Alerts
Section titled “Alerts”An alert gathers the live hits about one subject.
Who an alert is about
Section titled “Who an alert is about”The subject is the customer, account or counterparty the rule is about: its entity scope.
| Rule’s scope | The alert is about |
|---|---|
customer |
The customer, across all their accounts |
account |
One account |
counterparty |
The outside party, for example a wallet that many of your customers pay |
Most rules in the shipped packs are about the customer; D7 (many of your customers paying one counterparty) is about the counterparty. See Pack contents.
How hits become alerts
Section titled “How hits become alerts”There is at most one open alert per subject of each kind (see AML and fraud alerts). When new hits arrive for a subject:
- if the subject has no open alert, one is created;
- if it has one, the hits are added to it, however long ago it was opened;
- if the subject is already in an active case of the same kind, the new alert goes straight into that case (see Alerts that join a case automatically).
Suppose three rules match the same customer on the same evening. Without merging, three analysts might each investigate the same customer. With merging, there is one alert with three hits, and one analyst sees the whole picture.
When hits are added, the alert’s fields change like this:
| Field | Meaning | When a hit is added |
|---|---|---|
| Subject | Who or what it is about | Never changes |
| Severity | low, medium, high or critical |
Raised to the hit’s severity if that is higher; never lowered |
| Score | Orders the queue within a severity | Raised to the hit’s score if higher (the highest, not a sum) |
| Hit count | How many hits it holds | Goes up |
| Rules | The distinct rules that contributed, for example core.fan_in, gh.wallet_sweep_to_bank |
The hit’s rule is added if new |
| Exposure | The total value, in base currency, of the transactions behind its hits | The transaction’s value is added. A transaction hit by several rules at once counts once |
| Summary | What to read first | Replaced by the explanation of the most recent hit |
| First and last hit | When the activity started and when it was last seen | Widened to include the hit’s transaction time |
| Kind | aml for post-event rules, fraud for real-time rules (see below). The kinds sanctions and other are reserved: nothing raises them yet |
Never changes |
AML and fraud alerts
Section titled “AML and fraud alerts”Alerts come in two kinds, depending on where their hits came from:
| Kind | Raised by | Example rules |
|---|---|---|
aml |
Post-event rules, run after a transaction is recorded | core.fan_in, gh.wallet_sweep_to_bank |
fraud |
Real-time rules that fired while the decision API was answering, with the action block, review or step_up; and every payment answered by the failure policy because the checks couldn’t run in time (system.degraded_decision), whether it was allowed (fail-open) or held (fail-closed) |
fraud.card_testing, gh.sim_swap_payout |
The two kinds never merge: a customer can have an open AML alert and an open fraud alert at the
same time. Both appear in the same alert queue and are worked the same
way. In the queue, a fraud alert carries a FRAUD tag beside the subject; an AML alert has no
tag. Through the API, each alert has a kind field.
Cases are kept apart in the same way. A case opened from a fraud alert is recorded with the kind
fraud, and only fraud alerts join it; AML alerts join only an AML case. So a customer can have an
active AML case and an active fraud case at the same time, each with its own owner and deadline.
A payment answered by the decision API is also run through the post-event rules afterwards, so the same payment can contribute to both kinds.
The alert queue
Section titled “The alert queue”Open alerts are ordered by risk: critical first, then high, medium and low; within a severity, highest score first; then the most recent activity. You work the queue from the top.
Alert status
Section titled “Alert status”| Status | Meaning | How it gets there |
|---|---|---|
open |
Waiting for someone to look at it | Created by the stream evaluator |
in_case |
Part of a case; you now work the case, not the alert | Someone opened a case from it, or it joined the subject’s active case automatically |
closed |
Finished, with a disposition | Dismissed, or its case was closed |
A closed alert records its disposition, who closed it and when, and, if it was dismissed with
one, the rationale. The alert page shows all of these; the rationale only to people who can view
customers (entities.view), because it can name the customer.
Once an alert is no longer open, the next hit about the same subject starts a new alert.
What you can do with an open alert
Section titled “What you can do with an open alert”You have two choices, both needing the cases.work permission (Analyst, Senior analyst and
MLRO by default):
- Dismiss it with a disposition, if a quick review shows there is nothing to investigate.
- Open a case from it, if it needs investigating.
Dismissing records one of these alert dispositions:
| Disposition | Use it when |
|---|---|
false_positive |
The activity has a clear, legitimate explanation you checked |
no_action |
The alert is accurate but needs nothing further, for example activity already known and documented |
duplicate |
Another alert or case already covers the same activity |
A fourth value, escalated_to_case, is set by SpeculaPro itself on every alert in a case when
the case is closed. You can’t choose it.
A note is optional when dismissing, but write one whenever the reason isn’t obvious: dismissals are counted in each rule’s false-positive rate, and the note is what tells a rule owner why. Only open alerts can be dismissed; an alert already in a case is closed with its case.
Advice from the AI assistant
Section titled “Advice from the AI assistant”A workspace can switch on an AI assistant that reads an open alert and says whether it looks like a false positive or needs investigating, with its reasons. It is advice only: it never dismisses an alert, opens a case or changes anything, and it is never shown as false positive for sanctions alerts, critical alerts or alerts about PEPs and sanctioned subjects. The person who dismisses the alert or opens the case decides, and answers for it. It is off until an administrator switches it on; see AI assistant settings.
On a case, the same assistant can write a summary for whoever picks the case up: what it is about, the facts that matter and what is still open, with a suggestion of what to do next (looks like a false positive, a report may be warranted, needs more investigation, or not enough to tell). The suggestion is advice and changes nothing on the case: it is never false positive for sanctions cases, critical cases or cases about PEPs and sanctioned subjects, and closing a case or filing a report stays a person’s decision.
Two things make this quicker without changing who decides. A person can ask the assistant about the whole queue at once (every open alert without advice, or every case being worked without a summary), and a person can close several open alerts together with one outcome and one written reason. The assistant never closes anything; a bulk close is a person’s request, refused for sanctions alerts, critical alerts and alerts about PEPs, their relatives and close associates, sanctioned subjects, or an account one of them owns (together, held alerts). See Asking about the whole queue and How to close several alerts at once.
A case is the file you investigate. It belongs to one subject and collects every alert about that subject while it is active.
How to open a case from an alert
Section titled “How to open a case from an alert”When you open a case from an open alert:
-
If the subject already has an active case of the same kind (any status except
closed), the alert joins that case. No second case is created. An AML alert never joins a fraud case, nor a fraud alert an AML case: each gets a case of its own kind. If the alert is more severe than the case’s priority, the case’s priority is raised to match (see More serious activity raises the priority). -
Otherwise a new case is created:
- it gets the next number in your workspace, in the form SP-2026-000123 (the year it was opened, in UTC, then a six-digit sequence that keeps counting across years);
- its title is the subject’s name plus the alert’s summary;
- its priority is the alert’s severity (a critical alert makes a critical case);
- it is assigned to you, with status
open; - its SLA deadline is set from the priority. See Escalation and SLAs.
If your workspace has escalation policies, the first one that fits the new case decides its starting level, its team queue and its deadline. A case whose policy starts it at level 2 or 3 opens
escalatedand unassigned, for that level to take, instead of being assigned to you.
Either way the alert becomes in_case, the case’s score is raised to the alert’s score if
higher, and an alert_linked event is added to the case timeline. Asking again for an alert
that is already in a case simply returns that case.
Alerts that join a case automatically
Section titled “Alerts that join a case automatically”While a subject has an active case, SpeculaPro adds new alerts of the same kind about it
straight into the case, without anyone acting. The timeline shows an alert_linked event by the system,
listing the rules that fired, and the case’s score is raised if the new alert scores higher.
These alerts never appear in the open queue.
So a customer under investigation has one case that keeps growing, not a scatter of separate files.
New activity doesn’t pile up as a stream of tiny alerts either. While the case is active, new hits about the subject are added to the case’s most recent alert: its hit count and exposure grow, its rules list gains any new rule, and its severity rises if the new hits are more severe. A separate new alert is only created when the case has no alert of its own still attached, for example just after it was reopened, and that alert then joins the case automatically.
More serious activity raises the priority
Section titled “More serious activity raises the priority”If an alert joining a case, by hand or automatically, is more severe than the case’s current priority, the case’s priority is raised to match. Its SLA deadline becomes whichever is sooner: the deadline it already had, or now plus the new priority’s SLA. Priority is never lowered this way.
For example (illustrative): a case opened as low on Monday at 09:00 is due the following Monday. On Tuesday at 10:00 a critical alert about the same customer joins it. The case becomes critical and is now due Tuesday at 14:00, four hours later.
The timeline shows why: a status_changed event with the new priority and the reason “a
higher-severity alert joined” when a person added the alert, or an alert_linked event by the
system carrying the new priority when it happened automatically.
What a case holds
Section titled “What a case holds”| Field | Values |
|---|---|
| Number | SP-2026-000123, unique in your workspace |
| Title | Subject name and the first alert’s summary |
| Kind | aml or fraud, from the alert it was opened from |
| Status | open, in_progress, escalated, pending_approval, closed |
| Priority | low, medium, high, critical |
| Score | The highest score of its alerts |
| Assignee | Who is working it, or nobody |
| Escalation level | 1 to 3 |
| Team queue | The team whose queue it is in, or none |
| Escalation policy | The policy it follows, if one fitted when it was opened |
| SLA due | The deadline at the current level |
| Deadline missed | When the current deadline was recorded as missed, if it was |
| Disposition and note | Set when it is closed, or proposed for closure |
| Alert count and exposure | How many alerts it holds and the total value behind them |
| Evidence files | The documents people added to it, each with its name, size, SHA-256 and who added it. See Evidence files |
Case status
Section titled “Case status”open ─────── start or assign ──────▶ in_progressopen ──────────── escalate ────────▶ escalatedin_progress ───── escalate ────────▶ escalatedescalated ─────── start ───────────▶ in_progress
open, in_progress or escalated ── close ──▶ closed (low and medium priority)open, in_progress or escalated ── close ──▶ pending_approval (high and critical priority, four eyes for all, or the case's escalation policy)pending_approval ── approve ──▶ closedpending_approval ── reject ───▶ in_progressclosed ──────────── reopen ───▶ in_progress| Status | Meaning |
|---|---|
open |
Created and waiting to be worked. |
in_progress |
Someone is working it. |
escalated |
Sent up a level and unassigned, waiting for someone at that level to pick it up. See Escalation and SLAs. |
pending_approval |
Someone has proposed closing it, and a second person must approve. |
closed |
Finished, with a disposition. |
“Active” means every status except closed.
Working a case
Section titled “Working a case”| Action | What it does | Allowed when | Permission |
|---|---|---|---|
| Start | Moves open or escalated to in_progress. If nobody is assigned, assigns it to you |
open, escalated |
cases.work |
| Take (assign to yourself) | Makes you the assignee. An open case becomes in_progress; an escalated case stays escalated until someone starts it |
Not closed |
cases.work |
| Unassign | Removes the assignee, returning the case to the pool | Not closed |
cases.work |
| Assign to someone else | Gives the case to another active user in your workspace | Not closed |
cases.work and cases.approve (supervisors) |
| Comment | Adds a note to the timeline | Any status, including closed | cases.work |
| Escalate | Up one level, with a reason. See Escalation and SLAs | open, in_progress, escalated |
cases.work |
| Put in a team’s queue | Puts the case in a team’s queue, moves it to another or takes it out. The assignee keeps the case | Not closed |
cases.work |
| Close | Closes, or proposes closure, with a disposition and note | open, in_progress, escalated |
cases.close |
| Approve / reject closure | The second person’s decision | pending_approval |
cases.approve |
| Reopen | Brings a closed case back, with a reason | closed |
cases.approve |
An action that doesn’t fit the case’s current status is refused, and nothing changes.
Assignment
Section titled “Assignment”A case is assigned to one person or unassigned. Separately, it can sit in one team’s queue, which says whose work it is without naming a person.
- When you open a case, it is assigned to you.
- Analysts can take a case or unassign it, but only a supervisor (anyone with
cases.approve, by default the MLRO) can give a case to someone else. - Escalating unassigns the case so someone at the next level can take it, and moves it to the team queue its escalation policy names for that level, or out of any queue.
- A case whose escalation policy starts it above level 1 opens unassigned.
- Reopening assigns the case to the person who reopened it.
The case timeline
Section titled “The case timeline”Everything that happens to a case is an event on its timeline, with who did it and when:
| Event | Recorded when | By |
|---|---|---|
created |
A case is opened from an alert; records the number and the alert and, when a policy fitted, the policy’s name and the starting level | The person |
assigned |
Someone is assigned or unassigned (also at creation, unless the case opens unassigned at a higher level) | The person |
team_assigned |
The case is put in a team’s queue, or taken out of one, by hand | The person |
alert_linked |
An alert joins the case. For automatic links, also when new activity raises the case’s priority (the event then carries the new priority) |
The person, or the system for automatic links |
comment |
Someone writes a note | The person |
status_changed |
Someone starts work (open or escalated → in_progress), or an alert added by a person raises the priority (records the new priority and the reason) |
The person |
escalated |
The case goes up a level; records the levels, new priority, reason and, when there is one, the policy and the new team | The person, or the system when a missed deadline escalated it |
sla_breached |
The case’s deadline passed while it was still open; records the deadline and the level | The system |
approval_requested |
A closure is proposed and waits for a second person; records the disposition and note | The person |
disposition_set |
The case is closed directly; records the disposition and note | The person |
approved / rejected |
The second person’s decision, with an optional note | The approver |
reopened |
A closed case is reopened; records the reason | The person |
attachment_added |
An evidence file is added; records the file’s ID, name, size and SHA-256 | The person |
attachment_removed |
An evidence file is removed; records the file’s ID, name, SHA-256 and the reason | The person |
report_linked |
An STR is drafted from the case; records the report’s ID, number and type | The person |
Every action a person takes on an alert or a case is also written to the audit log in the same database transaction, and so is every alert the system links to a case by itself.
Evidence files
Section titled “Evidence files”A case keeps the documents an investigation collects: an ID document, a statement, the customer’s
letter, an email. Anyone with cases.work adds a file to a case that isn’t closed, up to 10 MB
each and 50 files a case, as pdf, png, jpg, jpeg, webp, txt, csv, eml, msg,
docx or xlsx. The content must be what the extension says, but files are not scanned for
malware.
- Protected. Each file is encrypted with the workspace’s key and stored with the case. Its SHA-256 is recorded on arrival and checked on every read.
- Downloaded, never displayed. A file is always saved to your computer, never shown in the
app. Downloading needs
entities.viewas well ascases.view, and every download is written to the audit log. - Removed with a record. The person who added a file, or anyone with
cases.approve, can remove it with a reason. The content is deleted for good; the record (name, SHA-256, who added it, who removed it and why) stays. A file that goes with a report no longer in draft can’t be removed. - Hidden names. People without
entities.viewsee File 1.pdf in place of each name, no notes, and can’t download.
See Evidence files for the steps.
Closing a case
Section titled “Closing a case”A case can only be closed with a disposition (the decision you reached) and a note of at least three characters explaining it. Regulators and auditors read this note.
| Disposition | Use when |
|---|---|
false_positive |
After investigation, nothing suspicious. These figures feed rule tuning. |
true_positive_no_report |
The rule was right to fire and the activity is unusual, but it doesn’t meet the threshold for reporting, for example because documents the customer provided explain it. |
report_filed |
You have filed, or are filing, an STR or other report. |
customer_exited |
The institution has ended the relationship. |
duplicate |
Already covered by another case. |
other |
Anything else, explained in the note. |
See Choosing a disposition for how to decide.
When a case closes, every alert in it that is still open is closed too, with the disposition
escalated_to_case.
Four-eyes closing
Section titled “Four-eyes closing”Closing needs cases.close: by default Senior analyst and MLRO. Analysts can work a
case but can’t close it.
Some closures need a second person:
| Case priority | What happens when you close |
|---|---|
low, medium |
The case closes at once (status closed) |
high, critical |
The case goes to pending_approval. Your disposition and note are recorded as a proposal |
| Any, if your workspace requires four eyes for all closures | pending_approval |
| Any, if the case follows an escalation policy with A second person closes | pending_approval |
The Close case panel tells you before you confirm whether your closure will need a second approver, and why. See Closing and approving.
A person with cases.approve (by default the MLRO) then:
- approves: the case is
closed, with your disposition, and its alerts close; or - rejects: the case goes back to
in_progresswith the same assignee, and the proposed disposition is cleared. Add a note saying what’s missing.
How to require four eyes for every closure
Section titled “How to require four eyes for every closure”By default only high and critical cases need a second person. To require it for every case, an
administrator (settings.manage):
- Selects Settings, then the Workspace tab.
- Under Security and approvals, ticks Second approver for every case closure.
- Selects Save changes.
It applies to the next closure proposed. Closures already waiting for approval stay as they are, and a medium or low case closed before the change stays closed. Switching it off again returns to the default. See Workspace settings.
Reopening a case
Section titled “Reopening a case”If new information comes to light, someone with cases.approve can reopen a closed case,
giving a reason. The case:
- goes back to
in_progress, assigned to the person who reopened it; - loses its disposition, so it must be closed again with a fresh one;
- gets a new SLA deadline from its current priority.
The original closure stays on the timeline, followed by the reopened event, so nothing is
lost. Alerts closed with the case stay closed; new activity on the subject joins the reopened
case automatically.
Reports
Section titled “Reports”When an investigation gives grounds to suspect, someone with reports.draft and
entities.view_pii drafts a suspicious transaction report (STR) from the case with Draft
STR. SpeculaPro pre-fills it from the case and adds a report_linked event to the timeline. A
second person approves it, it is exported as goAML XML and uploaded to the FIC, and the FIC’s
reference and answer are recorded on it:
draft ─▶ pending_approval ─▶ approved ─▶ submitted ─▶ acknowledged ▲ │ └─▶ rejected └─ sent back ─┘The approver must be different from the person who drafted it and the person who sent it for
approval; the database enforces this. The report and the case are separate: drafting or filing a
report doesn’t close the case, so close it as report_filed yourself. See
Regulatory reporting.
Notifications
Section titled “Notifications”SpeculaPro tells people by email, text message or WhatsApp when a case is assigned to them, when a closure needs their approval and how it was decided, when a case is escalated to their level, when a case arrives in their team’s queue, when a critical alert is raised, when a case is due within the hour, when it has missed its deadline and when it was escalated automatically. Each person chooses their channels under Settings → Notifications. There is no inbox in the app. See Notifications.