Turned a Spanish accounting firm's manual invoice grind into an AI-reviewed, Cegid-synced platform
How we built a multi-tenant accounting platform that reads invoices with AI, keeps a human in the loop on every posting, and syncs financial dashboards straight from Cegid instead of guessing.
- Client
- Taras P.
- Industry
- Accounting / FinTech
- Engagement
- Custom Software
- Duration
- 3 months

Key Results
- •AI Extraction, Human Approval: Built an OCR/AI pipeline that reads Spanish invoices — including withholding and disbursement rules — into an editable proposal that only an advisor can approve.
- •Zero Silent Auto-Posting: No record reaches Cegid without a human approval step, enforced structurally rather than left as a policy.
- •Full Traceability Chain: Every accounted document links original upload → OCR result → proposal → approving advisor → Cegid reference number.
- •Three Isolated Workspaces: Admin, Advisor, and Client roles run on the same platform with company-level data isolation enforced at the database layer, not just hidden in the UI.
- •Dashboards That Can't Drift: Financial and tax dashboards read only from Cegid-synced data, never from AI output, so what advisors see always matches the books.
- •Conversational Access to Real Data: Built an AI assistant that answers questions like "how many documents did we process this month" by querying the platform's live data — not reciting a script.
Accounting was happening off the platform
The client ran an accounting consultancy that served dozens of client companies, and every one of them was already used to a certain shape of workflow: drop invoices into a WhatsApp thread or a shared inbox, and wait.
There was no single place where a client could upload an invoice, see what happened to it, or ask a question about a document without starting a new chat with no record attached.
The advisors weren't any better off. Every invoice was opened by hand, read by hand, classified as a sale or an expense by a person, and keyed into Cegid one page at a time.
The client didn't want a system that made accounting decisions for their team. They wanted the reading and typing taken off the advisor's plate, while every decision that actually mattered stayed in a human's hands.
Three workspaces, one data model
We built the platform — internally called Externalize — as a multi-tenant system with three roles, each seeing a different slice of the same underlying data:
- Admins get a consultancy-wide view: every client, every advisor, every document, global financial and tax dashboards, and control over Cegid synchronization.
- Advisors work client-by-client: their assigned companies, that company's pending documents, and a review workspace to process them.
- Clients see only their own company — their documents, their status, their own simplified financial dashboard.
Every table carries a company_id, and access is enforced with row-level security at the database layer. An advisor querying for a document that isn't assigned to one of their clients gets nothing back — not a document the frontend is merely trusted not to render.
Every invoice declares what it is before AI touches it
Uploading a document isn't just a file drop. The client selects a type first — issued invoice, received invoice, Excel, or other — before anything gets processed.
That one decision removes an entire class of AI mistakes: the model never has to guess whether an invoice is money coming in or money going out. Get that backwards and every number downstream is backwards with it.
Reading Spanish invoices means modeling Spanish tax rules, not just running OCR
The extraction pipeline pulls the fields you'd expect — invoice number, dates, supplier and customer VAT numbers, line items — but the part that actually matters is two rules that are easy to get quietly wrong.
Retenciones (withholding). Common on Spanish invoices, and it changes the math:
Net Total = Base + VAT − Withholding
Suplidos (disbursements). Payments the supplier makes on the client's behalf. They add to what's owed, but they don't touch the taxable base, VAT, or withholding — folding them in would quietly corrupt the tax numbers:
Final Total = Base + VAT − Withholding + Disbursements
Get either one backwards and the platform isn't just wrong about a total — it's wrong about the client's VAT liability. We built extraction and proposal generation to keep these separated end to end, including for the notary-style invoices that pack several line items, a withholding, and a disbursement onto a single page.
The one hard rule: AI proposes, it never posts
Everything upstream of Cegid — OCR, field extraction, proposal generation — exists to produce one thing: an editable draft the advisor reviews before anything real happens.
The review workspace puts the original document, the extracted fields, and the generated proposal on one screen. The advisor can accept the proposal as-is, correct any field, or reject it outright. Nothing reaches Cegid — no journal entry, no posted total — until that approval happens.
This isn't a policy the team agreed to follow. There's no code path where a proposal reaches Cegid without an approving user and an approval timestamp attached to it. When AI confidence is low, or a client isn't enabled for AI at all, the same document routes through a fully manual entry screen instead — and both paths converge on the same approval gate before Cegid.

