The applicant uploads an electricity bill. It is issued by a real utility, it carries the applicant’s surname, the account number resolves, the PDF was produced by the utility’s own billing system, and every forensic signal reads clean. The reviewer rejects it anyway, and the reviewer is right. The bill is dated four months ago, it is addressed to the applicant’s partner, and the street address on it is the service address of a flat two floors below the one on the application.

Nothing about that document is false. It is a genuine record of a genuine account, and it still does not do the job it was submitted for. That is the ordinary case in proof-of-address review, not the exotic one. Forged bills exist, and they are worth a pipeline of their own, but the queue of rejected address documents is overwhelmingly made of real paper that fails a rule.

This matters for how the problem is built. A team that treats every rejection as a fraud signal will tune a detector against documents that were never fraudulent, raise its false-positive rate on honest applicants, and still not explain to any of them what to upload instead. The rule was the thing that failed. The rule is where the design has to start.

Four ways a real document fails

Almost every rejection of a genuine proof of address falls into one of four families. They are different questions, answered by different fields, and they deserve different reason codes.

  • Currency — the document is too old for the policy’s window. A bill from last spring proves where someone lived last spring.
  • Holder — the name on the document is not the applicant’s, or not only the applicant’s: a spouse, a parent, a landlord, a company, a joint account.
  • Type — the document is genuine but not on the accepted list. A mobile phone bill, a delivery note, a handwritten tenancy letter, a screenshot of an account page.
  • Address — the address on the page is a real address, but it normalizes to a different place from the one being verified: another unit, a mailing box, a billing address that is not the property.

None of the four is detected by asking “is this document authentic?”. All four are detected by reading the document correctly and then applying a written rule to what was read. That separation — extraction produces facts, policy produces a verdict — is the whole argument of this article.

The accepted list is a policy someone wrote

It is tempting to treat “what counts as proof of address” as general knowledge that a model can learn. In regulated onboarding it is not. In the United States, the customer identification program rule for banks, 31 CFR 1020.220, requires the bank to obtain an address before opening an account and specifies what that address must be: “for an individual, a residential or business street address”, with narrow fallbacks such as an Army or Fleet Post Office box number for someone who has no street address. For verification by documents, the same rule says the program “must contain procedures that set forth the documents that the bank will use.”

Two consequences follow, and both are about design rather than law. First, the list of acceptable documents is something each institution writes down, so it differs between institutions and changes over time inside one of them. Second, some of the constraints live in the address, not in the document: a perfectly genuine bank statement mailed to a post office box is a real document carrying an address that the rule does not accept for an individual.

This article does not tell anyone what their list should contain. The point is narrower: the list exists, it has a version, and a system that encodes it implicitly inside a classifier cannot say which version it applied when a rejected applicant asks why.

The acceptance matrix

Written out, most acceptance policies reduce to a matrix: document type against a validity window and a holder rule. The table below is an illustrative policy, not a recommendation and not a statement of any regulation — the values are exactly the part each institution sets for itself.

Document typeValidity window (example)Holder rule (example)What the extraction must supply
Utility bill (electricity, gas, water)Issued within 90 daysApplicant named as account holder, alone or jointlyIssue date, billing period, account holder names, service address and billing address as separate fields
Bank or card statementStatement period ending within 90 daysApplicant is an account holderStatement period start and end, all holder names, mailing address
Council or property tax noticeCurrent tax yearApplicant is the liable partyTax year as printed, liable parties, property address
Tenancy agreementIn force on the review dateApplicant is a named tenantStart and end date, tenants, landlord, let property address including unit
Government correspondenceIssued within 12 monthsAddressed to the applicantIssuing body, issue date, addressee, address
Mobile phone billNot accepted—Document type, so the rejection can say so

Read the right-hand column rather than the middle two. The matrix changes every time a compliance team revises it; the facts it needs from each document almost never do. That asymmetry is why the policy should sit outside the extractor. A new window is a configuration change, applied to facts that were already extracted and stored with their evidence. A window baked into a model is a retraining project.

The last row is deliberate. A document type the policy does not accept still has to be recognised with confidence, because “we do not accept phone bills” is a useful answer to an applicant and “unreadable document” is not.

“Within 90 days” of which date?

The validity window sounds like the simplest rule in the matrix and is the one most often implemented wrongly, because a single bill carries several dates and they mean different things.

  • Issue date — when the document was produced. Usually what a policy means, but not always printed as such.
  • Billing or statement period — a start and an end. A quarterly bill issued last week can cover a period that began five months ago.
  • Due date — a payment deadline, typically weeks after issue. Reading it as the issue date makes an expired document look current.
  • Meter reading or tax year — a date about the service, not about the document.
  • Upload date — when the applicant submitted it. Not on the page at all, and not the date the window should be measured from unless the policy says so.

So an extraction that returns one field called document_date has already made a policy decision by choosing which of those dates to put in it. The honest output is every date the page prints, each labelled by what it is, with the page and region it came from. The policy then states which one its window is measured from and against which clock — review date or submission date — and that choice is visible in the audit trail rather than hidden in a heuristic.

