IBAN validation made easy – a comprehensive guide

2026-07-17

When a payment file comes back just before the bank upload, the problem often lies not in the XML, but much earlier. An IBAN was treated as a number in Excel, an account number from an old AEB export was not padded cleanly, or the recipient name no longer matches the stored account details. That is exactly when IBAN validation turns from a nice add-on into a necessity.

In practice, processes rarely fail on theory. They fail on imported CSVs, historically grown fields and silent assumptions in the code. Anyone processing transfers or direct debits in bulk therefore needs more than a simple format check. What matters is the combination of a structure check, check-digit logic, clean error handling, and, since the arrival of the VoP world, also the separation between technical IBAN validation and actual recipient verification.

Introduction to IBAN validation

Many teams know the pattern. The department maintains account details in Excel, the ERP exports a CSV, and then a tool or script builds the SEPA file. As long as everything is cleanly formatted, the process runs. But as soon as an IBAN slips, spaces travel along, or a legacy format from AEB stock appears, the remittance blocks or triggers follow-up questions with the bank.

For SMEs in particular, this is not a marginal problem. The data comes from different sources, often without uniform field rules. A manual visual check is then not enough. It recognizes neither a formally wrong check digit nor a logically incorrectly assembled IBAN with an incompletely transferred account number.

Practical rule: IBAN validation does not belong only at the last step before export. It belongs at import, during processing and at the final approval point.

What reliably works in projects is a multi-stage process. First the system checks the syntax. Then comes the modulo-97 check. Afterwards the application evaluates special cases such as old AEB fields, leading zeros and the assignment of bank code and account number. Anyone working this way reduces not only technical errors, but also saves time in approvals and rework.

Understanding the IBAN structure

Most errors arise because the structure of the IBAN sounds familiar but is implemented imprecisely in daily use. For Germany, the structure is strict. The German IBAN has a fixed length of 22 characters and begins with DE, followed by a two-digit check number, an 8-digit bank code (BLZ) and a 10-digit account number. Any deviation leads to invalidation, as the description of the German IBAN structure at VR Bank explains.

A clear infographic explains the structure of a German IBAN with country code, check number, bank code and account number.

The fields of a German IBAN

A German IBAN can be broken down into four building blocks:

Component Content Meaning
Country code DE Identifies Germany
Check number two digits Used for formal checking
BLZ 8 digits Identifies the bank
Account number 10 digits Identifies the account

The critical point is the account number. In legacy systems, it is often stored shorter. For the IBAN, it must not stay that way. Shorter account numbers must be padded on the left with zeros so that the BBAN structure is formed correctly. This is exactly where most silent errors happen in migrations from old AEB formats.

Where historical formats cause problems

When an AEB export internally still works with separate fields or differing lengths, it is not enough to simply concatenate the values. Only correct normalization produces a valid BBAN. In Germany, it should additionally be checked whether the bank code contained in the IBAN still exists in the current Bundesbank directory. This is important in practice, because a formally plausible string can still point to a deleted or outdated bank connection.

An IBAN can look technically clean and still be operationally unusable if the underlying bank code comes from an old data set.

With transferred data, I always look at two things first: have leading zeros been preserved, and does the bank code really come from a current master data set. These two checks catch more errors in legacy projects than any subsequent manual correction.

Performing the modulo-97 check

The structure alone is not enough. The next hard check is the modulo-97 check. Here, the remainder of dividing the rearranged IBAN by 97 must be exactly 1, otherwise the IBAN is considered faulty, as the IBAN checker from Kalcify neatly summarizes.

As a visual short version, this illustration helps:

An infographic with four steps for performing the modulo-97 check for IBAN validation and account numbers.

The process without magic

The algorithm is standardized and simple enough to implement in any language:

  1. Move the first four characters to the end DEkk... becomes ...DEkk.

  2. Convert letters to numbers A=10 to Z=35. So for D and E, it becomes 13 and 14.

  3. Compute the resulting number modulo 97 For large numbers, it is best to process iteratively as a string.

  4. Check the remainder Only the remainder value 1 is valid.

