IBAN Validator: The Three Decisions That Decide Whether a Bank Account Number Is Real

IBAN Validator cover - three decisions that decide whether a bank account number is real
IBAN Validator cover - three decisions that decide whether a bank account number is real

Every IBAN looks like a long string of letters and numbers, but the first thing any validator does is split it into three parts: a two-letter country code, two check digits, and a country-specific Basic Bank Account Number (BBAN). Whether the number is real depends on three decisions made in a strict order: the country code must exist in the registry, the total length must match what that country issues, and the mod-97 checksum over the rearranged digits must equal 1. Skip any one and the answer is no, even if the number looks plausible. Get all three right and you have a number that is structurally valid — the bank still has to confirm it actually points at an account, but the typing is correct. Most IBAN validation tools hide those three decisions inside a single regex or a single library call. The IBAN Validator on Elysia Tools exposes them, which is the only way to debug the edge cases your form keeps returning.

IBAN Validator cover — three decisions that decide whether a bank account number is real

Decision 1: The country code is the routing table — get it wrong and every later check is meaningless

Decision 1 — country code lookup and registry coverage

An IBAN starts with two uppercase letters — GB for the United Kingdom, DE for Germany, FR for France, BR for Brazil, AE for the United Arab Emirates. Those two letters aren’t decoration. They tell the validator which length to expect, which BBAN format to parse, and which national clearing system the rest of the number will eventually land in. The first decision the validator makes is therefore a dictionary lookup: is this two-letter code in the IBAN registry, and if so, what length does that country issue?

The IBAN specification (ISO 13616) currently lists 70+ countries, and the actual length per country varies wildly. Norway issues 15-character IBANs, Malta issues 31-character ones, and the British Virgin Islands issues 24. A German IBAN is always 22 characters, a French one always 27, a Brazilian one always 29. There is no global default. If your validator hardcodes length === 22 because most of your users are German, it will silently accept a French IBAN with the last five characters truncated as “valid” — and the payment will bounce at the clearing house, not at your form.

This is also where the common “is this IBAN real?” bug lives. A user pastes gb82west12345698765432 in lowercase. A naive validator either rejects it as “invalid characters” or, worse, accepts the lowercased form and ships it downstream, where it doesn’t match the bank’s expected casing. The IBAN Validator on Elysia Tools normalizes the input by uppercasing it and stripping spaces and dashes before the country-code lookup, so the case of the input never matters. The lookup is also exhaustive — it covers 70+ countries from Albania (AL, 28 chars) to the British Virgin Islands (VG, 24 chars), and explicitly rejects codes it doesn’t know. That explicit rejection matters: a two-letter code that isn’t in the registry is a typo, not a “valid IBAN from a country we don’t support”.

For a quick visual on which countries are in the registry and which lengths they expect, the IBAN & SWIFT code sample set ships with one real IBAN per major country, formatted and unformatted. It’s the fastest way to sanity-check that your validator’s country table matches the spec you’re claiming to follow.

Decision 2: The length is the cheapest possible sanity check — and the most often skipped

Decision 2 — country-specific length check

Once the country code resolves, the next decision is length. The IBAN spec is unusual in that length is not constant — it is a function of the country. The validator’s job is to look up the expected length for the resolved country code, count the actual characters in the cleaned input, and reject if they don’t match. No heuristics, no “close enough”, no “we’ll let the bank figure it out”. A 22-character input with country code GB is structurally invalid. A 27-character input with country code DE is structurally invalid. There is no middle ground.

This check is so cheap to implement that it’s tempting to skip it. That’s a mistake. The length check catches the four most common IBAN errors in a single comparison: a user who copied only part of the number, a user who included the SWIFT/BIC by accident, a user who double-pasted, and the case where the country code was right but the BBAN was truncated at a form-field character limit. Without the length check, all four of those flow into the mod-97 step, where they either fail with a confusing “check digit mismatch” error (which the user reads as “the IBAN is wrong, but in a way I can’t fix”) or, if the user got lucky with the mod-97 arithmetic on a truncated number, succeed with the wrong account.

The IBAN Validator performs the length check immediately after the country-code lookup and prints the expected and actual length in the result, so the user — or your support team — can see at a glance whether they hit a truncation, a double-paste, or just typed one character too many. The “your IBAN is 19 characters long but German IBANs are 22 characters long” message is the kind of thing that turns a 30-minute support ticket into a 30-second re-paste.

When you’re building out your own test set, the IBAN & SWIFT sample page is the easiest way to see all the in-use lengths at a glance. One row per country, with both the formatted and stripped versions of a known-good IBAN. The moment you see that NO is 15 characters and MT is 31, you stop designing your validator around “around 22”.

Decision 3: The mod-97 checksum is the only check that catches a typed number, not a copy-pasted one

Decision 3 — mod-97 checksum over the rearranged IBAN

The first two decisions — country code and length — catch the IBANs that are obviously wrong. The third decision is the one that catches the IBANs that look right but aren’t. ISO 7064 defines a mod-97 algorithm: rearrange the IBAN by moving the first four characters to the end, convert every letter to a two-digit number (A=10, B=11, …, Z=35), and check that the resulting integer mod 97 equals 1. If it does, the check digits are consistent with the BBAN. If it doesn’t, somewhere along the way the user mistyped a character, the form mangled the input, or the IBAN was fabricated.

This is the only check that has any mathematical content. The country-code and length checks are table lookups; the mod-97 check is a real computation over the digits. It is also the only check that detects a single-character typo in the middle of a 30-character string. A user who pastes GB82WEST12345698765432 and accidentally types GB82WEST12345698765433 has the right country code (GB), the right length (22), the right character set, and the wrong number. The mod-97 check returns 0, not 1, and the validator reports the IBAN as invalid with the reason “check digit mismatch”.

The mod-97 step has two implementation traps worth knowing about. The first is that the rearrangement is non-obvious: you move the four-character prefix (country + check digits) to the end of the string, not the start, and then convert letters to numbers. The second is that the resulting integer is huge — 30+ digits — and most languages default to floating-point when you try to compute it directly. The right way is to process the string left-to-right, taking the running mod-97 at each step, so the number never grows past a few digits. The IBAN Validator implements the streaming version, which is the only one that works reliably in JavaScript for the longest IBANs. If you ever find yourself reaching for BigInt or a decimal library for this, you are doing it the hard way.

One last thing about mod-97. It catches typos, but it does not catch valid-but-unassigned numbers. An IBAN that passes mod-97 might still not correspond to a real account at the issuing bank. The three decisions above get you to “structurally valid” — the bank still has to confirm the account exists. The IBAN & SWIFT sample page lists the real, working IBANs that ship in production sample sets; if your test data isn’t at least as good as what’s on that page, your tests aren’t testing the edge cases the bank cares about.

Most IBAN typos don’t lose you money — they lose you hours. A payment form that rejects a valid IBAN because the country code was uppercased, or a back-office script that re-asks a customer to re-type their number because the spaces are in the “wrong” groups, costs more in support time than any fraud it might catch. The three decisions above — country code, length, mod-97 — are the floor of what any IBAN validator must do before it can claim to be useful. Once you treat them as the contract your validator promises to honor, the rest of the validation problem gets much smaller. For a working example that runs all three checks against real test IBANs from 70+ countries, see the IBAN Validator on Elysia Tools.

Comments

No comments yet. Why don’t you start the discussion?

    Leave a Reply

    Your email address will not be published. Required fields are marked *