How to test IBAN validation: a QA checklist with real test cases

What to feed an IBAN validator before you trust it: one valid IBAN per country, the failures it must catch, the input it must tolerate, and where the test data comes from.

By the Generate Random IBAN editorial team · · 8 min read

The MOD-97 arithmetic is the part of IBAN validation that rarely breaks. The bugs live around it: a regex that only allows digits, a length table copied from a forum post, a form that rejects pasted IBANs because they contain spaces, or a validator that accepts any 22-character string starting with two letters. To test IBAN validation properly you need test cases for each layer, and you need IBANs that are structurally correct without belonging to anyone.

This checklist covers both. The example IBANs are the official ones from the SWIFT IBAN Registry or were produced by our generator, so they all pass MOD-97 unless the text says otherwise.

What an IBAN validator has to check

An IBAN has three parts: a two-letter ISO 3166 country code, two check digits and a BBAN (the national account number, up to 30 characters). ISO 13616-1 defines that shape and the maximum length of 34 characters; the length and BBAN layout of each country are published by SWIFT, the ISO registration authority, in the IBAN Registry. A complete validator applies these layers in order, and each one needs its own test cases:

Layer Rule Input that must fail
Characters Only A-Z and 0-9 after normalisation DE89 3704 0044 0532 0130 0O (letter O for zero)
Country The first two letters are a country you support XX361234567890
Length Exactly the registry length for that country (22 for DE, 27 for FR, 15 for NO...) GB29NWBK6016133192681 (21 characters)
BBAN pattern Each position is a digit, a letter or either, as the registry says GB17NWB460161331926819 (digit inside the bank code)
MOD-97 The whole string, rearranged and converted to numbers, leaves a remainder of 1 when divided by 97 DE89370400440532013001
National check digits Where the country has them, they match the bank and account numbers BE41539007547035 (see below)

If a layer fails, the ones after it have nothing to say. A good validator reports the first failing layer and the position, which is also what you want to assert in tests. The IBANpedia article on check digits walks through the MOD-97 arithmetic if you want to recompute an expected value by hand.

Valid cases: one IBAN per country you accept

Start with the official example of every country your product supports. The registry publishes one per country, and they exercise the BBAN pattern as intended. A short selection that covers the awkward shapes:

Country Length Registry example Why it matters
Norway 15 NO9386011117947 The shortest IBAN in the registry
Belgium 16 BE68539007547034 National check digits at the end
Germany 22 DE89370400440532013000 Digits only; the most common test case and the least demanding
United Kingdom 22 GB29NWBK60161331926819 Letters in the bank code, same length as Germany
France 27 FR1420041010050500013M02606 A letter inside the account number, plus the two-digit RIB key
Italy 27 IT60X0542811101000000123456 A single letter (the CIN) as national check character
Saint Lucia 32 LC55HEMM000100010012001200023015 Letters in the bank code, long alphanumeric account
Russia 33 RU0304452522540817810538091310419 The longest IBAN in the registry

Twenty-eight of the 91 countries we cover require letters somewhere in the BBAN (the United Kingdom, the Netherlands, Ireland, Malta, Bulgaria, Qatar, Kuwait and others). A validator written against German IBANs alone will pass a digits-only regex and reject every one of them. The full list of lengths and layouts is in IBAN formats by country.

For each supported country, also test a few IBANs that are not the registry example. Our country pages show a fresh one on every load, for example the German generator or the British one, and the bulk export gives you a hundred at a time (more on that below).

Failure cases the validator must reject

Work through these for at least one country, and for every country if your length table is hand-maintained:

  1. Wrong length. Remove the last character of a valid IBAN and add one to another. GB29NWBK6016133192681 is 21 characters; the validator should say "expected 22 for GB", not "invalid IBAN".
  2. One changed character. DE89370400440532013001 differs from the registry example by its last digit. MOD-97 catches every single-character error, so this must fail on the check-digit layer. The check digits that would make this string valid are 62, which is a useful detail to show a user who typed one digit wrong.
  3. Swapped characters. Swap two adjacent digits in the BBAN. MOD-97 catches the great majority of these too, but write the test and confirm it for your fixtures.
  4. Check digits outside 02 to 98. ISO/IEC 7064 MOD 97-10 never produces 00, 01 or 99. DE00370400440532013000 must fail even before the arithmetic runs.
  5. Letters where digits belong, and digits where letters belong. GB17NWB460161331926819 has a digit in the bank code, which the UK format defines as four letters, and its check digits were recomputed so that MOD-97 passes. The arithmetic knows nothing about the UK layout; only the BBAN pattern check catches it.
  6. Unknown country code. XX361234567890 has correct check digits for its content. A validator that only runs MOD-97 accepts it. Decide what you want: reject outright, or accept with a warning that the format is unknown. Our validator reports "check digits correct, format not checked" in this case.
  7. Lower-case country code with otherwise valid content, if your normalisation runs after the country lookup rather than before it. This ordering bug is common.
  8. Empty string, a single character, 35 or more characters, and strings with only separators. These exercise the error path, and the error path is where exceptions leak.

