Monthly Amazon Order Import¶
How the Amazon order export gets into heezy-finance, so a card charge stops reading as
AMAZON MKTPL*RM1MB6TF3 and starts showing what was in the box.
The short version
Request Your Orders from Amazon's privacy portal, wait for the email, drop
Order History.csv into heezy/ingest/raw/amazon/ on the NFS share, then run the
Amazon CSV Import workflow in heezy-containers with dry_run unchecked. Everything below
is why, and what to check afterwards.
What this actually does¶
A bank statement gives you a merchant, a date, and an amount. Amazon never tells the bank what you bought. The import closes that gap in three steps:
- Load the export. Each CSV row is one item on one shipment. Rows group into orders
(
orders), items (order_items), and shipments (order_shipments). - Classify each item.
item_classifier.pyruns three tiers in order: keyword rules, then theitem_category_cachetable, then a local Ollama call. A title seen before never reaches Ollama. - Match shipments to charges. Each Amazon debit is paired with a shipment of the same amount
that shipped near the statement date. The pairing is written to
order_shipments.bank_transaction_id.
From there the reconcile tab draws the charge as identified, and a basket holding pet food and groceries splits across both categories instead of landing entirely in one.
Why shipments and not orders¶
Amazon charges the card once per shipment, on the ship date. An order that arrives in two boxes is two charges, and neither equals the order total. Ship lag runs from same-day to over a week. Matching on order totals and order dates catches roughly a quarter of what shipment matching does.
Step 1 — Request the export¶
Amazon does not offer a one-click download. The request takes hours to a day.
- Go to amazon.com/hz/privacy-central/data-requests/preview.html.
- Choose Your Orders from the category list. Not "Request All Your Data", which is enormous and arrives as dozens of files.
- Submit, then confirm from the verification email Amazon sends immediately.
- Wait for the second email, "Your Amazon.com data is ready", and download the archive.
The archive contains several CSVs. The one that matters is the retail order history: one row per
item, with Order ID, Order Date, Ship Date, Product Name, Unit Price and Total Amount
columns. Those column names are what the importer reads, so if a future export renames them the
parse comes back empty rather than wrong.
Step 2 — Stage the file¶
Rename it to Order History.csv and put it in the ingest folder on the NFS share:
That is the heezy/ingest/raw/amazon/ folder on the SMB share from a desktop, and
/nfs/heezy/ingest/raw/amazon/ on big-boi. Overwrite the previous file. Only one export lives here
at a time; each new export is a full history, not a delta.
The filename matters. The workflow passes that exact path, spaces and all.
Step 3 — Run the workflow¶
In heezy-containers, run Amazon CSV Import from the Actions tab. It is dispatch-only and never
fires on a push.
| Input | Default | What it controls |
|---|---|---|
since |
2025-05-01 |
Only recategorize bank transactions on or after this date |
import_since |
2025-04-01 |
Only import orders placed on or after this date |
dry_run |
false |
Parse and classify, write nothing |
Keep import_since earlier than since. A charge posting on the 2nd of a month can belong to an
order placed the previous month, and it will never find its order if the import window starts at the
same date.
For a routine monthly run the defaults are fine: the importer skips orders it already holds, so re-importing the same range costs nothing but a few seconds of lookups.
The job builds the finance image, then SSHes to big-boi and runs both scripts there. It runs on big-boi rather than in the job container because the job container cannot mount the NFS share.
How long it takes¶
Minutes if most item titles are already in item_category_cache. A first-time import over a fresh
range is much slower, because every unseen title costs one Ollama call and big-boi classifies on CPU.
Roughly 8 orders per minute is normal for uncached items.
Step 4 — Check the result¶
The workflow log ends with four numbers:
Done. Inserted 58 orders, 81 items. Skipped 898 already-existing (830 existing item rows backfilled).
Found 219 Amazon debit transactions to evaluate
Updated 39 transactions. No match: 36. Mixed category: 21. Already correct: 123.
Linked 160 shipments to a transaction (24 left unlinked as ambiguous).
- Updated — the charge's category changed to what its items say.
- Already correct — it already matched. Normal and expected to dominate on a repeat run.
- Mixed category — the shipment holds more than one category, so no single category is written. These still get linked and still split correctly in the reports.
- No match — no shipment of that amount shipped near that date.
- Ambiguous — two shipments of the same amount in the same window. Deliberately left unlinked rather than guessed.
Then open the Reconcile tab on finance.heezy.info and spot-check the newest month. Amazon rows should show a green check and a clickable item count. Clicking it opens the order, its items, and a link out to the order on Amazon.
When something looks wrong¶
The item count badge is missing¶
The charge has no linked shipment. Either the amount never matched, or two candidates tied. Check
the workflow's No match and ambiguous counts.
A charge sits under the wrong category¶
Open the item modal and change the item's category from the dropdown. It saves immediately, and the
category splits recompute on their own because they are read from order_items live. There is no
re-import needed and no cache to bust.
Fix it at the source too, if the title is one that recurs: add a keyword rule to
item_classifier.py in heezy-containers/dockerfiles/heezy-finance/. Rules beat both the cache and
Ollama, so the next import gets it right without a manual correction.
Nothing matches for an older stretch¶
Some periods cannot be reconciled by amount at all. Heavily discounted Subscribe & Save orders ship many small boxes on the same day, and a single card charge bundles an arbitrary subset of them. There is no amount to match against. This is a limitation of the export, not a bug to chase.
The workflow fails on the SSH step¶
Check that OpenBao still holds production/heezy/ssh/mcp-admin-private-key and
production/heezy/postgres/heezy-credentials. Both are read fresh on every run.
What the import never touches¶
- Receipts. Receipt line items come from the mailbot and OCR, on their own schedule. The two sources are read together but written separately.
- Non-Amazon merchants. A Costco or Meijer charge has no item data anywhere in the system unless a receipt was captured for it. Its category stays merchant-derived.
- Titles and prices. Editing them in the UI is not offered, because the next import would overwrite the edit. Category is the one field the UI can change.