IBAN Checksums Explained: The MOD-97 Algorithm

IBAN Checksums Explained: The MOD-97 Algorithm

Learn exactly how IBAN checksum digits are calculated with the MOD-97 algorithm, why they catch typos, and how to compute and validate them in code.

Written by Random IBAN Team · Published on 2025-01-15 · Updated on 2026-05-22
#IBAN checksum #modulo 97 #IBAN validation #IBAN algorithm #IBAN control digits #ISO 7064 #check digits

Every International Bank Account Number carries two small digits that do a surprisingly large amount of work. They sit right after the country code — positions three and four — and they are the IBAN's built-in error detector. Get one digit wrong anywhere in the account number and, most of the time, those two checksum digits no longer add up. The payment is rejected before a single cent moves.

This guide explains how those checksum digits are calculated, why the modulo 97 step is so effective, and how to compute or verify them reliably in your own systems.


What the IBAN Checksum Actually Is

The two digits after the country code are formally called the check digits. They are not random and they are not part of your account number — they are derived from the rest of the IBAN using a mathematical formula defined in ISO 7064 (the same family of standards behind many other check-digit schemes).

The whole point is integrity. When a customer types an IBAN into a payment form, fingers slip: a 3 becomes an 8, two adjacent digits get swapped, a character is dropped. The check digits let any bank — or your own validation code — detect those mistakes instantly, without contacting the destination bank.

Think of it like a parity bit on a much larger scale: a compact fingerprint of the account reference that travels alongside the data it protects.


How the Checksum Calculation Works

The validation routine is deceptively simple. Take a French IBAN such as FR76 3000 6000 0112 3456 7890 189. To check it:

  1. Move the first four characters to the end. FR76 goes to the back, leaving 30006000011234567890189FR76.
  2. Replace every letter with two digits. Each letter maps to a number: A=10, B=11, … Z=35. So F=15 and R=27, turning FR76 into 15277 6.
  3. Read the result as one big integer and compute integer mod 97.
  4. If the remainder is exactly 1, the IBAN is valid. Any other remainder means the number is corrupt.

That is the entire algorithm. The genius is in step 4: the check digits are chosen, when the IBAN is first created, precisely so that this remainder comes out to 1.

Calculating the Check Digits From Scratch

Generating a brand-new IBAN runs the process in reverse:

  1. Assemble the BBAN (the country-specific bank code, branch, and account number).
  2. Append the country code followed by 00 as a placeholder for the check digits.
  3. Convert letters to numbers and compute the big integer.
  4. Calculate 98 - (integer mod 97).
  5. Zero-pad the result to two digits — that is your check digit pair.

For example, building a German IBAN around a valid BBAN produces something like DE89 3704 0044 0532 0130 00, where 89 is the calculated pair. This is exactly what the Random IBAN generator does internally for every supported country: it builds a structurally correct BBAN, then derives the check digits so the final number passes MOD-97.


Why Modulo 97 (and Not Something Simpler)?

Designers could have used a basic checksum like "sum all the digits." They chose modulo 97 deliberately, and the choice has real consequences for accuracy.

  • 97 is prime. Using a prime modulus spreads errors evenly and prevents the blind spots that plague non-prime schemes.
  • It catches every single-digit error. Change any one digit and the remainder changes — guaranteed.
  • It catches almost all transpositions. Swapping two adjacent characters (a classic typo) is detected in the overwhelming majority of cases.
  • The detection rate is roughly 98.9% for random multi-character errors — far higher than a simple sum or a single check digit could achieve.

The trade-off is that you need big-integer arithmetic, because a 34-character IBAN expands to a number with dozens of digits. In practice this is a non-issue: every mainstream language handles it natively or with a one-line library, and there is a piece-wise trick (below) that avoids big integers entirely.


Computing the Checksum in Code

You rarely need a big-integer type. Because of how modular arithmetic works, you can process the IBAN in small chunks and keep a running remainder. Here is the canonical approach in a few languages.

JavaScript:

function isValidIban(iban) {
  const s = iban.replace(/\s+/g, '').toUpperCase();
  // Move first 4 chars to the end
  const rearranged = s.slice(4) + s.slice(0, 4);
  // Convert letters to numbers (A=10 ... Z=35)
  const numeric = rearranged.replace(/[A-Z]/g, ch =>
    (ch.charCodeAt(0) - 55).toString()
  );
  // Piece-wise mod 97 to avoid BigInt
  let remainder = 0;
  for (const digit of numeric) {
    remainder = (remainder * 10 + Number(digit)) % 97;
  }
  return remainder === 1;
}

