ibanchecker.cash
Developer ResourcesJune 3, 2026 · 7 min read

How to Validate IBANs in JavaScript (API & Manual)

Two approaches: call the ibanchecker.cash API for full bank data, or implement MOD-97 validation yourself. Includes working code for both.

Share

IBAN validation is a common requirement for any application that handles European or international payments. There are two main approaches: call a validation API (which returns bank name, BIC, and structured data), or implement the MOD-97 check yourself (fast, offline, no network dependency). This guide covers both.

Approach 1: Using the ibanchecker.cash API

The API approach is recommended when you need full bank data — name, BIC, branch, SEPA status — not just a pass/fail result. The API handles all 84 IBAN countries and returns a consistent JSON response.

Single IBAN Validation

const response = await fetch('https://ibanchecker.cash/api/v1/validate', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ iban: 'DE89370400440532013000' }),
});

const data = await response.json();

if (data.valid) {
  console.log(data.bank_name);   // "Deutsche Bank"
  console.log(data.bic);         // "DEUTDEDBXXX"
  console.log(data.country);     // "DE"
  console.log(data.transfer_type); // "SEPA+SWIFT"
} else {
  console.error(data.error);     // Human-readable error message
  console.error(data.error_code); // "INVALID_CHECK_DIGITS" etc.
}

Bulk Validation (up to 100 IBANs)

const response = await fetch('https://ibanchecker.cash/api/v1/validate/bulk', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    ibans: [
      'GB29NWBK60161331926819',
      'DE89370400440532013000',
      'FR7614508059952116425957022',
    ],
  }),
});

const { count, valid_count, invalid_count, results } = await response.json();
console.log(`${valid_count} valid, ${invalid_count} invalid out of ${count}`);

Response Structure

// Valid IBAN response
{
  "valid": true,
  "iban": "DE89370400440532013000",
  "formatted": "DE89 3704 0044 0532 0130 00",
  "check_digits": "89",
  "country": "DE",
  "country_name": "Germany",
  "bank_name": "Deutsche Bank",
  "bic": "DEUTDEDBXXX",
  "currency": "EUR",
  "transfer_type": "SEPA+SWIFT",
  "sepa": true
}

// Invalid IBAN response
{
  "valid": false,
  "iban": "DE89370400440532013001",
  "error": "Check digit verification failed.",
  "error_code": "INVALID_CHECK_DIGITS"
}

Rate Limits

The free tier allows 100 requests per hour per IP address. For production use at higher volumes, see the pricing page for API key tiers starting at 1,000 requests/month.

Approach 2: Client-Side MOD-97 Validation

If you only need format validation (no bank data), implementing MOD-97 in-browser or in Node.js is trivial and has zero latency. This is ideal for real-time input validation as a user types.

function validateIBAN(raw) {
  // Normalize
  const iban = raw.replace(/\s/g, '').toUpperCase();

  // Basic character check
  if (!/^[A-Z0-9]+$/.test(iban)) return { valid: false, error: 'Invalid characters' };
  if (iban.length < 15 || iban.length > 34) return { valid: false, error: 'Invalid length' };

  // MOD-97 check
  const rearranged = iban.slice(4) + iban.slice(0, 4);
  const numeric = rearranged.split('').map(c =>
    c >= 'A' ? String(c.charCodeAt(0) - 55) : c
  ).join('');

  let remainder = 0;
  for (let i = 0; i < numeric.length; i += 7) {
    remainder = parseInt(remainder + numeric.slice(i, i + 7), 10) % 97;
  }

  if (remainder !== 1) return { valid: false, error: 'Check digit mismatch' };
  return { valid: true, iban, formatted: iban.replace(/(.{4})/g, '$1 ').trim() };
}

// Usage
validateIBAN('GB29 NWBK 6016 1331 9268 19');
// { valid: true, iban: 'GB29NWBK60161331926819', formatted: 'GB29 NWBK 6016 1331 9268 19' }

React Hook Example

import { useState, useCallback } from 'react';

function useIBANValidation() {
  const [result, setResult] = useState(null);
  const [loading, setLoading] = useState(false);

  const validate = useCallback(async (iban) => {
    if (!iban.trim()) return;
    setLoading(true);
    try {
      const res = await fetch('/api/v1/validate', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ iban }),
      });
      setResult(await res.json());
    } finally {
      setLoading(false);
    }
  }, []);

  return { result, loading, validate };
}

Error Codes Reference

  • EMPTY — No IBAN provided
  • INVALID_CHARS — Contains characters other than letters and digits
  • INVALID_COUNTRY — First two characters aren't a recognized IBAN country code
  • INVALID_LENGTH — Wrong length for the given country
  • INVALID_CHECK_DIGITS — MOD-97 check failed (transcription error)

Best Practices

  • Strip spaces and uppercase before validation — users copy IBANs from bank statements in various formats.
  • Use client-side MOD-97 for real-time feedback as users type, then confirm with the API on form submission.
  • Cache API results for repeated validations of the same IBAN within a session.
  • Never store unvalidated IBANs — validate at the point of entry, before any payment processing.

Validate an IBAN instantly

Free IBAN checker — MOD-97 verification, bank lookup, and SEPA status across 84 countries.

Open IBAN Checker →

Related Articles