amagi-receipts-to-csv
Point it at a folder of receipt photos and PDFs and get one CSV back: date, vendor, subtotal, tax, tip, total and an expense category for every receipt. OCR runs on your own machine, so nothing is uploaded. It can also write a file that QuickBooks Online will take through Banking > Upload from file.
Built for freelancers and small-business bookkeepers who keep a shoebox (or a camera roll) of receipts and type them into a spreadsheet once a month.
Install
pipx install amagi-receipts-to-csv
Needs Python 3.10 or newer.
The OCR models ship inside the rapidocr-onnxruntime package, so there is nothing else to set
up and no API key.
Usage
The repo includes five made-up receipts in examples/receipts: two photos, one crumpled photo,
one scanned PDF and one PDF with a real text layer.
amagi-receipts-to-csv examples/receipts
amagi-receipts-to-csv: 5 file(s) in examples\receipts
ok 2026-10-07 Blue Fern Cafe 23.50 Meals blue_fern_cafe.jpg
ok 2026-10-03 Corner Hardware & Supply 51.21 Supplies corner_hardware.png
check 2026-10-12 Harbor Street Parking 12.00 Parking & Tolls crumpled_parking.jpg
no subtotal line; subtotal is the sum of the item lines
subtotal 11.86 looks misread; corrected to 11.06 so the receipt adds up
ok 2026-09-28 Metro Office Supply 171.17 Office Supplies metro_office_supply.pdf
ok 2026-09-30 Quickfuel #118 42.18 Fuel quickfuel_scan.pdf
5 receipt(s): 4 ok, 1 to check. Sum of totals: 300.06
Wrote receipts.csv
receipts.csv has one row per receipt:
file,date,vendor,subtotal,tax,tip,fees,total,category,status,notes,source
A row is ok only when the date, vendor and total were all found and, if the receipt prints a
subtotal, subtotal + tax + fees + tip equals the total. Everything else is check, and notes says what to look at. In the run
above, OCR read the parking stub's subtotal as 11.86. The tool caught that 11.86 + 0.94 does not
make 12.00, fixed the one digit that made the receipt add up, and still marked it for you to
check.
source tells you how the text was read: text-layer for a PDF with real text (no OCR
needed), or ocr:rapidocr / ocr:tesseract.
QuickBooks Online
amagi-receipts-to-csv examples/receipts -f qbo
This writes qbo_import.csv in the 3-column layout QuickBooks accepts for a bank upload, with
each receipt as money going out:
Date,Description,Amount
10/07/2026,Blue Fern Cafe,-23.50
10/03/2026,Corner Hardware & Supply,-51.21
10/12/2026,Harbor Street Parking,-12.00
09/28/2026,Metro Office Supply,-171.17
09/30/2026,Quickfuel #118,-42.18
Use -f qbo4 if your bank account is set up for the 4-column Date, Description, Credit, Debit
layout. Add --only-ok to leave out the receipts marked check until you have looked at them.
Receipts with no date or no total are always left out of the QuickBooks file, and the CLI lists
them.
Your own categories
The built-in categories are Meals, Fuel, Parking & Tolls, Office Supplies, Supplies, Travel,
Software & Subscriptions, Postage & Shipping, Utilities & Phone and Groceries, picked by
keyword. To use your own chart of accounts, pass a rules file. Your rules are tried before the
built-in ones, and the vendors block cleans up names:
{
"categories": {"Client Meals": ["blue fern"], "Vehicle": ["quickfuel"]},
"vendors": {"sq *blue fern": "Blue Fern Cafe"}
}
amagi-receipts-to-csv receipts/ --rules rules.json
Add --no-builtin-categories to use only your list.
A local LLM for the hard ones
If you run Ollama, the tool can ask a local model about receipts where a field is missing or the amounts don't add up:
amagi-receipts-to-csv receipts/ --llm llama3.2
For LM Studio or llama.cpp, add --llm-api openai --llm-url http://localhost:1234. The model
fills in missing fields, and it can replace an amount only when the receipt does not add up.
Any amount or date it gives that is not printed on the receipt is thrown away, and the notes say
so. The tool refuses to talk to a server that is not on your machine unless you pass
--llm-allow-remote.
Options
-o, --output OUTPUT output file, or - for stdout (default depends on --format)
-f, --format {csv,qbo,qbo4,json}
-r, --recursive look in subfolders too
--ocr {auto,rapidocr,tesseract}
OCR engine: rapidocr (bundled), tesseract (if installed), auto
--day-first read 03/10/2026 as 3 October, not March 10
--rules RULES JSON file with your own categories and vendor renames
--no-builtin-categories
use only the categories in --rules
--only-ok leave receipts marked 'check' out of the output
--text-dir TEXT_DIR also save the OCR text of each receipt here, for review
--llm MODEL ask a local model (e.g. llama3.2) about receipts the rules could not finish
--llm-url LLM_URL LLM server URL. Default: http://localhost:11434 (Ollama)
--llm-api {ollama,openai}
--llm-allow-remote allow an LLM server that is not on localhost
-q, --quiet print only the output path
It reads .jpg, .png, .webp, .tif, .bmp, .gif and .pdf. iPhone .heic photos work after
pipx inject amagi-receipts-to-csv pillow-heif.
Exit codes: 0 means the run finished (even if some receipts need checking). 1 means it could not run: missing path, no receipt files, bad rules file, no OCR engine, or an LLM server that is not local. 2 means a bad option.
How accurate is it?
On the five example receipts every field matches the expected values, and the test suite checks that with the real OCR engine. Made-up receipts are the easy case, though, so we also scored it on 13 real receipt photos from Wikimedia Commons, labelled by hand. Four of them have no fair answer (out of focus, a blank guest check, a slip with no printed total, a coin-counting voucher). On the other nine:
| Field | Right |
|---|---|
| Date | 6 of 6 labelled |
| Vendor | 4 of 8 labelled |
| Total | 6 of 7 labelled |
Four of the 13 photos came back ok, and all four were right on every labelled field. Every
miss landed on a check row. Four is a small sample, so look over your first batch closely.
To re-run the benchmark yourself (it downloads the photos once, with credits):
python bench/run_commons.py
Limits
- Crumpled, faded, blurry and handwritten receipts lose fields. The tool marks them
checkinstead of guessing, and the add-up check flags a misread amount, but a wrong vendor name can still come through on anokrow. Vendor is the weakest field (4 of 8 in the test above). - A date with no year ("07/23") is left blank.
- One currency per receipt and no currency column. Totals are added up as plain numbers.
- Categories come from keywords. Expect to fix some, or write a rules file.
- Speed on a plain CPU (no GPU): the OCR model takes about 2 seconds to load, then about 2 to 6 seconds per photo. PDFs with a text layer skip OCR.
Use it from Claude Code
The repo ships a SKILL.md. Copy it to ~/.claude/skills/amagi-receipts-to-csv/SKILL.md and
Claude Code will run amagi-receipts-to-csv when you ask it to put a folder of receipts in a
spreadsheet or get them into QuickBooks.
Star it if it saved you an evening
If amagi-receipts-to-csv got you out of a month of typing receipts into a spreadsheet, a star helps
other freelancers and bookkeepers find it. Bug reports with the OCR text of a receipt it got
wrong (--text-dir saves it) are the most useful thing you can send.
Other AmagiLabs projects
- amagilabs on GitHub: the full catalog of small open-source tools from AmagiLabs (Amagisolutionsgroup, Inc.).
- amagi-watch: turns a video URL into something Claude can read (transcript, key frames and a timestamped index).
- amagi-legal-review-skills: Claude Code skills for contract and lease review.
Development
pip install -e ".[dev]"
pytest
python tests/make_fixtures.py rebuilds the example receipts. The tests run the real RapidOCR
engine on them; the Tesseract test is skipped if Tesseract is not installed.
License
MIT. See LICENSE. Copyright (c) 2026 Amagisolutionsgroup, Inc. (AmagiLabs).
Metadata
Release files for amagi-receipts-to-csv 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| amagi_receipts_to_csv-0.1.0.tar.gz | 35.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| amagi_receipts_to_csv-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 63.4 kB
Release files / amagi_receipts_to_csv-0.1.0.tar.gz
| Download URL | amagi_receipts_to_csv-0.1.0.tar.gz |
|---|---|
| Size | 35.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
272b7cde0276649d0f34213059cbeae969f15ac9c974ee2cf6bb21c8a5d460b1
|
|
BLAKE2b-256 checksum How to use checksums |
98da7e98aba667b171ed55f99f61cc45bffc079d30d38e14d89aaf6a2025b25b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.4
|
Release files / amagi_receipts_to_csv-0.1.0-py3-none-any.whl
| Download URL | amagi_receipts_to_csv-0.1.0-py3-none-any.whl |
|---|---|
| Size | 28.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a3ea098df7a11154f6e0e7124e9eaf0e417bbf16c335bee44dd8500ee4605388
|
|
BLAKE2b-256 checksum How to use checksums |
598dd1076682e49326756c10e89318bbfe10559a5809f810ec96425b70a47368
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.4
|
Security for amagi-receipts-to-csv 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.