Product Guide 13
Fintech AI

SME Treasury: How to Build It

A step-by-step guide to building cash and treasury software for Indian small businesses. Eight stages, the options at each one, exactly how each step connects to the next, real costs, and what breaks. Written for someone who has not built this before.

Verified September 2026Free · No signupOfficial sources only
BeginnerStart here. No prior knowledge assumed.

How to use this page

This page walks you through building one product: software that tells a small business how much money it has, how much is coming, how much is going out, and what to do about the gap. Multiple bank accounts, unpaid invoices, a payroll date, and a surplus sitting in a current account earning nothing.

This is the thirteenth and last product guide, and it is the one where the other twelve meet. Almost every boundary described across this section runs through a treasury product, which is why it is a harder build than it looks and why it is last.

Note

It is also the least regulated product in this set, and that is the trap rather than the relief. There is no treasury licence. There is nothing to apply for. What there is instead is four lines you must not cross, each of which is crossed by a feature a customer will ask you for and an engineer can build in a sprint. The fastest way to become regulated in this product is to be helpful.

What SME treasury actually is

SME treasury is visibility, timing and control over money a business already has and already owes. You are not a bank, not a lender, not a broker and not a payment company — and the product is largely defined by staying that way.

The four lines, and the feature request that crosses each one:

They ask forYou becomeInstead
“Hold our money so payouts are instant”A payment aggregator. Escrow with a scheduled commercial bank, net worth ₹15 crore rising to ₹25 crore, day-end balance equal to the amount realisedNever touch the money. Initiate from their account, on their mandate
“Tell us where to park the surplus”An investment adviser. Registration, a capped fee, and you may not executeShow their own bank’s options and the arithmetic. Recommend nothing
“Front us the cash until the invoice clears”A lender. NBFC registration, the Digital Lending Directions, a KFSRoute to a regulated lender, or to TReDS
“Convert this to dollars for us”Inside FEMA, needing an authorised dealerTheir AD bank does the conversion. You do the tracking
Watch out

None of those four looks like a licensing decision at the moment it is made. Each arrives as a support ticket from a customer you like, gets scoped as a fortnight of work, and is shipped by someone who has never read a Master Direction. Put the four assertions in code on day one — a boundary you can only enforce by remembering it is not a boundary.

What it is not:

  • Not an accounting package. Accounting is what happened; treasury is what is about to happen and what you will do about it.
  • Not an ERP module. The value is across banks and counterparties, which is exactly what a single-system module cannot see.
  • Not a forecast. A forecast is one output. The product is the decision it supports.

The whole journey, in one table

#StepIn plain words
1Decide what you are notThe four lines, asserted in code.
2See the cashEvery account, one position, one currency base.
3ReceivablesAnd the IRN that makes one real.
4PayablesApprovals, limits, and who may release money.
5ForecastA range with a confidence, not a number.
6The surplusShow the arithmetic. Recommend nothing.
7CurrencyIf they trade abroad, there is a queue waiting for them.
8Close the loopReconciliation, and an audit trail of decisions.
Note

Steps 1, 3 and 8 are the skipped ones, and they are unusual company: a licensing question, a tax-compliance dependency and a reconciliation job. None of the three is what a treasury product demo is about, and all three are what makes one trustworthy.

IntermediateBuild it. Pipelines, tools and working code.

Steps 1 and 2 — the four lines, and the cash position

Steps 1 and 2 — What you are not, and what the money is

Python — steps 1 and 2, the four assertions and one honest cash position
from datetime import date, timedelta
from decimal import Decimal

# STEP 1. THE FOUR LINES, AS CODE RATHER THAN AS A POLICY DOCUMENT.
# Each of these is a single feature away from a licence you do not hold.

def assert_boundaries(action, ctx):
    # 1. Money never rests with you. Not for an hour, not "in transit".
    assert action["settlement_account_owner"] == "customer", \
        "holding customer funds makes you a payment aggregator"
    # 2. You may show options and arithmetic. You may not rank, default-sort,
    #    badge, or personalise them. See the robo-advisory guide.
    assert not action.get("recommends_instrument"), \
        "ranking an investment for a specific customer is investment advice"
    # 3. Bridging a gap with your own balance sheet is lending.
    assert action["funding_source"] != "platform_balance_sheet", \
        "advancing funds is lending"
    # 4. Conversion belongs to an authorised dealer bank.
    assert action.get("fx_conversion_by") in (None, "customer_ad_bank"), \
        "converting currency requires an AD bank"
    return True

