← Back home

Selected work / 2026

Nila: building an AI accountantPaused

About four months building an AI accounting product on my own, from messy invoice PDFs to GST workings an accountant can check.

My role
Solo founder-engineer, from talking to firms to shipping it
Timeframe
About four months in 2026 (May to October)
Working system
PDF upload, invoice review, GST workings, exports and Tally posting
Outcome
Worked on real bills; paused before any firm adopted it

I spent about four months building Nila, an AI accounting app for chartered-accountant firms in India. The job was simple to say: take the pile of bills a client sends every month, get the details into a working file, and show the accountant exactly what needs checking before they file the GST return.

I did all of it myself: visiting firms, deciding what to build, the Phoenix backend, the React front end, the extraction pipeline, deployment, and a Windows connector for Tally. I leaned heavily on AI coding agents. They wrote a lot of the code, and I made the product and engineering calls, chased down failures, and decided what stayed.

Source code · Product website · Extraction deep dive

One bill, then a whole month

You upload a PDF. Nila works out which pages belong to which invoice, reads each one, and puts the result right beside the original bill. The accountant can check the tax, compare the totals with what’s printed, and fix anything that’s off.

Original invoice beside extracted line items, IGST, and matching taxable, tax, and grand totals

An invoice in review. Open the image to see the full screen.

Printed on the bill

Printed GST total: 22,860.00

Extracted by Nila

Extracted GST total: ₹22,860.00
Invoice 75/2026-27: the printed and extracted GST totals both equal ₹22,860.00. These close-ups come from the full review screenshot.

All the month’s invoices then roll up into a sales working, with GST checks, GSTR-1 sections, and an Excel working and JSON file to download. The accountant always has the source bills to go back to, so they aren’t handed a spreadsheet of model output they have to take on faith.

Monthly GSTR-1 summary with 13 sales invoices, section totals, and Excel and JSON downloads

The month’s summary, with the workings ready to download.

Where I put the boundaries

It’s a Phoenix app with a React and TypeScript front end. PostgreSQL holds the data and Oban runs the background jobs. The AI models only hand back structured readings of the bills; everything that decides money, like calculations, validation, corrections and the return itself, lives in Elixir code I can test.

The main flow:

Original PDF
  → find the pages and group them into documents
  → read each invoice, keeping where each value came from
  → clean up and run fixed checks
  → accountant reviews and corrects
  → monthly GST workings and exports

I cared about this split because “the model gave me valid JSON” and “this invoice can go into a tax return” are very different things. An invoice can come back perfectly shaped and still be in the wrong month, be missing tax details, or need a treatment the return doesn’t support.

I also kept what’s printed on the bill apart from anything calculated. If a tax amount isn’t on the bill, Nila leaves it as unknown instead of quietly turning it into zero. When the accountant corrects something, the original reading is kept, and the month is rebuilt with the correction applied.

Sales rules and corrections · How printed taxes are read

When a long upload fails halfway

Reading a big PDF takes many model calls. If one fails and you start the whole upload again, you pay twice, and invoices can shuffle around under someone who’s halfway through reviewing them.

So the pipeline saves its progress as it goes. A retry picks up where it stopped, and invoices keep the same IDs. You can look at a half-read upload, but it doesn’t count towards the month’s totals or exports until it’s finished.

Re-reading an upload that already finished is handled separately. It checks whether anyone has made corrections, and only swaps in the new result once the whole read succeeds. If it fails, the old result stays.

Checkpoints and re-reads

Posting into Tally

Nila could also post reviewed invoices straight into Tally, through a small Windows connector I built in C#/.NET. The tricky part was a lost reply: Tally might have saved the voucher anyway, and if you just retry, you book the same sale twice. So the connector checks for an existing voucher before writing and reads it back afterwards, and anything it can’t confirm gets marked “outcome unknown” for someone to check. It worked against Tally on my own machine, but no firm used it for real. Connector source, built on the open-source TallyConnector library.

The Nila Connector window open over TallyPrime, showing Nila Cloud and TallyPrime both connected and two test companies ready to sync

The connector running beside TallyPrime with two test companies.

The deepest work: deciding what to trust

Most of my time didn’t go into picking a model. It went into questions like where one document ends and the next begins, whether to read a PDF’s own text or an image of the page, how to shape the output, which taxes are actually printed and which are worked out, and how far you can trust a check that says a value is “on the page”.

One experiment tested a tax schema that looked clearer. The model kept copying line-item taxes into the invoice summary, or inventing a CGST/SGST split for a single combined tax amount. So I tried keeping the breakdown and the total in separate fields, plus a third version with named item fields.

I ran five bills I’d already checked by hand, five times each, through all three versions, with the same inputs, settings and examples. 74 of the 75 requests finished. A response only passed if it captured the summary figures exactly as printed, without adding anything that wasn’t there.

Format Faithful printed summaries
Earlier tax list 18 / 25
Separate breakdown and total 10 / 25
Same, with named item fields 7 / 24

On one bill, the new formats kept turning a single tax total into both CGST and SGST, which doubles the tax. So I kept the old format, even though the new one looked cleaner.

It was a small test on five bills I already knew well, so it tells you nothing about Nila’s overall accuracy. The article has the full method and caveats.

Scored results and test method · Full extraction article →

What the market taught me

I visited 16 firms and tested Nila on real bills, but I never got a paying customer or even an agreed trial. Some firms had a lot of manual preparation work. Others had lighter workflows, or tools that already did the job well enough. In October 2026 I paused Nila, because nobody needed it badly enough to change how they worked.

Looking back, I should have pushed for a small trial much earlier. Getting documents and hearing about the pain taught me how the work is done, but it never told me whether anyone would actually switch and pay.

Where to look in the code