4 live 1 building on the bench: Pehra Pro, Snap Receipt last shipped

Projects

Snap Receipt

Status
Live
Platforms
iPhone · Android
Since
February 2026
Stack
Flutter · TypeScript · Hono · PostgreSQL · BullMQ · MCP
Last shipped
Links

What did that job actually cost?

Most tradespeople find out at tax time. From a shoebox.

Photograph a supply-counter receipt. Snap Receipt reads every line item, files it under the right supplier and costs it to the right job. You know what a job has cost so far, in money and in materials, and you can show the client where the money went.

A Home Depot receipt read by Snap Receipt on Android: PTFE tape, saw blades and nitrile gloves, each line with its quantity and unit price, filed under Materials, $51.07 in all, and a job one tap away.

Who it's for

Plumbers, electricians, HVAC techs, handymen, mobile mechanics, builders and fitters. Solo operators and crews of up to five.

Not household budgets. Not invoicing, payroll or bank reconciliation.

Built for consumers, kept by tradespeople

Snap Receipt launched as a consumer spending app, with budgets, shopping lists and subscription detection. In June 2026 the usage data told a different story: the people who stayed were self-employed trade contractors, using it as a receipt shoebox for their jobs.

So I rebuilt the product around jobs, suppliers and clients, and shipped it on 2 August. The consumer features weren't hidden behind a setting. They were deleted, and their endpoints answer 410 so old app versions get a clean answer. Tax figures became a by-product instead of the point.

What it does

  • Line-item scanning. Merchant, date, taxes, tips, fees, total, payment method, and every line with quantity and unit price. A 60-line supply-house invoice gives you 60 items.
  • Bad scans get flagged. Unreadable receipts are flagged, likely duplicates are caught, and photos that aren't receipts are rejected.
  • Jobs, clients and budgets. Live job cost by category and supplier, with budget alerts.
  • One supplier, however it's spelled. Five spellings of the same supply house add up to one real total.
  • Price history. What you paid for that fitting last month, and where it was cheaper.
  • Reports for clients and accountants: job cost, client expenses, supplier spend, quarterly figures. PDF and CSV.
  • Ask. A question in plain English, answered from your own records.
  • Your AI assistant, connected (on Pro). Claude, ChatGPT, Codex and Grok can read your records through a secure connector, plus a plugin with five ready-made skills: job cost, supplier prices, quarter-end figures, client report, receipt clean-up.
  • Snap Receipt's dashboard on Android for July 2026: $10,968.35 across 47 receipts, Materials the top category, two active jobs, the receipts still to cost to a job, and the plan's scans used so far.
    Dashboard
  • Further down Snap Receipt's dashboard on Android: July's spending climbing through the month, and the total split by category, Materials and subcontractor labour first.
    Expenses by category
  • A job in Snap Receipt on Android: Flooring for the Johnson Residence, $3,050 spent of a $5,000 budget, where the money went, and buttons for the full report and the client expense report.
    Job

Where should AI be trusted with money?

Only where you can check its work.

Extraction. One structured call per receipt, against a strict schema. The prompt's first rule: a wrong value is worse than an empty one. The model never infers a missing amount and never "fixes" the arithmetic, so some receipts come back with a field for you to fill. An empty field gets noticed. A wrong one gets filed. Every receipt records which model read it, so the model can be swapped without losing the audit trail.

Ask. The model is a query planner, not an oracle. It turns your question into a typed query. The server runs it, computes the figures and writes the answer. The model never sees your job, client or supplier names, and never produces a number.

The connector (MCP)

  • Read-only by construction. Its 25 tools come from an explicit list, and the only one that changes anything is switch_account, which changes whose records you're reading, not the records. A test enforces it.
  • Sign-in through its own OAuth server: PKCE, single-use codes, the app's own email sign-in, and refresh tokens that rotate, where a replayed token revokes the chain.
  • A coverage tool tells the assistant which questions the data can't answer, like revenue or mileage, so it declines instead of guessing.
  • Receipt photos never leave the app.

A permission check can be wrong. A tool that doesn't exist can't be called.

Decisions

Why is manual entry never limited? #

Because a tool that stops you recording the work is a tool you stop opening. AI scans cost money, so each plan includes a number of them. Typing a receipt in by hand is unlimited on every plan.

How do you match suppliers without wrecking someone's data? #

A deterministic key plus a similarity score. Above one threshold it links automatically, above a lower one it suggests a merge, and a merge never destroys anything. A human's decision always outranks the matcher.

How do you stop a new category shipping unreachable? #

The category list in the AI prompt is generated from the same table the tax report uses. One source, so they can't drift.

What happens to old app versions when an endpoint goes away? #

Retired endpoints answer with a clean "gone", so old versions degrade politely instead of crashing.

Technology choices

LayerChoiceWhy
MobileFlutter, Riverpod 3, GoRouter, DioOne codebase for iPhone and Android, on the same architecture as my other Flutter apps
SubscriptionsRevenueCatStore billing on both platforms through one entitlement model
BackendNode.js and Hono, use-case architectureEvery request runs through a use-case with its own context. Easy to test, easy to expose to agents
DatabasePostgreSQL with Drizzle ORMTyped schema, migrations as code, line items as first-class rows
Background workRedis and BullMQSummaries, alerts and heavy jobs stay off the request path
AIVercel AI SDK through OpenRouter, Zod schemasThe model is configuration. It moved from Gemini to an OpenAI model in September without a rewrite
Agent accessMCP over streamable HTTP, its own OAuth server with PKCEA standard door for Claude, ChatGPT and Codex
ReportsPuppeteerPixel-accurate PDFs from HTML templates
MonitoringSentryErrors from the phone and the server in one place

The numbers

  • 934 commits since 11 February 2026. One author.
  • About 62,000 lines of Dart and 66,000 lines of TypeScript, tests included.
  • Version 26.10.1 on both stores, 1 October 2026.

What this project says about how I work

  • I changed the audience when the usage data said to, and deleted what the new audience didn't need.
  • The model plans the query. The server computes every number the user acts on.