# STEP 2. ONE POSITION, ACROSS BANKS.
# The whole reason this product exists: a business with four accounts at three
# banks has four balances and no position.

def position(accounts, as_of=None):
    as_of = as_of or date.today()
    total = Decimal(0); stale = []
    for a in accounts:
        # A balance is only as good as its timestamp. Say so on the screen.
        age_h = (as_of - a["balance_as_of"]).days * 24
        if age_h > 24:
            stale.append({"account": a["id"], "age_hours": age_h})
        total += Decimal(a["balance_paise"])
    return {
        "as_of_ist": as_of.isoformat(),
        "total_paise": total,
        "by_account": [{"id": a["id"], "bank": a["bank"],
                        "balance_paise": a["balance_paise"],
                        "as_of": a["balance_as_of"].isoformat()} for a in accounts],
        # Never present a stale figure as current. An SME will make a payroll
        # decision on this number.
        "stale_accounts": stale,
        "confidence": "LOW" if stale else "OK",
    }

# WHAT TO CHECK
# [ ] every one of the four assertions runs on every money-adjacent action,
#     not in a design review
# [ ] a balance carries its own timestamp all the way to the screen
# [ ] "available" is not "balance" -- subtract uncleared cheques, holds, and
#     the minimum the bank requires
# [ ] one currency base, converted at a STORED rate with a timestamp, never
#     at today's rate applied to yesterday's balance
# [ ] read-only access by default. The consent to SEE money and the consent
#     to MOVE money are different permissions and should look different
# [ ] aggregate in IST against bank cut-offs, not a UTC calendar day

On data: a business’s bank data reaches you through the Account Aggregator framework with a consent artefact, and GSTN is an information provider inside it, so returns are available on the same rails. Two things carry over from the AA guide and are not repeated here: verify the consent artefact signature, and remember that two clocks apply — how long you may fetch is not how long you may keep.

Steps 3 and 4 — receivables, the IRN, and payables

Step 3 — Receivables, and the IRN that makes one real

An SME treasury product lives on the receivables ledger, and in India that ledger has a tax dependency most treasury software treats as somebody else’s problem.

RulePosition
E-invoicing appliesAATO above ₹5 crore in any financial year since 2017-18. Permanent once crossed — it keeps applying to every GSTIN under that PAN even if a later year falls below
The 30-day hard stopAATO ₹10 crore and above, from 1 April 2025: an invoice, credit note or debit note must reach the IRP within 30 days of its date. The portal refuses it afterwards
What a miss costsNo IRN means no valid tax invoice, which means your customer cannot claim input tax credit
Cancellation24 hours on the IRP. After that it is a credit note, which itself must be reported
Turnover is aggregateAcross all GSTINs under one PAN: taxable, exempt, exports and inter-state stock transfers, excluding GST itself
Watch out

This is where a treasury problem becomes a customer relationship problem, and it is the finding worth carrying off this page. A missed IRN does not hurt the business that issued the invoice first. It hurts their customer, who loses input tax credit on a purchase they have already paid for — and who will remember it at renewal. Model the IRN as a state on the receivable, not as a field on the invoice, with an age, an owner and an escalation before day 30. A receivable with no IRN is not a receivable you can chase, finance or count.

The rest of receivables is ordinary and still usually done badly: ageing buckets that mean something, a promised-payment date that is separate from the due date, and a single reference that survives from invoice to bank credit. If the invoice cannot be matched to the credit automatically, the whole product degrades into a spreadsheet with a login.

Step 4 — Payables, which is really about permission

The engineering here is small and the design is not. Three questions decide it: who may approve, up to what, and who may release. In most small businesses one person does all three, and the product’s job is to make the separation cheap enough to adopt rather than to enforce a policy nobody asked for.

Note

The control that pays for itself is beneficiary verification on change, not approval limits. Invoice-redirection fraud does not defeat an approval workflow — the payment is genuinely approved, to genuinely the wrong account. Treat a change of bank details on an existing supplier as a separate event requiring separate confirmation through a channel the request did not arrive on. It is a day of work and it is the single highest-value control in this product.