Python:

def is_valid_iban(iban: str) -> bool:
    s = "".join(iban.split()).upper()
    rearranged = s[4:] + s[:4]
    numeric = "".join(
        str(ord(c) - 55) if c.isalpha() else c
        for c in rearranged
    )
    return int(numeric) % 97 == 1   # Python ints are arbitrary-precision

PHP:

function isValidIban(string $iban): bool {
    $s = strtoupper(preg_replace('/\s+/', '', $iban));
    $rearranged = substr($s, 4) . substr($s, 0, 4);
    $numeric = '';
    foreach (str_split($rearranged) as $ch) {
        $numeric .= ctype_alpha($ch) ? (string)(ord($ch) - 55) : $ch;
    }
    // bcmod handles the large integer safely
    return bcmod($numeric, '97') === '1';
}

All three follow the same four steps. The only real difference is how each language handles the large number — Python uses native big integers, PHP leans on bcmod, and JavaScript sidesteps the problem with the running-remainder loop.


Validate Early, Validate Twice

Catching a bad IBAN at the right moment saves everyone pain. A few practices that consistently pay off:

  • Validate client-side first. Run the MOD-97 check in the browser as the user types or on blur, so they fix the typo immediately instead of after submitting.
  • Re-validate on the server. Never trust the client alone — repeat the check on the backend to guard against tampering and scripted requests.
  • Normalise before you check. Strip spaces, uppercase everything, and reject characters outside A–Z and 0–9 before running the algorithm.
  • Separate format errors from checksum errors in your messaging. "This IBAN is too short for Germany" is far more useful to a customer than a generic "invalid IBAN."

Remember the limit of the checksum: it confirms the number is structurally sound, not that the account exists. A perfectly valid IBAN can still point to a closed or non-existent account. For that, you need account verification with the bank or a dedicated service.


Generating Valid Test IBANs for Your Tests

Hard-coding a single IBAN into your test suite is fragile, and using a real one is a compliance risk. Instead, generate checksum-valid synthetic IBANs on demand.

When you create numbers with Random IBAN, every value is built with the MOD-97 method from ISO 13616, so it passes validation in any compliant library. Use them to:

  • Unit-test your validation functions with known-good and known-bad inputs.
  • QA bulk imports by exporting hundreds of IBANs to CSV or JSON.
  • Demo payment journeys without ever touching a real account number.

Pair this with the IBAN validator to confirm your own implementation agrees with the reference algorithm, and re-check your fixtures whenever a country updates its IBAN format. For deeper background on the standard itself, see our guide on what an IBAN number is.


FAQ

Why are there always exactly two check digits?

The IBAN standard fixes the check digit field at two digits for every country, regardless of total length. Two digits give 100 possible values, which is enough to satisfy the modulo-97 requirement (remainders range from 0 to 96) while keeping the format compact and uniform worldwide.

Can a wrong IBAN still pass the MOD-97 check?

Yes, although it is unlikely. The algorithm catches roughly 98.9% of random errors and every single-digit mistake, but a small fraction of multi-character errors can coincidentally still produce a remainder of 1. The check guarantees structure, not that the account is real or correct.

What is the difference between the check digits and the national check digits?

The two IBAN check digits (positions 3–4) protect the entire IBAN using MOD-97. Some countries — Spain, France, Italy and others — also embed their own national check digits inside the BBAN to protect the domestic account number. They are separate mechanisms that operate at different layers.

Do I need a big-integer library to validate an IBAN?

Not necessarily. The piece-wise remainder method shown above processes the number in small steps and keeps a running value below 97, so plain integer math is enough. You only need big integers if you compute int(numeric) % 97 in one shot, as the Python example does.

Why does converting letters use A=10 instead of A=1?

Each letter expands to a two-digit number from 10 to 35. Starting at 10 (rather than 1) guarantees every letter maps to exactly two digits, which keeps the positional arithmetic consistent. If A were 1, letters would produce a mix of one- and two-digit values and the calculation would break.

How do I generate an IBAN with valid check digits for testing?

Use the Random IBAN generator: pick a country, and it builds a correctly structured BBAN and computes the check digits for you automatically. Every result passes MOD-97 validation, so it works as a drop-in test fixture without exposing any real banking data.

Try Our IBAN Tools

Put your knowledge into practice with our free tools.