# IBAN Validator & Bank Enricher – Bulk IBAN API (`lwsdjfls/iban-validator-enricher`) Actor

Bulk IBAN validation, fully offline: ISO 13616 check digits and the national format of all 89 IBAN countries, bank and branch code, bank name and BIC for German, Belgian and Dutch IBANs, and the likely fix for a typo. No name check and no account existence check.

- **URL**: https://apify.com/lwsdjfls/iban-validator-enricher.md
- **Developed by:** [Leyten Data](https://apify.com/lwsdjfls) (community)
- **Categories:** Business, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 iban validateds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does IBAN Validator & Bank Enricher do?

**Bulk IBAN validation** for payment onboarding, supplier master data and accounting imports: every IBAN is validated offline against the Swift IBAN Registry (all 89 countries and territories that issue IBANs), split into bank code, branch code and account number, enriched with the **bank name and BIC** for German, Belgian and Dutch IBANs from public bank lists, and, when it is invalid, accompanied by the single-character fixes that would make it valid. The registry and the bank lists are bundled with the Actor: no third-party service is called, nothing is kept between runs, and the IBANs you send stay inside your own run: in its input, its dataset and, while it delivers, its key-value store.

#### What this Actor does not do

Read this before you rely on the output:

- **It does not check that the account exists** (geen bestaanscontrole). A valid result means the string is a correctly formed IBAN of that country and, where a bank list exists, that the bank code belongs to a real bank. Whether that bank has an account with that number is something only the bank knows.
- **It is not a name check** (geen naam-rekeningcontrole). It does not compare the IBAN with the account holder's name (Verification of Payee / IBAN-Name Check / Confirmation of Payee). Since October 2025 payment service providers in the euro area must offer that check for euro credit transfers (the rest of SEPA follows by 2027); use it there, or a licensed VoP provider.
- **It does not say whether the account is open, blocked, or able to receive SEPA payments.** `sepa` tells you the *country* takes part in SEPA, not the account.
- **It does not return bank addresses or contact details**, only the bank's name and BIC.

What it is good for: catching mistyped, truncated and mangled IBANs before you store a supplier record, submit a payment file, or send a customer a form error, and adding the BIC where a payment file or ERP still requires one.

#### How an IBAN is validated

Each IBAN goes through the checks in this order, and the first failure is the reason you get. One exception: a value whose positions 3 and 4 are not two digits is `structure` straight away, before the length and the check digits are looked at.

| Reason | What was found |
| --- | --- |
| `empty` | Nothing left after removing spaces and separators |
| `characters` | Characters that never occur in an IBAN (only A–Z and 0–9 do); the text names them |
| `country-unknown` | The first two characters are not a country in the IBAN Registry: no IBANs are issued there |
| `length` | Wrong number of characters for that country (the text gives both numbers) |
| `checksum` | The ISO 13616 mod-97 check digits do not match: a character was mistyped or two were swapped (a dropped or added character shows up as `length`) |
| `structure` | The national format is not met: letters where digits belong, or the reverse. Positions 3 and 4 that are not two digits also land here, before the length and the check digits are checked |

Spaces, dashes, dots, lower case and an "IBAN" prefix are removed first, so `iban: nl91 abna 0417.1643-00` validates as `NL91ABNA0417164300`. Territories that use another country's IBAN format (`GF`, `GP`, `MQ`, `RE`, `PF`, `TF`, `YT`, `NC`, `BL`, `MF`, `PM`, `WF` for France; `IM`, `JE`, `GG` for the United Kingdom; `AX` for Finland) are validated with that format.

The mod-97 check digits catch every single-character error and every swap of two adjacent digits. A swap in which a letter is involved can slip through, because a letter counts as two digits in the calculation. National check digits inside the BBAN (Belgium and France carry one, for instance) are not verified separately: they would catch a few of the typos that survive mod-97, so read a valid result as "correctly formed IBAN of that country", not as "checked twice".

#### Bank name and BIC: only from lists that may be reused

The Swift BIC Directory, the one complete IBAN-to-BIC source, is licensed and may not be redistributed. This Actor therefore bundles only public lists whose reuse is permitted, and every record says which one answered (`bankSource`):

| Country | List | Version | Bank codes | Coverage |
| --- | --- | --- | --- | --- |
| `DE` | Deutsche Bundesbank, Bankleitzahlendatei (public download) | valid 2026-09-07 to 2026-12-06 | 3,432 | complete: an unknown bank code is reported as a warning |
| `BE` | National Bank of Belgium, identification codes of Belgian banks | Version 01/09/2026 | 782 | complete: an unknown bank code is reported as a warning |
| `NL` | Major Dutch banks, curated by hand from the BICs the banks publish | September 2026 | 45 | major banks only: an unknown bank code is not a warning |

- **Germany** and **Belgium** are complete: a valid IBAN whose bank code is not in the list gets an entry in `warnings`, because no bank uses that code (a typo that happened to keep the check digits right, or a bank that no longer exists).
- **The Netherlands** covers the major consumer and business banks. The Dutch Payments Association publishes the complete Dutch BIC list, but its terms forbid redistribution, so smaller banks and foreign branches return `bankName: null` without a warning.
- **Other countries** return the bank and branch code as parsed from the IBAN, without a name or BIC.

The table above is generated from the bundled files, so it always names the versions this release carries; `bankSource` tells you per record which of the three answered (`bundesbank`, `nbb` or `curated`), and a warning about an unknown bank code quotes the list version it was checked against.

#### Suggested corrections

An IBAN that fails the check digits (`checksum`) or the national format (`structure`) usually contains one of a few classic mistakes. With **Suggest corrections** on (default), the Actor tries each one and keeps only the candidates that validate:

- **Letter/digit confusion** at one position: `O` ↔ `0`, `I` ↔ `1`, `L` ↔ `1`, `S` ↔ `5`, `B` ↔ `8`, `Z` ↔ `2`, `G` ↔ `6`
- **Two adjacent characters swapped**
- **Wrong check digits** with an otherwise plausible account part: it only says what the check digits *would* be if the rest is right, so it is the weakest kind and comes after the other kinds of equal plausibility. But, like any candidate, a check-digit candidate that names a bank from a bundled list is still listed before candidates that name none

A candidate that passes both the check digits and the national format is a strong lead: the chance that a random correction does so is about 1 in 97. At most three suggestions are returned per IBAN, the ones that name a bank from a bundled list first, because a corrected IBAN whose bank code belongs to a real bank is rarely a coincidence. An IBAN with the wrong number of characters (`length`), with characters that cannot occur (`characters`) or with an unknown country (`country-unknown`) gets no suggestions: a dropped or added character is not a single-character fix, and the reason already says what is wrong. Suggestions are proposals for a human or a retry prompt, not automatic replacements.

### Features

- **Bulk IBAN checker** for up to 100,000 IBANs per run (20,000 by default; above 50,000 give the run 2 GB of memory), entirely offline inside your Apify run
- **IBAN validation for all 89 IBAN countries** from the Swift IBAN Registry (TXT edition, read on 15 September 2026): ISO 13616 mod-97 check digits, length and national format
- **Bank code, branch code and account number** split as the IBAN Registry defines them per country
- **IBAN to BIC and bank name** for German, Belgian and Dutch IBANs, from public bank lists that may be redistributed
- **IBAN typo correction**: up to three single-character fixes that turn an invalid IBAN into a valid one, the ones that name a real bank first
- **Warnings on valid IBANs** whose bank code no bank uses (Germany and Belgium), and on a territory prefix most banks there do not issue
- **SEPA country flag** per IBAN, straight from the registry
- **Deterministic and private**: no external API, nothing kept between runs, the same answer every time
- Runs through the Apify API, from Make, Zapier or n8n, or as a scheduled task over an export

### Use cases

#### Payment onboarding and supplier master data

Validate the IBANs of new suppliers or customers when they are entered, in a nightly batch or before a payment run. Reject `valid: false` with `reasonText` and, when there is one, the suggestion ("did you mean NL91 ABNA 0417 1643 00?"); flag `warnings` for review; fill the BIC from `bic` where your bank or ERP still demands one.

```js
// npm install apify-client
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('lwsdjfls/iban-validator-enricher').call({
    ibans: suppliers.map((supplier) => supplier.iban),
});
const { items } = await client.dataset(run.defaultDatasetId).listItems({ clean: true });
const byInput = new Map(items.map(({ payload }) => [payload.input, payload]));

for (const supplier of suppliers) {
    const result = byInput.get(supplier.iban.trim());
    if (!result?.valid) {
        await flagSupplier(supplier.id, result?.reasonText, result?.suggestions[0]?.ibanFormatted);
    } else {
        await updateSupplier(supplier.id, { iban: result.iban, bic: result.bic, bank: result.bankName, review: result.warnings });
    }
}
```

10,000 supplier IBANs cost $5.00.

#### Accounting and CRM teams: cleaning an export

Export the bank account column, run it once, and sort by `reason`: `length`, `checksum` and `structure` are typos, `characters` are usually leftovers of another field that landed in the IBAN column, `country-unknown` are account numbers that were never IBANs.

#### Treasury: SEPA batch pre-check

Run the IBANs of a pain.001 batch before you submit it. A malformed IBAN comes back as a rejection of the single transaction or of the whole file, depending on the bank, and often hours later. This check answers in seconds and the same run gives you the German, Belgian and Dutch BICs for the batch.

#### Developers: form validation through the API

Call the Actor from a backend when a user submits an IBAN, and show `reasonText` or the first suggestion as the form error. For an interactive form the check digits alone are enough client-side; the value of this Actor is the bank identification and the corrections.

### How to use it

1. Paste the IBANs into **IBANs**. Spacing and case do not matter, so a column copied straight out of a spreadsheet or an export works as it is. Nothing leaves the run: validation happens against the IBAN Registry and the bank lists shipped inside the Actor, with no external service involved.
2. Leave **Suggest corrections** on for a supplier or customer file. An IBAN that fails the check digit then comes back with the most likely repair, so a typed `O` instead of a zero or two swapped characters is something you can fix rather than merely reject.
3. Put it in front of your payment run. The `validation` view gives the verdict per IBAN and the `bank` view gives bank name, BIC, bank code and branch code where the national list covers them, which is what a treasury team pastes back into the master file.

Because there is no network call, a run of a few thousand IBANs takes seconds and the result is the same every time. Keep an eye on the log if you send very large batches: the run tells you how many IBANs fit in the memory it was given and what to raise if some were left over, rather than silently validating part of the list.

Be clear about the limit before you rely on it. This is a structural check, not a bank check. It proves the IBAN is well formed and which bank it belongs to. It cannot tell you that the account exists, that it is open, or that it belongs to the name on your invoice. For that you need your bank's own verification service.

```json
{
  "ibans": ["NL91 ABNA 0417 1643 00", "DE89 3704 0044 0532 0130 00", "BE68 5390 0754 7034"],
  "suggestCorrections": true
}
```

### Input

| Field | What it does | Example |
| --- | --- | --- |
| `ibans` | One IBAN per line, at least one, at most 80 characters per line. Spaces, dashes, dots, lower case and an "IBAN" prefix are fine. A duplicate is checked and charged once. | `["NL91 ABNA 0417 1643 00", "DE89 3704 0044 0532 0130 00"]` |
| `suggestCorrections` | For an IBAN that fails, list up to three single-character fixes that would make it valid. Default `true`. | `true` |
| `maxIbansPerRun` | Caps the validated (and charged) IBANs in one run; anything beyond it is skipped, not charged and mentioned in the log. Default `20000`. | `20000` |

By default a run validates the first 20,000 distinct IBANs. With the default 1 GB of memory you can raise `maxIbansPerRun` to 50,000; above that, start the run with 2 GB of memory or split the list. A run with less memory than its cap needs validates only what fits (20,000 below 1 GB, 50,000 below 2 GB) and says so in the log; skipped IBANs are not charged.

```json
{
  "ibans": [
    "NL91 ABNA 0417 1643 00",
    "DE89 3704 0044 0532 0130 00",
    "BE68 5390 0754 7034",
    "GB29 NWBK 6016 1331 9268 19",
    "FR14 2004 1010 0505 0001 3M02 606",
    "NL91 ABNA 0417 1643 0O",
    "DE89 3704 0044 0532 0310 00"
  ],
  "suggestCorrections": true
}
```

`ibans` needs at least one non-empty line: a run with an empty list stops with *Add at least one IBAN.* before anything is charged, and a line over 80 characters fails the input check (no IBAN is that long: the longest anywhere, Russia's, is 33 characters, 41 with spaces). Empty lines and duplicates cost nothing; of a duplicate, the first spelling you gave is the one reported. Running the example above (the prefilled input) returns seven records. Five are valid: the Dutch and German IBANs with bank name and BIC, the Belgian one with a warning that bank code 539 is not in the Belgian list, and the British and French ones without bank data. Two are invalid, one with a single suggested correction and one with three.

#### Supported countries

All 89 entries of the Swift IBAN Registry (TXT edition, read on 15 September 2026), plus the 16 territory prefixes that share another country's format, shown with it. Positions are counted inside the BBAN, the part after the country code and check digits.

| Prefix | Country | Length | SEPA | Bank code (BBAN positions) | Branch code | Example |
| --- | --- | --- | --- | --- | --- | --- |
| `AD` | Andorra | 24 | yes | 1–4 | 5–8 | `AD1200012030200359100100` |
| `AE` | United Arab Emirates (The) | 23 | no | 1–3 | – | `AE070331234567890123456` |
| `AL` | Albania | 28 | no | 1–3 | 4–8 | `AL47212110090000000235698741` |
| `AT` | Austria | 20 | yes | 1–5 | – | `AT611904300234573201` |
| `AZ` | Azerbaijan | 28 | no | 1–4 | – | `AZ21NABZ00000000137010001944` |
| `BA` | Bosnia and Herzegovina | 20 | no | 1–3 | 4–6 | `BA391290079401028494` |
| `BE` | Belgium | 16 | yes | 1–3 | – | `BE68539007547034` |
| `BG` | Bulgaria | 22 | yes | 1–4 | 5–8 | `BG80BNBG96611020345678` |
| `BH` | Bahrain | 22 | no | 1–4 | – | `BH67BMAG00001299123456` |
| `BI` | Burundi | 27 | no | 1–5 | 6–10 | `BI4210000100010000332045181` |
| `BR` | Brazil | 29 | no | 1–8 | 9–13 | `BR1800360305000010009795493C1` |
| `BY` | Belarus | 28 | no | 1–4 | – | `BY13NBRB3600900000002Z00AB00` |
| `CH` | Switzerland | 21 | yes | 1–5 | – | `CH9300762011623852957` |
| `CR` | Costa Rica | 22 | no | 1–4 | – | `CR05015202001026284066` |
| `CY` | Cyprus | 28 | yes | 1–3 | 4–8 | `CY17002001280000001200527600` |
| `CZ` | Czechia | 24 | yes | 1–4 | – | `CZ6508000000192000145399` |
| `DE` | Germany | 22 | yes | 1–8 | – | `DE89370400440532013000` |
| `DJ` | Djibouti | 27 | no | 1–5 | 6–10 | `DJ2100010000000154000100186` |
| `DK` | Denmark | 18 | yes | 1–4 | – | `DK5000400440116243` |
| `DO` | Dominican Republic | 28 | no | 1–4 | – | `DO28BAGR00000001212453611324` |
| `EE` | Estonia | 20 | yes | 1–2 | – | `EE382200221020145685` |
| `EG` | Egypt | 29 | no | 1–4 | 5–8 | `EG380019000500000000263180002` |
| `ES` | Spain | 24 | yes | 1–4 | 5–8 | `ES9121000418450200051332` |
| `FI` (also `AX`) | Finland | 18 | yes | 1–3 | – | `FI2112345600000785` |
| `FK` | Falkland Islands (Malvinas) | 18 | no | 1–2 | – | `FK88SC123456789012` |
| `FO` | Faroe Islands | 18 | no | 1–4 | – | `FO6264600001631634` |
| `FR` (also `GF`, `GP`, `MQ`, `RE`, `PF`, `TF`, `YT`, `NC`, `BL`, `MF`, `PM`, `WF`) | France | 27 | yes | 1–5 | 6–10 | `FR1420041010050500013M02606` |
| `GB` (also `IM`, `JE`, `GG`) | United Kingdom | 22 | yes | 1–4 | 5–10 | `GB29NWBK60161331926819` |
| `GE` | Georgia | 22 | no | 1–2 | – | `GE29NB0000000101904917` |
| `GI` | Gibraltar | 23 | yes | 1–4 | – | `GI75NWBK000000007099453` |
| `GL` | Greenland | 18 | no | 1–4 | – | `GL8964710001000206` |
| `GR` | Greece | 27 | yes | 1–3 | 4–7 | `GR1601101250000000012300695` |
| `GT` | Guatemala | 28 | no | 1–4 | – | `GT82TRAJ01020000001210029690` |
| `HN` | Honduras | 28 | no | 1–4 | – | `HN88CABF00000000000250005469` |
| `HR` | Croatia | 21 | yes | 1–7 | – | `HR1210010051863000160` |
| `HU` | Hungary | 28 | yes | 1–3 | 4–7 | `HU42117730161111101800000000` |
| `IE` | Ireland | 22 | yes | 1–4 | 5–10 | `IE29AIBK93115212345678` |
| `IL` | Israel | 23 | no | 1–3 | 4–6 | `IL620108000000099999999` |
| `IQ` | Iraq | 23 | no | 1–4 | 5–7 | `IQ98NBIQ850123456789012` |
| `IS` | Iceland | 26 | yes | 1–2 | 3–4 | `IS140159260076545510730339` |
| `IT` | Italy | 27 | yes | 2–6 | 7–11 | `IT60X0542811101000000123456` |
| `JO` | Jordan | 30 | no | 1–4 | 5–8 | `JO94CBJO0010000000000131000302` |
| `KW` | Kuwait | 30 | no | 1–4 | – | `KW81CBKU0000000000001234560101` |
| `KZ` | Kazakhstan | 20 | no | 1–3 | – | `KZ86125KZT5004100100` |
| `LB` | Lebanon | 28 | no | 1–4 | – | `LB62099900000001001901229114` |
| `LC` | Saint Lucia | 32 | no | 1–4 | – | `LC55HEMM000100010012001200023015` |
| `LI` | Liechtenstein | 21 | yes | 1–5 | – | `LI21088100002324013AA` |
| `LT` | Lithuania | 20 | yes | 1–5 | – | `LT121000011101001000` |
| `LU` | Luxembourg | 20 | yes | 1–3 | – | `LU280019400644750000` |
| `LV` | Latvia | 21 | yes | 1–4 | – | `LV80BANK0000435195001` |
| `LY` | Libya | 25 | no | 1–3 | 4–6 | `LY83002048000020100120361` |
| `MC` | Monaco | 27 | yes | 1–5 | 6–10 | `MC5811222000010123456789030` |
| `MD` | Moldova, Republic of | 24 | no | 1–2 | – | `MD24AG000225100013104168` |
| `ME` | Montenegro | 22 | no | 1–3 | – | `ME25505000012345678951` |
| `MK` | North Macedonia | 19 | no | 1–3 | – | `MK07250120000058984` |
| `MN` | Mongolia | 20 | no | 1–4 | – | `MN121234123456789123` |
| `MR` | Mauritania | 27 | no | 1–5 | 6–10 | `MR1300020001010000123456753` |
| `MT` | Malta | 31 | yes | 1–4 | 5–9 | `MT84MALT011000012345MTLCAST001S` |
| `MU` | Mauritius | 30 | no | 1–6 | 7–8 | `MU17BOMM0101101030300200000MUR` |
| `NI` | Nicaragua | 28 | no | 1–4 | – | `NI45BAPR00000013000003558124` |
| `NL` | Netherlands (The) | 18 | yes | 1–4 | – | `NL91ABNA0417164300` |
| `NO` | Norway | 15 | yes | 1–4 | – | `NO9386011117947` |
| `OM` | Oman | 23 | no | 1–3 | – | `OM810180000001299123456` |
| `PK` | Pakistan | 24 | no | 1–4 | – | `PK36SCBL0000001123456702` |
| `PL` | Poland | 28 | yes | 1–8 | – | `PL61109010140000071219812874` |
| `PS` | Palestine, State of | 29 | no | 1–4 | – | `PS92PALS000000000400123456702` |
| `PT` | Portugal | 25 | yes | 1–4 | – | `PT50000201231234567890154` |
| `QA` | Qatar | 29 | no | 1–4 | – | `QA58DOHB00001234567890ABCDEFG` |
| `RO` | Romania | 24 | yes | 1–4 | – | `RO49AAAA1B31007593840000` |
| `RS` | Serbia | 22 | no | 1–3 | – | `RS35260005601001611379` |
| `RU` | Russian Federation | 33 | no | 1–9 | 10–14 | `RU0304452522540817810538091310419` |
| `SA` | Saudi Arabia | 24 | no | 1–2 | – | `SA0380000000608010167519` |
| `SC` | Seychelles | 31 | no | 1–6 | 7–8 | `SC18SSCB11010000000000001497USD` |
| `SD` | Sudan | 18 | no | 1–2 | – | `SD2129010501234001` |
| `SE` | Sweden | 24 | yes | 1–3 | – | `SE4550000000058398257466` |
| `SI` | Slovenia | 19 | yes | 1–5 | – | `SI56263300012039086` |
| `SK` | Slovakia | 24 | yes | 1–4 | – | `SK3112000000198742637541` |
| `SM` | San Marino | 27 | yes | 2–6 | 7–11 | `SM86U0322509800000000270100` |
| `SO` | Somalia | 23 | no | 1–4 | 5–7 | `SO211000001001000100141` |
| `ST` | Sao Tome and Principe | 25 | no | 1–4 | 5–8 | `ST23000100010051845310146` |
| `SV` | El Salvador | 28 | no | 1–4 | – | `SV62CENR00000000000000700025` |
| `TL` | Timor-Leste | 23 | no | 1–3 | – | `TL380080012345678910157` |
| `TN` | Tunisia | 24 | no | 1–2 | 3–5 | `TN5910006035183598478831` |
| `TR` | Turkiye | 26 | no | 1–5 | – | `TR330006100519786457841326` |
| `UA` | Ukraine | 29 | no | 1–6 | – | `UA213223130000026007233566001` |
| `VA` | Holy See | 22 | yes | 1–3 | – | `VA59001123000012345678` |
| `VG` | Virgin Islands (British) | 24 | no | 1–4 | – | `VG96VPVG0000012345678901` |
| `XK` | Kosovo | 20 | no | 1–2 | 3–4 | `XK051212012345678906` |
| `YE` | Yemen | 30 | no | 1–4 | 5–8 | `YE15CBYE0001018861234567891234` |

`sepa` follows the SEPA column of the IBAN Registry (the 27 EU member states plus Iceland, Liechtenstein, Norway, Switzerland, the United Kingdom, Andorra, Monaco, San Marino, the Vatican City State and Gibraltar).

### Output

One record per distinct IBAN:

- `valid`: `true` or `false`, and for invalid IBANs `reason` (`empty`, `characters`, `country-unknown`, `length`, `checksum`, `structure`) plus `reasonText`, one sentence you can show a user
- `iban` (normalised: upper case, no spaces or separators) and `ibanFormatted` (groups of four, for letters and screens; `null` for an invalid IBAN)
- `countryCode`, `countryName`, `sepa` (all `null` when the country code is not in the registry)
- `checkDigits`, `bban`, `bankCode`, `branchCode`, `accountNumber` as the IBAN Registry defines them for that country: filled for a valid IBAN, `null` for an invalid one, and `branchCode` also `null` for countries whose IBAN carries no branch code
- `bankName`, `bic` and `bankSource` when the bank code is in a bundled bank list (Germany, Belgium, the Netherlands)
- `suggestions`: for an invalid IBAN, the single-character corrections that would make it valid, each with the corrected IBAN and what was probably mistyped
- `warnings`: doubts about a *valid* IBAN. Two exist: a German or Belgian bank code that is not in the country's complete bank list, and an IBAN that starts with a territory prefix (`GF`, `JE`, `AX` …) where most banks issue IBANs of the parent country instead
- `input`: your value as you gave it, so you can join the results back to your own records

Each record is wrapped in the standard envelope of this portfolio (`id`, `hash`, `changeType`, `sourceUrl`, `scrapedAt`) with the fields above under `payload`. Below: a Dutch IBAN with the letter O typed for the last zero, invalid, with the corrected IBAN as suggestion.

```json
{
  "envelopeVersion": 1,
  "id": "iban:NL91ABNA041716430O",
  "scope": "batch",
  "changeType": "added",
  "sourceUrl": "https://www.swift.com/standards/data-standards/iban-registry",
  "scrapedAt": "2026-09-15T10:00:00.000Z",
  "firstSeenAt": "2026-09-15T10:00:00.000Z",
  "hash": "3ac11d7bf692a0c82c28b4ff633f2b0eeff5df0c4c4979dd48b7c257224bf8d9",
  "previousHash": null,
  "changes": [],
  "summary": "Added: NL91ABNA041716430O",
  "diffText": null,
  "payload": {
    "input": "NL91 ABNA 0417 1643 0O",
    "valid": false,
    "reason": "checksum",
    "reasonText": "The check digits do not match (expected 64); a digit was mistyped, dropped or transposed.",
    "iban": "NL91ABNA041716430O",
    "ibanFormatted": null,
    "countryCode": "NL",
    "countryName": "Netherlands (The)",
    "sepa": true,
    "checkDigits": null,
    "bban": null,
    "bankCode": null,
    "branchCode": null,
    "accountNumber": null,
    "bankName": null,
    "bic": null,
    "bankSource": null,
    "suggestions": [
      {
        "iban": "NL91ABNA0417164300",
        "ibanFormatted": "NL91 ABNA 0417 1643 00",
        "kind": "letter-digit-confusion",
        "description": "O at position 18 read as 0",
        "bankName": "ABN AMRO Bank N.V."
      }
    ],
    "warnings": []
  }
}
```

The dataset opens on the **Validation** view: your input, valid or not, the normalised IBAN, country, bank code, bank name, BIC, the reason and explanation, the suggestions and the warnings. The **Bank and BIC** view shows what was parsed out of each IBAN (bank code, branch code, account number, bank name, BIC and which bank list answered) for filling a payment file or an ERP record; invalid IBANs appear in it too, with those fields empty. The `RUN_SUMMARY` record in the run's key-value store counts what the run saw, validated and delivered, and what it charged.

### Pricing

| Event | Name | What it means | Price |
| --- | --- | --- | --- |
| `apify-actor-start` | Actor start | Charged by Apify when a run starts: once for a run of up to 1 GB of memory, and once more for every extra GB. It covers the first five seconds of compute. | $0.00005 per run up to 1 GB of memory ($0.05 per 1,000) |
| `iban-validated` **(primary)** | IBAN validated | One IBAN checked (check digits, country format, bank and branch code), with bank name and BIC where a public bank list exists and suggested corrections when it is invalid. A duplicate in the same batch is checked and charged once. | $0.0005 per IBAN ($0.50 per 1,000) |

Validation runs offline in your Apify account, so there is no per-call cost from a third-party API behind this price: 1,000 IBANs cost $0.50, 100,000 cost $50. A supplier file of 2,500 IBANs costs $1.25, plus $0.00005 for the start event of a run with the default 1 GB of memory (five cents per thousand runs). The compute is on us: more memory only raises that start event ($0.00005 more for every GB above the first), never the price per IBAN.

You pay for IBANs that were validated, not for the run. A duplicate in the same batch is checked and charged once, empty lines are skipped for free, and IBANs above `maxIbansPerRun` or above what the run's memory holds are skipped and not charged. A run that stops before validating anything (an empty list, a line over 80 characters, a cancelled run) costs the start event alone, so a failed run costs a fraction of a cent. There is no external source that can be down: the registry and the bank lists are in the image, so a run either validates your list or fails on its own input.

### FAQ

#### The IBAN is valid but `bankName` is null. Is something wrong?

For Germany and Belgium, yes, probably: those lists are complete, so an unknown bank code comes with a warning. For the Netherlands the bundled list covers the major banks only. For every other country the Actor has no bank list and returns the bank code alone.

#### Can I get the BIC for French, Spanish or Italian IBANs?

Not from this Actor: no public, reusable bank list with BICs exists for those countries, and the Swift BIC Directory is licensed. In SEPA the BIC is no longer required for payments ("IBAN only" since 2016), so most systems can leave it empty.

#### Does a valid result mean I can pay this account?

No. It means the IBAN is well formed and, where a list exists, names a real bank. Existence, ownership and status of the account are only known to the bank; use Verification of Payee at your bank for that.

#### Is IBAN validation with this Actor GDPR-compliant?

An IBAN of a natural person is personal data. This Actor processes IBANs entirely inside the Apify run: no request goes to any external service, and the results exist nowhere outside your own run. The Actor keeps no state between runs: a later run knows nothing of an earlier batch. While a run delivers, its own key-value store holds the delivery plan with the results; the plan is deleted when the run ends. Only a run whose delivery failed keeps it in that run's store, so that resurrecting the run finishes delivery without charging twice. Delete the run's dataset, and such a failed run itself, when your GDPR retention rules require it. It is not affiliated with Swift, the Bundesbank, the National Bank of Belgium or any bank; it applies the public IBAN Registry and the public bank lists named above.

#### What are the limitations?

- Bank names and BICs are available for Germany, Belgium and the major Dutch banks only. Other countries return the bank and branch code as parsed from the IBAN, without a name or BIC.
- The IBAN Registry and the bank lists are bundled at build time (registry read on 15 September 2026; the list versions are in the table above). A country that starts issuing IBANs later is `country-unknown`, and a bank code registered after that date is unknown, until the next release of this Actor.
- National check digits inside the BBAN are not verified, so a valid result is one check (mod-97 plus the national format), not two independent ones.
- Suggestions only exist for an IBAN of the right length whose check digits or national format fail, at most three per IBAN, and they are leads for a human, not replacements.
- Up to 100,000 IBANs per run (20,000 unless you raise `maxIbansPerRun`); a run validates at most 20,000 below 1 GB of memory and 50,000 below 2 GB.

### Related Actors

- [VIES VAT Validator: the same bulk check for EU VAT numbers](https://apify.com/lwsdjfls/vies-vat-validator), live against VIES, with outage handling and consultation numbers.
- [EU Sanctions Screening: check who is behind the account](https://apify.com/lwsdjfls/eu-sanctions-screening) against the EU, UN and UK sanctions lists before you pay a new supplier.
- [Peppol Participant Lookup: whether a customer can receive e-invoices](https://apify.com/lwsdjfls/peppol-participant-monitor) over the Peppol network, by KvK, VAT, KBO, GLN or SIREN number.

### Support

Missing a bank list that may be reused, or a country? Open an issue on the Actor page.

# Changelog

This Actor's version history is a separate document: https://apify.com/lwsdjfls/iban-validator-enricher/changelog.md

# Actor input Schema

## `ibans` (type: `array`):

One IBAN per line, at least one; a line may be at most 80 characters (the longest IBAN anywhere is 33). Spaces, dashes, dots, lower case and an "IBAN" prefix are fine. A duplicate is checked and charged once, an empty line is skipped for free.

## `suggestCorrections` (type: `boolean`):

For an IBAN that fails, list the single-character fixes that would make it valid: a letter O read as a zero, I as 1, S as 5, two adjacent characters swapped, or corrected check digits.

## `maxIbansPerRun` (type: `integer`):

Caps the validated (and charged) IBANs in one run; anything beyond it is skipped, not charged and mentioned in the log. The default 1 GB of memory handles up to 50,000; above that, give the run 2 GB. A run with less memory than this value needs validates only what fits and says so in the log.

## Actor input object example

```json
{
  "ibans": [
    "NL91 ABNA 0417 1643 00",
    "DE89 3704 0044 0532 0130 00",
    "BE68 5390 0754 7034",
    "GB29 NWBK 6016 1331 9268 19",
    "FR14 2004 1010 0505 0001 3M02 606",
    "NL91 ABNA 0417 1643 0O",
    "DE89 3704 0044 0532 0310 00"
  ],
  "suggestCorrections": true,
  "maxIbansPerRun": 20000
}
```

# Actor output Schema

## `validation` (type: `string`):

Every IBAN with its result: valid or not, the reason and a sentence you can show a user, country, bank code, bank name, BIC, suggested corrections and warnings.

## `bank` (type: `string`):

The parts parsed out of each IBAN (bank code, branch code, account number) with the bank name, BIC and the bank list they came from. Invalid IBANs are in this view too, with these fields empty.

## `runSummary` (type: `string`):

How the run ended, how many IBANs were validated and delivered, and the events charged with their estimated cost.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "ibans": [
        "NL91 ABNA 0417 1643 00",
        "DE89 3704 0044 0532 0130 00",
        "BE68 5390 0754 7034",
        "GB29 NWBK 6016 1331 9268 19",
        "FR14 2004 1010 0505 0001 3M02 606",
        "NL91 ABNA 0417 1643 0O",
        "DE89 3704 0044 0532 0310 00"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("lwsdjfls/iban-validator-enricher").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "ibans": [
        "NL91 ABNA 0417 1643 00",
        "DE89 3704 0044 0532 0130 00",
        "BE68 5390 0754 7034",
        "GB29 NWBK 6016 1331 9268 19",
        "FR14 2004 1010 0505 0001 3M02 606",
        "NL91 ABNA 0417 1643 0O",
        "DE89 3704 0044 0532 0310 00",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("lwsdjfls/iban-validator-enricher").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "ibans": [
    "NL91 ABNA 0417 1643 00",
    "DE89 3704 0044 0532 0130 00",
    "BE68 5390 0754 7034",
    "GB29 NWBK 6016 1331 9268 19",
    "FR14 2004 1010 0505 0001 3M02 606",
    "NL91 ABNA 0417 1643 0O",
    "DE89 3704 0044 0532 0310 00"
  ]
}' |
apify call lwsdjfls/iban-validator-enricher --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,lwsdjfls/iban-validator-enricher"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/BDDPWOBG224s3MOIh/builds/UNzDDWqLk93aGqY6Y/openapi.json