The clock matters more than it looks. A document that was 85 days old when the applicant uploaded it and 95 days old when a reviewer got to it has not changed. Whether it passes depends on a sentence in the policy, and a case that sat in a queue over a weekend should not flip from accepted to rejected because nobody wrote that sentence down.

Whose name is on it

Holder rules generate more friction than any other family, because households do not organise their paperwork around onboarding checklists. The utility account is in one partner’s name, the bank account is joint, the lease names both tenants but lists one with a maiden name, and the council tax notice is addressed to “The Occupier”.

The extraction work here is precise and unglamorous: return every name the document prints as a party, in the order and role in which it prints them — account holder, joint holder, tenant, landlord, addressee, care-of recipient. Do not return a single name field chosen by proximity to the address block, because on a joint statement that field will contain whichever holder the layout happened to print first.

Name comparison against the application is a separate step, and it should return its reasoning rather than a score alone: exact match, match on surname and initial, match after transliteration, or no match. Whether “surname and initial” passes is, again, policy. So is whether a document in a spouse’s name can be accepted together with a document that evidences the relationship. What the extraction owes that policy is the full list of named parties, so the rule has something to evaluate.

The address that is real but somewhere else

The fourth family is the subtlest, because both sides of the comparison are valid addresses. The failure is that they are not the same address, and the difference is often a single token.

What the document showsWhy it does not verify the applicationWhat the extraction must keep
Same street and number, no unitA building with twelve flats is twelve residences; the document may belong to any of them.The absence of a unit as an explicit fact, not a blank that normalizes to a match.
Same street and number, different unitA neighbour’s bill, a previous flat, or a typo on the application.The unit as its own component, compared on its own.
Billing address differs from service addressThe utility is billing the property to someone who lives elsewhere, often a landlord or an agent.Both addresses, labelled; the policy chooses which one proves residence.
Post office box or mail forwarding serviceA mailing address, not a residential street address.The address type, recognised before any comparison.
“Care of” line above the addressThe addressee receives mail there; it does not say they live there.The care-of line as a separate component, not merged into the name.

Every row in that table is lost by the same shortcut: normalizing the document address into a single string and fuzzy-matching it against the application. Fuzzy matching is designed to forgive small differences, and in this family the small differences are the finding. Parse into components first — unit, number, street, locality, postal code, country, address type — then compare component by component, and let the policy state which components are allowed to differ.

What the extraction has to deliver

Put together, the contract between the document and the policy engine is short, and none of it is a verdict.

  • Document type with confidence — including the types the policy does not accept, so a rejection can name what was received.
  • Every printed date, labelled — issue, period start and end, due date, tax year, each with its source region, never collapsed into one field.
  • Every named party, with its role — holder, joint holder, tenant, landlord, addressee, care-of recipient, in the order printed.
  • Every address, parsed and typed — service and billing addresses kept apart, unit kept as its own component, mailing boxes recognised as mailing boxes.
  • Unread distinguished from absent — a unit the document does not print and a unit the extractor could not read are different facts and must not arrive as the same empty string.
  • A citable origin for each value — page and region, the same coordinate contract any reviewable extraction owes, so a reviewer lands on the date that failed rather than rereading the bill.

On the other side of that contract, the policy engine returns a verdict with a reason code from the four families — outside_validity_window, holder_not_applicant, type_not_accepted, address_component_mismatch — plus the policy version it applied. A reason code is what turns a rejection into an instruction, and the version is what lets the decision be re-examined after the policy changes.

Not a fraud problem, and not a resubmission problem

Two neighbouring problems share vocabulary with this one and should stay separate from it.

A fabricated or edited proof of address is a real threat, and the generative fraud article covers it: a bill rendered to match a utility’s public template, with dates placed inside the acceptable window on purpose. Everything in this article assumes the document is genuine. The two checks run side by side and answer different questions — is this document authentic, and does this authentic document satisfy the rule — and folding them into one score makes both worse. A forger reads the acceptance policy too; that is why the fake bill is always inside the window.

What happens after a rejection is a workflow question. Asking the applicant for one specific replacement, and deciding which earlier checks a new document reopens, belongs to partial resubmission, and the requirement slot the replacement fills belongs to the collection portal. This article stops at the verdict and its reason code, which is exactly what both of those flows need as input.

A rule is not a detector

The genuine document that fails the policy is the common case, and the reason it is hard is not that it hides anything. It is that the rule it fails is written somewhere else, in a compliance manual, with a version and an owner, and the document has to be read carefully enough for that rule to apply.

So build the two halves apart. Let extraction return every date, every party and every address component the page prints, with evidence behind each one. Let the policy, versioned and owned, turn those facts into a verdict with a reason. Then a rejected applicant can be told which date, which name or which unit failed — and the next policy revision is a change to a table rather than a retraining exercise.