What goes wrong in real software

The most common implementation error is not the algorithm itself, but the preprocessing. Developers do not remove spaces consistently, leave lowercase letters unnormalized, or cast long digit sequences into data types unsuited for it. In JavaScript, this is especially tricky when someone works with numeric types instead of strings.

A second error concerns German account numbers from legacy formats. If the padding to ten digits is missing before the IBAN is built, the entire sequence can fail syntactically. That is why I always separate normalization, IBAN generation and checking in projects.

If your application validates directly against raw data, you often only validate the error state. Normalize first, then check.

Anyone who wants to test an existing check routine can use a public IBAN validator for individual checks and compare the results with their own implementation. For a quick cross-check, this is useful, but it does not replace the logic in your own data flow.

To illustrate the calculation path, this video is helpful:

Regular expressions and code examples

Regex is useful for IBAN validation, but only for the first layer. With it, you check the form and permitted characters. Real validation only comes together with per-country length rules and the mod-97 method. This is especially relevant when your system processes more than just German IBANs. The IBAN checker engine from iban.com supports all 37 official SEPA member countries and distinguishes 97 data structures for country-specific length and check-digit rules.

What regex can and cannot do

For a rough syntax check of German IBANs, a pattern like this is enough:

^DE[0-9]{20}$

For multiple countries, things quickly become unwieldy. A more general pattern is then sensible:

^[A-Z]{2}[0-9]{2}[A-Z0-9]{1,30}$

But this is only an entry filter. It says nothing about whether the length fits the country or whether the check digit is correct.

A brief classification:

  • Well suited for early form errors such as special characters, spaces or wrong prefixes
  • Poorly suited for country-specific detailed rules
  • Unsuitable for the actual checksum logic

JavaScript for clients and API frontends

In the browser or in Node.js, a combination of normalization, country check and iterative modulo calculation is often enough.

function validateGermanIBAN(input) {
  const iban = input.replace(/\s+/g, '').toUpperCase();

  if (!/^DE[0-9]{20}$/.test(iban)) {
    return { valid: false, reason: 'Format error' };
  }

  const rearranged = iban.slice(4) + iban.slice(0, 4);
  const converted = rearranged.replace(/[A-Z]/g, ch => (ch.charCodeAt(0) - 55).toString());

  let remainder = 0;
  for (const digit of converted) {
    remainder = Number(String(remainder) + digit) % 97;
  }

  return { valid: remainder === 1, reason: remainder === 1 ? null : 'Invalid check digit' };
}

What I pay attention to in the frontend:

  • Keep strings instead of numeric conversion
  • Remove whitespace early
  • Separate error messages between format error and check-digit error

Python for backends and batch processes

Python is well suited for import jobs, file processing and data pipelines.

import re

def validate_german_iban(value: str) -> dict:
    iban = re.sub(r"\s+", "", value).upper()

    if not re.fullmatch(r"DE\d{20}", iban):
        return {"valid": False, "reason": "Format error"}

    rearranged = iban[4:] + iban[:4]
    converted = "".join(str(ord(ch) - 55) if ch.isalpha() else ch for ch in rearranged)

    remainder = 0
    for digit in converted:
        remainder = int(f"{remainder}{digit}") % 97

    return {"valid": remainder == 1, "reason": None if remainder == 1 else "Invalid check digit"}

Handling historical AEB formats cleanly

With old AEB data, the art lies not in the regex, but in the pre-logic. For this, I usually place a small normalization step before the actual validation:

  • Read the BLZ separately and bring it to the expected length
  • Pad the account number on the left with zeros
  • Only then assemble the German BBAN
  • Only after that compute mod-97

If your system allows multiple countries, a country table is worthwhile instead of hard-coded rules. That stays maintainable. A monster regex does not.

Batch validation and error handling

Individual checks are nice. In practice, lists arrive. Excel files, CSV exports, JSON payloads from an ERP, or mixed legacy stock from AEB formats. Anyone processing this data serially without a log is building in later detective work.

