Every payment company has the same quiet problem: the money a customer paid, the fee that was charged, and the amount that finally settled to the merchant should all agree. When they don't, someone has to find out why, and that someone is usually looking through spreadsheets.
I built AI Finance Controller, a reconciliation engine that checks payments automatically and flags settlement discrepancies, fee mismatches, and payment lifecycle anomalies. On my adversarial validation datasets it reached 100% precision and 93.7% recall. This post covers how it works and how I tested it.
What goes wrong in payment reconciliation
A single payment passes through several states: created, authorized, captured, settled, and sometimes refunded. Errors appear in a few common ways:
- Fee mismatches: the fee charged is not what the fee schedule says it should be.
- Settlement discrepancies: the amount settled to the merchant doesn't match the sum of the transactions it covers.
- Lifecycle anomalies: a payment skips a state, such as being settled without ever being captured, or is refunded twice.
[Replace with the exact anomaly types your rules cover, and delete any of the above that you didn't implement.]
Why I used deterministic rules, not a model
In finance, every flag has to be explainable. If a system tells an accountant that a transaction is wrong, the next question is "why?" A rule like "fee charged 2.4% but the schedule says 2.0%" answers it. A probability score doesn't.
So I built the validation layer from deterministic rules. Each rule checks one specific invariant, and each flag comes with the rule that raised it.
Architecture
The system is a set of small FastAPI services, each with one job:
- Ingestion service: accepts payment and settlement records through REST endpoints
- Validation service: runs the rule set against matched records
- Reporting: returns flagged anomalies with the reason for each
I used a microservice layout so that rules can change without touching ingestion, and each service can be tested on its own. Everything is containerized with Docker, so the whole system starts the same way on any machine.
A rule, in code
def check_fee_mismatch(payment, fee_schedule, tolerance=0.01):
expected = round(payment.amount * fee_schedule.rate, 2)
if abs(payment.fee_charged - expected) > tolerance:
return Anomaly(
payment_id=payment.id,
type="FEE_MISMATCH",
detail=f"charged {payment.fee_charged}, expected {expected}",
)
return None
[Replace with a short rule from your actual code.]
How I tested it
Easy test data would only prove that the rules work on easy cases. So I built adversarial validation datasets: records designed to be hard, with [describe yours, e.g. fees off by one paisa, partial settlements, out-of-order lifecycle events, duplicate refunds]. Each record is labeled with whether it is a real anomaly, so I can measure results exactly.
| Metric | Result |
|---|---|
| Precision | 100% |
| Recall | 93.7% |
| Dataset size | [N records, M injected anomalies] |
In plain terms: every transaction the system flagged really was an anomaly (no false alarms), and it caught 93.7% of the anomalies I planted.
In reconciliation, I'd rather have that than the reverse. A system that raises false alarms trains people to ignore it.
The 6.3% I missed
Recall of 93.7% means some anomalies got through. Looking at the missed cases was the most useful part of the project
I covered these edge cases with functional and regression tests so that once a case is fixed, it stays fixed.
Try it
- Code: https://github.com/vishal-mundewadi/ai-finance-controller
- Live demo: https://ai-finance-controller-ebon.vercel.app
If you work on payments or finance operations and see edge cases I've missed, I'd like to hear about them in the comments.
Top comments (0)