Steps 5 to 8 — forecast, surplus, currency, close

Steps 5 to 8 — Forecast, surplus, currency, close

Python — steps 5 to 8, a forecast with a confidence, a surplus without advice, and the close
# STEP 5. FORECAST. A NUMBER IS A LIE; A RANGE IS A FORECAST.
# The useful output is not "you will have 42 lakh on the 30th". It is "payroll
# on the 30th is covered unless these two invoices slip, and here they are".

def cash_forecast(position, receivables, payables, horizon_days=45):
    base = position["total_paise"]
    rows = []
    for d in range(horizon_days):
        day = date.today() + timedelta(days=d)
        inflow_p50 = sum(r["amount_paise"] * r["p_pay_by"](day) for r in receivables)
        outflow = sum(p["amount_paise"] for p in payables if p["due"] == day)
        base = base + inflow_p50 - outflow
        rows.append({"date": day.isoformat(), "expected_paise": base,
                     "committed_outflow_paise": outflow})
    return {"rows": rows,
            "confidence": position["confidence"],      # inherits its inputs
            "drivers": top_swing_factors(receivables), # WHICH invoices decide it
            "breach_dates": [r["date"] for r in rows if r["expected_paise"] < 0]}

# The single most useful screen in the product is not the chart. It is:
# "these three invoices decide whether the 30th works."

# STEP 6. THE SURPLUS, WITHOUT BECOMING AN ADVISER.
def surplus_options(customer, amount_paise, days_until_needed):
    opts = customer["bank"].deposit_products(amount_paise, days_until_needed)
    return {
        "amount_paise": amount_paise,
        "days_until_needed": days_until_needed,
        # Arithmetic, in a stable order, with the assumptions visible.
        "options": [{"name": o["name"], "rate_pa": o["rate_pa"],
                     "lock_in_days": o["lock_in_days"],
                     "interest_paise": simple_interest(amount_paise, o["rate_pa"],
                                                       days_until_needed),
                     "breaks_before_needed": o["lock_in_days"] > days_until_needed}
                    for o in opts],
        "sort": "stable_by_lock_in",     # NOT by return. A default sort ranks.
        "recommended": None,             # and it stays None
        "disclaimer_is_not_the_control": True,
    }

# STEP 7. CURRENCY -- if they trade abroad, there is a queue waiting for them.
def fx_exposure(invoices, base="INR"):
    open_entries = [i for i in invoices if i["edpms_idpms_status"] == "OPEN"]
    return {"by_currency": bucket(invoices, "currency"),
            # Entries stay open until somebody closes them, and resurface as a
            # bank declining the next transaction. Queue, owner, age.
            "open_regulatory_entries": len(open_entries),
            "oldest_open_days": max([i["age_days"] for i in open_entries] or [0])}

# STEP 8. CLOSE THE LOOP.
def close(period, ledger, statements):
    # FULL OUTER JOIN. A bank line matching no ledger entry is the interesting
    # case -- money that moved and nobody can explain.
    matched, only_ledger, only_bank = full_outer_match(ledger, statements)
    assert control_total(statements) == expected_total(period), "abort: file incomplete"
    return {"matched": len(matched), "unexplained_bank_lines": len(only_bank),
            "unmatched_ledger": len(only_ledger),
            "decisions_log": period["decisions"]}   # what was decided, and why

# WHAT TO CHECK
# [ ] a forecast carries the confidence of its worst input, not its best
# [ ] name the invoices that decide the outcome. That is the product
# [ ] surplus options are never ranked, sorted by return, or badged. Stable
#     order, visible assumptions, nothing recommended
# [ ] control totals BEFORE matching, and abort on mismatch -- a truncated
#     statement reconciles perfectly on the rows it contains
# [ ] full outer join, never left. The unexplained bank line is the point
# [ ] EDPMS and IDPMS entries tracked as a queue with an owner and an age
# [ ] log the DECISION, not only the transaction: what was chosen, on what
#     figures, by whom. That log is the difference between a tool and a record

On forecasting, briefly, because the temptation is large. This is the step where a team reaches for a model, and for most SMEs a model is the wrong tool for an honest reason: the outcome is usually decided by two or three specific invoices, not by a pattern across thousands. Naming those invoices is more useful than predicting the aggregate, it is explainable, and it survives the month the business wins an unusually large order. If you do use a model, everything in the alternative credit scoring guide applies — including that a rule engine is a model and that you must be able to say why.

