The receipt is flawless. A restaurant in Florence, printed on paper that has not had time to fade, photographed flat under good light. The extractor returns the merchant, the address, the VAT number, six line items, a subtotal of EUR 84.00, EUR 8.40 of tax at 10%, a EUR 7.60 tip and a total of EUR 100.00. The arithmetic reconciles. Every field comes back above 0.95 confidence. The expense is refused anyway.

It is refused because the company’s meal limit for Florence is set per person, and nothing on the receipt says how many people ate. It is refused because the claim was filed against a trip that ended the day before the dinner. It is refused because a colleague already submitted a photo of the same receipt, and this is the second claim for one meal. None of those reasons is an extraction error. The OCR did its job perfectly, and the decision still could not be made from the document.

That gap is the most common source of wasted effort in expense automation. Teams that buy receipt OCR expecting the refusal rate to fall find that the refusals change character instead: fewer typos, just as many policy questions. The reason is structural. A receipt proves that a purchase happened. Whether the purchase is reimbursable is a question about the claimant, the trip and a policy table, and the receipt carries almost none of that.

What a receipt is actually able to prove

The clearest statement of what a receipt can carry comes from the tax rules, because they were written to decide exactly this: which parts of an expense a document proves, and which parts a person has to state. IRS Publication 463 (2025 edition) says documentary evidence will ordinarily be considered adequate if it shows the amount, date, place and essential character of the expense. For a business meal, it lists what the restaurant receipt must show: the name and location of the restaurant, the number of people served, and the date and amount.

The same publication is equally clear about what documents do not carry. The business purpose of an expense generally requires a written statement from the person claiming it, and a canceled check by itself does not prove a business expense without other evidence of its purpose. The rule was written for taxpayers, not for an expense system, but the division of labour it describes is the right one for software too. The document supplies amount, date, place and character. A person supplies purpose. A policy supplies the limit.

Note the one field in the restaurant list that many receipts do not print: the number of people served. Some point-of-sale systems show covers; many thermal receipts do not. When it is absent, the most important input to a per-person meal limit is simply not on the page.

Document fields and policy fields

The practical move is to classify every field an expense decision needs by where its value comes from. Only one of the three sources is the image.

Field the decision needsWhere the value comes fromWhat an empty value means
Merchant, date, total, currencyThe receipt.Unreadable or cropped image. A capture problem: ask for a new photo.
Tax by rate, tip, line itemsThe receipt, when the merchant prints them.Often legitimately absent on a simplified receipt. Not an error.
Number of people servedThe receipt sometimes; otherwise the claimant.A question for the claimant, never an OCR retry.
Attendees and their business relationshipThe claimant.The claim is incomplete. The document cannot fix it.
Business purposeThe claimant, in writing.The claim is incomplete, whatever the image quality.
Trip dates and destinationThe travel booking or the trip record.The expense cannot be placed in a trip, so no location-based limit applies yet.
Applicable limit (per diem, meal cap, room cap)The policy table, indexed by location, date and employee grade.The policy has no rule for this case. Route to a person who owns the policy.
Cost centre or projectThe claimant or the approver.An allocation decision, not a reading.
Card transactionThe card feed, matched on amount, date and last four digits.A cash expense, or a card transaction that has not posted yet.

Two things follow from the table. First, the right-hand column contains four different kinds of emptiness, and each routes somewhere else: back to the camera, to the claimant, to the travel record or to the policy owner. A system that collapses them into one “missing field” flag sends the claimant a request for a clearer photo when what it actually needs is a list of attendees. Second, more than half the rows are not extraction problems at all. Better OCR moves the first two rows and leaves the rest exactly where they were.

Absence is a value, not an error

The distinction the table forces is between a field that is not on the document and a field that is on the document but not legible. They look identical in a JSON response that returns null for both, and they demand opposite actions.

An extractor that is honest about this reports the two differently. A tip field that is absent because the merchant did not print one should come back as absent with high confidence: the extractor looked, and there is nothing there. A tip field that is present but smudged should come back with a low confidence and a pointer to the region of the image, so a reviewer can look at the same pixels. Downstream, the policy engine needs to know which of the two it got, because “no tip was paid” and “a tip was paid and we could not read it” lead to different reimbursement amounts.

The same discipline applies to the fields the receipt never carries. The number of attendees is not a low-confidence reading of the receipt; it is a question the system has not asked yet. Treating it as an extraction gap is how teams end up re-running OCR on a perfectly good image, hoping for a field that was never printed.

Five perfect receipts that are still refused

