PROJECT STUDY
Ledger & Reconciliation
Every rupiah traced, every gap explained.
Payment reconciliation for Indonesian finance teams: QRIS, virtual account and e-wallet payments on a balanced ledger, matched to provider settlements and bank statements with reasons.
Explore the build
At a glance
- Industry
- Finance
- Capabilities
- 6
- Technologies
- 8
- Year
- 2026
The challenge
Indonesian businesses take payments through QRIS, virtual accounts at several banks, e-wallets and card gateways, and providers settle in batches, net of fees, sometimes days later.
Finance teams reconcile orders, provider settlements and bank statements by hand in spreadsheets, so partial payments, duplicates, refunds and late settlements can take days to resolve.
The work needs more than a match rate. Every figure in a cash report has to lead back to the journal that produced it, and every correction has to leave a trail that an auditor can follow.
What we built
Ledger & Reconciliation connects payment events, a double-entry ledger and statement matching in one TypeScript product, with a workbench where the finance team confirms what the engine suggests.
A balanced, append-only ledger
Accounts and journals in whole rupiah, where every journal's postings sum to zero, a correction is a reversal entry rather than an edit, and any balance can be read as of a point in time
Verified payment webhooks
Events from a QRIS acquirer, a bank virtual account and an e-wallet are checked for an HMAC signature and a fresh timestamp, de-duplicated and applied through a payment state machine
Explainable matching
Provider settlement and bank statement CSVs are matched against the ledger by exact reference, deterministic rules and fee-aware amount and date windows, and many-to-one batch settlements are solved as a bounded subset-sum. Every match records its reason and a confidence
A reconciliation workbench
Statement lines sit on one side and ledger items on the other, with suggested matches and their reasons in between, next to an exceptions inbox and a journal explorer
Exceptions closed by journal
Unmatched lines, amount mismatches, duplicates and late settlements are assigned and resolved, and each resolution posts an adjusting journal
Reports that open their journals
Daily cash position, fee (MDR) analysis per channel and ageing of unreconciled items, with every figure traceable to the journals behind it
A balanced, append-only ledger
Accounts and journals in whole rupiah, where every journal's postings sum to zero, a correction is a reversal entry rather than an edit, and any balance can be read as of a point in time
Verified payment webhooks
Events from a QRIS acquirer, a bank virtual account and an e-wallet are checked for an HMAC signature and a fresh timestamp, de-duplicated and applied through a payment state machine
Explainable matching
Provider settlement and bank statement CSVs are matched against the ledger by exact reference, deterministic rules and fee-aware amount and date windows, and many-to-one batch settlements are solved as a bounded subset-sum. Every match records its reason and a confidence
A reconciliation workbench
Statement lines sit on one side and ledger items on the other, with suggested matches and their reasons in between, next to an exceptions inbox and a journal explorer
Exceptions closed by journal
Unmatched lines, amount mismatches, duplicates and late settlements are assigned and resolved, and each resolution posts an adjusting journal
Reports that open their journals
Daily cash position, fee (MDR) analysis per channel and ageing of unreconciled items, with every figure traceable to the journals behind it
How it works
Payments into the ledger
Each provider's webhook is verified, stored once and applied by a state machine that accepts events in any order. The payment's state change, its journal and an outbox message commit in one transaction, and the transactional outbox then publishes the ledger event.
Statements into matches
Settlement reports and bank statements arrive as CSV files and are matched in tiers: exact reference first, then deterministic rules, then amount and date windows net of each channel's fees. A bank credit that covers a batch of payments is explained as a bounded subset-sum within a tolerance, and every match carries its reason and confidence into the workbench.
Exceptions into journals
Whatever stays unmatched lands in the exception queue as unmatched, amount mismatch, duplicate or late. A person assigns and resolves each item, and the resolution posts an adjusting journal, so the ledger and the reports stay in step.
Reports from postings
Balances are derived from postings, so any balance can be read as of a point in time. The daily cash position, the fee analysis per channel and the ageing of unreconciled items are built from the same postings, and each figure opens the journals behind it.
Engineering insights
Money rules are enforced where they cannot be skipped: in the database, at the webhook boundary and in property-based tests.
Stack by layer
- Frontend
- React
- TypeScript
- Vite
- Backend
- Node.js
- TypeScript
- Fastify
- Data
- PGlite (PostgreSQL)
- Drizzle ORM
- Infrastructure
- fast-check
- Biome
The database refuses an unbalanced journal
Amounts are whole rupiah integers, never floating point, and a journal whose postings do not sum to zero is rejected by the application and again by the database. Corrections are reversal entries, and an idempotency key makes a retried posting return the first journal instead of posting twice
A webhook is a claim until verified
Each event needs a valid HMAC signature and a timestamp inside a tolerance window, and it is stored once under its event ID, because the window alone would still let a replay through while it is open. The state machine then accepts events in any order, so a late expiry cannot undo a confirmed payment
One transaction, then the outbox
A payment's state change, its journal and its outbox message commit together, so downstream systems never hear of a payment the ledger does not hold
Batches solved as a bounded search
Many-to-one settlements are explained as a subset-sum over the candidate items, bounded in size and within a tolerance, so the search stays small. The answer reaches the workbench as a suggested match with its reason and confidence
Properties, not examples
Property-based tests with fast-check generate payment histories and assert that every journal balances, that balances equal the sum of postings at any point in time, that a reversal restores balances and that matching never uses a statement line twice
Design system
Ledger precise is calm, numerical and auditable, made for finance staff who spend month-end in dense tables: navy ink on a paper ground stays restful through long sessions, and each status colour means one thing only, so attention goes straight to what needs a decision.
Colour palette
- Navy ink
#0b2545Text, figures, headings and primary actions - Paper
#f7f9fcPage, table and panel background - Matched mint
#0f9d7aMatched status, as icons, row markers and match lines beside a navy label - Suggested amber
#c27c0eSuggested matches waiting for a person to confirm, beside a navy label - Exception red
#c0362cExceptions only, never a negative amount - Neutral line
#dbe2eaTable rules and dividers
Colour
Matched mint, suggested amber and exception red each mark one status, and red marks exceptions only, never a negative amount. Mint and amber sit just above WCAG's 3:1 on paper, enough for icons and markers but not for text, so every status pairs its colour with a navy label
Typography
Inter with tabular figures on every amount, so digits align down a column, with amounts right-aligned in whole rupiah. References such as virtual account numbers, provider transaction IDs and journal numbers are set in a monospace face, so long identifiers can be compared character by character
Components
A workbench that sets statement lines beside ledger items, match details that show the reason and confidence, an exception queue whose resolution posts an adjusting journal, and report tables in which every figure opens the journals behind it
Traceability
Every number on screen is traceable to its journal, which is the trail an auditor follows
Where this fits
Any business that takes payments through several channels can start from the same foundation: a ledger that cannot be unbalanced and matching that explains itself. Explore our business systems and web apps, or talk to us about your reconciliation process.
KEEP EXPLORING
Another problem. A different approach.

AI Customer Service
A marketplace and food-delivery support platform connecting cited AI answers, policy-checked tools, human handoff, an agent CRM and a versioned knowledge CMS.

Logistics Intelligent
A dispatch and supply-planning system for delivery routes, fleet disruptions and retail replenishment across multiple warehouses.
Let’s connect the dots
Let's put these ideas to work.
Share a process, product, or problem you want to improve. We will work through the possibilities together.