An infographic explains four steps for efficient batch validation and error handling of IBANs through automation and analysis.

What proves itself in batch jobs

I always treat batch processing as a pipeline with clear status values. Not just valid or invalid, but rather imported, normalized, formally invalid, substantively suspicious and ready for approval. This way, a run can be cleanly repeated without touching everything again.

For large files, these rules work well:

  • Use chunking instead of loading entire files into memory at once
  • Store the original value and the normalized form, so that corrections remain traceable
  • Log error codes instead of just returning “invalid”
  • Build repeatable jobs, so that corrected rows can be checked again

Typical error cases in daily life

Not every invalid IBAN is a typo. Some records fail because Excel truncated leading zeros. Others because old field definitions still live in an ERP. And since the new recipient verification, a formally correct IBAN is often no longer enough for transfers.

Many existing processes ignore the new VoP requirement from October 2025, under which banks must match recipient names and IBANs. If this automatic reconciliation is missing, the transfer can be blocked, as the consumer advice center on the new obligation to match name and IBAN describes.

A batch check without a clean error log is just a fast route to a long manual rework.

My advice is clear: separate technical validation from business approval. The first stage checks structure and check digit. The second evaluates legacy formats, recipient names and correction needs. That is exactly where a validator becomes a robust process.

Integrating into systems and using APIs

For integration, there are two clean routes. Either you validate directly with libraries in your own stack, or you outsource parts of the check to an API service. Both have their place.

An infographic on the efficient integration of IBAN validation into systems and APIs with various strategies and recommendations.

Library or API

Direct libraries fit well when you need full control. They run without network dependency, integrate deeply into import jobs, and are ideal for simple format and check-digit checks.

REST APIs make sense when you want to bring validation into several systems without maintaining the logic twice everywhere. This is especially practical when bank details, BIC assignment or conversion from legacy formats are also needed. One example is GenerateSEPA, which converts Excel, CSV, JSON and AEB files into SEPA XML and also provides a JSON API for technical integration.

What counts in production environments

Since October 2025, banks must automatically verify name and IBAN in the recipient match before a SEPA transfer is authorized. To classify the processes around this requirement, it is useful to look at the bank account verification process in the GenerateSEPA blog.

For the technical implementation, I look at these points:

  • Authentication with clear key management
  • Timeouts and retries only where they make sense from a business standpoint
  • Response models with machine-readable error codes
  • SLA planning for critical payment windows

An API is not a substitute for internal data quality. It is a clean integration point. If the input data comes in unstructured from legacy formats, the preprocessing must still be solved cleanly within your own system.

Summary and best practices

IBAN validation works reliably when it is built in multiple stages. First comes the normalization of the data, then the structure check, then the modulo-97 logic, and finally the business handling of legacy formats, bank-code problems and recipient matching. Anyone who uses only regex catches only part of the errors.

The short checklist for daily use:

  • Always normalize inputs
  • Pad German account numbers correctly
  • Never replace mod-97 with regex
  • Log batch jobs with error codes
  • Handle VoP requirements separately from the pure IBAN check

If you want to transfer Excel, CSV, JSON or old AEB files into clean SEPA processes, GenerateSEPA is a practical option. The service converts stock into valid SEPA XML, supports IBAN checks, and fits teams that want to process recurring remittances without a local installation.


Frequently Asked Questions

What is the difference between syntax and modulo-97 checks?
Syntax checks length, characters and structure. Modulo 97 validates the check digits on the normalised IBAN. Together they catch most entry and export errors.
Why do many validations fail on normalisation?
Spaces, lowercase letters or Excel numeric cell formats change the string before calculation. Clean the input first, then validate — otherwise tools falsely report invalid IBANs.
What does VoP mean for IBAN validation?
Verification of Payee adds a name-and-account match at the beneficiary bank. Treat it separately from pure modulo-97 logic.
How do you validate large lists of IBANs efficiently?
Use batch jobs with machine-readable error codes, log per row and keep normalisation, validation and export as distinct steps to avoid manual rework before bank upload.

Related posts