Tool · Web app · Applied AI · Email

Receipt Relay

Photo → email, via AI · Free tool

Production

Open receiptrelay.321enterprise.com (opens in new tab) All projects

A photo of a paper restaurant receipt with a handwritten tip, next to the clean transactional email Receipt Relay built from it
01The story

Problem, approach, outcome

AI extraction demos usually stop at the JSON. In real use the model is sometimes wrong, and a wrong answer delivered confidently is worse than an honest “not sure.” I wanted to see what it takes to put a vision model in front of a real deliverable, an email a customer would actually receive, without letting its mistakes through.

One vision-model call turns the photo into a schema.org Order. The output is constrained to a JSON schema and validated before it reaches the UI, so a bad read surfaces as “couldn’t read this receipt,” never as a half-filled form. The model marks every field it’s unsure of, and an arithmetic check (line items → subtotal → total) catches missed lines instead of quietly “fixing” them. A correction screen puts the photo beside every field, so a person fixes what the model got wrong before the email renders.

The model is configuration, not code: one OpenAI-compatible adapter, prototyped locally on Qwen3-VL 8B in LM Studio and run in production through OpenRouter. The production model was picked by measurement, not by reputation: on 14 real receipts I checked by hand (faded, angled, rotated, Italian, 29 lines long, plus a ticket and a voucher), Qwen3-VL 235B read 95% of line items correctly with no timeouts, at about a sixth of a cent per receipt. The smaller, cheaper 30B timed out on every long receipt. The full results, with three closed models for reference, are below.

Live as a free tool, running on the model the bake-off picked.

02Overview

About Receipt Relay

Receipt Relay is applied AI that ends in something real. Photograph a paper receipt, invoice or ticket; a vision model reads it into structured order data; you check and correct it; and out comes a production-quality transactional email you can copy, download as an .eml, or send to your own inbox once you’re invited.

I built it to show AI extraction and production email working in a single loop. Most of the effort went into the part demos skip: what happens when the model is wrong. Crumpled, rotated, badly lit phone photos are the normal case, so the tool is built around structured output, per-field confidence, a cross-check on the math, and a human who signs off before anything is sent.

The email end is held to the same standard. There are two templates: Modern, built on the MIT-licensed ACORN email framework, and Paper, a line-by-line recreation of the printed receipt. Both carry dark-mode styles and preview at desktop and mobile widths in a sandboxed frame. Sending goes out from its own authenticated subdomain, so a demo can never touch the main domain’s mail reputation.

03Bake-off

Which model reads receipts best, measured

Before launch I measured the candidates instead of picking one by reputation. Fourteen real phone photos: faded thermal paper, an angled shot, two taken sideways, Italian receipts with VAT, a 29-line grocery run, a concert ticket, a gift voucher, and a business card that isn’t a receipt at all. Each one has an answer key (Claude drafted them from the photos; I checked every line against the paper), and every model was scored on the same things: line items to the cent, the total, the date, the merchant, and the kind of document.

Every model got the setup production uses: the same prompt and JSON schema, the same 2-megapixel image the browser uploads, and the same 50-second limit a visitor gets. All calls went through OpenRouter to zero-data-retention hosts only. Alongside the two open Qwen models I ran three closed frontier models, to see how close the open one gets.

14 hand-checked receipts · 2 MP images · 50 s limit · October 2026
ModelWeightsLine items (F1)Every item exactTotal rightMerchant rightMedian timeCost per receipt
Qwen3-VL 235B (in production)Open0.9510 of 1414 of 1411 of 149.6 s$0.0015
Qwen3-VL 30BOpen0.267 of 1410 of 146 of 1418.3 s$0.0005
Claude Sonnet 5.5Closed0.9913 of 1413 of 1414 of 144.6 s$0.020
GPT-6.1 SolClosed0.9913 of 1414 of 1414 of 149.0 s$0.013
Gemini 4 ArgonClosed0.9913 of 1414 of 1414 of 146.3 s$0.011

Line items are scored as F1: an item counts only if its price is right to the cent and its name matches. The 30B row is from the first pass the same day; it was dropped there, so it wasn’t re-run with the final prompt. Sonnet’s one missed total is a free ticket it left blank instead of $0.00.

The closed models are better. All three got every merchant right, and the only line item any of them missed was on the concert ticket, where every model in the final run wrote something other than the printed “GENERAL ADMISSN”, mostly the name of the tour (I scored that strictly). The open Qwen3-VL 235B read 95% of line items and every total, at a seventh to a thirteenth of the cost per receipt. The smaller 30B was never close: it ran out of time on every long receipt, and some still failed when I lifted the limit to two minutes.