Dashboards read the books, not the guesses
The financial and tax dashboards were the other place we drew a hard line. It would have been faster to calculate "income this month" straight from uploaded invoices — the data's right there. We didn't do that.
Every dashboard number comes from a sync job that pulls posted entries back out of Cegid — balances, VAT, withholdings, fiscal year data — into internal reporting tables. Dashboards query those tables, never Cegid directly, and never the AI's extracted-but-unapproved numbers. If a company hasn't synced yet, the dashboard says so instead of quietly showing a number that isn't real.
An n8n orchestrator runs the scheduled sync, retries failures, and fires the notification and alert workflows around it — but it doesn't make a single accounting decision itself. It's a scheduler and a plumber, not a participant in the numbers.

An assistant that can actually answer, not just chat
Alongside the review workspace, we built a tool-calling AI assistant for admins and advisors that can query the platform's own data on request — "how many documents did we process this month," "which clients are at risk" — and answer with a real number pulled live from the system, instead of a canned response.
It's scoped the same way the rest of the platform is: an advisor's assistant can only see what that advisor is already allowed to see. The assistant reads; it doesn't get to touch a posting decision any more than the OCR pipeline does.
Closing the loop: incidents, notifications, and a recycle bin that isn't a trash can
A few smaller pieces exist for the same reason as everything else: removing the parts of the old workflow that left no record behind.
- Incidents replace the WhatsApp-and-email back-and-forth. Every incident is tied to a specific document, carries its own chat thread and file attachments, and moves through new → in review → resolved → closed with a full history.
- Notifications cover the events that used to depend on someone remembering to say something out loud — a document was rejected, a sync failed, a tax deadline is approaching — delivered by email and configurable per user.
- Deletion is soft by default. Nothing accounted or sent to Cegid can be hard-deleted without an admin override; everything else lands in a recycle bin instead of disappearing.
Every one of these actions — uploads, status changes, approvals, incident messages, deletions — writes to an append-only audit log. The table itself blocks updates and deletes at the database level, so the trail can't be edited after the fact, even by someone who wanted to.
Where It Stands Now
The build is complete and handed off. The client is finishing the last mile on their end — wiring in production Cegid credentials and onboarding their first real client companies — before the platform takes over the invoice grind for good.
What doesn't need to wait is the architecture underneath it: a human still has to say yes to every number that reaches the books, and every dashboard the team looks at is reading the same source of truth Cegid does.
What Changed
| Area | Before | After |
|---|---|---|
| Invoice intake | WhatsApp, email, shared inboxes | Structured upload with mandatory document typing |
| Invoice reading | Manual, line by line | AI extraction, Spain-specific tax rules included |
| Posting to Cegid | Fully manual entry | Reviewed proposal → one approval → Cegid |
| Financial dashboards | Didn't exist | Synced from Cegid, role-scoped visibility |
| Advisor–client questions | Untracked chat threads | Document-linked incidents with full history |
| Data isolation | No shared platform | Row-level security enforced per company |
| Action history | Whoever remembered to note it | Append-only, immutable audit log |
The Stack
Frontend & Backend
Next.js (App Router) • TypeScript
Data & Auth
Supabase • PostgreSQL • Row-Level Security • Realtime
AI & Document Processing
OCR / Document AI • LLM-Based Extraction • Tool-Calling Assistant
Accounting System of Record
Cegid API Integration
Orchestration
n8n
Notifications
Resend
Still re-keying invoices a computer already read once?
If your team is opening documents one at a time and typing them into your accounting system by hand, that's not a staffing problem — it's a missing pipeline. We build the ones that keep a human in charge of every decision that actually matters.
Let's talk about what's actually eating your team's time.