Problem
A deal is one row. Its accounting is four.
When a pre-IPO share deal closes, the CRM records it as a completed lead with a set of economics attached: what the buyer paid, what the seller received, what the broker earned. Turning that into books is not a copy. The broker's commission attracts GST, and the payment to the broker attracts tax withheld at source under section 194H, so a single commercial event becomes a four-legged journal in which two of the legs exist only because of tax law.
Doing that by hand is slow and, more importantly, inconsistent — the rate applied depends on who prepared it that week. Doing it with a generic accounting import loses the derivation entirely, because the import format has a field for amount and no field for why this amount was split this way.
Architecture
Compile the deal, don't transcribe it
A Python adapter reads the CRM over a dedicated read-only database role, on a separate host, with host-based access restricted to a single address. From a closed deal it compiles a journal: commission and its GST on the debit side, the broker's payable and the withheld tax on the credit side. Every ledger the journal needs — the broker's account, the commission head, the GST and TDS heads — is created on demand if it doesn't exist, so onboarding a new broker is not a setup task.
The posting itself goes through the accounting core's single voucher service, keyed for idempotency on the deal reference. Re-running the endpoint for a deal that has already posted does nothing. That property is what makes the whole thing safe to re-run after a CRM correction.
Every line of this system lives in its own adapter tree. The accounting core was not modified once — not a column, not a branch, not an import.
That isolation is deliberate and enforced: client behaviour lives in an adapter plus a link table keyed by the CRM's own deal identifiers, and core is forbidden from importing client code. It is the same constraint that lets TourTripX and UnlistedZone share one accounting engine while having almost nothing in common commercially. Both tenants were cut over to this adapter without a core migration.
AI components
Extraction and classification, with the arithmetic kept deterministic
- Document extraction — demat and holding statements are parsed into structured positions, so share movements can be checked against what the CRM says a deal delivered.
- Bank narration classification — the same tiered pipeline used across the platform: deterministic rules first, learned patterns second, a model only where the narration is genuinely ambiguous, and always as a suggestion a human confirms.
- Reconciliation typing — deal payments carry their own reconciliation semantics in the CRM (expected, pending, refund), and the adapter maps those into ledger intent rather than inferring them from amounts.
- Deliberately not AI — the commission split, the GST rate and the 194H withholding are computed by rule. A tax figure produced by a language model is a liability, not a feature. The model never sees the arithmetic.
This is the boundary we draw on every financial system: models are allowed to interpret language, and never allowed to determine a number that a tax authority will later read.
What it runs today
Live on both tenants, one endpoint deep
Both UnlistedZone tenants run on the adapter in production, against a platform that transacted over ₹2,100 crore in FY 2025–26. Posting commissions for a deal is a single endpoint call that compiles and posts the journal, creating any missing ledgers as it goes; the accounting side then carries those entries into the same GST and TDS reporting the rest of the platform uses.
The set of deals with complete economics attached is currently a subset of all closed deals — the CRM's own commercial workflow decides when a deal is accounting-complete, and the adapter posts only those. That is by design. A deal missing its economics is left visibly unposted rather than posted with assumed numbers.
Outcome
The tax treatment stopped being a judgement call
Commission accounting moved from a manual monthly exercise to a derivation that runs off the deal record, with the same rates applied the same way every time. Because the journal is compiled rather than transcribed, the reasoning is inspectable: each leg exists for a stated reason, and the whole journal reverses cleanly if the underlying deal is corrected.
The architectural outcome is the one we would point at in a pitch. A second, structurally unrelated business was added to an existing accounting core with zero changes to that core. That is what an adapter boundary is worth, and it is the single most useful thing we do for a client who already has a system they cannot afford to destabilise.