Messy input your users will paste

Real users copy IBANs from PDFs, emails and banking apps. The validator should accept all of the following as the German example above:

  • DE89 3704 0044 0532 0130 00 (the print format defined by ISO 13616: groups of four separated by spaces)
  • de89370400440532013000 (lower case)
  • IBAN DE89370400440532013000 and IBAN: DE89... (the label copied along with the number)
  • the same IBAN with a trailing newline, a tab, or a non-breaking space between the groups, which is what many web pages and PDFs insert
  • full-width digits and letters (DE89...), common with Chinese and Japanese input methods

It should reject, with a useful message, an IBAN that contains a Cyrillic А or Е instead of the Latin letter. They look identical on screen, they are different code points, and a validator that strips "invalid characters" silently will turn them into a wrong-length error that nobody can act on. Our validator points at the position and says the character is not Latin.

Decide which of these you normalise and which you reject, write the decision down, and test both directions. Store and transmit the electronic format (no spaces, upper case); display the print format.

National check digits

Many countries protect the BBAN with their own check digits, independent of the two IBAN check digits: the Belgian two-digit key, the French clé RIB, the Italian CIN, the Spanish dígitos de control and the Norwegian single digit among them. The IBAN check digits are computed over the final BBAN, so an IBAN can pass MOD-97 and still carry a BBAN that no Belgian or French bank would ever issue.

Belgium is the easiest to test by hand. The BBAN is a three-digit bank code, a seven-digit account number and a two-digit key equal to the first ten digits modulo 97: for the registry example, 5390075470 mod 97 = 34, which is how BE68539007547034 ends. Change the key to 35 and recompute the IBAN check digits and you get BE41539007547035: valid for MOD-97, wrong for Belgium. If your validator checks national digits, this must fail; if it does not, this must pass, and you should know which behaviour you have.

Our generator computes the national check digits of 27 countries, so the IBANs it produces pass both layers, and the validator verifies them. The algorithms and their official sources are listed in national check digits.

Boundary cases and policy decisions

Some inputs need a product decision before they can become a test. Make the decision once and pin it with a test:

  • Countries outside the registry. Algeria and Morocco use IBAN-shaped numbers but are not in the SWIFT registry (we support them and label them as unofficial). Validators built strictly on the registry reject them. Decide which behaviour you want.
  • Territories that share an entry. Jersey, Guernsey and the Isle of Man issue GB IBANs; the French overseas departments issue FR IBANs; Åland uses FI. There is no JE or GP format, so a country list that includes them is wrong.
  • Kosovo. XK is in the IBAN Registry but is not an ISO 3166-1 code. If your country validation uses an ISO library, it will reject a valid Kosovan IBAN.
  • Countries with constant check digits. Because of how their national algorithm works, every Bosnian IBAN starts with BA39, every Montenegrin one with ME25, every Serbian one with RS35. A test that "generates a second IBAN with different check digits" will fail for these countries, and that is correct.
  • Maximum length. No IBAN is longer than 34 characters. Cap the input early (we cut at 64 to still be able to report what was pasted) so a megabyte of text does not reach the arithmetic.

Where to get test data

Never use IBANs from production. Beyond the privacy problem, they teach your tests nothing about countries you have few customers in.

  • The generator on this site produces a fresh, structurally valid IBAN for any of the 91 countries. By default it runs in realistic mode: bank codes come from real published lists for 84 countries, alphanumeric positions are filled with digits as banks actually do, and national check digits are computed. Switch realistic mode off when you want fully random BBANs that still pass MOD-97, which is useful for fuzzing the format layer rather than the bank directory.
  • Bulk export gives you 1 to 100 IBANs per country as CSV, JSON, SQL or plain text, one column per segment (bank code, branch, account, national check), so the same file can seed a database and drive a parameterised test.
  • The REST API returns the same data for your CI pipeline (GET /api/v1/generate/DE?count=100 for a batch, GET /api/v1/validate/ followed by the IBAN to check one); it needs a free key requested by email, and the API docs list every endpoint. The MCP server at /mcp exposes the same tools without a key.
  • A second opinion. Run your fixtures through the IBAN validator and through iban-check, our open-source JavaScript library, and diff the verdicts. A disagreement is either a bug on one side or a policy difference, and both are worth knowing about before a customer finds them.

A generated IBAN is not issued by any bank. That is what makes it safe to commit to a repository, and it is also why every test that goes beyond structure (does the account exist, does the name match) needs a bank sandbox rather than a generator.

Sources

Check an IBAN now

Paste an IBAN to check its length, format, MOD-97 check digits and, for 27 countries, the national check digits. It runs in your browser.

Open the IBAN validator