A risk decision has three audiences, and they are not the same. The system carrying the transaction needs an answer in the moment: proceed, hold, or stop.
The systems around it need a durable record of what was decided, so they can route, notify, reconcile, and learn. And a human needs to open any single decision later and understand exactly why it went the way it did.
Most platforms serve one of these well and improvise the other two. Loci exposes a purpose-built surface for each, and all three show the same decision, described the same way.
The thread that runs through them is the platform's whole reason to exist: every decision a machine makes should be readable, defensible, and re-runnable by the human who asked for it. Below is how that decision reaches you three times, and what to do with it each time.
Surface one: the synchronous decision, in the moment
You send a transaction; Loci returns a decision before the transaction proceeds. This is the surface that gates the flow.
You post the transaction and the context that gives it meaning: the entity, the amount and direction, the timing, and any fields your controls reference. Loci evaluates the active controls against the entity's baseline behavior and returns a decision fast enough to sit inside the transaction flow rather than beside it.
In benchmarking (see the note below) the end-to-end path measured 21 to 49 ms at p95. The fields you act on:
| Field | Meaning | How downstream systems use it |
|---|---|---|
decision | approve, review, or decline | The primary control signal. Let approvals through, route reviews to step-up or a queue, stop declines before settlement. |
fraud_score | Composite risk on a normalized 0 to 100 scale | Feed your own tiered handling. A review at 32 is not a review at 71. |
decision_reason | Plain-language explanation of the outcome | Log it with the transaction; surface it to whoever or whatever handles a held transaction. |
decision_source | Which layer drove the outcome: a blocking action, a critical control, or the score band | Tells you whether a decline came from a hard control or a score threshold, which changes how you treat borderline cases. |
data.triggeredRules | The controls that fired, with their weights and scores | The evidence behind the number. Attach to the case, and step up only when a specific control fired. |
policy.thresholds | The approve, review, and decline bands in force | Lets a client render or reconcile the decision against the org's current policy. |
The design point: the decision and its reasons arrive together, in one response, fast enough to sit inside the transaction flow. You are not given a score and left to guess. You are given the outcome, the band it fell in, and the named controls that produced it.
Surface two: the decision as a durable event
The synchronous response tells the transaction flow what to do. It does not, on its own, feed everything else that needs to know. That is the webhook's job.
Loci emits a decision.created event for every successful evaluation that produces a decision, approvals included, delivered durably with retries and signed so you can trust its origin. A request that fails validation or cannot be evaluated returns an error and produces no decision event.
Every event shares one envelope:
| Field | Meaning |
|---|---|
event_id | Stable id for this event. Use it as your idempotency key so a redelivery is a no-op. |
event_type | decision.created. The same channel carries control and screening events under their own types. |
event_version | The envelope contract version, so your parser can evolve safely. |
occurred_at | When the decision was made. |
org_id | The organization the decision belongs to. |
data | The decision itself. |
Inside data you get the same outcome the synchronous response carried (decision, fraud_score, decision_reason, whether it was flagged or approved), the controls that triggered, and the transaction as evaluated.
Every delivery carries a signature header derived from a secret only you and Loci hold, plus a timestamp, so your endpoint can verify the event is genuine before acting on it.
What this surface is for:
- Case and workflow systems. Turn a review or decline into a case, route it to an inbox, notify a team. The event carries the evidence, so the case opens with the reasons already attached.
- Analytics and the warehouse. Because the event fires on every decision, not only the flagged ones, your base rates are complete. Approvals are signal too.
- Ledgers and downstream records. Annotate the transaction record with the decision and its reason, so your system of record and Loci agree.
- Notifications and alerting. Fire on the outcomes that matter to you, filtered to the decision bands you care about.
The distinction from surface one is timing and durability. The synchronous response is for the decision you must act on now. The event is for every system that needs the decision recorded, delivered reliably, and consumed on its own schedule.
Surface three: the single decision, for the human
Numbers and events serve machines. A person reviewing an alert needs the decision opened up: not a score, but the case for the score.
The control plane's single-transaction view is that surface. It takes one decision and lays out everything behind it on one screen.
What the analyst sees, and works with:
- The recommended action and why it was flagged, in plain language, at the top. No hunting.
- The controls that fired, named, so the reviewer knows which behavior triggered the alert rather than inferring it from a total.
- The score in its bands, shown against the org's approve, review, and decline thresholds, so a borderline case reads as borderline.
- The entity's recent activity and network risk, giving the transaction its context. A single transfer means one thing from a dormant account and another from a busy one.
- A one-click disposition. Approve or mark as fraud in place, which closes the loop and feeds the record.
This surface is where the platform's promise gets tested, because it is where a human either can or cannot defend the decision.
Every element on the screen traces to a control someone authored and a value the engine computed. So the answer to "why did this happen?" is always available, and the answer to "was this right?" becomes a decision the reviewer records rather than a mystery they inherit.
One decision, three surfaces, one truth
The reason these three surfaces agree is that they are not three systems producing three views. They are three windows onto the same evaluated decision.
The outcome and its reason in your synchronous response, the data in your webhook event, and the summary on the analyst's screen are the same facts, formatted for the moment each one serves: the transaction flow that must act, the systems that must record, and the person who must review.
Field names and nesting differ by surface, so read each contract for exact paths. The facts underneath do not change.
Build against them accordingly. Gate the flow on the synchronous decision. Feed your records, cases, and analytics from the event. Send your analysts to the single-decision view when a human needs to look.
Each surface gives you the outcome, the reasons, and the evidence, because in a system built so that every decision can be read and defended, there is no other kind of output to give.
See the three surfaces on your flow
A short technical walkthrough: the synchronous decision, the signed event, and the single-decision view a human can defend.