Where the 235B goes wrong. It read a scratched $4.38 as $4.36 on a McDonald’s receipt, and $2.99 as $2.29 on a Publix receipt photographed sideways. The same photo turned upright read perfectly, which is why the upload screen has a rotate button. On a long Italian grocery receipt it named one item after the loyalty-card line printed beside it. And three times it picked the wrong name for the merchant: a promotional headline on an Autogrill receipt, the card processor on a restaurant receipt, and the concert promoter on the ticket.

A stronger prompt made it worse. My first fix for the merchant names was a stricter rule in the prompt. I ran it three times against the original: it didn’t fix a single merchant, and on the Publix receipt it started listing “You Saved” as a purchased item, every time. So the rule came out and the fix moved into code: after extraction, a deterministic check recognises card processors, payment brands and ticket promoters, and flags the merchant name for a person to confirm. A prompt change touches every receipt; a check in code touches only the cases it names.

Why production still runs the open model. Receipt Relay is a free tool and every read is paid for, so a model that costs a fraction as much matters. More to the point, the design already assumes the model will sometimes be wrong: a misread price leaves the items short of the printed total, which the arithmetic check flags; an uncertain field is marked; and a person confirms everything before the email renders. The 235B’s misses are the kind that design exists to catch. If this were reading invoices for a business with no one checking, I’d pay for a closed model. Because the model is one line of configuration, switching would be a config edit, re-scored against the same fourteen answer keys.

04Features

What it does

  • Phone-photo upload with in-browser downscaling, rotate and crop
  • Vision-model extraction to a validated schema.org Order, with per-field confidence flags
  • Card numbers cut to the last four digits on the server, before anything is shown or exported
  • Arithmetic check that flags missed line items rather than hiding them
  • Correction screen: every field editable, photo alongside with a zoom loupe, flags clear as you fix
  • Two templates (Modern on ACORN, and Paper) with light/dark and desktop/mobile preview
  • Export as HTML or .eml (optionally with the original photo), or send to your inbox via SPF/DKIM/DMARC-authenticated mail: invite-only, with a request-access flow I approve
  • JSON inspector: the corrected order as a tree, with its validation state and a schema.org JSON-LD view
  • Spots a photo that isn’t a receipt and says so, instead of showing an empty form
  • Swappable model: changing provider or model is a config edit
06Live samples

The real email, live

These are the actual HTML emails the tool produced from sample receipts, not screenshots. They follow your device’s light or dark mode.

Modern template · restaurant receipt with a handwritten tip
Paper template · grocery receipt (scroll inside the frame)
07Stack

How it’s built

  • Vision LLMs over an OpenAI-compatible API (Qwen3-VL 235B via OpenRouter in production; Qwen3-VL 8B in LM Studio locally)
  • JSON Schema + schema.org Order as the extraction contract
  • HTML, CSS and vanilla JavaScript — no framework
  • PHP proxy: key handling, SSRF protection, rate limiting
  • ACORN email framework (MIT)
  • Resend on a dedicated, authenticated sending subdomain
  • Strict CSP and a sandboxed email preview
08Roadmap

Where it’s going

  1. Shipped

    End-to-end prototype

    Photo to extraction, correction, two templates, export and sending.

  2. Shipped

    Rendering checks in real inboxes

    Gmail, Apple Mail and Outlook on desktop and phone, light and dark.

  3. Shipped

    JSON payload inspector

    A tree view of the corrected order data, with validation state and a schema.org view.

  4. Shipped

    Open prototype

    Anyone can try it; sending is invite-only, with a request-access flow.

  5. Shipped

    Model bake-off

    Fourteen hand-checked receipts, measured for accuracy, speed and cost; Qwen3-VL 235B won.

  6. Shipped

    Full launch

    The production model, a Labs listing and search.

  7. Exploring

    Deals, weights and discounts

    Show lines like “2 for $7.00” and “2.47 lb @ $2.99/lb” in the Modern template, not just the Paper copy.

09Feedback

Using Receipt Relay? Tell me how it’s going.

Bug reports, ideas, questions and the occasional “this works” all land here.

What happens next
I read every message. Ideas that stick end up on the roadmap.
Your data
Used only to answer you. No mailing list, ever.

Want something built instead? Start a conversation

Hiring for applied AI work?

I build practical AI features that end in something people actually use. If that’s the kind of work your team needs, I’d like to hear about it.

Get in touch See all projects