IBANforge · Schema

IBANValidationResult

FinanceBankingComplianceMCPA2A

Properties

Name Type Description
trial object Present ONLY on a call served by the keyless weekly trial: POST /v1/iban/validate with a real `iban` and no API key is served 25 times a week per source address (IPv6 counted per /64; ISO week in UTC,
attribution object Free tier only. When these results are shown to people, display `text` with a link to `url`; backend-only use owes nothing. Absent on paid plans and on x402 calls.
iban string The IBAN as provided (normalized)
valid boolean ISO 13616 only: structure and mod-97. It says nothing about the bank: read bank_code_holder and checks before a payment.
bank_code_holder string Who holds the bank code. confirmed: a register that publishes holders names the holder of this code (a national register that settles the code space, or a partial register on a hit). inferred: we name
checks object One status per check: pass (checked against a source that settles it), fail (checked, and wrong), inferred (answered from a source that does not settle it), unknown (attempted, no conclusion), not_che
national_check_digits object The check key a country keeps inside the BBAN, recomputed from the IBAN alone. Present only on a valid IBAN of FR, MC, BE, IT, SM or ES (GB has modulus_check instead); absent elsewhere, where checks.n
country object
check_digits string
bban object
bic objectnull
formatted string IBAN formatted in groups of 4
clearing objectnull Swiss clearing enrichment from the SIX BankMaster directory — present for CH and LI IBANs only, and included at no extra cost in the 0.005 USDC validation. Full rail participation, not just a name loo
error string Present ONLY when `valid` is false, on an HTTP 200: an invalid IBAN is not an HTTP error. Absent on every successful validation.
error_detail string Present ONLY when `error` is, and explains it in one sentence (e.g. "Modulo 97 check returned 28, expected 1.").
reference_check object Present ONLY when the request carried a `reference` field.
cost_usdc number
processing_ms number
sepa object SEPA compliance details. Only present when the IBAN is valid and the country participates in SEPA.
issuer object Issuer classification for the institution behind the IBAN. Useful for vIBAN detection and KYC enrichment. Present when the IBAN is valid and either the BIC resolved or an official register names the h
psd_registration object The EBA's PSD2 register of payment and electronic money institutions naming the holder of this bank code. Joined on country + national reference code, and served ONLY for countries where that code was
risk_indicators object AML/CFT risk indicators derived from the IBAN structure, issuer type, and country. Designed for compliance pre-screening and fraud prevention workflows. Only present when the IBAN is valid.
bank_code_check object Separate verdict on the BBAN bank code. `valid` answers ISO 13616 (structure + mod-97) and says nothing about whether the bank code identifies an institution; this field answers that, and states how m
official_identity object Present ONLY when a central bank publishes the holder of the code we resolved: reached by LEI on any BIC lookup, and by the national bank code for FR and ES. Absent rather than negative on a miss, and
modulus_check object UK modulus check on the sorting code and account number a GB IBAN carries — present for GB only, and included at no extra cost in the 0.005 USDC validation. A second checksum, independent of mod-97: t
next_steps array Ordered advice derived from THIS result: what blocks a payment first, what merely enriches it after. Branch on `code`, never on the prose. Absent or empty for an IBAN that failed validation, since the
View JSON Schema on GitHub

JSON Schema

ibanforge-ibanvalidation-result-schema.json Raw ↑
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://raw.githubusercontent.com/api-evangelist/ibanforge/main/json-schema/ibanforge-ibanvalidation-result-schema.json",
  "title": "IBANValidationResult",
  "x-generated": "2026-09-25",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/ibanforge-compliance-api-openapi.yml#/components/schemas/IBANValidationResult",
  "type": "object",
  "required": [
    "iban",
    "valid",
    "cost_usdc"
  ],
  "properties": {
    "trial": {
      "type": "object",
      "description": "Present ONLY on a call served by the keyless weekly trial: POST /v1/iban/validate with a real `iban` and no API key is served 25 times a week per source address (IPv6 counted per /64; ISO week in UTC, reset on Monday 00:00 UTC), with no payment. Says how many calls are left this week, when the count resets, and how to take a free key. Absent with a key, with an x402 payment, and on every other endpoint. Until 24 September 2026 the trial was daily and this block carried `calls_used_today`, `calls_left_today` and `daily_limit`; they were replaced, not kept, because they would have carried weekly counts under daily names.",
      "required": [
        "calls_used_this_week",
        "calls_left_this_week",
        "weekly_limit",
        "resets",
        "resets_at",
        "free_key",
        "docs"
      ],
      "properties": {
        "calls_used_this_week": {
          "type": "integer"
        },
        "calls_left_this_week": {
          "type": "integer"
        },
        "weekly_limit": {
          "type": "integer"
        },
        "resets": {
          "type": "string"
        },
        "resets_at": {
          "type": "string",
          "format": "date-time",
          "description": "Next Monday 00:00:00 UTC: the instant the weekly count goes back to zero."
        },
        "free_key": {
          "type": "string",
          "description": "The request that ends the trial in your favour: a key that needs no email address, on every endpoint, 200 requests a month once claimed (25 a month before that)."
        },
        "docs": {
          "type": "string",
          "format": "uri"
        }
      }
    },
    "attribution": {
      "type": "object",
      "description": "Free tier only. When these results are shown to people, display `text` with a link to `url`; backend-only use owes nothing. Absent on paid plans and on x402 calls.",
      "required": [
        "required",
        "text",
        "url",
        "note"
      ],
      "properties": {
        "required": {
          "type": "boolean",
          "enum": [
            true
          ]
        },
        "text": {
          "type": "string"
        },
        "url": {
          "type": "string",
          "format": "uri"
        },
        "note": {
          "type": "string"
        }
      }
    },
    "iban": {
      "type": "string",
      "description": "The IBAN as provided (normalized)"
    },
    "valid": {
      "type": "boolean",
      "description": "ISO 13616 only: structure and mod-97. It says nothing about the bank: read bank_code_holder and checks before a payment."
    },
    "bank_code_holder": {
      "type": "string",
      "enum": [
        "confirmed",
        "inferred",
        "not_allocated",
        "unknown"
      ],
      "description": "Who holds the bank code. confirmed: a register that publishes holders names the holder of this code (a national register that settles the code space, or a partial register on a hit). inferred: we name a holder from a source that cannot settle it (our composite map, the prefix fallback, a published structural rule), so read it as our inference. not_allocated: the national register says nobody holds this code, so do not send. unknown: no conclusion. valid stays true in all four: it only means the IBAN is well formed. bank_code_check.status verified means resolved; this field says whether a source settles it. Present ONLY when valid is true and the bank code was read from the BBAN."
    },
    "checks": {
      "type": "object",
      "description": "One status per check: pass (checked against a source that settles it), fail (checked, and wrong), inferred (answered from a source that does not settle it), unknown (attempted, no conclusion), not_checked (IBANforge does not make this check here), not_applicable (the check has no object for this IBAN). payee_name: never checked here; the name check is made by the payee's bank through Verification of Payee (VoP), and sepa.vop_register_status says whether that bank answers VoP requests. account_exists: never checked here; only the payee's bank knows whether the account is open. payee_sanctions: never checked; the sanctions screen of POST /v1/iban/compliance is made on the payee's bank (BIC8) and country only. institution_sanctions and country_sanctions are filled by POST /v1/iban/compliance and not_checked on a validation. national_check_digits: the check key a country keeps inside the BBAN, a second check independent of mod-97. Checked for FR and MC (RIB key), BE (the last two digits, modulo 97), IT and SM (CIN) and ES (DC), with the proof in the national_check_digits block, and for GB (Vocalink modulus), with the proof in modulus_check; not_checked elsewhere (the German account-number methods are not checked yet). pass means the account number is well formed, never that the account exists; fail means it cannot have been issued as written, and valid stays true. A key may be added later; a key is never removed. Present only when valid is true.",
      "required": [
        "iban_structure",
        "iban_checksum",
        "bank_code",
        "bic",
        "sepa_reachability",
        "national_check_digits",
        "account_exists",
        "payee_name",
        "institution_sanctions",
        "country_sanctions",
        "payee_sanctions"
      ],
      "properties": {
        "iban_structure": {
          "type": "string",
          "enum": [
            "pass"
          ]
        },
        "iban_checksum": {
          "type": "string",
          "enum": [
            "pass"
          ]
        },
        "bank_code": {
          "type": "string",
          "enum": [
            "pass",
            "fail",
            "inferred",
            "unknown"
          ]
        },
        "bic": {
          "type": "string",
          "enum": [
            "pass",
            "inferred",
            "unknown",
            "not_applicable"
          ]
        },
        "sepa_reachability": {
          "type": "string",
          "enum": [
            "pass",
            "fail",
            "unknown",
            "not_applicable"
          ]
        },
        "national_check_digits": {
          "type": "string",
          "enum": [
            "pass",
            "fail",
            "not_applicable",
            "not_checked"
          ]
        },
        "account_exists": {
          "type": "string",
          "enum": [
            "not_checked"
          ]
        },
        "payee_name": {
          "type": "string",
          "enum": [
            "not_checked"
          ]
        },
        "institution_sanctions": {
          "type": "string",
          "enum": [
            "not_checked",
            "pass",
            "fail",
            "unknown"
          ]
        },
        "country_sanctions": {
          "type": "string",
          "enum": [
            "not_checked",
            "pass",
            "fail",
            "unknown"
          ]
        },
        "payee_sanctions": {
          "type": "string",
          "enum": [
            "not_checked"
          ]
        }
      }
    },
    "national_check_digits": {
      "type": "object",
      "description": "The check key a country keeps inside the BBAN, recomputed from the IBAN alone. Present only on a valid IBAN of FR, MC, BE, IT, SM or ES (GB has modulus_check instead); absent elsewhere, where checks.national_check_digits is not_checked. country is the IBAN country. scheme names the algorithm: fr_rib_key (FR and MC: the RIB key, the last two digits of the BBAN, over the bank code, branch code and account number), be_mod97 (BE: the last two digits, the first ten digits modulo 97, or 97 when the remainder is 0), it_cin (IT and SM: the CIN, the control letter at the start of the BBAN, over the ABI, CAB and account number), es_dc (ES: the two DC digits, positions 9 and 10 of the BBAN). status: pass (the key matches, so the account number is well formed; it does not prove the account exists or is open) or fail (the key does not match: this account number cannot have been issued as written, a typo or a made-up number). A fail never makes valid false, because the IBAN check digits are right: read the two separately, and confirm the details with the beneficiary before paying. not_applicable is reserved for a BBAN without the national layout, which a valid IBAN never has. detail, present on fail and not_applicable only, says which digits disagree; it never gives the expected key. checks.national_check_digits repeats status.",
      "required": [
        "country",
        "scheme",
        "status"
      ],
      "properties": {
        "country": {
          "type": "string",
          "description": "The IBAN country: MC stays MC, SM stays SM. Today: FR, MC, BE, IT, SM, ES."
        },
        "scheme": {
          "type": "string",
          "description": "The algorithm applied, a stable snake_case name. Today: fr_rib_key, be_mod97, it_cin, es_dc."
        },
        "status": {
          "type": "string",
          "enum": [
            "pass",
            "fail",
            "not_applicable"
          ]
        },
        "detail": {
          "type": "string",
          "description": "Present on fail and not_applicable only: one sentence saying which digits disagree. It never gives the expected key."
        }
      }
    },
    "country": {
      "type": "object",
      "properties": {
        "code": {
          "type": "string"
        },
        "name": {
          "type": "string"
        }
      },
      "required": [
        "code",
        "name"
      ]
    },
    "check_digits": {
      "type": "string"
    },
    "bban": {
      "type": "object",
      "properties": {
        "bank_code": {
          "type": "string"
        },
        "branch_code": {
          "type": "string"
        },
        "account_number": {
          "type": "string"
        }
      },
      "required": [
        "bank_code",
        "account_number"
      ]
    },
    "bic": {
      "type": [
        "object",
        "null"
      ],
      "properties": {
        "code": {
          "type": "string",
          "description": "The BIC as the consulted source publishes it: 8 or 11 characters. Do NOT compare a supplied BIC against this field — compare on bic8 and read the branch code separately."
        },
        "bic8": {
          "type": "string",
          "description": "The eight characters of the institution, and the field to compare a supplied BIC against. The branch code (the last three characters of `code`) is informational: in a cooperative network it names the LOCAL bank while the first eight name its clearing institution, so an equality test on the full code turns a correct BIC into a mismatch."
        },
        "redirected_from": {
          "type": "string",
          "description": "The bank code you asked about, when the register answered for the one that took over its clearing. CH and LI only today: SIX marks an IID concatenated and publishes its successor. The IBAN stays valid and the account payable — a redirect is not a retirement."
        },
        "bank_name": {
          "type": [
            "string",
            "null"
          ],
          "description": "Null, never an empty string, when no source names the institution."
        },
        "city": {
          "type": [
            "string",
            "null"
          ],
          "description": "Where the consulted register places THIS bank code. May differ from address.city, which is the legal seat — both true, different questions. Null, never an empty string, when the source leaves the town blank."
        },
        "source": {
          "type": [
            "string",
            "null"
          ],
          "description": "Which dataset named this institution."
        },
        "as_of": {
          "type": [
            "string",
            "null"
          ],
          "description": "Year-month that dataset was last refreshed. This dates the IMPORT, which for one source is not the date of the data — see source_as_of."
        },
        "source_as_of": {
          "type": "string",
          "description": "Year-month the source DATA is from, present ONLY when it differs from as_of. On a curated_map or directory_prefix answer it dates the directory row that supplied the name, the city, the LEI or the address when that row comes from a frozen public copy; never present on a national_register answer, whose name comes from the register and is dated by as_of. Absent means no gap has been established, never 'this is current'."
        },
        "listed_in_current_source": {
          "type": [
            "boolean",
            "null"
          ],
          "description": "Whether this BIC8 still appears in a list refreshed this cycle: GLEIF, the directory sources that carry no vintage, a national register, the EPC scheme registers. true when one of them carries it; null when it was not found in what could be read in full (never false by default). false is reserved for an index built from every list read in full, which is not the case today: the EBA STEP2 and NBP lists are only read through our deduplicated directory, so this field answers true or null. It does NOT prove the bank still exists under this name: a clearing list can keep the name of a bank that was absorbed."
        },
        "basis": {
          "type": "string",
          "enum": [
            "national_register",
            "curated_map",
            "directory_prefix"
          ],
          "description": "WHERE the bank code to BIC pairing came from, and therefore what may be done with the BIC. national_register: the country's own register publishes this BIC for this bank code — today Germany, Austria, Belgium, Slovakia, Czech Republic, Bulgaria, Switzerland, Liechtenstein and San Marino; the SIX BankMaster carries the exact 11-character BIC per IID and the German Bankleitzahlendatei per BLZ. curated_map: our maintained bank-code map made the pairing on an exact key. Usually right, and not an allocation record. directory_prefix: the bic8 LIKE fallback, which can match several institutions at once — read bank_code_check.candidates. Answers the settlement question directly: only national_register is settlement-grade, so outside those registers a derived BIC is advisory and should be confirmed with the beneficiary or your bank before it becomes a stored routing instruction."
        },
        "authoritative": {
          "type": "boolean",
          "description": "Whether this BIC may be stored and settled against. Derived from `basis` by a single table, so the two cannot disagree. NOT the same claim as bank_code_check.authoritative, which is about the BANK CODE — whether a national register was consulted about its existence. San Marino is where they part: the pairing is the supervisor's, while the code space is not its to settle."
        },
        "lei": {
          "type": [
            "string",
            "null"
          ],
          "description": "Legal Entity Identifier, read from the same directory row /v1/bic/:code serves. Null means GLEIF publishes no LEI for this BIC, never that the institution has none."
        },
        "lei_status": {
          "type": [
            "string",
            "null"
          ]
        },
        "address": {
          "type": [
            "object",
            "null"
          ],
          "description": "Registered / head-office address (GLEIF, CC0). Entity-level, not per-branch. Always dated by its own as_of, which is the entity last filing and is usually OLDER than the as_of above.",
          "properties": {
            "type": {
              "type": "string",
              "enum": [
                "registered"
              ]
            },
            "street": {
              "type": [
                "string",
                "null"
              ]
            },
            "post_code": {
              "type": [
                "string",
                "null"
              ]
            },
            "region": {
              "type": [
                "string",
                "null"
              ]
            },
            "city": {
              "type": [
                "string",
                "null"
              ]
            },
            "country": {
              "type": "string"
            },
            "romanized": {
              "type": [
                "string",
                "null"
              ]
            },
            "romanization": {
              "type": "string",
              "enum": [
                "original_latin",
                "gleif_english",
                "unavailable"
              ],
              "description": "unavailable means the entity filed a non-Latin address and GLEIF ships no official Latin form. No transliteration is invented."
            },
            "source": {
              "type": "string"
            },
            "language": {
              "type": [
                "string",
                "null"
              ]
            },
            "as_of": {
              "type": [
                "string",
                "null"
              ]
            }
          }
        },
        "postal_address": {
          "type": "object",
          "description": "The institution seat expressed as an ISO 20022 PostalAddress, for the November 2026 structured-address rules (SPS 2026 in force 14 Nov 2026, Fedwire production 16 Nov 2026, T2 R2026.NOV). Purely additive — the `address` block beside it is unchanged and keeps the full untruncated street. Present only when TwnNm and Ctry can both be filled; absent fields are absent, never guessed.",
          "properties": {
            "strt_nm": {
              "type": "string",
              "description": "StrtNm. Present ONLY when the source really separates street from number — in practice the SIX BankMaster register for Swiss and Liechtenstein institutions. Its absence means the source published one concatenated line (which is then served as adr_line), NOT that the institution has no street."
            },
            "bldg_nb": {
              "type": "string",
              "description": "BldgNb. Same condition as strt_nm — never split out of a joined line."
            },
            "pst_cd": {
              "type": "string",
              "description": "PstCd."
            },
            "twn_nm": {
              "type": "string",
              "description": "TwnNm. Mandatory in SPS and Fedwire; always present when this block is."
            },
            "ctry": {
              "type": "string",
              "description": "Ctry, ISO 3166-1 alpha-2."
            },
            "adr_line": {
              "type": "array",
              "items": {
                "type": "string",
                "maxLength": 70
              },
              "maxItems": 2,
              "description": "AdrLine, at most 2 lines of at most 70 characters, never repeating a value already served in a structured element above. A concatenated street line goes here rather than into strt_nm. Omitted rather than truncated when the line cannot fit in two lines — the full line stays in the `address` block."
            },
            "format": {
              "type": "string",
              "enum": [
                "structured",
                "hybrid"
              ],
              "description": "structured: every element served has its own ISO 20022 element, no AdrLine. hybrid: structured elements plus at most two AdrLine. Derived from the block, so it cannot disagree with the fields it labels."
            },
            "source": {
              "type": "string",
              "description": "The dataset this address came from, named as its publisher names it. It can differ from `address.source`: a Swiss institution is served from the SIX register while `address` stays GLEIF."
            },
            "as_of": {
              "type": [
                "string",
                "null"
              ],
              "description": "When the SOURCE last stated this address (a SIX validity date, a GLEIF filing date). Null when the dataset publishes none — never a clock read, and never the date our database was refreshed."
            }
          },
          "required": [
            "twn_nm",
            "ctry",
            "format",
            "source",
            "as_of"
          ]
        }
      },
      "required": [
        "code",
        "bank_name",
        "city"
      ]
    },
    "formatted": {
      "type": "string",
      "description": "IBAN formatted in groups of 4"
    },
    "clearing": {
      "type": [
        "object",
        "null"
      ],
      "description": "Swiss clearing enrichment from the SIX BankMaster directory — present for CH and LI IBANs only, and included at no extra cost in the 0.005 USDC validation. Full rail participation, not just a name lookup.",
      "properties": {
        "iid": {
          "type": "string",
          "description": "Zero-padded 5-digit IID / BC-Nummer"
        },
        "name": {
          "type": "string"
        },
        "type": {
          "type": "string",
          "enum": [
            "bank",
            "cantonal_bank",
            "postfinance",
            "raiffeisen",
            "central_bank",
            "foreign_participant"
          ]
        },
        "town": {
          "type": "string"
        },
        "sic": {
          "type": "boolean",
          "description": "SIC (Swiss Interbank Clearing) participation"
        },
        "instant_payments_chf": {
          "type": "boolean",
          "description": "Instant Payments CHF participation"
        },
        "eurosic": {
          "type": "boolean",
          "description": "euroSIC participation"
        },
        "qr_iid": {
          "type": [
            "string",
            "null"
          ],
          "description": "QR-IID allocation for QR-bill reference, null when the institution has none"
        }
      }
    },
    "error": {
      "type": "string",
      "enum": [
        "invalid_format",
        "unsupported_country",
        "wrong_length",
        "invalid_check_digits",
        "checksum_failed",
        "invalid_bban_structure"
      ],
      "description": "Present ONLY when `valid` is false, on an HTTP 200: an invalid IBAN is not an HTTP error. Absent on every successful validation."
    },
    "error_detail": {
      "type": "string",
      "description": "Present ONLY when `error` is, and explains it in one sentence (e.g. \"Modulo 97 check returned 28, expected 1.\")."
    },
    "reference_check": {
      "allOf": [
        {
          "$ref": "#/$defs/ReferenceCheckBlock"
        }
      ],
      "description": "Present ONLY when the request carried a `reference` field."
    },
    "cost_usdc": {
      "type": "number"
    },
    "processing_ms": {
      "type": "number"
    },
    "sepa": {
      "type": "object",
      "description": "SEPA compliance details. Only present when the IBAN is valid and the country participates in SEPA.",
      "properties": {
        "member": {
          "type": "boolean",
          "description": "Whether the IBAN country is a SEPA member"
        },
        "schemes": {
          "type": "array",
          "description": "SEPA schemes available for this account. When the resolved institution has rows in the EPC scheme registers these are ITS schemes (basis = \"epc_register\"); otherwise the country-level schemes (basis = \"country_default\"), even for a bank code nobody holds: for the bank itself, read bank_schemes and bank_reachability. SCT = Credit Transfer, SDD = Direct Debit, SCT_INST = Instant Credit Transfer.",
          "items": {
            "type": "string",
            "enum": [
              "SCT",
              "SDD",
              "SCT_INST"
            ]
          }
        },
        "vop_required": {
          "type": "boolean",
          "description": "Whether Verification of Payee (VoP) is required under the EU Instant Payments Regulation in this COUNTRY. It says nothing about the bank: read vop_register_status for the payee's bank."
        },
        "vop_participant": {
          "type": [
            "boolean",
            "null"
          ],
          "description": "Bank-level VoP readiness: true when the resolved institution is listed as \"ready\" in the EPC Verification of Payee scheme register; false when it is not; null when no institution was resolved or when the VoP register is not loaded on this deployment (not consulted, which is not a \"no\"); a resolved bank outside the SEPA area is answered false from the country either way. Listing means the bank answers VoP requests — it does not run the name check for you. The same as vop_register_status === \"active\"; vop_register_status also says pending."
        },
        "bank_reachability": {
          "type": [
            "string",
            "null"
          ],
          "enum": [
            "listed",
            "not_listed",
            "no_bank",
            "bank_code_not_allocated",
            null
          ],
          "description": "Whether the EPC scheme registers list the resolved BANK, never borrowed from the country (member, schemes and basis still describe the country and are unchanged). listed: the bank has rows in the SCT, SCT Inst or SDD register. not_listed: it has none (an absence from the register is not an exclusion from the scheme). no_bank: no BIC resolved for this bank code, so no bank could be looked up in the EPC registers (a register may still name the holder: see bank_code_holder and bank_code_check). bank_code_not_allocated: the national register says nobody holds the bank code. null: the registers are not loaded on this deployment (not consulted, never read as not_listed). Absent outside SEPA."
        },
        "bank_schemes": {
          "type": [
            "array",
            "null"
          ],
          "items": {
            "type": "string",
            "enum": [
              "SCT",
              "SDD",
              "SCT_INST"
            ]
          },
          "description": "The bank's own schemes from the EPC registers when bank_reachability is listed; [] for a bank code nobody holds; null otherwise. Absent outside SEPA."
        },
        "vop_register_status": {
          "type": [
            "string",
            "null"
          ],
          "enum": [
            "active",
            "pending",
            "inactive",
            "not_listed",
            null
          ],
          "description": "The bank's status in the EPC Verification of Payee register: active (the same as vop_participant true), pending, inactive, or not_listed when the register has no row for it; null when no BIC resolved or the register was not consulted (screened false). Outside the SEPA area the country answers instead of the register (not_listed on POST /v1/iban/compliance) whether or not the register is loaded; the validation carries no sepa.vop_register_status there. It says whether the payee's bank answers VoP requests; IBANforge never runs the name check itself. Absent outside SEPA."
        },
        "basis": {
          "type": "string",
          "enum": [
            "country_default",
            "epc_register"
          ],
          "description": "Where `schemes` comes from: \"epc_register\" when the resolved BIC has rows in the embedded EPC scheme registers (bank grain), \"country_default\" otherwise. Absent when enrichment stopped early. Audit 2026-09-01 (DATA-02)."
        }
      },
      "required": [
        "member",
        "schemes",
        "vop_required"
      ]
    },
    "issuer": {
      "type": "object",
      "description": "Issuer classification for the institution behind the IBAN. Useful for vIBAN detection and KYC enrichment. Present when the IBAN is valid and either the BIC resolved or an official register names the holder of the bank code (see psd_registration).",
      "properties": {
        "type": {
          "type": [
            "string",
            "null"
          ],
          "enum": [
            "bank",
            "digital_bank",
            "emi",
            "payment_institution",
            null
          ],
          "description": "Type of financial institution (bank = traditional bank, digital_bank = neobank/challenger, emi = Electronic Money Institution, payment_institution = licensed PI). Null when we hold no support for a type: falling back to bank would be an assertion, and a payee pre-flight must not be handed one."
        },
        "name": {
          "type": "string",
          "description": "Name of the institution holding this BIC"
        },
        "classification": {
          "type": "string",
          "enum": [
            "curated",
            "register",
            "default"
          ],
          "description": "Whether the type was established or assumed. curated = the BIC8 is in the issuer set, so this is an identification. register = an official register names the holder of this bank code and says what it is; also an identification, and one that carries a date and an issuing authority in the psd_registration block beside it. It only ever replaces a default, never a curated verdict. default = nothing is on file and 'bank' is the fallback, which covers 42,195 of 43,199 distinct BIC8 (97.7%, recounted 29/07/2026; the count drifts at every monthly refresh). When sizing exposure to virtual IBANs, count curated and register, never default."
        },
        "iban_issuer": {
          "type": "string",
          "enum": [
            "confirmed",
            "not_listed"
          ],
          "description": "Whether the country's own list of IBAN-issuing providers names the holder of this bank code. Present only where such a list exists, today NL. confirmed = the identifier belongs to a provider that issues IBANs. not_listed = it resolves to a BIC, but the holder is not among the known issuers, so the account may not exist: measured 29/07/2026, only 90 of our 815 Dutch codes are on that list and the rest resolve to corporate treasuries that hold a Dutch BIC for their own SWIFT traffic. NOT a denial, because the Dutch list is explicitly not exhaustive, which is also why NL keeps bank_code_check.authoritative false."
        }
      },
      "required": [
        "type",
        "name",
        "classification"
      ]
    },
    "psd_registration": {
      "type": "object",
      "description": "The EBA's PSD2 register of payment and electronic money institutions naming the holder of this bank code. Joined on country + national reference code, and served ONLY for countries where that code was measured to be the one the IBAN actually carries — today Spain alone. The register carries no BIC and no LEI, and in 29 of its 30 countries it files authorisations under a company or tax number from an unrelated register (a Polish NIP, a French SIREN, a Dutch DNB reference), so joining those to a bank code would attach a real institution's authorisation to an unrelated bank. Absent on a miss: there is no negative form, because the register's own disclaimer states that an institution omitted from it is authorised all the same.",
      "properties": {
        "registered": {
          "type": "boolean",
          "description": "Always true. There is no negative form of this block."
        },
        "entity_type": {
          "type": "string",
          "enum": [
            "payment_institution",
            "emi",
            "aisp",
            "exempted_emi",
            "exempted_payment_institution"
          ],
          "description": "The register's own category. emi = electronic money institution, payment_institution = authorised PI, aisp = account information service provider (reads accounts, issues nothing), exempted_emi / exempted_payment_institution = small operators waived FROM authorisation, which is not a licence. Only emi and payment_institution move issuer.type."
        },
        "name": {
          "type": "string",
          "description": "Insti

# --- truncated at 32 KB (56 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/ibanforge/refs/heads/main/json-schema/ibanforge-ibanvalidation-result-schema.json

Work with this as data

Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for schemas

4 MCP tools reach this
  • find_json_schemasBrowse and filter every JSON Schema in the catalog.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This JSON Schema
curl "https://apis.io/api/v1/json-schemas/ibanforge-ibanvalidation-result"
All schemas
curl "https://apis.io/api/v1/json-schemas?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.