Watch out

Step 6 is where this product most often crosses a line without noticing. Showing a customer what their own bank offers on a 30-day deposit, with the interest worked out, is arithmetic. Sorting that list by return is a recommendation. So is a “best for you” badge, a default selection, and a nudge that appears only when the balance is large. The robo-advisory guide sets out the three screen tests; run them on this screen every release, because this is the screen a growth team will want to optimise.

Where this product touches the rest of the section

Thirteen guides in, the map is worth drawing once. A treasury product is an integration of other people’s regulated surfaces, and each one has its own page:

SurfaceWhere the detail is
Consented bank and GST dataAccount Aggregator
Paying suppliers, collecting from customersBuild Sheet 05 and UPI
Standing instructions and auto-debitsRecurring Payments
Turning an unpaid invoice into cashInvoice Discounting
Paying or being paid across bordersCross-Border Payments
Anything resembling a recommendationRobo-Advisory
Anything resembling a credit decisionAlternative Credit Scoring

What it costs

SME treasury — what it costs

Verified September 2026
Registrationsdirect
None, if you hold the four lines. That is the entire commercial argument for building this product rather than a lending or payments one — and it evaporates the first time money rests in your account.
Account Aggregatordirect
Per fetch, plus the build. Scope it as two modules if you are a regulated entity: joining as an FIU can also require joining as an FIP. Detail in the Account Aggregator guide.
Bank connectivitydirect
The real integration cost, and it is per bank. Coverage is the product; a treasury tool that sees three of a customer’s four accounts is worse than a spreadsheet, because it looks complete.
E-invoicing integrationdirect
IRP connectivity, or a GSP. Small against what a blocked IRN costs a customer’s customer in lost input tax credit.
Forecast accuracyindirect
Not a line item and the thing you are actually selling. A wrong forecast that looks confident is worse than no forecast, because an SME will schedule payroll against it.
The support cost of being rightindirect
Every stale balance, unmatched credit and open EDPMS entry becomes a conversation. Staff reconciliation as a queue with an owner, not as a month-end task.
What you are competing withindirect
A spreadsheet and a WhatsApp group, and they are free and already working. The bar is not another treasury product. It is the incumbent process, which has no licence fee and no integration risk.
Where to buy these: Payments Reconciliation Build Sheet names every tool with its unit cost. Getting Access covers which ones you can sign up for today, which need a sales call, and which are licensed.
Note

The honest pricing observation for this product: an SME will pay for a decision it can act on and will not pay for a dashboard. The willingness to pay sits on “payroll on the 30th is covered unless these two invoices slip” — a sentence, not a chart — and everything on this page exists to make that sentence true and defensible.

AdvancedShip it. Failure modes, thresholds and evidence.

Three versions you could build

Read-only visibility

Build: AA consent → balances across every account with timestamps → receivables ageing with IRN state → one position, one currency base.

You get: the thing the spreadsheet cannot do, with no regulated surface at all. Read-only is a legitimate destination, not a stepping stone.

Visibility plus initiation

Build: the above, plus approval workflow, beneficiary-change verification, payment initiation from the customer’s own account on their own mandate, and reconciliation with control totals and a full outer join.

Trade: initiation is where the four assertions start earning their place daily. Money still never rests with you — if a feature needs it to, the feature is the problem, not the assertion.

Treasury with financing and currency

Build: the above, plus routing to TReDS or a regulated lender for the cash gap, EDPMS and IDPMS tracked as an aged queue, and surplus options shown as arithmetic in a stable order.

It breaks when: one of the four boundaries is crossed for a good reason. The sequence is always the same — a customer asks, it is scoped as a fortnight, and it ships. Make the assertion fail the build rather than fail a review.

Note

If you take one thing from this page: the four boundaries are code, not policy. Every one of them will be crossed by a feature request that is reasonable, well-intentioned and small. An assertion that fails the build is the only version of that boundary that survives contact with a roadmap.

What goes wrong

