MoneyFlock may earn a commission if you subscribe to a Lovable Business plan through links in this article, at no extra cost to you. TJ Alam is a certified Lovable Expert.
To build an expense approval app with AI, keep the approval thresholds in a database table instead of in the prompt, let a model read the receipt but make a person confirm the amount before anything routes, and write every state change to an append-only events table. The build is an afternoon. The design decisions are the work.
That is the short version. The longer version is that most guides to this build stop at a form and a status column, which is the easy 20 percent. The parts that decide whether finance actually uses the thing are the threshold matrix, the confirm step, the audit trail and the export column order. This article covers all four, with the platform limits that shape them checked on the day.
Verified in the browser on 29 September 2026: lovable.dev/pricing, docs.lovable.dev/integrations/ai, docs.lovable.dev/features/publish, docs.lovable.dev/changelog and Lovable's ExpenseDesk template page. Every price and platform limit below is dated. Lovable ships weekly, so re-check anything you are about to design around.
What an expense approval app has to do that a tracker does not
An expense tracker records what was spent. An approval app moves a claim through states and produces a financial record that someone downstream relies on. Those are different problems, and the second one is where the build gets interesting.
A working claim moves through something like this:
- Draft: the claimant is still attaching receipts and can change anything.
- Submitted: the claim is locked to the claimant and now belongs to the workflow.
- Approved or rejected at each required level, with a reason recorded on a rejection.
- Exported: handed to whatever pays it.
- Paid: reconciled back with a payment date and reference.
The state list matters because every transition is an event worth recording, and because a claim that can quietly move backwards is a claim nobody can reconstruct later. If you have already built the money-coming-in side, the mechanics will feel familiar, but the trust model is inverted: an invoice app asks a customer to pay you, while an expense app asks your own organisation to pay an employee on the strength of a photograph. We covered the first case separately in our guide to building an invoice app without code.
Three parts do the heavy lifting: thresholds, receipts and the audit trail. Take them in that order.
Put the approval threshold matrix in a table, not in the prompt
The single most common mistake in an AI-built approval app is describing the rules in the prompt. It works on day one and becomes a liability in month two, when the travel limit changes and a rule that lives in generated code needs a rebuild to move. A rebuild costs credits, introduces a regression risk and means nobody in finance can change a limit without you.
Store the rules as rows instead. A starting matrix looks like this, in whatever currency your organisation reports in:
| Claim amount | Category | Who approves | Target turnaround |
|---|---|---|---|
| Under $100 | Any | Auto-approve, line manager notified | Immediate |
| $100 to $1,000 | Any | Line manager | 2 business days |
| Over $1,000 | Any | Line manager, then finance | 3 business days |
| Any amount | Travel and client entertainment | Finance in addition to the manager | 3 business days |
| Any amount | Missing or unreadable receipt | Finance, with a written reason | 5 business days |
Those bands are an example, not a recommendation. Pick your own and put them in a table your finance lead can edit without opening the editor.
The columns that make the rule table survive contact with reality
- An effective-from and effective-to date on every rule, so a claim submitted in March is still explainable in November.
- A currency column, because a distributed team submits in several and a threshold in one currency is not a threshold in another.
- Explicit band boundaries. Decide once that a band is greater than or equal to the lower bound and strictly less than the upper bound, write it in the column header, and never leave a $1,000 claim to chance.
- A rule identifier stored on the claim at submission time. The claim should remember which rule routed it, so that changing the rule later never rewrites history.
- A supersede flag rather than a delete. Old rules stay in the table and stop being effective; they never disappear.
How to ask for it
A prompt that produces the right shape is specific about storage, not just behaviour. Something close to this works:
"Create an approval_rules table with columns: id, min_amount, max_amount, currency, category, first_approver_role, second_approver_role, effective_from, effective_to, superseded_by. On submit, select the matching rule for the claim's amount, currency and category, store the matching rule id on the claim, and create the approval steps from that rule. Do not hard-code any amounts in the application code."
Roles are a separate question from rules, and Lovable's workspace roles are not the same thing as the approver roles inside your app. We covered the workspace side in our piece on running a finance team in a Lovable workspace; inside the app, your approver roles are just data on a table.
Receipt capture, and the confirm step you cannot skip
Lovable's AI documentation lists image and document analysis as a built-in capability: extracting, summarising and interpreting key information from unstructured content, through a connector that manages the API key and runs calls server-side rather than from the browser. For receipts, that is exactly the right shape, and you do not need a provider account to use it.
One constraint is worth knowing before you plan the build. The 23 September 2026 changelog entry that added Anthropic's Claude models for in-app AI features says they can be added to any newer app, specifically one created from 13 May 2026 onward, which is when projects moved to TanStack Start. If you are extending an older project, check which models are actually available to it before you design a PDF field-extraction flow around one.
Extract, then confirm. Always.
Do not let the extracted amount post itself. Show the claimant what the model read, next to the receipt, and make them confirm it. Store both numbers: the extracted value and the confirmed value, plus who confirmed and when.
This is not pessimism about the models. It is that receipts are a genuinely hostile input. A restaurant receipt has a subtotal, a service charge, a tax line and a handwritten tip, and the largest number on the page is often the one you do not want. A hotel folio has a running balance. A crumpled photograph taken in a car park at night has a decimal point that is anyone's guess. A receipt in a script the claimant cannot read is a receipt nobody can check.
Keeping both numbers gives you something valuable for free: the gap between extracted and confirmed is a quality signal. If it is near zero across a few hundred claims, you can start trusting extraction for the small band. If it is not, you have evidence rather than a feeling.
Use the right kind of model for each job
The docs draw a line worth following. Typed decision models return a structured judgment, a category or a score or a yes-or-no probability, and are the right tool for classification, routing, ranking and verification. Chat models are the right tool for writing, summarising and free-form extraction. So: a chat model reads the receipt, a typed decision model classifies the category and flags a possible policy breach, and your own code applies the threshold and picks the approver.
Keep the threshold decision in code, not in a model. An approval route is a rule your organisation can be asked to explain, and "the model decided" is not an explanation. The model's job is to read and to classify. The routing is arithmetic.
What the AI actually costs, and what happens when credits run out
Two numbers and two error codes, all read from the docs on 29 September 2026.
Free, Pro and Business workspaces receive a 4-credit monthly AI grant for AI gateway usage in deployed apps. The docs label it a temporary offering, subject to change. On Free plans the grant resets on the 1st of each calendar month at 00:00 UTC; on Pro and Business it refreshes with the subscription billing cycle. It does not roll over. Once the grant is used, AI gateway usage draws on your general credits.
That is a small allowance for a tool that reads a few hundred receipts a month, which makes the failure modes worth designing for rather than discovering at month end.
| Condition | What the platform returns | What your app should do |
|---|---|---|
| Workspace out of credits | 402 Payment Required | Accept the claim with a manually typed amount, queue the receipt, retry extraction later |
| Too many model calls per minute | 429 Too Many Requests, request not processed | Queue and retry with backoff; expect this at month end |
| App cancels an in-flight request | Some usage may still be billed | Do not build an aggressive client-side timeout that retries eagerly |
The first row is the one that matters most. A reimbursement should never be blocked by a credit balance. If extraction is unavailable, the claimant should still be able to submit with a typed amount and a receipt attached, and the app should come back to the extraction later. Build that path on day one, because the day you need it is the day everybody is filing at once.
Rate limits are applied per workspace and measured in requests per minute, not tokens, so the constraint is call volume rather than receipt size. Every project also gets a Cloud and AI activity view under Cloud and then AI, which shows each request with its status, model, token counts, credit cost and duration. Use it for a week before you promise anyone a monthly figure.
One more thing worth knowing before you plan around provider pricing: the built-in AI connector always bills your workspace credits, and you cannot point it at your own API key. If you want usage billed to your own provider account instead, the documented route is to have the app call the provider directly from a backend edge function with the key stored as a secret, at which point you are paying the provider and only consuming regular Cloud usage for the function. For how credits work more generally, see our breakdown of what a Lovable MVP actually costs in credits and the full pricing comparison.
The audit trail: append-only, and never called audit-proof
Keep two tables. The claims table holds the current state of each claim. A separate events table holds how it got there, and nothing ever updates or deletes a row in it.
A workable event row:
- claim_id and a monotonically increasing event sequence number.
- event_type: submitted, extracted, confirmed, approved, rejected, exported, paid.
- actor_id and the actor's role at the time, not just the word "system".
- from_state and to_state.
- amount_at_event, so a later change to the claim amount is visible as a change rather than a silent overwrite.
- rule_id, the approval rule that was in force when the event happened.
- A free-text reason, mandatory on a rejection.
- created_at generated by the database on the server, never sent by the client.
What makes it credible
Server-side timestamps, a named actor, the rule version and the amount at the time. Those four turn a log into something that can answer the only question anyone ever asks about an old claim, which is why it was paid at that amount to that person.
What it is not
It is not tamper-proof, and you should be explicit about that internally. Anyone with direct database access, including a workspace owner, can change rows. An append-only table is a discipline enforced by your application and your access rules, not a cryptographic guarantee. Do not describe the app as audit-proof to anyone, because the first person who tests that claim will be the person you least want testing it.
Keep the original receipt files as well as the extracted values, and keep them for as long as your local rules require. Retention periods for expense records differ by jurisdiction and by the kind of expense, and this is a question for your own finance or tax advisers rather than something to infer from a builder's documentation. The practical implication for the build is simple: never delete a receipt file when a claim is deleted, and make sure the file storage has its own retention setting rather than inheriting whatever the table does.
Access rules are the other half of this. We wrote the row-level security detail up separately in our piece on whether Lovable is safe for financial data, and it applies unchanged here, so it is not repeated below.
Duplicate receipts are the case you will actually hit
Expense fraud in a small organisation is rarely elaborate. It is the same receipt submitted twice, usually by accident, occasionally not. Three cheap checks catch nearly all of it, and they run in this order:
- Hash the uploaded file. Store a SHA-256 of the file bytes and compare on upload. This catches the identical file re-submitted, which is the most common case by a distance.
- Build a soft key of vendor, date, amount and currency. This catches a receipt that was photographed twice, where the file differs but the transaction does not.
- Flag the same claimant submitting the same amount within seven days, even when vendor and date differ.
Flag, do not block. A genuine duplicate is usually a resubmission after a rejection, and an app that refuses the resubmission teaches people to work around it. Record the reason for the flag on the claim so the approver sees why it was raised and can clear it in one click, and record the clearing as an event.
Two smaller details that save time later: run the hash check against receipts from all claimants, not only the current one, because a shared taxi receipt submitted by two people is a real pattern. And store the hash even when the check passes, so that the check works retroactively once the table has some history in it.
Export in the column order the accounting tool imports
Here is the quiet reason internal expense apps get abandoned: the app works, and the finance person still retypes everything into the accounting system. If the export does not import cleanly, the app has added a step rather than removed one.
So do this before you design a single screen. Open your accounting tool's import template, note the exact column headers and their order, and build the export to match it. Not a similar set of columns. The same columns, in the same order, with the same header spelling.
A typical set, for reference only, since yours will differ:
| Column | Format | Note |
|---|---|---|
| Transaction date | ISO 8601, YYYY-MM-DD | The date on the receipt, not the submission date |
| Vendor | Plain text | Match the accounting tool's supplier spelling where one exists |
| Description | Plain text | Short; many tools truncate |
| Account or category code | The tool's own code | Map your categories to these codes in a table, not in the export script |
| Amount | Unformatted number | No currency symbol, no thousands separator |
| Currency | ISO 4217 code | Its own column, always |
| Tax amount | Unformatted number | Separate from the gross amount |
| Employee reference | The tool's own employee id | Not an email address unless the tool asks for one |
| Claim reference | Your claim id | The join back to your app |
Two rules that prevent most import failures. Export one row per expense line, not per claim, so a claim with three lines becomes three rows sharing a claim reference. And export the approval fields, approver and approval timestamp, in a second file rather than squeezing them into columns the import does not expect.
If the finance team lives in a spreadsheet rather than an accounting package, the newer Microsoft connectors change the shape of this problem, because the workbook can stay where it is. We covered that set in our write-up of Lovable's Microsoft 365 and Copilot Managed Runtime release and in the wider look at connectors in a finance stack.
Who can open the app: the plan gate that decides this build
This is the part that changes the answer for an expense app specifically, and it is documented plainly.
On Free and Pro plans, anyone with the link can visit your published app. The docs are direct about it: publishing is always external to the web, and you cannot restrict website access on those plans. For a marketing site that is fine. For an app holding employee receipts, reimbursement amounts and approver names, a link that works for anyone who has it is not an access model.
On Business and Enterprise plans, the publish dialog opens a Who can view your site picker with three options: Public, Workspace, meaning only logged-in workspace members, and Custom, where you compose the audience from the whole workspace, groups, individual members and people outside your workspace invited by email.
The external approver case, which fits this build exactly
Plenty of organisations have their books kept by an outside accountant or bookkeeper. The Custom audience covers that: invite them by the email address they use, and they get access marked with an EXT label without ever becoming a workspace member. Invites do not expire, and removing someone from the audience revokes access when you apply the change. That is a better fit than the usual workaround of making the app public and hoping the URL stays obscure.
The downgrade trap, worth reading before you commit
The docs describe what happens if the plan changes later, and it catches people out. Your published app stays live and the access restriction keeps being enforced. But on a Free or Pro plan, Lovable does not publish changes to an app that is published to your workspace or to a custom audience. Selecting Publish changes shows the message that publishing to a workspace requires a Business plan, and the live version stays online.
Read that carefully, because the consequence is specific: after a downgrade, your internal expense app keeps running exactly as it is, and you can no longer ship a fix to it unless you make it public first. For an app that people file reimbursements through every month, being frozen at the current version is a real operational risk, not a theoretical one.
Two workspace controls worth turning on
- Default website access, set by workspace admins and owners, so a new internal project does not get published publicly by whoever builds it next. Individual projects can still override it in the publish dialog.
- Block publishing with critical issues, which prevents a publish while critical security findings are unresolved. New Enterprise workspaces that Lovable creates start with it enabled; on Business you turn it on yourself.
Publishing itself is free and works even at a zero credit balance, and publishing deploys a snapshot rather than pushing changes automatically, so remember to publish changes after each fix. If you are building an internal expense app for a real team, the workspace audience control is the feature you are actually paying for, and it lives on the Business plan. You can start a build on the partner link, and if you want the setup reviewed by a certified Lovable Expert before it holds real data, TJ's Expert directory profile is the direct route.
Test the access rules before one real receipt goes in
Row-level security is covered in detail elsewhere in this series, so this is just the test script for this particular app. Create three accounts, a claimant, a different claimant and an approver, and check all five:
- Claimant A cannot open claimant B's claim by changing the id in the URL, and the API returns nothing rather than an empty page.
- An approver can read claims routed to them and no others, including claims above their threshold band.
- A logged-out request to the data API returns nothing at all.
- An approver cannot approve a claim they submitted. Enforce approver id not equal to claimant id in the database, not in the interface. Self-approval is the single most common hole in a first build.
- Receipt files are checked separately from rows. File storage is its own permission surface, and a claim that is properly locked down can still have a receipt sitting behind a guessable public URL.
Run the check again after any change to the rule table, because a new rule can widen who counts as an approver. If a build gets stuck or a policy fights you along the way, our guide to Lovable build errors, loops and RLS fixes covers the usual causes.
What Lovable's own template gives you, and what it leaves out
There is an official starting point. Lovable's ExpenseDesk template, under Apps and then Internal Tools, showed 2.1K remixes when we opened it on 29 September 2026. Its own page lists an expense submission form, receipt uploads, a two-step approval workflow, real-time status tracking, a spending analytics dashboard, a full audit trail, role-based access control, an AI expense assistant, and CSV import and export, built on React, TypeScript, Tailwind CSS and shadcn/ui.
That is a genuinely useful base and remixing it will save you the first afternoon. It is also worth being clear about what a template of that description does not claim to include:
| What this build adds | Why the template cannot assume it |
|---|---|
| A threshold matrix stored as editable rows | A two-step workflow is a fixed shape; your bands and categories are yours |
| Duplicate receipt detection | Needs a file hash and a soft key that your data volume justifies |
| An export mapped to your accounting tool | Column order is specific to the tool you actually use |
| Self-approval prevention in the database | Depends on how you model approvers and claimants |
| A retry path for 402 and 429 responses | Depends on your volume and your credit plan |
| Multi-currency thresholds | Only matters for a distributed team |
The honest recommendation is to remix the template for the shell and then spend your build time on the six rows above, because those are the ones finance will judge the app on.
A build order that does not waste credits
Every rebuild costs credits, so build the parts that are least likely to change first, and the part most likely to be rebuilt last.
- Schema first: claims, claim lines, approval rules, approval steps, events, receipt files. Get the column names right before anything renders.
- Access rules next, with the five-point test above, while the data is still fake.
- State transitions third, including the rejection reason and the event write on every transition.
- The interface fourth. This is where iteration is cheap in consequence and expensive in credits, so know what you want before you start.
- AI receipt extraction last, behind the manual-amount path that already works.
That order has a second benefit. The app is useful to a finance team after step three, with amounts typed by hand, which means you can put it in front of the people who will use it before you spend anything on the AI layer. If they want different bands or a different export, you have changed a table rather than rebuilt a feature.
For a view of where this sits against the alternatives, and where Lovable is the wrong tool, our full Lovable review for 2026 is the pillar for this series.
Frequently asked questions
Can AI approve an expense automatically?
It can, but limit it to a band you would be comfortable defending, and make the automatic approval a rule in your table rather than a model decision. A sensible pattern is to auto-approve small claims with a readable receipt and a known vendor, notify the manager rather than asking them, and route everything else to a person. Keep the routing decision in code so it can be explained.
Do I need a Business plan to build an expense approval app?
You can build and test one on any plan. You need Business or Enterprise to restrict who can open the published app, because Free and Pro publish externally to anyone with the link. For an app holding employee receipts and reimbursement amounts, that restriction is the point, so in practice a real internal deployment means Business.
How accurate is AI receipt scanning?
Accurate enough to save typing, not accurate enough to remove the person. Totals on clean printed receipts are usually read correctly; tips, service charges, tax lines, multi-page folios and poor photographs are where it goes wrong. Store the extracted and confirmed amounts separately and you will have your own accuracy figure within a month, which is worth more than anyone else's.
Can it connect to my accounting software?
Through an export in most cases, and through a connector in some. Start with the export, because it works regardless and it forces you to get the column mapping right. Add a direct connection later if the volume justifies it.
Is an app like this acceptable as an audit record?
That depends on your jurisdiction, your auditor and the kind of expense, and it is a question for your finance or tax advisers rather than one a builder's documentation answers. What you can do is make the record as good as possible: server-side timestamps, a named actor on every event, the rule version that routed each claim, the original receipt file kept unchanged, and no deletes.
What happens to the app if the workspace runs out of credits?
The published app stays online and publishing itself is free, but features that make model calls return a 402 Payment Required, and an app using the built-in backend needs credits to serve requests. This is why the manual-amount path matters: the approval workflow should keep working even when the receipt reading does not.
The short version
Build the table before the screen. Keep the thresholds as data so finance can change them without you. Let the model read the receipt and let a person confirm it. Write every transition to an append-only events table with a server timestamp and a named actor, and never call the result audit-proof. Match the export to the accounting tool's own column order before you design the interface. And check which plan you need for the audience control, because on Free and Pro anyone with the link can open the app.
If you want to start the build, the Lovable partner link is here, and a certified Lovable Expert can be reached through the partner directory profile.
About the author and disclosure
TJ Alam is a certified Lovable Expert (Website Builder track) and the founder of Digi Flock Enterprises. He built tjalam.com and cyberdance.in on Lovable. The certification is a partner credential and is not a Lovable endorsement of this article.
MoneyFlock may earn a commission if you subscribe to a Lovable Business plan through links in this article, at no extra cost to you. TJ Alam is a certified Lovable Expert.
References
- Lovable AI features documentation, read 29 September 2026
- Lovable publish documentation, read 29 September 2026
- Lovable changelog, read 29 September 2026
- Lovable pricing, read logged out in the browser 29 September 2026
- Lovable ExpenseDesk template page, read 29 September 2026