Case study · Internal product

Receipt Intake

Receipts were being posted into Slack by hand, one photo at a time. I saw that the problem wasn't the photos, it was that we had no structured expense data at all. So I built an app where staff scan a receipt and AI reads it, as the first piece of a real accounting system. A person still approves every payment.

RoleProduct owner, designer and builder
TimelineAug–Sep 2026; live Sep 28, 2026
UsersField staff, accounting, leadership
StackNext.js · Claude · Supabase · Airtable · Buildium API
~5 wks
from first commit to a live production app
37
expense categories, 33 mapped to real ledger accounts
1
sign-in per person, so every receipt is attributed

The problem

How it worked before: field staff photographed receipts and posted them in Slack, in whatever channel or DM was handy. Someone in accounting then had to scroll back, read each photo, work out which property and unit it was for, choose a ledger account, and type it into the property-management system by hand. That had to happen by the 5th of the following month, so the expense came out of the right owner's payout. The receipts often named no property at all, because a hardware store prints "Valued Customer", not an address.

The need I saw: nobody had asked for an app. But every receipt passing through Slack was data we were throwing away: who spent what, on which property, in which category. They were photos in a chat thread, not records. I proposed and built Receipt Intake to turn each receipt into a structured record from the moment it's captured. It works as a front door for expenses and a first building block toward a proper accounting system, where spend can be searched, reported on and reconciled rather than reconstructed from Slack.

For field staff

No single place to send a receipt. A photo in a Slack thread was easy to lose, and hard to match to a property later.

For accounting

Every receipt meant scrolling back through Slack, looking things up and entering them by hand under a monthly deadline. Money was at stake when one was missed or put on the wrong property.

Constraints

Key decisions

1

The software creates the bill. A person pays it.

The app writes a bill to the accounting system, with the receipt image attached. It never marks a bill paid. A reviewer in accounting approves each one.

This was my answer to "how much financial access should AI have": a defined line, written down, not a vague "we'll be careful."
2

Use the real chart of accounts, not invented categories.

My first version had 21 friendly categories. Once I could read the real general ledger, I replaced them with 37 categories, 33 mapped to actual accounts, so a bill lands in the right place with no translation step.

3

A proper database as the system of record, with Airtable kept as a mirror.

Receipts live in Postgres (Supabase), with private image storage. A one-way sync copies each receipt into Airtable, so accounting can keep reviewing where they already work. Review decisions are written back through a narrow function that can only update a receipt's status.

I chose not to give Airtable a database key that could read everything. The write-back function can only move a review decision.
4

Design for the person holding the phone.

The camera is the main action. The app checks for blur before upload, and plain messages say "no signal, your work is safe." Staff can write the property by hand on the receipt and the AI will read it. A two-tap fallback means there's never a dead end.

5

Be honest about what a login proves.

Each person has their own sign-in, so every receipt records who filed it. I documented that this identifies people rather than strongly authenticating them, which is enough to attribute an expense but not to approve one. Approval sits behind a separate reviewer permission.

How it works

1 · Capture 2 · Read 3 · Record 4 · Review Private storage 5 · Bill Phone web appphoto + property tag AI extractionvendor, date, lines, total Postgres databasesystem of record Accounting reviews in Airtableapprove · reject · duplicate original imagetime-limited links only Bill in accounting systemimage attached · paid by a person sync write-back image on approval A human checks the extracted fields at step 1 and approves at step 4. The software never pays.
Redrawn for this portfolio. The flow and the design decisions are the real ones; names and data are generic.

The experience

Maple Street RentalsSam R.
Receipt Intake
Get the whole receipt in frame. If it doesn't name the property, write it on the receipt and we'll read it.
CORNER HARDWARE CO.
10/02/26   14:12
------------------------
2 × PVC elbow 3/4"    4.58
1 × Pipe tape          2.99
1 × Shutoff valve     11.49
------------------------
TOTAL            $19.06
"14 Birch #2" (handwritten)
Take photo
Upload a file
Check the detailsHigh confidence
VendorCorner Hardware Co.
Date · TotalOct 2, 2026 · $19.06
Property · Unit14 Birch St · Unit 2 from handwriting
CategoryMaintenance — Plumbing
Lines2 × $2.29 · 1 × $2.99 · 1 × $11.49
The property came from handwriting. Please confirm before filing.
File receipt
Accounting review3 waiting
Corner Hardware
14 Birch #2 · Plumbing
$19.06
Lakeside Supply
220 Oak · Appliances
$86.40
Northside Paint
9 Elm #1 · Painting
$54.12
Approve & create bill
Reject · Mark duplicate
Bill due the 5th of next month. Payment is recorded by a person.
Rebuilt mockups with sample data (fictional company, vendors and amounts). They show the real flow: capture, check, review.

Outcome

What I'd do differently