What goes wrongWhyFix
Funds rest in a platform account“Instant payouts” shipped as a feature.Assert the settlement account owner. You are not a payment aggregator.
Surplus list sorted by returnIt is the obvious default sort.Stable order, no ranking, nothing recommended.
Stale balance shown as currentThe timestamp was dropped at the API layer.Carry it to the screen. Payroll gets decided on that number.
Receivable with no IRN, past day 30IRN treated as a field, not a state.State with an age, an owner and escalation before day 30.
Customer loses input tax creditA missed IRN on an invoice they already paid.Same fix, and tell them early rather than at reconciliation.
Payment approved, to the wrong accountInvoice redirection defeats approval, not verification.Beneficiary change is a separate event, confirmed out of band.
Forecast confident and wrongConfidence not inherited from inputs.A forecast carries the confidence of its worst input.
Reconciled perfectly against a truncated fileNo control totals.Control totals first, abort on mismatch.
Unexplained bank credits never surfaceLeft join instead of full outer.Full outer join. The unmatched bank line is the point.
EDPMS backlog discovered by a declined transactionNobody owned the queue.Owner and age, from the first transaction.
Three of four accounts connectedOne bank had no integration.Say so on screen. A partial position that looks complete is worse than none.

Where to go next

Watch out

This page is a guide, not a specification. A treasury product sits next to four regulated activities and the distance between it and each of them is one feature. Nothing here is legal advice. Have your fund flows, your surplus screen and your financing referrals reviewed by qualified counsel before launch, and re-review them whenever the roadmap adds something a customer asked for.

Sources

Every figure, rule and date on this page, and where to check it. Entries are typed so you can see which are primary-sourced and which are industry reporting.

  1. officialGST e-invoicing under Rule 48(4), CGST Rules — the ₹5 crore aggregate annual turnover threshold applying since 1 August 2023 to any financial year from 2017-18 onwards and continuing to apply once crossed; aggregate turnover computed across all GSTINs under one PAN including taxable, exempt, export and inter-state stock transfer values and excluding GST; and the treatment of an invoice issued without a valid IRN as not issued. www.cbic.gov.in
  2. officialGSTN advisory of 5 November 2024 on the IRP reporting window — the 30-day limit for reporting invoices, credit notes and debit notes to the Invoice Registration Portal, extended from taxpayers with AATO of ₹100 crore and above to those with ₹10 crore and above with effect from 1 April 2025, after which the portal refuses the document; and the 24-hour cancellation window on the IRP. einvoice.gst.gov.in
  3. officialRBI (Regulation of Payment Aggregators) Directions, 2025 — the escrow requirement with a scheduled commercial bank, the exclusion of own funds, the day-end balance equal to the amount realised, and the ₹15 crore to ₹25 crore net worth path — the regime a treasury product enters the moment customer funds rest in its own account. Detail in Build Sheet 05. www.rbi.org.in
  4. officialSEBI position on the advisory perimeter — that a program recommending securities to a specific person on the basis of their circumstances is giving investment advice, and that a disclaimer does not change what an activity is — the basis for showing surplus options as arithmetic in a stable order rather than as a ranked list. Detail in the Robo-Advisory guide. www.sebi.gov.in
  5. officialAccount Aggregator framework and the NBFC-AA Master Direction — the consent-artefact mechanism through which bank and GST data reaches a treasury product, the requirement to verify the artefact signature, and the separate consent-expiry and data-life clocks. Detail in the Account Aggregator guide. www.rbi.org.in
  6. officialFEMA and the EDPMS / IDPMS reporting framework — the requirement that currency conversion run through an authorised dealer bank, and that export and import entries remain open until documented — the queue that resurfaces as a bank declining the next transaction. Detail in the Cross-Border Payments guide. www.rbi.org.in
  7. industryE-invoicing implementation commentary — the operational read on threshold proposals below ₹5 crore, portal authentication changes, and the practical consequence of a blocked IRN for a recipient’s input tax credit. Directional; confirm any threshold against the current notification before relying on it.
  8. industrySME cash-management practice — the observation that the incumbent process is a spreadsheet and a messaging group, and that willingness to pay attaches to an actionable decision rather than to a dashboard. Judgement, not a measured figure.

Checked September 2026. GST thresholds have been lowered repeatedly and proposals below ₹5 crore have been discussed; confirm the current figure against the notification rather than against this page.

Ask an AI about this page

Opens your assistant with this page as the source, and a question rather than a summary. It will ask what you are building before it answers.

Nothing is sent from here. The link carries only this page’s title and address.