Validate IBAN format, country length, and checksum
An International Bank Account Number can look convincing while containing the wrong number of characters or a mistyped check digit.
Run — free
This validator normalizes ordinary spaces and hyphens, identifies the country code, checks the official length assigned to that country, and applies the ISO 7064 mod-97 checksum rule. It returns each decision separately, making the result useful both for a person checking one account number and for software deciding whether a payment record is ready for the next stage.
Start with a clean, recognizable IBAN
Paste or send the complete IBAN, including its two-letter country code and two check digits. Spaces used to group characters for readability are accepted, as are hyphens, and the validator removes them before checking the value. Lowercase letters are converted to uppercase in the normalized result. No other punctuation is silently discarded because doing so could hide a copy-and-paste mistake. A structurally usable value must begin with two letters followed by two digits, and every remaining character must be a letter or digit. The response includes the normalized IBAN so an integration can store or compare a consistent representation. It also exposes the country code, actual length, and expected length instead of returning only a vague yes-or-no answer. If the country prefix is not in the supported IBAN registry, the request produces an input error. That distinction matters: an unknown scheme cannot be evaluated reliably and should not be treated as merely a failed checksum. This first stage catches formatting problems before any arithmetic is attempted.
Understand the country-length and mod-97 checks
IBANs do not all have one universal character count. Each participating country defines a fixed length, so a German IBAN has a different expected size from a Norwegian or Maltese IBAN. The validator looks up the length associated with the leading country code and compares it with the normalized value. It then performs the checksum procedure defined for IBAN under ISO 7064: the first four characters move to the end, letters are expanded to their numeric values from A equals 10 through Z equals 35, and the resulting decimal sequence is evaluated modulo 97. A valid checksum leaves a remainder of one. The implementation calculates the remainder incrementally, digit by digit, rather than constructing an enormous integer that could exceed a language's safe numeric range. The response reports `length_valid` and `checksum_valid` independently, then sets `valid` only when both checks pass. A wrong length prevents a checksum pass, keeping the final decision conservative and easy for automated workflows to interpret.
Use validation at the right point in a payment workflow
Run this check when an IBAN enters your system: during form submission, CSV import, beneficiary onboarding, or a final review before a payment instruction is created. A failed result is evidence of a formatting, length, or checksum problem, so it is useful for catching common transcription errors early. It is not proof that the bank account exists, is open, belongs to the named recipient, or can receive a particular transfer. Those questions require bank or payment-provider services and may involve regulated identity checks. Keep the validator's role narrow: reject obviously malformed identifiers, show the specific failed checks, and ask the user to confirm the number from a trustworthy source. The algorithm is deterministic and uses no network, random value, clock, or external lookup during execution, which makes repeated calls reproducible. One API request costs $0.002, while the page can run the same pure validation logic in the browser. Avoid logging full account numbers unless your security and retention policies explicitly require it; validation does not remove the need to protect financial identifiers.
What you can do with it
Validate a beneficiary form
Catch an incorrect country length or check digit before a beneficiary record is submitted.
Screen imported payment data
Normalize and validate IBAN fields from a batch while preserving exact reasons for rejection.
Review an account number
Check a manually copied IBAN before it moves into a payment approval workflow.
FAQ
What does one API validation cost?
Each request costs $0.002. The browser tool can run the same deterministic check locally.
Does a valid result prove the account exists?
No. It confirms the registered country length and checksum only; it does not contact a bank or verify ownership.
Are spaces and hyphens allowed?
Yes. They are removed before validation, and lowercase letters are normalized to uppercase.
Why is an unknown country code an error?
Without a recognized country definition, the required IBAN length cannot be established reliably.
How is the checksum calculated safely?
The rearranged alphanumeric value is expanded and reduced modulo 97 incrementally, avoiding oversized integers.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/data/iban-validate \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"iban":"DE89 3704 0044 0532 0130 00"}'const res = await fetch("https://api.kit.forhosting.com/data/iban-validate", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"iban": "DE89 3704 0044 0532 0130 00"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/data/iban-validate",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"iban": "DE89 3704 0044 0532 0130 00"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/data/iban-validate", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"iban":"DE89 3704 0044 0532 0130 00"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"iban":"DE89 3704 0044 0532 0130 00"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/data/iban-validate", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"iban": "DE89 3704 0044 0532 0130 00"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "data.iban_validate",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_mb | 25 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |