# Validate IBAN
Checks that an IBAN is well formed and returns its parts. For IBANs from Germany, Austria, Switzerland, Liechtenstein, Belgium and the Czech Republic, the response also contains the bank's name, BIC and town, as far as the national bank directory lists them.
A valid IBAN is not a verified account
A valid IBAN is well formed and has correct check digits. It does not prove that the account exists, is open, or who holds it. Every validation response repeats this in its notice field.
The validation is computed on our servers from the published IBAN formats and bank directories. No bank or other third party is contacted.
# Validate a single IBAN
Request Method: GET
Request URL: https://api.vatcheckapi.com/v2/iban?iban=[[ iban ]]
# Request Parameters
| Parameter | Type | Mandatory | Description |
|---|---|---|---|
apikey | string | ️ | Your API Key |
iban | string | ️ | The IBAN in electronic (DE89370400440532013000) or print format (DE89 3704 0044 0532 0130 00). Spaces and lower case are accepted. At most 64 characters of UTF-8 text |
# Sample Request
curl -G https://api.vatcheckapi.com/v2/iban \
-d iban=DE89370400440532013000 \
-H "apikey: YOUR-APIKEY"
To send the print format, let curl encode the spaces:
curl -G https://api.vatcheckapi.com/v2/iban \
--data-urlencode "iban=DE89 3704 0044 0532 0130 00" \
-H "apikey: YOUR-APIKEY"
# Sample Response
{
"iban": "DE89370400440532013000",
"iban_print_format": "DE89 3704 0044 0532 0130 00",
"valid": true,
"reason": null,
"checks": {
"length": true,
"structure": true,
"checksum": true,
"national_checksum": true
},
"country_code": "DE",
"sepa": true,
"bban": "370400440532013000",
"bank_code": "37040044",
"branch_code": null,
"account_number": "0532013000",
"bank": {
"name": "Commerzbank",
"bic": "COBADEFFXXX",
"city": "Köln",
"source": "Quelle: Deutsche Bundesbank"
},
"notice": "A valid IBAN is well formed and has correct check digits. It does not prove that the account exists, is open, or who holds it."
}
An IBAN that fails a check is not an error: the response is a 200 with valid: false, and reason names the first check that failed. Once the length and structure checks pass, the parts and the bank are returned even when the check digits are wrong, which helps to spot a typo:
{
"iban": "DE88370400440532013000",
"iban_print_format": "DE88 3704 0044 0532 0130 00",
"valid": false,
"reason": "invalid_checksum",
"checks": {
"length": true,
"structure": true,
"checksum": false,
"national_checksum": null
},
"country_code": "DE",
"sepa": true,
"bban": "370400440532013000",
"bank_code": "37040044",
"branch_code": null,
"account_number": "0532013000",
"bank": {
"name": "Commerzbank",
"bic": "COBADEFFXXX",
"city": "Köln",
"source": "Quelle: Deutsche Bundesbank"
},
"notice": "A valid IBAN is well formed and has correct check digits. It does not prove that the account exists, is open, or who holds it."
}
# Validate up to 100 IBANs
Request Method: POST
Request URL: https://api.vatcheckapi.com/v2/iban/batch
Runs the same checks and bank lookup as the single request for up to 100 IBANs.
# Request Body
| Field | Type | Mandatory | Description |
|---|---|---|---|
ibans | array of strings | ️ | Up to 100 IBANs in electronic or print format, each at most 64 characters of UTF-8 text. One comma-separated string is accepted too |
- The IBANs are normalised (spaces removed, upper case) and duplicates are removed before the limit of 100 is checked. The list may hold up to 1,000 entries before that.
- The result is an object keyed by the normalised IBAN, in the order in which each IBAN first appears. The
noticeis sent once for the whole batch. - The IBANs are read from the request body only: a JSON body as below, or a form-encoded one. An
ibansparameter in the query string is refused with a422. - The batch is checked against your remaining quota before it runs. If its cost would use up the remaining quota, it is refused with a
429and nothing is processed or billed.quota.requiredholds the batch's cost, anderror.codenames the quota that runs short:quota_exceeded(monthly quota),grace_quota_exceeded(grace quota after a failed payment) oroverage_quota_exceeded(overage budget). - If your plan does not include batch requests, the endpoint answers
403with the codeplan_upgrade_required.
# Sample Request
curl https://api.vatcheckapi.com/v2/iban/batch \
-H "apikey: YOUR-APIKEY" \
-H "Content-Type: application/json" \
-d '{"ibans": ["DE89 3704 0044 0532 0130 00", "DE88370400440532013000", "de89370400440532013000"]}'
# Sample Response
The first and third IBAN are the same once normalised, so the batch has two results and costs 2 requests (X-Cost: 2).
{
"data": {
"DE89370400440532013000": {
"iban": "DE89370400440532013000",
"iban_print_format": "DE89 3704 0044 0532 0130 00",
"valid": true,
"reason": null,
"checks": {
"length": true,
"structure": true,
"checksum": true,
"national_checksum": true
},
"country_code": "DE",
"sepa": true,
"bban": "370400440532013000",
"bank_code": "37040044",
"branch_code": null,
"account_number": "0532013000",
"bank": {
"name": "Commerzbank",
"bic": "COBADEFFXXX",
"city": "Köln",
"source": "Quelle: Deutsche Bundesbank"
}
},
"DE88370400440532013000": {
"iban": "DE88370400440532013000",
"iban_print_format": "DE88 3704 0044 0532 0130 00",
"valid": false,
"reason": "invalid_checksum",
"checks": {
"length": true,
"structure": true,
"checksum": false,
"national_checksum": null
},
"country_code": "DE",
"sepa": true,
"bban": "370400440532013000",
"bank_code": "37040044",
"branch_code": null,
"account_number": "0532013000",
"bank": {
"name": "Commerzbank",
"bic": "COBADEFFXXX",
"city": "Köln",
"source": "Quelle: Deutsche Bundesbank"
}
}
},
"notice": "A valid IBAN is well formed and has correct check digits. It does not prove that the account exists, is open, or who holds it."
}
# Response Fields
| Field | Type | Description |
|---|---|---|
iban | string | The IBAN in electronic format: all whitespace removed, upper case |
iban_print_format | string / null | Groups of four characters. null when reason is invalid_characters |
valid | boolean | true when every check passed. A national_checksum of null does not make an IBAN invalid |
reason | string / null | The first check that failed, see Check order. null when the IBAN is valid |
checks.length | boolean | The IBAN has the length of its country |
checks.structure | boolean | The check digits are digits and the BBAN matches the country's structure |
checks.checksum | boolean | The ISO 7064 MOD 97-10 check digits are correct |
checks.national_checksum | boolean / null | The country's own check digits inside the BBAN, see National check digits |
country_code | string / null | The first two characters when they are letters, otherwise null. Also null when the IBAN has characters other than A-Z and 0-9 |
sepa | boolean / null | The country takes part in SEPA, according to the IBAN Registry. null when the country is not in the registry or the IBAN has invalid characters |
bban | string / null | The Basic Bank Account Number: the IBAN without country code and check digits |
bank_code | string / null | The bank identifier as the IBAN Registry defines it for the country (in Germany the Bankleitzahl) |
branch_code | string / null | The branch identifier, for countries where the IBAN Registry defines one (for example ES, IT and GB) |
account_number | string / null | The BBAN without the bank and branch identifiers. In some countries it also holds national check digits: in ES9121000418450200051332, for example, it is 450200051332, the control digits 45 followed by the account number. In IT and SM it starts with the CIN check character, which comes before the bank code in the BBAN: IT60X0542811101000000123456 gives X000000123456 |
bank | object / null | The bank from the national directory, see Bank data. null for other countries, for bank codes that are not in the directory, and when the length or structure check failed |
bank.name | string | The bank's name as the directory lists it |
bank.bic | string / null | The BIC as the directory lists it, null when it lists none |
bank.city | string / null | The town as the directory lists it. null for BE and CZ, whose directories list no town |
bank.source | string | The source, worded as the directory's terms of use require |
notice | string | A valid IBAN does not prove that the account exists or who holds it. Top level of the response, once per batch |
bban, bank_code, branch_code and account_number are set once the length and structure checks pass, also when the check digits are wrong. Before that they are null.
# Check Order
The checks run in this order and stop at the first failure. reason names that failure; the checks after it are not run and report false, and national_checksum reports null.
| # | Check | reason when it fails |
|---|---|---|
| 1 | Characters: once spaces are removed, only A-Z and 0-9 | invalid_characters |
| 2 | Country: the first two characters are a country of the IBAN Registry (89 countries) | unsupported_country |
| 3 | Length: the length of the country's IBAN. A partly typed IBAN such as DE89 fails here | invalid_length |
| 4 | Structure: the check digits are digits and the BBAN matches the country's structure (which positions are digits, letters or either) | invalid_structure |
| 5 | Check digits: ISO 7064 MOD 97-10 over the whole IBAN. The check digits 00, 01 and 99 are never valid | invalid_checksum |
| 6 | National check digits, where a public algorithm is applied, see below | invalid_national_checksum |
# National Check Digits
Many countries put check digits of their own into the domestic account number. Where a public algorithm exists, the API checks them too, so it catches typos that the MOD 97-10 check digits miss.
| Country | Algorithm |
|---|---|
| DE | The check digit method that the Deutsche Bundesbank's bank code directory assigns to the bank code (Prüfzifferberechnungsmethode) |
| BE | The last two digits: the first ten digits modulo 97 |
| CZ, SK | Modulo 11 over the account prefix and over the account number |
| EE | Weights 7, 3, 1 over the domestic account number |
| ES | The two control digits of the bank account code (CCC) |
| FI | Luhn over the account number in machine format |
| FR, MC | The RIB key |
| HR | ISO 7064 MOD 11,10 over the bank code and over the account number |
| HU | Weights 9, 7, 3, 1 over the bank block and the account block |
| IT, SM | The CIN check character |
| NO | Modulo 11 with weights 5, 4, 3, 2, 7, 6, 5, 4, 3, 2 |
| PL | The check digit of the bank's settlement number |
| PT | The NIB check digits |
| BA, ME, MK, RS, SI, TL, XK | ISO 7064 MOD 97-10 over the BBAN |
national_checksum is null when:
- no algorithm is applied for the country, for example AT, CH, LI, GB or NL (Dutch account numbers have not followed the old Dutch check since the IBAN migration, so it is not applied);
- the account has no check digit to verify (for example German bank codes whose method does not use one);
- a German IBAN's bank code is not in the Bundesbank directory;
- an earlier check failed.
# Bank Data
The bank object comes from the bank code directories that the national central banks and, for Switzerland and Liechtenstein, SIX publish. We check every directory daily for a new edition and import it when it has changed. Names, BICs and towns are passed on as the directory publishes them: we only remove padding and the spaces in printed BICs, and treat placeholders such as N/A as no BIC. For Belgium the English name is used where the directory has one.
| IBAN country | Directory | Published | bank.source |
|---|---|---|---|
| DE | Bankleitzahlendatei, Deutsche Bundesbank | Quarterly | Quelle: Deutsche Bundesbank |
| AT | SEPA-Zahlungsverkehrsverzeichnis, Oesterreichische Nationalbank (OeNB) | Daily | Source: Oesterreichische Nationalbank (OeNB), SEPA-Zahlungsverkehrsverzeichnis (excerpt), © OeNB, licensed under CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/), provided without warranty |
| CH, LI | Bank Master, SIX Interbank Clearing | Daily | Source: SIX Interbank Clearing Ltd, Bank Master. BIC are the property of SWIFT SCRL, 1310 La Hulpe, Belgium. |
| BE | Bank identification codes, National Bank of Belgium (NBB) | When a code changes | Source: National Bank of Belgium (NBB). This information is also available free of charge at https://www.nbb.be/en/payments-and-securities/bank-identification-codes |
| CZ | Číselník kódů platebního styku, Česká národní banka (ČNB) | When the list changes | Zdroj: ČNB |
bank.source carries the wording each directory's terms of use ask for. These terms require the source to be named when the data is passed on, so keep bank.source with the bank data if you show or forward it.
The Belgian bank identification codes are also available free of charge on the National Bank of Belgium's website (opens new window).
For IBANs from other countries bank is null. Swiss and Liechtenstein IBANs share the SIX directory, because banks in both countries are identified by the same institution identification numbers (IIDs).
# IBAN Formats
IBAN formats derived from the SWIFT IBAN Registry (ISO 13616), Release 103, September 2026. The API supports the 89 countries of this release:
AD, AE, AL, AT, AZ, BA, BE, BG, BH, BI, BR, BY, CH, CR, CY, CZ, DE, DJ, DK, DO, EE, EG, ES, FI, FK, FO, FR, GB, GE, GI, GL, GR, GT, HN, HR, HU, IE, IL, IQ, IS, IT, JO, KW, KZ, LB, LC, LI, LT, LU, LV, LY, MC, MD, ME, MK, MN, MR, MT, MU, NI, NL, NO, OM, PK, PL, PS, PT, QA, RO, RS, RU, SA, SC, SD, SE, SI, SK, SM, SO, ST, SV, TL, TN, TR, UA, VA, VG, XK, YE
SWIFT publishes new releases of the registry several times a year. Each release is reviewed before the API's formats are updated from it, so for a short time after a new release the API can still use the previous one.
# Cost
- Each IBAN costs 1 request, whether it is valid or not. An IBAN that fails validation is a successful call (
200withvalid: false). - A batch costs 1 request per unique IBAN.
- Error responses (
4xxand5xx) cost nothing. The request that uses the last unit of your quota is served; the next one gets a429. - The
X-Costresponse header states what a call cost. - On the free plan, the minute rate limit counts each unique IBAN of a batch as one request.
# Sandbox API Keys
With a sandbox API key (opens new window) the checks run exactly as with a live key, and every call costs nothing (X-Cost: 0). The bank object is a placeholder instead of the directory record, for every IBAN from a country with a bank directory that passes the length and structure checks:
"bank": {
"name": "Sandbox Bank",
"bic": "XXXXDEXXXXX",
"city": "Sandbox City",
"source": "Placeholder for sandbox keys; live keys get the bank from the national bank directory"
}
The placeholder BIC contains the IBAN's country code (XXXXDEXXXXX for a German IBAN). For other countries bank is null, as with a live key.
# Privacy
The single request carries the IBAN in the URL. To validate several IBANs, use the batch request: it takes the IBANs in the request body only. Send your API key in the apikey header rather than the query string.
# Not Covered
- Whether an account exists, is open, or who holds it (no account holder or payee verification).
- Calculating an IBAN from a domestic account number.
- Account numbers that are not IBANs, such as US routing numbers or UK sort codes on their own.