AI-Assisted Expense Reporting: A Practical Workflow
How I used AI to handle three trips worth of backed-up expenses, from raw receipt photos to a fully submitted expense report.
I hate putting in my expenses for travel, and shamefully I’ve skipped it more than once because of how much I hate doing it. Receipts pile up across trips, currencies mix, and the cognitive overhead of translating a stack of crumpled receipts into a report that will be accepted is enough to put it off for weeks, or indefinitely. So when I finally had three trips backed up, I decided to let AI handle as much of it as possible.
Here’s how a recent multi-trip filing got handled almost entirely by AI, from raw photos to a fully receipted, submission-ready expense report, and what broke along the way.
The Raw Material
Three reports: a team lunch, an international two-week business trip, and a conference. Throughout each one I’d gotten into the habit of photographing every receipt on the spot before it hit my pocket or the bottom of my bag. Not organized, not named, just snapped and dumped into a folder. That turns out to be enough. The AI doesn’t need clean inputs, it needs some input, and a blurry photo of a restaurant bill beats a missing receipt every time. The result was a folder of receipt photos from my phone, restaurant itemized bills, bank terminal CC slips, Uber PDFs, and at least one image that turned out to be a menu. Mixed currencies, no organization, no naming convention. Completely normal starting point.
Phase 1: Making Sense of the Stack
The first AI session handled everything that didn’t require touching the actual expense system, reading the receipts, reconciling them against the card statement, organizing the files, and building a clean submission package.
Reading the receipts. All the images got processed in parallel, pulling out merchant, date, amount, and currency from each one. The AI immediately spotted paired files, since a lot of European restaurants produce both an itemized receipt and a separate bank terminal slip for the same charge, and grouped them together. It also flagged a personal booking that had ended up in the business folder, which got excluded before anything else happened.
Cross-referencing the statement. I fed in the credit card statement for the period and had every line item matched against the extracted receipts. This surfaced transportation charges, smaller meals, and a handful of miscellaneous items with no receipt documentation. For the legitimate business ones, I pulled the missing receipts from the relevant apps and matched them back. The statement crosscheck is honestly the step most people skip, and it’s the one that catches things that would otherwise silently disappear from the record.
Organizing the files. All the receipt photos got renamed from meaningless camera timestamps to something structured: date, merchant, amount, currency. Paired files got matching base names with suffixes. A rename script handled the whole folder in seconds. This naming convention really matters later, because when you’ve got 30-plus files to sort into the right expense report, human-readable names are the difference between a five-minute task and a twenty-minute one.
Building the submission package. The output from Phase 1 was a clean list of 34 line items, merchant, date, amount, currency, category, receipt file path, and notes on which entries were large entertainment expenses that would need a business purpose annotation. That got handed off to the second agent as a brief.
Phase 2: Getting It Into the System
The second AI operated in the browser with access to the expense management platform. Its job: create the reports, enter all 34 line items, attach the receipts, and link everything correctly. Here’s how that actually went.
Start with reconnaissance. Before touching any form, I had the agent opened a fully submitted expense report from a prior trip and read its structure, category taxonomy, required fields, how attendees worked, how multi-currency entries displayed. Two minutes of upfront reading prevented a full rework cycle. Every subsequent entry used the correct category names from the start.
Creating the reports. Three reports, one per trip. An existing draft for the international trip got reused. EUR-denominated entries were entered in local currency and the platform applied its own exchange rate, which is correct behavior. No pre-converting anything.
Entering the line items. Each of the 34 entries needed date, category, amount, currency, attendees, and a memo. A few things made bulk entry harder than it looks:
The attendee field is mandatory for every entry, not just meals, but transportation too. That wasn’t obvious from the form; it surfaced through save errors. Once known, the agent adapted, but those first few failures meant rework. The better move would’ve been to test-save a dummy entry in each category type before starting, which would surface all required fields upfront.
The form layout also shifts depending on what combination of category and currency you pick. Meals & Entertainment adds a tip field. EUR adds exchange rate and conversion fields. Each addition shifts everything else down the page, including the attendee checkbox that needed to be clicked for every single entry. Coordinate-based UI automation is fragile this way, since what works for one form variant silently misses on another. The agent had to recalibrate click targets for each configuration.
Attaching the receipts. This is where the workflow hit a genuine wall.
The browser extension used for automation doesn’t have local filesystem access on macOS. It can’t read files and attach them to upload inputs, the call returns “Not allowed” regardless of what’s being uploaded. Several approaches got tried: direct file upload, navigating to file:// URLs, JavaScript injection. All blocked, either by the extension sandbox or by the site’s content security policy.
The workaround was the platform’s email-to-receipt feature: send attachments to a dedicated inbox address with the report code in the subject line, and the platform routes them to the correct report. One extra wrinkle, the platform only accepts image formats via email, not PDFs. The Uber receipts, originally downloaded as PDFs, got converted to PNG with a local command-line tool before sending.
This added a manual step. Three emails, one per report batch. One batch got partially sent to the wrong report, caught during the linking phase when receipts dated to the international trip showed up in the conference report. The correct files were re-uploaded; the misrouted copies are still sitting as orphans in the wrong report.
Linking receipts to entries. With receipts landed in each report, the agent opened the receipt management view, filtered to “show only unlinked,” and worked through each image: read the date and amount from the info bar, find the matching line item, link. The platform’s auto-match suggestion was right about half the time. The other half required manually scrolling the item list, which defaults to newest-first with no search-by-amount capability.
Paired receipt and CC slip pairs both got linked to the same line item. In a few cases the itemized bill and the terminal slip showed slightly different amounts due to tip; the entry matched to the charged amount, not the pre-tip subtotal.
Final counts: 30 receipts across 24 line items for the international trip, 12 across 9 for the conference, 2 for the domestic dinner.
What Would Make This Better
The workflow worked, all 34 entries submitted, all receipts attached and linked. But a few friction points are worth calling out if you’re thinking about replicating this.
File attachment needs a non-browser path. The inability to attach local files through the browser extension is a real constraint, not a configuration problem. For platforms that offer it, uploading receipts through the API directly, authenticated with a session token and files posted as multipart form data, would be far more reliable than the email workaround and would cut out the manual step entirely. The email approach works for this platform specifically but doesn’t generalize.
APIs beat browser automation for structured data entry. Browser automation through a UI is inherently fragile. Form layouts shift, coordinates drift with window size, error states are ambiguous, and custom widget libraries often don’t respond to synthetic events predictably. For something as structured as expense entry, fixed fields and known data types, a direct API call is an order of magnitude more reliable. The browser agent is a capable fallback when no API exists, but it shouldn’t be the first choice. Unfortunately in this case it had to be a browser agent.
Receipt routing should be generated, not manual. The misrouted batch happened because emails got assembled by hand. A better version of this step would generate pre-addressed draft emails programmatically, one per report, correct subject line, exactly the right file list, so the only job is reviewing and clicking Send.
Required field discovery through errors is avoidable. The attendee requirement on transportation entries got found the hard way. A quick test-save pass at the start of bulk entry, one dummy entry per category type, immediately cancelled, would surface all required fields before 20 entries are already in.
What This Actually Demonstrates
No single step here was magic. Reading receipts, matching statement lines, renaming files, entering form data, attaching documents, a person can do all of this. The point is that doing it manually would take most of an afternoon, and most of that time would be low-value mechanical work.
The AI handled all the mechanical work. I made the decisions: what was personal versus business, whether a gap was worth pursuing, whether a charge needed an explanation. That’s the right division of labor.
It’s also genuinely repeatable. A consistent folder structure and naming convention from Phase 1 means future trips start cleaner. The statement crosscheck is now a fixed part of the process rather than something that gets skipped. The submission package format is established. Each iteration should be faster.
The real ceiling here is proper API integration, receipt files uploaded programmatically, line items posted as structured data, no browser required. That version runs in minutes and has near-zero failure rate. The browser-based approach is a practical stepping stone that works today with existing tools, even when the tools occasionally fight back.