Key takeaways
- Register every document before anything reads it. An identifier, a file hash and an arrival record come first, because the documents that fail extraction are exactly the ones you otherwise cannot count.
- Design the confidence bands, not the accuracy. Extraction returns a per-field spectrum, so write down what happens in each band — post unattended, repair one field, full review, reject — and let any failed arithmetic check override the band whatever the confidence says.
- Deduplicate on content, not on the file. The same invoice arrives as a portal download and as an email attachment with different bytes, and only a key built from supplier, invoice number, date and gross catches both.
- Name the exceptions before you automate: unreadable scan, several documents in one file, wrong currency, missing tax ID, line items that do not sum, the cross-channel duplicate, and the document that is not an invoice at all. Seven branches, not one queue called manual review.
- Keep what a supporting document has to show — payee, amount, date incurred and description — with the original attached to the posted record and traceable to the part of the page each figure came from. A shared mailbox is not an archive.
Every channel an invoice arrives on is a channel you have to watch
Before any of this is a data problem it is an intake problem. Most teams can name the shared mailbox and one portal, and are then surprised by the invoice that spent three weeks in a colleague's inbox. A channel nobody watches produces invoices nobody has: you find out it existed when a supplier calls about a payment there is no record of.
Enumerate them first, then decide what each one does to the document before you ever see it.
| Channel | What arrives | What it does to the document |
|---|---|---|
| Shared AP mailbox | PDF attachments, sometimes several in one message | One message is not one invoice. Register per attachment, or you will post the first and lose the other three. |
| Supplier portal | Downloads you must fetch, often without notification | Needs a scheduled sweep. The same invoice usually also arrives by email, in a different file. |
| Post and scanning | Scanned batches, image-only, occasionally crooked | No text layer to fall back on, and batch boundaries have to be inferred rather than read. |
| Forwarded from a colleague | An invoice buried under a thread about something else | Arrival timestamp is the forward, not the receipt. Due dates are already partly spent. |
| Photographs from phones | Receipts and small supplier invoices, taken at an angle | The most common source of an unreadable document. Worth fixing upstream rather than downstream. |
The document lifecycle, step by step
Ten steps take a file from arrival to a posted record with the original attached. Each is labelled by who should own it once the process runs itself: fixed code, model judgment, or a person.
- 01Receive and registerTriggerStore the original bytes unmodified, hash them, and assign an internal document identifier together with the channel, sender and arrival time. Registration happens before anything interprets the content, so a document that later fails to extract is still a document you can count.
- 02Classify the documentAI judgmentSupplier invoice, credit note, statement, delivery note, or not an accounting document at all. Roughly one in every batch is something else, and the cheapest moment to find out is before extraction rather than after a coding question.
- 03Split or keep wholeCodeA scanned batch holding five invoices becomes five registered documents, each carrying the identifier of the file it came from. A single invoice spanning four pages stays one document. Getting this backwards produces either four postings or one.
- 04Extract the fieldsAI judgmentSupplier identity, invoice number, dates, currency, net, tax, gross, tax ID, PO reference and line items. Each field carries its own confidence and a reference to where on the page it was read from. A field that was not found is recorded as absent, never as an empty string.
- 05Validate what was readCodeLine items sum to the stated net, net plus tax equals gross, the tax rate is one you permit, the currency matches the supplier default, the date is neither in the future nor ancient, and the supplier exists on the master file. None of this needs judgment, and all of it catches confident nonsense.
- 06Check for duplicatesCodeTwo keys, not one. The file hash catches the same attachment forwarded twice. A content key built from supplier, invoice number, date and gross catches the portal download and the emailed copy, which are the same invoice in different bytes.
- 07Route by confidenceCodeTake the lowest confidence among the fields that change the money and apply your bands: post, repair one field, full review, or reject. This step is arithmetic on a written-down rule, which is why it belongs to code even though the input came from a model.
- 08Code to account and cost centreCodeWhere the line description matches a pattern this supplier has used before, the coding is a lookup. Where it does not, the process proposes and a person confirms — and the confirmed rule is written back so the same question is not asked twice.
- 09Post and attachCodeWrite the record keyed by the internal document identifier, so a repeated attempt updates rather than duplicates, and attach the original file to the posting. From here the payable enters matching and approval under the separate payables process.
- 10Reconcile against the statementCodeCompare the supplier statement line by line against posted documents and surface only the residue: statement lines with no document, documents absent from the statement, and differences outside tolerance. This is where the invoices that never arrived at all become visible.
Extraction confidence is a spectrum, so design what happens in each band
The question teams ask about capture is “how accurate is it?”, and it is the wrong question. A reading step does not return right or wrong. It returns a value per field with a confidence attached, and the design work is deciding what your process does at each level — including the levels where it should refuse to act. Confidence belongs to the field, not the document: a document-level score averages away the one number that matters.
| Band | What the process does | What the person sees | What is recorded |
|---|---|---|---|
| High on every money field, every check passed | Posts unattended | Nothing, beyond a weekly sample review | Per-field confidences and the version of the bands in force |
| High except on one field | Asks for that field alone | The field, the page region it was read from, and the document beside it | The value before, the value after, who changed it and when |
| Low on any money field | Full review before anything posts | The whole extraction next to the original document | Which fields were corrected, as an ordered set of events |
| Unreadable, or classification uncertain | Rejects or routes. No extraction attempted | The document and the reason it could not be read | The rejection, its reason, and the message sent |
| Any validation failure, at any confidence | Overrides the band and goes to a person | The check that failed and the figures involved | The failed check by name, not just “exception” |
The last row is the one that earns its place. A confident figure that contradicts arithmetic should never post, because the confidence describes how clearly the number was printed, not whether it is the right number.
The middle bands also need designing as a piece of human work, not just a queue. A pre-filled form invites agreement: the reviewer sees a plausible value and confirms it without looking at the document. The EU AI Act names this directly, requiring that high-risk systems be designed so that overseers can stay aware of the tendency to over-rely on their output. In practice that means showing the region of the page the value came from rather than the value alone, keeping the repair queue small enough that people read it, and sampling auto-posted documents so the top band is checked by someone occasionally.
Illustrative volumes for a team receiving 140 documents in a week across four channels. Made-up figures for shaping a design conversation, not customer results.
- 96 clear every check inside the top band and post without anyone reading them.
- 22 need one field confirmed, most of them an invoice number on a layout the supplier changed last month.
- 11 go to full review: 6 line-item mismatches, 3 missing tax IDs, 2 in an unexpected currency.
- 5 are not invoices — two delivery notes, two statements and a marketing email with a PDF attached.
- 4 are duplicates: 3 caught on the file hash, 1 caught only by the content key after arriving from the portal and by email.
- 2 are unreadable photographs and are sent back.
The 96 are the boring win. The 33 needing a person are the actual design problem, and the number worth watching is not the total but the trend per supplier: a layout change shows up as a cluster of repairs from one name, days before anyone notices it as a pattern.
Who approves what once the reading is automated
The approvals here are about the document, not about the money. Approving the spend and releasing the payment sit downstream in the payables process and are matched to amount bands. What follows is the smaller matrix that governs capture, and it stays with the process permanently.
| Action | Who decides | Why it sits there |
|---|---|---|
| Post a document inside the top band with every check passed | Nobody, with a sampled review weekly | A gate on every document would be a re-keying job with extra steps. The sample is the control. |
| Confirm a single repaired field | The AP clerk working the queue | Low risk, high volume. Worth making fast and worth showing the page region for. |
| Accept a new account and cost centre combination | The cost centre owner. Permanent | A new coding rule applies to every future document from that supplier, so it is a policy decision, not a data-entry one. |
| Post a document from a supplier not on the master file | The AP lead, after onboarding. Permanent | The process must never create a supplier record in order to clear a document in front of it. |
| Reject a document back to the supplier | The AP clerk, with the reason recorded | It leaves the building with your name on it, and it cannot be unsent. |
| Accept a reconciliation difference above tolerance | The financial controller. Permanent | An accepted difference is a decision about the ledger, and someone has to be answerable for it. |
Seven exceptions to name before you automate anything
“Manual review” is not an exception path, it is the absence of one. Each of these behaves differently, needs a different person, and produces a different fix — and the fix is usually upstream.
| Exception | What it looks like | What the process does |
|---|---|---|
| Unreadable scan | A photograph at an angle, a fax-quality image, a blank page | Registers it, attempts no extraction, requests a re-send quoting the document identifier. Never guesses from a partial read. |
| Merged or split documents | Five invoices in one scanned file, or one invoice arriving as three separate images | Splits or joins into registered documents before extraction, each keeping the identifier of the file it came from. |
| Wrong currency | A supplier who normally bills in one currency sends another | Holds. Never converts. A person confirms against the document and the contract before anything posts. |
| Missing or invalid tax ID | A required registration number absent or malformed | Blocks the posting only where your jurisdiction requires it, and requests a corrected document. Never edits the supplier's document. |
| Line-item mismatch | Line items do not sum to the stated net, or net plus tax does not equal gross | Full review. The printed total wins once a person has confirmed it, and which figure was right gets recorded. Transposed digits are the usual cause. |
| Duplicate across channels | The same invoice from the portal and from the supplier's mailbox, in different files | Attaches the second arrival to the first record with its own timestamp, and posts once. The file hash alone will not see this. |
| Not an invoice | A delivery note, a statement, a dunning letter, a newsletter with a PDF | Classifies, routes, closes, creates no ledger entry. A rising rate means a channel is being used for something else. |
Track each of these by supplier and by channel. The counts are an input-quality report, and most of the entries have a cheaper fix outside your process than inside it: ask a supplier to send to the mailbox instead of the portal, or to attach a PDF instead of a photograph.
What the capture step has to keep, and for how long
Capture is the step that creates the evidence everything downstream relies on, which makes retention a design constraint rather than an afterthought. The IRS is specific about what a supporting document must show — the payee, the amount paid, proof of payment, the date incurred and a description of what was bought — and it states that the same requirements apply to records kept in an automated system. Its general guidance on recordkeeping periods starts at three years, with longer periods in specific circumstances. Confirm what applies to you with your accountant.
Read as a specification for an automated capture step, that has four consequences. The original file has to survive independently of the mailbox or portal it arrived through, because a shared inbox is not an archive and rarely outlives the person who owns it. The extracted values have to stay attached to the posted record, not only inside whatever produced them. Each value should remain traceable to the region of the page it came from, so a figure in the ledger can be defended years later rather than merely asserted. And every repair, rejection and approval needs a name, a timestamp and the version of the rules that was in force at the time.
That last point is why all-agents records every run and keeps it replayable, and why the steps you pin keep their approval permanently after the rest of the process has become code. A process you cannot replay is a process you cannot explain, and an unexplainable invoice is the expensive kind. If you want the underlying reasoning rather than the finance-specific version, the procedure guide covers how to write this down before automating it.
Take the procedure with you
Two versions of the same process. The SOP is what a person follows and what you edit when a rule changes. The blueprint is the same process written for a machine, and it is the document to argue over before anything is built. Both use bracketed placeholders for your thresholds, systems and roles, and neither needs an account.
Invoice Automation SOP
The document lifecycle written out for a person to run: the four channels, twelve steps, six decisions including the confidence bands, seven exceptions, six approvals, the KPIs worth tracking and the audit record.
Preview the fileHide preview
# Invoice Automation SOP — [Company name]
Document status: [Draft / In review / Approved] · Applies from: [date] ·
Owner: [role] · Review cycle: [quarterly]
This procedure covers the supplier invoice **as a document**: how it arrives,
how it is registered, read, checked, coded, posted and reconciled. Approval of
the spend itself, the payment run, and changes to payee master data are governed
by the separate [Accounts Payable Processing SOP].
## Purpose
Turn every supplier invoice that reaches [Company name], on any channel, into a
correctly coded posted record with the original document retrievable against it
— and make an explicit, written decision about what happens at each level of
extraction confidence, so that no figure enters the ledger without either
passing a validation check or being seen by a named person.
## Scope
In scope: arrival across [AP mailbox], [supplier portal(s)], [scan inbox] and
forwarded attachments; registration and identity; document classification;
field extraction; validation; duplicate detection; coding to account and cost
centre; posting to [accounting system]; reconciliation against supplier
statements.
Out of scope: approval routing for spend commitment, payment preparation and
release, and supplier bank-detail changes ([Accounts Payable Processing SOP]);
customer invoices we raise ([Billing SOP]); employee expense claims ([Expenses
SOP]); credit control ([AR SOP]).
## Owner
- Accountable for the day-to-day procedure: [AP Clerk].
- Accountable for coding rules and the chart of accounts mapping:
[Management Accountant].
- Reviewing and approving changes to thresholds: [Financial Controller].
- Escalation for supplier-facing rejections: [AP Lead].
Nobody may hold both the extraction-review role and the payee-maintenance role
in [accounting system].
## Trigger
Event triggers:
- A message with one or more attachments arrives in [AP mailbox].
- A new document appears in [supplier portal] on the [daily 09:00] sweep, for
portals that do not notify.
- A batch is scanned into [scan inbox].
- A colleague forwards an invoice from their own mailbox to [AP mailbox].
Scheduled triggers:
- [Daily 09:00] portal sweep.
- [Weekly, Monday] supplier statement reconciliation for statements received.
- [Working day 2] month-end sweep for documents registered but not yet posted.
## Inputs
| Input | System of record | Required |
| --- | --- | --- |
| The original document file, unmodified | [Document store] | Yes |
| Channel, sender and arrival timestamp | [Document store] | Yes |
| Supplier master: legal name, trading names, tax ID, default currency | [Accounting system] | Yes |
| Chart of accounts and cost centre list, with valid combinations | [Accounting system] | Yes |
| Coding history: what this supplier was coded to previously | [Accounting system] | Where it exists |
| Open purchase orders and goods receipts | [Purchasing system] | For PO-backed spend |
| Supplier statement | [AP mailbox / portal] | Monthly, where sent |
## Prerequisites
- Every channel that can receive an invoice is enumerated and watched. An
unwatched channel is not a slow path, it is an invisible one.
- Supplier master records carry a default currency and a tax ID. Validation
rules below depend on both.
- Confidence bands (D1) and the validation tolerance (D5) are written down and
approved by [Financial Controller] before anything runs unattended.
- Retention is configured so the original document and its posted record stay
retrievable for [retention period], independently of the mailbox or portal it
arrived through.
- A named person is on the exception queue every working day.
## Steps
1. **Receive.** Take the document from the channel. Store the original bytes
unmodified. Never let a downstream step overwrite the source file.
2. **Register.** Assign an internal document identifier, and record channel,
sender, arrival timestamp and file hash. Registration happens before anything
reads the content, so a document that later fails is still accounted for.
3. **Fingerprint for duplicates.** Compute a channel-independent fingerprint
from supplier identity, invoice number, invoice date and gross total once
those are known. → Decision **D2**.
4. **Classify.** Decide what the document is: supplier invoice, credit note,
statement, delivery note, dunning letter, or not an accounting document at
all. → Decision **D3**. Anything not an invoice leaves this procedure here.
5. **Split.** Where one file holds several documents, split it into separate
registered documents, each inheriting the parent identifier as its origin.
Where one document spans several pages, keep it whole.
6. **Extract fields.** Read supplier identity, invoice number, invoice date, due
date, currency, net, tax, gross, tax ID, PO reference and line items. Each
field carries its own confidence and a reference to where on the page it was
read from. A field that was not found is recorded as absent, never as an
empty string.
7. **Validate.** Run the checks that do not need judgment: line items sum to the
stated net; net plus tax equals gross; tax rate is one of [permitted rates];
currency matches the supplier default or is on the supplier's permitted list;
invoice date is not in the future and not older than [age limit]; the
supplier exists on the master file; the invoice number has not been seen
before. → Decision **D5**.
8. **Route by confidence.** Apply the bands in D1 to decide whether the document
posts untouched, goes to a person for a specific field, goes to a person in
full, or is rejected to the supplier.
9. **Code.** Assign account, cost centre and, where used, project. Follow the
supplier's established coding where the line description matches a known
pattern. → Decision **D4**. A new account and cost centre combination is
never assigned silently.
10. **Post.** Write the document to [accounting system] against the internal
document identifier, so that a repeat attempt updates rather than
duplicates. Attach the original document to the posted record.
11. **Hand over.** PO-backed invoices continue into matching and approval under
the [Accounts Payable Processing SOP]. This procedure has no authority to
commit spend.
12. **Reconcile.** On receipt of a supplier statement, compare it line by line
against posted documents for that supplier. Surface only the residue:
statement lines with no posted document, posted documents absent from the
statement, and amount differences outside D5 tolerance.
## Decisions
**D1 — Confidence bands.** For each document, take the lowest confidence among
the fields that change the money (currency, net, tax, gross, supplier identity,
invoice number).
- At or above [high threshold] on all of them, with every validation check
passed: post without a person.
- At or above [high threshold] except on one field: ask a person for that field
alone, showing the page region it was read from.
- Below [low threshold] on any money-changing field: full human check, document
beside the form.
- Below [low threshold] across the document, or unreadable: reject (E1).
- Any validation failure overrides the band. A confident figure that contradicts
arithmetic is never posted unattended.
**D2 — Duplicate.** Same supplier, same invoice number: duplicate, whatever the
channel. Same supplier, same gross, same invoice date, no invoice number:
suspected duplicate, to a person. Attach the later arrival to the existing
record rather than creating a second one.
**D3 — Classification.** If the document does not state an amount payable by us
to the sender, it is not an invoice. Credit notes go to [credit note handling].
Statements go to step 12. Everything else is returned to [sender] or filed under
[other correspondence].
**D4 — Coding.** Use the supplier's most recent coding where the line
description matches a known pattern for that supplier. Where the pattern is new,
or the combination of account and cost centre has not been used for this
supplier before, route to the cost centre owner (A3) and write the resulting
rule back into this procedure.
**D5 — Validation tolerance.** Rounding differences up to [tolerance amount] on
gross are accepted and posted. Anything above goes to a person as a line-item
mismatch (E5). The tolerance is an amount, not a percentage of the invoice.
**D6 — Rejection.** Reject to the supplier only for: unreadable document,
missing legally required fields for [jurisdiction], or a document that is not
addressed to a [Company name] entity. Never reject for a coding question that we
can answer internally.
## Exceptions
| Code | Exception | Handling |
| --- | --- | --- |
| E1 | Unreadable scan or image | Register, do not extract. Request a re-send from [sender] with the document identifier quoted. Do not guess figures from a partial read. |
| E2 | Several documents in one file, or one document split across files | Split or join into registered documents before extraction. Record the origin file identifier on each. |
| E3 | Currency differs from the supplier default | Never convert automatically. Confirm the currency against the document and the contract with [AP Lead], then record the corrected default. |
| E4 | Missing or invalid tax ID | Post-blocking where [jurisdiction] requires it on a valid invoice. Request a corrected document; do not amend the supplier's document. |
| E5 | Line items do not sum to the stated total | Full human check. Read the printed total, not the computed one, and record which was correct. Transposed digits are the common cause. |
| E6 | Same invoice arrived on two channels | Attach the second arrival to the first record with its own arrival timestamp. Post once. |
| E7 | Not an invoice | Classify, route per D3, close the document. Track the rate: a rising rate usually means a channel is being used for something else. |
Every exception is recorded against the document identifier with its code, who
handled it, and what they decided.
## Approvals
| Ref | Action | Approver |
| --- | --- | --- |
| A1 | Post a document that passed every check inside the bands | None. Sampled review of [n] documents [weekly] by [AP Lead] |
| A2 | Confirm a single repaired field | [AP Clerk] |
| A3 | Accept a new account and cost centre combination | [Cost centre owner] |
| A4 | Post an invoice from a supplier not on the master file | [AP Lead], after onboarding |
| A5 | Reject a document back to the supplier | [AP Clerk], reason recorded |
| A6 | Accept a reconciliation difference above [tolerance amount] | [Financial Controller] |
A3, A4 and A6 remain human approvals permanently, regardless of how well the
automated steps perform.
## Output
- A posted accounting record carrying the internal document identifier.
- The original document, unmodified, attached to that record.
- The extracted fields with their confidence and source page region.
- An exception record where one applied, with its code and its resolution.
- A reconciliation position per supplier per statement period.
## SLA / KPI
| Measure | Definition | Target |
| --- | --- | --- |
| Time to register | Arrival to registered with an identifier | [target] |
| Time to post | Arrival to posted, for documents needing no person | [target] |
| Exception queue age | Oldest unresolved exception | [target] |
| Repair rate | Documents needing at least one field confirmed | Track the trend, not the level |
| Rejection rate by supplier | Documents returned to each supplier | Investigate any supplier above [threshold] |
| Duplicate catches | Second arrivals attached rather than posted | Track; a fall to zero usually means a channel stopped being watched |
Targets are set by [Financial Controller] against your own baseline. Do not
adopt figures from a vendor.
## Audit record
For every document, retain for [retention period]:
- The original file, unmodified, with its hash and arrival metadata.
- The identity of the payee, the amount, the date incurred and a description of
what was bought — the fields a supporting document is expected to show, kept
in a form that survives the mailbox the invoice arrived in.
- Proof of payment, linked from the payment record created under the [Accounts
Payable Processing SOP].
- Who approved what, when, and which version of this procedure was in force.
- The extracted values and their source regions, so a figure in the ledger can
be traced back to the pixel it came from.
The same expectations apply whether records are kept on paper or in an automated
system. Confirm the retention period that applies to [Company name] with
[accountant / tax adviser]; three years from the filing date is a common
starting point in the United States but is not universal.
## Revision log
| Version | Date | Change | Author |
| --- | --- | --- | --- |
| 0.1 | [date] | Initial draft from the all-agents invoice automation playbook | [name] |
| | | | |
Adapted from the invoice automation playbook at
https://www.all-agents.io/solutions/finance-accounting/invoice-automation —
educational material about process design, not financial, accounting or tax
advice.
Invoice capture workflow blueprint
The same lifecycle written out for a machine: start and termination conditions, per-step data contracts, which steps are code and which keep a person, branches, byte and content idempotency keys, rollback limits and fourteen test cases.
Preview the fileHide preview
# Invoice Automation Workflow Blueprint — [Company name]
Status: [Draft] · Version: v1.0 · Applies from: [date]
The executable shape of the invoice document lifecycle: what starts it, what each
step consumes and produces, who performs it, how it branches, and what has to be
true before you would let it run without watching. It is the companion to the
Invoice Automation SOP, which describes the same process in prose, and its step
numbers follow that document. The two human gates are shown as `8H` and `9H`.
This blueprint stops at the posted document. Matching to a purchase order,
approval of the spend, the payment run and bank reconciliation belong to the
Accounts Payable Workflow Blueprint.
Placeholders in [brackets] are yours to fill in. This describes a process, not
any particular product's connectors or extraction engine. Educational template,
not financial, accounting or tax advice.
---
## Trigger and termination conditions
**Start conditions**
- `document.arrived.email` — a message with one or more attachments reaches
[AP mailbox]. One run per attachment, never one per message; a message with
four PDFs is four documents.
- `document.arrived.portal` — the [daily 09:00] sweep of [supplier portal] finds
a document not yet registered.
- `document.arrived.scan` — a batch appears in [scan inbox]. One run per file in
the batch.
- `document.arrived.forward` — a colleague forwards an invoice from their own
mailbox. Treated as a first-class channel, not an exception.
- `schedule.statement_reconciliation` — [weekly, Monday 07:00], one run per
supplier statement received.
- `manual.reprocess` — a person reopens a registered document by its identifier,
with a reason recorded. Never a silent re-run.
**Terminate successfully when**
- the document reaches `posted`, the original file is attached to the posted
record, and the audit record is complete; or
- the document is classified as something other than an invoice, routed under D3
and closed with its classification retained; or
- the document reaches `attached_as_duplicate` against an existing record; or
- the document reaches `rejected_to_supplier` with a reason and the outbound
message retained.
**Terminate unsuccessfully when**
- extraction has failed twice on a document the supplier has already re-sent
once, at which point a person owns it rather than the process; or
- an exception has been open beyond [3] working days, at which point it
escalates rather than expires; or
- the coding target is still invalid after a human repair — the process does not
invent an account to clear a document.
**Never start when**
- the same file hash is already registered and its run is still in flight; or
- the document identifier is already in state `posted`; or
- the channel is in [quarantine] following a bulk mis-delivery, where a person
triages the batch first.
---
## Ordered steps with data contracts
| # | Step | Actor | Consumes | Produces |
| --- | --- | --- | --- | --- |
| 1 | Receive | Deterministic code | `channel`, `raw_bytes`, `sender`, `received_at` | `document{doc_id, sha256, channel, sender, received_at, bytes_uri}` |
| 2 | Register | Deterministic code | `document` | `state = registered`, immutable arrival record |
| 3 | Fingerprint (byte key) | Deterministic code | `sha256` | `byte_key`, `exact_file_matches[]` |
| 4 | Classify | Model judgment | `page_images[]`, `text_layer?` | `classification{type, confidence, evidence[]}` |
| 5 | Split or keep whole | Deterministic code | `page_images[]`, boundary markers | `child_doc_ids[]` each with `origin_doc_id` and `page_range` |
| 6 | Extract fields | Model judgment | `page_images[]`, `supplier_master`, `field_schema` | `fields{name → {value \| absent, confidence, page, region}}` |
| 7 | Validate | Deterministic code | `fields`, `supplier_master`, `tax_rules`, `D5` | `validation{checks[], failures[], arithmetic_ok, currency_ok, age_ok}` |
| 8 | Route by confidence | Deterministic code | `min(confidence)` over money fields, `validation`, `bands_version` | `route ∈ {auto_post, field_repair, full_review, reject}` |
| 8H | Repair or confirm (A2) | Human | one field or the whole document, with `page`, `region` and the original beside it | `repair{field, before, after, by, at}` |
| 9 | Code | Deterministic code, with a model proposal on new patterns | `line_descriptions[]`, `supplier_coding_history`, `chart_of_accounts` | `coding{account, cost_centre, project?, rule_id \| proposed}` |
| 9H | Confirm new coding (A3) | Human | `coding.proposed`, the document, prior coding for this supplier | `coding_rule{approved_by, at, written_back}` |
| 10 | Post | Deterministic code | `fields`, `coding`, `doc_id` | `posting{ledger_ref, doc_id}`, original attached to the record |
| 11 | Hand over | Deterministic code | `posting` | `payable.registered` event consumed by the payables process |
| 12 | Reconcile to statement | Deterministic code | `statement_lines[]`, `posted_documents[]` | `reconciliation{matched[], statement_only[], ledger_only[], differences[]}` |
Field-level contract notes:
- **Confidence is per field, never per document.** A document-level score hides
the one field that matters. Step 8 reads the minimum across the money-changing
fields only: `supplier_identity`, `invoice_number`, `currency`, `net`, `tax`,
`gross`.
- **Every money field carries its `currency`.** No step compares or sums amounts
across currencies, and no step in this process converts one.
- **A missing field is `absent`, not `""` or `0`.** An empty string in a total is
indistinguishable from a zero invoice downstream.
- **Every extracted value keeps `page` and `region`.** This is what lets a figure
in the ledger be traced back to the part of the document it was read from, and
what a reviewer is shown at 8H.
- **`classification.type` is a closed set:** `invoice`, `credit_note`,
`statement`, `delivery_note`, `other`. A model that cannot fit a document into
the set returns `other` and escalates; it does not invent a type.
- **No step in this process writes to the supplier master.** Not the tax ID, not
the default currency, and never the bank details.
---
## Step classification (deterministic / model judgment / human approval)
**Deterministic — steps 1, 2, 3, 5, 7, 8, 9, 10, 11, 12.** Hashing, registering,
splitting on boundary markers, arithmetic, threshold application, coding lookup
against an existing rule, posting by identifier, and set-based reconciliation.
Identical inputs must give identical outputs. If one of these needs a model, the
rule underneath it has not been written down yet.
**Model judgment — steps 4 and 6, and the proposal half of step 9.** Deciding
what a document is, reading fields off a layout nobody has seen before, and
proposing coding where the line description matches no known pattern. Two
hundred suppliers means two hundred layouts, which is genuine open-ended
variety. The model reads and proposes. It does not decide whether something
posts — step 8 does that from the confidence and the validation result.
**Human — 8H and 9H, plus A4, A5 and A6 in the SOP.** These exist because
someone has to be answerable for a figure entering the ledger that nothing could
check, for a new coding rule that will apply to every future document from that
supplier, and for a document leaving the building addressed to a supplier.
---
## Branches and retries
| Condition | Branch |
| --- | --- |
| `classification.type ≠ invoice` | D3: route the document (credit note, statement, delivery note, other), close it, no ledger entry — E7 |
| `classification.confidence` below [low threshold] | Human classifies. Two `other` results on the same file end the run |
| One file contains several documents | E2: split into registered children, each carrying `origin_doc_id` and `page_range` |
| One document spans several files | E2: join before extraction; never extract from a fragment |
| Page unreadable or no usable text | E1: no extraction attempted, re-send requested quoting the document identifier. Do not guess figures from a partial read |
| `exact_file_matches` non-empty, or content key already posted | E6: attach the later arrival to the existing record with its own timestamp. Post once |
| `currency ≠ supplier.default_currency` | E3: hold, human confirms against the document and the contract. The process never converts |
| Tax ID absent or malformed where [jurisdiction] requires it | E4: block posting only, request a corrected document. Never amend the supplier's document |
| `sum(line_items) ≠ stated_net`, or `net + tax ≠ gross`, beyond D5 tolerance | E5: full review. Read the printed total, record which was correct |
| Any validation failure, whatever the confidence | Overrides the band and routes to a person. A confident figure that contradicts arithmetic never posts unattended |
| Supplier not on the master file | Hold at step 9. The process does not create a supplier to clear a document (A4) |
| Repair open beyond [1] working day | Remind, then escalate per the ladder below |
**Retries.** Retry only steps that are safe to repeat: 1, 2, 3, 7, 12. Extraction
may be retried at most [2] times, and only where the failure was in producing a
result at all — not to fish for a better number. Where two extractions disagree,
take the lower confidence and route accordingly; never average them. Step 10 is
guarded by the posting key rather than by retry policy, so a repeated attempt
updates rather than duplicates. Never auto-retry an outbound rejection: a second
message to a supplier is a new record with its own reason.
---
## Idempotency
- **Byte key** `sha256(raw_bytes)`, computed at step 1. Catches the same file
arriving twice — the common forward-and-forward-again case.
- **Content key** `hash(supplier_id, invoice_number, invoice_date, gross,
currency)`, computed after step 6 and checked before step 10. Catches the same
invoice arriving as a portal download and as an email attachment, where the
bytes differ but the invoice does not. The byte key alone will not see this.
- **Posting key** is the internal `doc_id`. Step 10 is an upsert on `doc_id`, so
a repeated post writes nothing new and creates no second ledger entry.
- **Split children are deterministic:** `child_doc_id = hash(origin_doc_id,
page_range)`. Re-splitting the same file yields the same identifiers rather
than a second set of documents.
- **Repairs are append-only events.** Replaying the event log reproduces the same
field state, and the original extracted value is never overwritten in place.
- **Reconciliation is set-based.** Step 12 is safe to run repeatedly on the same
statement; matching an already-matched line is a no-op.
---
## Escalation and rollback
**Escalation ladder.** Exception or repair open [1] working day → remind the
assignee. [3] days → [AP Lead]. [5] days → [Financial Controller] and onto the
month-end exception list. Any document whose due date falls inside the ladder
skips it and goes straight to [AP Lead]: a lost early-payment discount or a late
charge is a real cost, and a queue is not a neutral place to leave a document.
**Rollback by stage.**
- Before step 10: fully reversible. Void the document record, keep the arrival
record and the reason. Nothing has entered the ledger.
- After step 10, before hand-over: reverse the posting with an adjusting entry
that references `doc_id`. Never delete the original entry — a corrected ledger
and an edited ledger look identical afterwards, and only one of them is
defensible.
- After hand-over: the document is now a payable. It is corrected under the
payables process, and this process records the correction against `doc_id`
rather than reaching into the payable.
- A rejection already sent to a supplier cannot be unsent. The follow-up is a new
outbound record linked to the same document.
**When the process stops trusting itself.** Stop the automated path and route to
full review if: the repair rate for one supplier's layout exceeds [threshold]
over [n] consecutive documents; classification returns `other` twice for the
same file; or the unmatched count at step 12 exceeds [n] lines for a supplier in
one statement period. In each case something upstream changed — a new template,
a new channel, a new entity — and a person should find out what before the
process keeps posting.
---
## Permissions and sensitive data
- **Least privilege by step.** Steps 1–3 need read access to the channels and
write access to the document store only. Steps 4–9 need read access to the
supplier master, the chart of accounts and coding history, and write access to
the document record. Only step 10 may write to [accounting system], and only
to create or update a posting keyed by `doc_id`.
- **No path from this process to master data.** Supplier records, default
currencies, tax IDs and bank details are maintained by [Vendor Master
Administrator] outside this process. An automated capture step that can also
edit a payee record has removed the control it was supposed to feed.
- **Sensitive fields on the document:** bank account and IBAN, tax registration
numbers, contract pricing, and any personal data on an expense-type invoice.
Mask these in logs, notifications and anything sent to a model beyond what the
extraction step needs. Retain them only inside the stored original.
- **Logs record field names, confidences and regions — not full document text.**
A log line is a copy of the invoice if you let it be.
- **The original file is immutable.** Its hash is recorded at arrival and checked
before posting. Corrections are new records; nothing edits the source bytes.
- **The audit trail is append-only.** Every repair, classification, exception and
approval records who, when, and which version of the bands and rules was in
force.
- **Retention.** The stored document plus its extracted fields must still show
the payee, the amount, the date incurred and a description years later; see the
IRS guidance on [what kind of records to keep](https://www.irs.gov/businesses/small-businesses-self-employed/what-kind-of-records-should-i-keep),
on [automated records](https://www.irs.gov/businesses/automated-records), and
on [recordkeeping periods](https://www.irs.gov/taxtopics/tc305). Confirm the
period that applies to you with your accountant. The mailbox the invoice
arrived in is not an archive.
---
## Test cases and acceptance criteria
Run each case on your own historical documents before the process handles live
volume unattended. Every case states what must be true for it to pass.
| # | Case | Passes when |
| --- | --- | --- |
| T1 | Clean invoice, all money fields above the high band, every check passed | Posts unattended; bands version and per-field confidences recorded |
| T2 | The same PDF forwarded twice | Byte key catches it at step 3; second arrival attached, not posted |
| T3 | Same invoice downloaded from the portal and emailed by the supplier | Content key catches it before step 10 even though the bytes differ |
| T4 | Five invoices in one scanned file | Five child documents, each with `origin_doc_id` and `page_range`; ids stable on a re-split |
| T5 | One invoice spanning three pages | One document, one posting — not three |
| T6 | Invoice in a currency other than the supplier default | E3 raised; no conversion performed anywhere in the run |
| T7 | Line items do not sum to the printed total | E5 raised; full review; the resolution records which figure was correct |
| T8 | Tax ID missing where [jurisdiction] requires it | E4 raised; posting blocked; corrected document requested; the supplier's document is not amended |
| T9 | Photograph of a crumpled receipt | E1 raised; no extraction attempted; re-send requested quoting the identifier |
| T10 | Delivery note sent to the AP mailbox | Classified, routed under D3, closed; no ledger entry created |
| T11 | Supplier absent from the master file | Held at step 9; the process creates no supplier |
| T12 | Line description matching no known pattern for this supplier | Coding proposed, not applied; A3 required; the approved rule is written back |
| T13 | High confidence on every field, but `net + tax ≠ gross` | Validation overrides the band; the document does not post unattended |
| T14 | Supplier statement re-imported | Step 12 is a no-op on already-matched lines |
**Acceptance criteria before this runs unattended**
- T1–T14 pass on documents you have actually received, not only on invented
ones. Synthetic invoices are uniformly legible in a way real post is not.
- Every confidence band has fired at least once during testing, including the
reject band.
- A sample of auto-posted documents has been re-checked by a person against the
originals, and the sample is retained.
- Every test document produces a complete audit record: original file, extracted
values with regions, repairs, approvals and the rules version in force.
- A named finance owner has read this blueprint and the Invoice Automation SOP
together and agrees they describe the same process.
## Revision log
- v1.0 — 2026-07-24 — initial draft — [Your name].
Limitations and when not to use this
- This page covers the invoice as a document, up to a posted record. Matching against purchase orders and goods receipts, approval routing by amount, the payment run and bank reconciliation are a separate job with separate controls, and are covered in the accounts payable playbook.
- It is process-design material, not financial, accounting or tax advice, and no substitute for your accountant or auditor. Retention periods, required invoice fields and tax identification rules vary by jurisdiction and entity. Statutory e-invoicing regimes, where the invoice arrives as structured data through a mandated channel, change the intake and validation steps substantially and are not covered here.
- Under a couple of dozen invoices a month, do not automate this. A weekly slot, a checklist and a single mailbox will beat any automated pipeline on total effort, and the written procedure is worth having either way.
- Nothing here claims that all-agents connects to a particular accounting package, scanner, portal or extraction engine, or states an accuracy figure for reading a document. What a process can reach depends on what you set up, and confidence behaviour depends on your own documents — which is precisely why the bands are yours to set.
Sources
- What kind of records should I keep — U.S. Internal Revenue Service Accessed 24 July 2026
- Automated records — U.S. Internal Revenue Service Accessed 24 July 2026
- Topic no. 305, Recordkeeping — U.S. Internal Revenue Service Accessed 24 July 2026
- Article 14: Human oversight — EU Artificial Intelligence Act Accessed 24 July 2026
Bring one week of invoices to a 30-minute scoping call
Walk your own documents through the lifecycle with us and leave knowing which channels are unwatched, where your confidence bands should sit, and which exceptions you are actually seeing.
Bring one week of invoices to a 30-minute scoping callUli Prantz
Builds and operates all-agents
Uli Prantz builds all-agents, the process-automation platform this site documents. He writes about the operational side of automating recurring business work: where deterministic code beats model judgment, where it does not, and where a human still has to approve.