SaaS
Reconciliation service for a consumer lending platform
Built by Rafael Bautista
Built the service that matches disbursements and repayments against partner settlement files, and flags what does not line up.
Builder email verified
Verification
- Type
- Professional
- Category
- SaaS
- Published
- Jul 25, 2026
- Updated
- Jul 25, 2026
About this project
- The problem
The lender moved money through four partners, and each sent a settlement file on its own schedule in its own layout. Finance reconciled these in spreadsheets, which took two people most of a week each month and still left a tail of unexplained differences that just carried forward. Beyond the labour, the real risk was that a genuine failure — money that left but never arrived — looked identical to a formatting difference until somebody manually chased it. They needed the matching automated and, more importantly, they needed the exceptions surfaced quickly instead of buried.
- My role
Senior backend engineer, effectively the only engineer on this service for the first four months. I worked directly with the finance lead rather than through a product manager, which was faster and meant I had to learn more accounting than I expected.
- What I owned
I owned the whole service end to end: file intake, the matching engine, the exception model, and the API the internal tool reads from. The matching rules were the substance — exact match first, then amount-and-date within tolerance, then a fuzzy pass on reference strings, with every match recording which rule caught it and why. I built the exception workbench endpoints so finance could accept, split, or annotate a difference without an engineer. I also wrote the daily digest that goes out at 7am with the previous day's unmatched total.
- Technical & product decisions
I made the matching rules data rather than code — each rule is a row with its own tolerances and ordering, editable by finance through an internal screen. The alternative was a rules file we deploy, which is simpler to build and would have made me the bottleneck for every tolerance tweak. I also chose to store every match attempt, not just the winning one; it roughly tripled the table size and it is the only reason anyone can answer 'why did this match'. On storage I stayed with PostgreSQL and used partitioned tables by month rather than reaching for anything columnar, because the query pattern is almost always one month at a time. Go over Node here was mostly about the file parsing throughput and the fact that the platform team already ran Go services.
- Constraints
Everything had to be auditable — the regulator's expectation was that any figure in a report could be traced back to a source line, so nothing could be recomputed on the fly and discarded. Partner files could not be requested on demand; we got what they sent, when they sent it, and one partner's file arrived twice on some days with overlapping rows. I also had no access to production data during development, so all my test fixtures came from anonymised samples the finance lead built by hand.
- Result & impact
The monthly close went from about eight person-days to under one, and the unexplained tail — which had been growing quietly — was cleared and then held near zero. In the first quarter after launch the fuzzy pass surfaced two genuine failed disbursements within a day instead of at month end, which is the outcome finance cared about most. Match rate on the automatic rules settled around ninety-four percent, with the rest going to the workbench, and that number is on the digest so nobody has to ask.
- Who else worked on it
The finance lead defined every rule and tolerance and reviewed the match explanations line by line for the first month. A frontend engineer built the exception workbench against my API in the last six weeks. Our security engineer reviewed the file intake path, which is where she found that I was logging full account references.