Repair an invalid IBAN: check digits and OCR near-misses
An OCR pass over a scanned invoice produces a near-miss IBAN — one wrong digit, an unreadable character. One paid call recomputes the check digits and recovers the missing characters before an agent pays the wrong account.
By Matthias Begot · · Updated
An agent that ingests invoices reads IBANs through OCR, and OCR is lossy: a
scanned account number comes back with one transposed digit or a character the
scanner could not resolve. Paying that number as-is routes money to the wrong
account — or to no account at all. Before the disbursement, one paid call —
GET /iban/repair — recomputes the check digits and
reconstructs the unreadable characters, returning valid candidates ranked by
known bank. This article shows where it fits an invoice-to-pay pipeline and how
to read its result without trusting a guess.
The problem: OCR turns a valid IBAN into a near-miss
A structurally valid IBAN satisfies the country’s BBAN layout (ISO 13616) and
the mod-97 checksum (ISO 7064). OCR breaks exactly those guarantees: it flips a
5 to a 6, or hands back a character it could not read at all. The result
fails validation — but it fails near the truth, usually a single edit away
from the correct number. A pure validator can only tell the agent the IBAN is
invalid; it cannot recover the right one.
Recovering it needs the country’s BBAN structure plus the national bank registry to break ties between candidates — bulky, frequently-updated public data that fits a pay-per-call lookup rather than an LLM’s weights.
The call: recompute, enumerate, rank
GET /iban/repair takes a degraded iban and returns a RepairResult: whether
it could be repaired, whether the answer is ambiguous, and a candidates
list. It works two ways:
- Wrong check digits (positions 3–4) on an otherwise intact body are recomputed and re-validated — no marking needed.
- Unreadable characters must be marked with a
?. The service substitutes each?with the characters allowed at that position by the country’s BBAN structure and keeps only the combinations that parse (structure + checksum).
Crucially, it does not guess silently: apart from the check digits, it never
corrects a character you did not mark — no implicit O→0 or I→1. If OCR is
unsure about a character, mark it ?; if it is confident but wrong, only the
checksum path applies.
Each surviving candidate carries bank_known and a full resolution (the same
shape GET /iban/resolve returns), so you get
bank/BIC/reachability for each candidate without a second call. Candidates
are ranked known-bank first — the registry breaks ambiguity that a validator
alone cannot.
Reading the result honestly
A repaired IBAN is a structurally valid candidate, not a guarantee the account exists or is the one on the invoice:
| Result | What the agent should do |
|---|---|
repaired: true, not ambiguous | One valid candidate — still verify it before paying |
repaired: true, ambiguous | Several parse; known-bank-first ranking is a hint, not a verdict — escalate |
already_valid: true | Input parsed as-is; no repair was needed |
repaired: false | TOO_AMBIGUOUS or UNREPAIRABLE — no confident repair |
Two scope facts to keep straight:
- A too-ambiguous or unrepairable input is a 200 with
repaired: false, not an error. Per the x402 golden rule, the agent pays for the answer to its question, and “this cannot be repaired” is a successful answer. The4xxrange is reserved for requests the service genuinely cannot answer. - Repair reconstructs structure (a number that passes layout + checksum and, ideally, maps to a known bank). It does not confirm the account is live, reachable, or owned by the payee. That confirmation is the next step.
Where it sits in an invoice-to-pay pipeline
Repair is the first gate after extraction, feeding the rest of the loop:
- OCR the invoice; extract the candidate IBAN, marking unreadable
characters
?. - Repair —
GET /iban/repair— recompute/enumerate; pick the candidate when unambiguous, escalate whenambiguous. - Resolve / screen the chosen IBAN
(
GET /iban/resolve) to confirm bank, BIC and reachability — and screen it if the workflow requires. - Pay the confirmed beneficiary through your own rails.
Each paid call follows the same x402 pattern as every Invoket endpoint. The
Quickstart walks the whole discover → 402 → pay → replay
cycle with runnable snippets. Price and accepted rails are not pinned here — they
are served live by the catalog; see the
endpoint reference for the current figure.
Repairing a batch of invoices
A reconciliation run rarely has one IBAN. POST /iban/repair/batch
repairs up to 500 degraded IBANs under one x402 settlement instead of one
settlement per row — the cost is one settlement per call regardless of batch
size, which is what makes a whole invoice batch workable as a single pre-payment
pass.
What repair does not do
- It does not invent corrections you did not mark, beyond the check digits — no silent OCR substitution.
- It does not assert that a repaired candidate is the IBAN on the invoice,
or that the account exists. A confident-looking single candidate still needs
GET /iban/resolveto confirm bank/BIC/reachability, andGET /iban/screenwhere the workflow demands it.
Used for what it is — a structural recovery step that turns an OCR near-miss into
ranked, valid candidates — it lets an autonomous accounting agent fix the
fixable and escalate the ambiguous, before money leaves. For the full field
reference and error codes, see the
GET /iban/repair documentation; for how agents
discover and call Invoket endpoints, see For agents.