Ledge

Inspiration

Every company has a spreadsheet someone calls "the source of truth." It's 40,000 rows of transaction data, a PDF expense policy nobody reads, and a finance team manually cross-referencing both. Policy violations slip through. Approvals pile up. And answering a simple question like "what did we spend on travel last quarter?" takes hours.

We wanted to build the thing that should already exist — a platform where you upload your data once, and your spending becomes fully queryable, automatically audited, and actually understandable.


What It Does

Ledge is an AI-powered expense intelligence platform built for finance and ops teams.

You upload your company's transaction spreadsheet and expense policy PDF. From there:

  • Ask anything in plain English"What were our top merchants last month?" or "Show me the monthly trend for travel spend" — and get back a narrative answer with an inline chart or breakdown table
  • Automatic policy enforcement — every transaction is evaluated against 8 built-in compliance rules (receipt requirements, pre-approval thresholds, alcohol purchases, ticket/fine detection, duplicate and split transaction detection, and more) with severity levels and evidence
  • Expense report clustering — transactions are automatically grouped by location, category, and date into expense reports, each with an AI-generated approve/review/deny recommendation
  • Manual flagging — anyone can flag a suspicious transaction directly from the dashboard, and it immediately surfaces in the policy engine
  • Custom policy workflows — a node-and-edge workflow builder lets you define your own rules using a DSL that supports field comparisons, tag checks, time windows, and aggregations

How We Built It

Frontend: Next.js 16 with the App Router and Turbopack. All charts are custom SVG — no chart library. The policy workflow designer uses @xyflow/react for the node/edge graph.

Backend: Next.js API routes handle all data operations. Transactions are parsed from XLSX using ExcelJS with dynamic column header normalization, auto-tagged by merchant name and MCC code into 11 spend categories, then inserted into Supabase in chunks.

Database: Supabase (PostgreSQL) with row-level security. The schema tracks transactions, organizations, users, and departments. Policy status, tags, and evaluation timestamps are written back onto each transaction after a compliance pass.

AI layer: We built a thread-based chat architecture where user queries are parsed for intent (spend category, time period, comparison mode), a deterministic analysis runs locally, and the result is sent to an LLM assistant alongside the original question and the indexed policy document for grounded, accurate answers. If the assistant isn't provisioned, the deterministic analysis runs as a standalone fallback.

Policy engine: ~1,200 lines of rule evaluation logic with a custom expression DSL supporting hasTag(), missing(), withinHours(), withinDays(), pair matching across transactions, and aggregation functions.


Challenges We Ran Into

Getting the AI to return structured, visualization-ready data alongside natural language answers required careful prompt engineering — the response needs to carry both a human-readable narrative and a machine-readable visualization spec simultaneously.

The policy engine was the hardest part to get right. Detecting split transactions and duplicate charges requires cross-transaction reasoning, not just row-level checks — a pattern that defeats simple per-row validation entirely.

We also had to design an onboarding flow that handles messy real-world spreadsheets — column headers are rarely consistent, so we built dynamic normalization that maps whatever headers exist to our internal schema.


Accomplishments We're Proud Of

A fully functional end-to-end product — CSV upload → auto-tagging → policy analysis → natural language querying → expense report clustering — built in a single hackathon. The chat interface returns inline charts and tables that feel genuinely useful, not just a demo. The policy engine catches things that would realistically slip past a manual review.


What We Learned

How to combine retrieval-augmented generation with deterministic structured output to build reliable AI features. The deterministic layer guarantees a valid response even when the LLM doesn't return a perfect answer — the product never breaks, it just gets better when the assistant is available.

Also: custom SVG charts are more work but give you complete control over exactly how data looks.


What's Next

Multi-user orgs with role-based access, direct integrations with corporate card providers, anomaly detection on spend patterns using an autoencoder model we prototyped, and scheduled policy runs with email alerts.

Built With

Share this project:

Updates