FinTech
Real-time fraud detection inside the transaction flow
A payments platform scores every transaction for fraud while it is being processed. The Deep Netts model runs inside the Java payment service itself – no Python scoring service, no network hop.
30%
reduction in fraud losses
ms
decision latency, in-process
0
extra Python infrastructure
How it works – the animation
- 0
- Scored
- 0
- Approved
- 0
- Blocked
- 0
- Last score
Every payment passes through the platform's Java service. Fraud is a small fraction of them, and its patterns keep changing – rules alone are easy to bypass.
Case: payments platform, not named – 30%, ms and 0 from the case. Features, model, 0.70 threshold, benchmark and test results: Deep Netts talk “AI in Java for the Financial Industry”, Amsterdam JUG at ING, Oct 2026 (an example model, not the customer's). Payments drawn are illustrative.
1.In short
- A payments platform has to decide for every payment, while it is being processed, whether it looks like fraud.
- Sending each payment to a separate Python scoring service added a network hop, more infrastructure and a second stack to run.
- With Deep Netts the fraud model runs inside the Java payment service itself: it is loaded once and scores each payment in the same JVM.
- The customer reports 30% lower fraud losses, decisions in milliseconds and no extra Python infrastructure.
2.The problem
Fraud is a tiny fraction of all payments, and its patterns keep changing. The talk quotes a projection of $33 billion lost to payment-card fraud worldwide every year (The Nilson Report).
Fixed rules ("block payments over X from country Y") are simple, but they age fast and fraudsters learn to step around them. A machine learning model learns the patterns from the transaction history instead, and can be retrained when they change.
3.What the system must do
| Requirement | Why it matters |
|---|---|
| Low latency | A payment cannot wait. High transaction rates call for several small, fast models. |
| High scalability | Volume peaks (holidays, sales) must not slow scoring down. |
| Infrastructure and cost | Every extra service is more machines, more monitoring and more people to run it. |
| Integration | The model has to fit into the infrastructure that already processes the payments. |
4.What the model sees
A model does not see a payment – it sees numbers built from it. The talk groups the usual inputs for fraud detection into four families:
| Family | Examples |
|---|---|
| Core attributes | Amount, time of day, merchant category |
| Spatial context | Cross-border flag, distance from the last transaction, distance from home |
| Velocity and frequency | Number of transactions in the last 5 / 10 / 30 minutes, 1 hour, 24 hours; number of merchants in the last 5 / 10 / 30 minutes |
| Derived features | Ratio to the customer's median purchase, combinations of the indicators above |
The 8 inputs of the example service
The Spring Boot service shown in the talk builds 8 numbers for every payment – the same 8 the animation shows next to the network:
| # | Input | Meaning |
|---|---|---|
| 1 | amount | How much the payment is for |
| 2 | crossBorder | 1 if the card and the merchant are in different countries, else 0 |
| 3 | attemptsLast30Min | Payment attempts with this card in the last 30 minutes |
| 4 | minutesSincePreviousTransaction | Time since the card's previous payment |
| 5 | distanceFromPreviousTransactionKm | How far this payment is from the previous one |
| 6 | differentMerchantsLast30Min | Different merchants in the last 30 minutes |
| 7 | customerCategory | The customer's segment, as a number |
| 8 | productCategory | What is being bought, as a number |
5.Where Deep Netts comes in
Everything happens in one process – the payment never leaves the JVM to be scored:
Payment arrives
The Java payment service receives the transaction.
Features
The service turns it into the 8 numbers above.
- Deep Netts
Fraud model
A feed-forward network, loaded once at start-up, returns a probability 0–1.
Decision
0.70 or more: block. Below: approve and continue.
Before, the third box was a separate Python service: one more network call per payment, one more deployment, one more runtime to monitor. Now it is a method call.
6.Three models to choose from
Deep Netts has the three models the talk recommends for fraud out of the box. All three are built with the same builder and answer the same question: how likely is it that this payment is fraud.
Logistic regression – the baseline
The simplest classifier: one weight per input, a probability out. Easy to explain (each weight says how much an input matters) and a good first baseline.
CreditCardFraudLogisticRegression
FeedForwardNetwork logReg = FeedForwardNetwork.builder()
.addInputLayer(numInputs)
.addOutputLayer(1, SIGMOID)
.lossFunction(CROSS_ENTROPY)
.build();Feed-forward neural network – the one in the animation
Logistic regression with hidden layers in between. The hidden layers let the model combine inputs (a small amount, but abroad, the fifth attempt in ten minutes …) and catch patterns a single weight per input cannot – higher precision and fewer missed frauds.
FraudDetectionNN.java
FeedForwardNetwork neuralNet = FeedForwardNetwork.builder()
.addInputLayer(numInputs)
.addFullyConnectedLayer(32, ActivationType.RELU)
.addFullyConnectedLayer(16, ActivationType.RELU)
.addOutputLayer(numOutputs, ActivationType.SIGMOID)
.lossFunction(LossType.CROSS_ENTROPY)
.build();Auto-encoder – anomaly detection
Learns only from normal payments what "normal" looks like, and flags what it cannot reproduce. Useful when there are too few labelled frauds to train a classifier.
CreditCardFraudAutoencoder
FeedForwardNetwork autoencoder = FeedForwardNetwork.builder()
.addInputLayer(numInputs)
.addFullyConnectedLayer(5)
.addFullyConnectedLayer(3)
.addFullyConnectedLayer(5)
.addOutputLayer(numInputs, SIGMOID)
.lossFunction(MEAN_SQUARED_ERROR)
.build();7.Training
Training shows the model past payments with the answer (fraud or not) and lets it reduce its error step by step. Three settings decide when it stops and how big each step is:
Training the network
neuralNet.getTrainer()
.setStopEpochs(10000) // at most this many passes over the data
.setStopError(0.15f) // or stop when the error is this low
.setLearningRate(0.01f); // how big each correction is
neuralNet.train(trainingSet);8.Inside the payment service
The trained model is a file. The service loads it once when it starts, and from then on every payment is one predict call in memory. The threshold is configuration, so it can change without a new release.
FraudDetectionService.java (Spring Boot)
@Service
public class FraudDetectionService implements AutoCloseable {
private final String modelPath;
private final double threshold;
private FeedForwardNetwork network;
public FraudDetectionService(@Value("${fraud.model-path}") String modelPath,
@Value("${fraud.threshold:0.70}") double threshold) {
this.modelPath = modelPath;
this.threshold = threshold;
}
@PostConstruct
public void loadModel() throws IOException {
network = NeuralNetwork.load(modelPath, FeedForwardNetwork.class);
}
public FraudResponse predict(FraudRequest request) {
float[] features = new float[] {
request.amount().floatValue(),
request.crossBorder() ? 1.0f : 0.0f,
request.attemptsLast30Min().floatValue(),
request.minutesSincePreviousTransaction().floatValue(),
request.distanceFromPreviousTransactionKm().floatValue(),
request.differentMerchantsLast30Min().floatValue(),
request.customerCategory().floatValue(),
request.productCategory().floatValue()
};
float[] output = network.predict(features);
double prob = output[0];
return new FraudResponse(prob, prob >= threshold, threshold);
}
}9.How good is it
The talk tests the example network on 200,000 payments it did not see in training. Every payment ends in one of four boxes:
| Really fraud | Really good | |
|---|---|---|
| Model said fraud | 11,447 caught (true positive) | 1,445 good payments blocked (false positive) |
| Model said good | 6,034 frauds missed (false negative) | 181,075 correctly approved (true negative) |
| Measure | Value | In plain words |
|---|---|---|
| Accuracy | 96.26% | How often the model is right overall |
| Precision | 88.79% | Of the payments it blocks, how many really are fraud |
| Recall | 65.48% | Of all frauds, how many it catches |
| F1 score | 75.38% | One number that balances precision and recall |
10.The 0.70 threshold
The network does not say "fraud" or "not fraud" – it gives a probability. The service turns it into a decision with a threshold, 0.70 by default in the example.
- A lower threshold blocks more: more frauds caught (higher recall), but more good customers stopped (lower precision).
- A higher threshold blocks less: fewer false alarms, but more frauds slip through.
- Because the threshold is a configuration value, the fraud team can move it without retraining or redeploying the model.
11.Speed and hardware
Deep Netts can use the Java Vector API (CPU) or an Nvidia GPU through CUDA – switched on with a JVM option and one line of code:
Hardware acceleration
// Vector API – JVM option: --add-modules jdk.incubator.vector
DeepNetts.getInstance().setUseVectorAPI(true);
// Nvidia GPU / CUDA – JVM option: --enable-native-access=ALL-UNNAMED
DeepNetts.getInstance().setUseCuda(true);| Dataset | CPU, single thread | Vector API | GPU |
|---|---|---|---|
| 1M rows | 1,238 ms | 554 ms (2.2×) | 595 ms (2.1×) |
| 10M rows | 11,763 ms | 5,847 ms (2.0×) | 1,285 ms (9.2×) |
| 20M rows | 25,587 ms | 11,884 ms (2.2×) | 2,684 ms (9.5×) |
| 50M rows | 62,957 ms | 31,716 ms (2.0×) | 6,680 ms (9.4×) |
12.Results for the customer
| Result | |
|---|---|
| Fraud losses | 30% lower |
| Decision time | Milliseconds, in-process – inside the JVM that processes the payment |
| Extra infrastructure | None – no separate Python scoring service |
| Way of working | The fraud team iterates on models with the tools the platform team already runs |
13.Glossary
- In-process
- Running inside the same program (here: the same JVM), so no network call is needed.
- Feature
- A number the model gets as input, built from the payment and its history.
- Feed-forward network
- The classic neural network: numbers in, layers of neurons, a score out.
- ReLU, sigmoid
- Activation functions. ReLU in the hidden layers; sigmoid squeezes the output into 0–1.
- Cross-entropy
- The error measure used to train a yes/no classifier.
- Threshold
- The probability above which a payment is blocked (0.70 in the example).
- Precision
- Of the blocked payments, the share that really were fraud.
- Recall
- Of all frauds, the share the model caught.
- Auto-encoder
- A network that learns to reproduce normal data; what it cannot reproduce is suspicious.
- Vector API
- A Java API that uses the CPU's vector instructions to do many calculations at once.
14.Sources
- Deep Netts, "AI in Java for the Financial Industry", talk at ING, Amsterdam – models, code, test results and benchmark on this page.
- The Nilson Report, as quoted in the talk – the $33B annual payment-card fraud projection.
- The customer's case (the customer is not named) – 30% lower fraud losses, in-process decisions, no Python service.
Have a workload like this?