Each of these arrives with every document field read correctly. Each is refused, or should be, for a reason that lives outside the image.

  • The dinner with no head count — a EUR 100.00 total against a per-person limit. Without the number of attendees, the system can neither approve nor refuse; it can only ask. The receipt is not wrong.
  • The hotel folio with a minibar — room, tax, breakfast and two minibar charges on one document. Publication 463 describes a hotel receipt as adequate when it shows separate amounts for lodging, meals and other charges. The extraction has to keep those amounts separate, because the policy reimburses some lines and not others.
  • The receipt outside the trip — dated the day after the return flight. The date is read correctly. Whether it is reimbursable depends on the trip record, and on whether the policy allows travel-day meals.
  • The same meal, claimed twice — two attendees each photograph the receipt and each file it. Both images are real. The duplicate is visible only across claims, on merchant, amount, time and card, never inside one document.
  • The line the policy excludes — an itemised bar tab where the policy reimburses food but not alcohol. The line items are read perfectly; the refusal is a rule applied to them.

What these cases share is that the extraction is a precondition for the decision, not the decision. A receipt pipeline that measures itself only on field accuracy will report excellent numbers on all five, while every one of them still needs a person or a rule to resolve.

The limit is a dated table, not a model

The limits themselves are data, and they change on a calendar. In the United States, the General Services Administration publishes per diem rates for federal travel by location and by fiscal year, and many private policies either adopt those rates or keep their own table with the same shape: a destination, a date range, a lodging cap and a meals allowance. A dinner in September and the same dinner in October can fall under different rows.

That has three consequences for where the logic lives. The limit belongs in a versioned policy table, not in the extraction prompt, so that a rate change is a data update rather than a model change. Every approval and refusal should record which version of the table it applied, so that an audit a year later can reproduce the decision against the rule that was in force. And currency conversion belongs to the policy side too: the receipt states the amount in the currency paid, and the policy names the rate and the date at which it converts. An extractor that silently converts EUR 100.00 into another currency has made a policy decision it had no mandate to make.

This is also the honest reading of the “policy flags” slot that receipt extraction outputs often carry, including the Cogneris receipt extraction sample. A flag like “within meal limit” is the result of a rule evaluated against the extracted fields plus the inputs the table above names. The flag is only as good as the attendee count, trip record and policy row it was computed from, and a response that shows the flag without them has hidden the part a reviewer most needs to see.

What to build, in order

None of this argues against receipt OCR. It argues for placing it correctly, so that it removes the typing and leaves the judgment where it can be audited.

  • Extract with evidence — amount, date, merchant, tax by rate, tip and line items, each with a confidence and a pointer to the region it came from.
  • Separate absent from illegible — return them as different states, and route illegible fields to recapture and absent fields to nothing at all.
  • Ask the claimant for claimant fields — purpose, attendees and their relationship, and project, collected at submission rather than discovered at review.
  • Join to the trip and the card — place every receipt in a trip record and match it to a card transaction before any limit is applied.
  • Apply a versioned policy table — and store the version, the inputs and the rule on every decision.
  • Check duplicates across claims — not only within one submission, because the second claim for a meal is filed by someone else.

The order matters. A team that starts at the bottom of the list, building rules on top of fields it has not separated into document and claimant values, ends up writing rules that fire on missing data and refuse legitimate expenses for reasons nobody can explain.

Where this sits next to accounts payable

The word “receipt” means two different documents in finance operations, and the difference is the whole boundary of this article. In accounts payable, the goods receipt is the warehouse’s confirmation that ordered items arrived, and it is the third document in a three-way match between purchase order, goods receipt and supplier invoice. Tolerances, partial deliveries and line-level matching belong there.

An employee expense has no purchase order to match against. Its counterparts are the claim, the trip and the policy, and the only external record that corroborates it is the card transaction. When the card feed is available as a statement rather than an API, reading it line by line is its own problem, covered in reading a bank statement by its lines. The expense receipt is the smallest document in either workflow, and in both it is the one that proves the least on its own.

A refusal should cite the rule, not the image

The Florence dinner is a useful test for any expense system. Hand it the perfect receipt and see what comes back. If the answer is an approval, the system decided without the head count. If the answer is a request for a clearer photo, it confused an absent field with an illegible one. The right answer is a question to the claimant, naming the one input the receipt could not supply and the policy row that needs it.

That is the standard to hold receipt automation to. Every approval and every refusal should point to the document fields it read, the claimant fields it was given, and the version of the rule it applied. The receipt is evidence of a purchase. Everything else a decision needs has to come from somewhere that can be named.