Check an IBAN as someone types

Add IBAN structure and checksum validation to an HTML field, then check the submitted value on your server.

JavaScript (browser)Last tested Download and run ↓
On this page

Working example

HTML + form.js

Run the example

Download HTML

validate-iban-javascript.html

Replace YOUR_PUBLIC_API_KEY in the downloaded file with your public key. Add localhost to that key's allowed domains. In a terminal in the download folder, run:

Terminal · Python 3
python3 -m http.server 8000

Open localhost:8000/validate-iban-javascript.html. When publishing, add your website's hostname to the key. Keep secret keys on your server.

Need a key? Set up this example

Mark your IBAN field

Add IBAN validation to your existing form with form.js and data-parse="iban". Use a text input: an IBAN contains letters and can include leading zeroes.

HTML
<script src="https://cdn.parseapi.com/v1/form.js" data-key="YOUR_PUBLIC_API_KEY" data-parse-version="2.0.0" defer></script>
<div class="field">
  <label for="iban">IBAN</label>
  <input id="iban" name="iban" data-parse="iban" autocomplete="off" autocapitalize="characters" spellcheck="false" placeholder="DE89 3704 0044 0532 0130 00">
</div>
<div class="field">
  <label for="bank-name">Bank name, when known</label>
  <input id="bank-name" data-parse-from="iban" data-parse-fill="bank_name" readonly>
</div>
<div class="field">
  <label for="bank-bic">BIC, when known</label>
  <input id="bank-bic" data-parse-from="iban" data-parse-fill="bic" readonly>
</div>

The person can paste spaces or hyphens, or type lowercase ASCII letters. Other punctuation and Unicode lookalikes receive an input error. The script checks after a typing pause and sends the input in the body of POST /bank, never in the lookup URL. Keep account input and returned data out of your own analytics and logs. The API checks the number's country-specific length, structure, and checksum, and the script shows feedback beside the field.

Check the number

Try DE89 3704 0044 0532 0130 00. Change its last digit to 1 to see a checksum failure. The preset shows the first correction from issues and reads the API's valid answer; a successful HTTP request alone does not mean the number passed.

Editing the IBAN clears the old verdict. A failed request leaves the field unchecked. Submission remains your form's job, and the script never waits for a pending lookup before allowing it.

Need the bank name in an existing field? Add data-parse-from="iban" data-parse-fill="bank_name" to that field. Unknown bank details stay blank.

Use data-parse-country="DE" only when the country prefix is missing; the input must still include its two numeric check digits. After changing that attribute, call parseform.scan() to refresh the result.

Build directly with the Bank API for the full response and a custom integration.

Add diagnostic fields when needed

The parse event includes answer.checks and answer.issues. Checks report passed, failed, not_checked, or not_supported. A national check marked not_supported does not invalidate the IBAN. Bind an existing output with data-parse-from="iban" data-parse-fill="issues.0.message" to show the first issue, or data-parse-fill="checks.checksum" to show its checksum state. Diagnostic bindings work for invalid results too.

Handle the result on your server

Check the submitted IBAN on your server before relying on it. The browser field can be edited or bypassed. This excerpt belongs inside your server handler: input is the submitted IBAN and PARSE_API_KEY is your secret environment key. It returns the normalized account details or a field error:

javascript
const response = await fetch('https://api.parseapi.com/bank', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': process.env.PARSE_API_KEY,
    'Parse-Version': '2.0.0',
  },
  body: JSON.stringify({ iban: input }),
});
if (!response.ok) throw new Error('Bank check unavailable; retry later.');
const answer = await response.json();
if (!answer.valid) {
  // Render as text beside the relevant input. Keep future issue codes supported.
  return { error: answer.issues[0]?.message ?? 'Check the IBAN.' };
}
return { iban: answer.iban, bank: answer.bank_name, bic: answer.bic };

A null bank name or BIC is not an invalid-account verdict. Keep it null or leave its optional field blank. This check does not establish account existence, ownership or payment eligibility. POST keeps account input out of the request URL; it does not prevent body or response logging elsewhere in your application.

Complete example

One HTML file with your fields, styles, and the form.js include. Replace YOUR_PUBLIC_API_KEY with your public key, then run it on a domain you have added to that key.

View and copy the complete source
validate-iban-javascript.html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Check an IBAN as someone types</title>
  <style>
    :root { color-scheme: light dark; --bg: #fff; --ink: #152029; --muted: #5e6b75; --line: #d9e2e7; --field: #f6f9fa; --accent: #007c91; --error: #b42335; }
    @media (prefers-color-scheme: dark) {
      :root:not([data-theme="light"]) { --bg: #0b1015; --ink: #eff7fa; --muted: #94a6b2; --line: #2c3942; --field: #121b23; --accent: #67e8f9; --error: #fda4af; }
    }
    :root[data-theme="dark"] { color-scheme: dark; --bg: #0b1015; --ink: #eff7fa; --muted: #94a6b2; --line: #2c3942; --field: #121b23; --accent: #67e8f9; --error: #fda4af; }
    :root[data-theme="light"] { color-scheme: light; }
    * { box-sizing: border-box; }
    [hidden] { display: none !important; }
    body { margin: 0; padding: 24px; background: var(--bg); color: var(--ink); font: 15px/1.5 system-ui, sans-serif; }
    main { max-width: 540px; margin: 0 auto; }
    label { display: block; margin-bottom: 8px; font-size: 14px; font-weight: 600; }
    input { display: block; width: 100%; min-width: 0; padding: 13px 14px; border: 1px solid var(--line); border-radius: 8px; background: var(--field); color: var(--ink); font: inherit; }
    input::placeholder { color: var(--muted); }
    :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
    /* Your form owns these styles. form.js adds semantic markup and states. */
    input[data-parse-status="invalid"], input[data-parse-status="disposable"] { border-color: var(--error); }
    .parse-hint { margin: 6px 0 0; color: var(--muted); font-size: .875em; line-height: 1.4; overflow-wrap: anywhere; }
    .parse-hint[data-parse-status="invalid"], .parse-hint[data-parse-status="disposable"] { color: var(--error); }
    @media (max-width: 380px) { body { padding: 18px; } }
  </style>
</head>
<body>
  <main>
    <!-- example:form -->
    <script src="https://cdn.parseapi.com/v1/form.js" data-key="YOUR_PUBLIC_API_KEY" data-parse-version="2.0.0" defer></script>
    <div class="field">
      <label for="iban">IBAN</label>
      <input id="iban" name="iban" data-parse="iban" autocomplete="off" autocapitalize="characters" spellcheck="false" placeholder="DE89 3704 0044 0532 0130 00">
    </div>
    <div class="field">
      <label for="bank-name">Bank name, when known</label>
      <input id="bank-name" data-parse-from="iban" data-parse-fill="bank_name" readonly>
    </div>
    <div class="field">
      <label for="bank-bic">BIC, when known</label>
      <input id="bank-bic" data-parse-from="iban" data-parse-fill="bic" readonly>
    </div>
    <!-- /example:form -->
  </main>
</body>
</html>

Need a key? Set up this browser example. For every field and parameter, see Bank API reference.