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.
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
- No engineering team and no budget. I designed and built it myself, with Claude as a coding partner.
- Financial data. Original images had to stay private, and nothing could quietly post money.
- An accounting system with gaps. Its API has no credit-card account type, and many vendors have no default ledger account.
- Field reality. Staff work in basements with poor signal, and on iPhones that ignore the usual "open the camera" shortcut.
- Existing workflows in a spreadsheet-database (Airtable) that the team wasn't ready to leave.
Key decisions
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.
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.
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.
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.
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
The experience
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)
14 Birch #2 · Plumbing
220 Oak · Appliances
9 Elm #1 · Painting
Outcome
- Live in production on Sep 28, 2026. Real bills were created end to end in the accounting system, with the receipt image attached and the due date set by the company's own rule (the 5th of the following month).
- Extraction was accurate on real receipts. It resolved two-digit years, picked the total over the subtotal, and declined to guess a property when none was named.
- The field team liked it. One field technician's reaction, as relayed to me, was "frickin' cool."
- Honest note on time saved: early feedback from accounting was that the reviewing still took real thought. The app removed the retyping, not the judgement. That shaped the next step below.
What I'd do differently
- Design for offline from day one. A capture lived in memory, so locking the phone could lose it. A local queue (service worker + IndexedDB) should have been in v1, given where field staff work.
- Measure the reviewer's time before and after. I had good data on accuracy but not on minutes saved per receipt, which is the number accounting actually feels.
- Put the vendor-to-account mapping first. Less than half of vendors had a default ledger account, so reviewers made that call every time. Fixing the mapping would have cut review effort more than any UI work.
- Make errors explain themselves earlier. Every launch-day failure was a missing setting that looked like something else. I added self-diagnosing errors afterwards, and they turned an afternoon of debugging into three minutes.