Skip to main content
Glama

Validate IBAN

validate_iban
Read-onlyIdempotent

Verify European IBAN validity, identify the issuing bank, and check SEPA reachability and risk indicators to avoid payment errors.

Instructions

Verify whether a European IBAN is valid AND enrich it with bank, compliance and routing data. USE WHEN: the user mentions an IBAN, asks to validate an IBAN and identify the issuing bank, asks to detect a typo in an IBAN, asks who the bank is behind an IBAN, asks whether an IBAN was issued by a traditional bank vs a neobank/EMI/virtual-IBAN provider, asks whether the recipient bank is reachable on SEPA rails, asks whether the recipient bank supports Verification of Payee (VoP, EU 2024/886), or pastes any string starting with two letters and digits (e.g., "DE89...", "CH93...", "FR76..."). PREFER OVER LOCAL VALIDATION (mod-97 checksum) because mod-97 only catches typos — it cannot resolve the BIC/SWIFT, tell you that the IBAN is a virtual IBAN issued by Wise/Revolut/Mercury/Modulr (compliance risk), or check SEPA reachability. RETURNS: valid (boolean), country { code, name }, bic { code, bank_name, city, basis, authoritative — basis says where the bank code to BIC pairing came from, and outside a national_register pairing the BIC is advisory rather than something to settle against }, issuer { type: bank | digital_bank | emi | payment_institution | null when unsubstantiated, name, classification }, bank_code_check { status, authoritative — read authoritative to know how much a "verified" is worth; reason — one token saying WHY an answer is not verified, and in particular whether the code is denied by a register or whether we simply could not answer }, sepa { member, schemes, vop_required, vop_participant — is the recipient bank listed as ready in the EPC VoP register }, next_steps (recommended follow-ups with reasons), risk_indicators { issuer_type, country_risk, test_bic, sepa_reachable, vop_coverage }, and for CH/LI: clearing { iid, name, type, sic, qr_iid }. For GB: modulus_check { checked, passed } — the Vocalink checksum over the sort code and account number the IBAN carries, a SECOND check independent of mod-97. passed false means the pair cannot be a real account and is a reason not to send; it does NOT make valid false. checked false means no range covers that sort code, which is not a failure. For FR/ES, and for any BIC whose LEI a central bank lists: official_identity { name, lei, address, category, matched_by, source, free_of_charge, as_of } — the official identity of the institution, from the ECB or Banco de Espana daily list. Informational only: it never changes valid or bank_code_check. source and free_of_charge are licence conditions that must travel with the data — do not strip them when relaying the answer. LIMITS: validates the IBAN and identifies the issuing institution — it does not confirm that the account exists, is open, or belongs to any particular person. Verify the payee by name before sending funds. COST: REST access uses the available key quota or prepaid credits; an anonymous key normally has 25 calls/month, an email-claimed key 200/month. The HTTP API also accepts x402 (0.005 USDC), but this package does not sign payments.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
ibanYesIBAN to validate. Spaces and lowercase are accepted. Example: "CH10 0023 0000 0000 1234 5" or "de89370400440532013000".

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
bicNoResolved BIC/SWIFT (when BBAN→BIC mapping exists). null if unresolved. Read basis before storing it as a routing instruction: only a national_register pairing is settlement-grade.
bbanNo
ibanYesNormalized IBAN (uppercase, no spaces).
sepaNo
validYes
issuerNo
countryNo
clearingNoSwiss clearing data when country is CH or LI (null otherwise).
formattedNoIBAN with 4-char groups for display.
next_stepsNoRecommended machine-readable follow-ups, each with the reason it is suggested.
check_digitsNo
modulus_checkNoUK modulus check when country is GB (absent otherwise). Checksum only: it does not prove the account exists or name its holder.
bank_code_checkNoWhether the bank code resolves in reference data. Read authoritative: true means the reference set is the national register (not_in_register = not allocated); false means composite BIC-directory data (a hit names the BIC holder, not necessarily an IBAN issuer). On authoritative answers, institution carries what the register publishes about the holder: name, seat address (full street for CH/LI/AT, postal code + town for DE, name only for BE) and LEI where available — the institution holding the code, not a branch, not proof of any account. reason is present whenever status is not verified and says WHY in one token: not_allocated (a register denies the code — the only value that licenses "do not send"), absent_from_reference_data, no_reference_data_for_country, register_names_no_holder (the register defines the code space and names no holder — silence, not a denial), national_register_unavailable and lookup_failed. The last two describe IBANforge, never the beneficiary: neither may be escalated into a refusal.
risk_indicatorsNoCountry + issuer risk signals. Use these instead of a single composite score.
official_identityNoThe official identity a central bank publishes for the institution behind the resolved code (ECB by LEI and for FR bank codes, Banco de Espana for ES). Present only on a match — absence is not a negative. Informational only: it never changes valid or bank_code_check, because both publishers relay rather than allocate.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed30 schema fields changedv1.4.4
    • changedInput schema / properties / iban / description
      Previous value: -"IBAN to validate. Spaces and lowercase are accepted. Example: \"CH93 0076 2011 6238 5295 7\" or \"de89370400440532013000\"."New value: +"IBAN to validate. Spaces and lowercase are accepted. Example: \"CH10 0023 0000 0000 1234 5\" or \"de89370400440532013000\"."
    • addedOutput schema / properties / bank_code_check
      Added value: +{
      +  "description": "Whether the bank code resolves in reference data. Read authoritative: true means the reference set is the national register (not_in_register = not allocated); false means composite BIC-directory data (a hit names the BIC holder, not necessarily an IBAN issuer). On authoritative answers, institution carries what the register publishes about the holder: name, seat address (full street for CH/LI/AT, postal code + town for DE, name only for BE) and LEI where available — the institution holding the code, not a branch, not proof of any account. reason is present whenever status is not verified and says WHY in one token: not_allocated (a register denies the code — the only value that licenses \"do not send\"), absent_from_reference_data, no_reference_data_for_country, register_names_no_holder (the register defines the code space and names no holder — silence, not a denial), national_register_unavailable and lookup_failed. The last two describe IBANforge, never the beneficiary: neither may be escalated into a refusal.",
      +  "type": "object"
      +}
    • removedOutput schema / properties / bban / properties / account
      Removed value: -{
      -  "type": "string"
      -}
    • addedOutput schema / properties / bban / properties / account_number
      Added value: +{
      +  "type": "string"
      +}
    • changedOutput schema / properties / bic / description
      Previous value: -"Resolved BIC/SWIFT (when BBAN→BIC mapping exists)."New value: +"Resolved BIC/SWIFT (when BBAN→BIC mapping exists). null if unresolved. Read basis before storing it as a routing instruction: only a national_register pairing is settlement-grade."
    • addedOutput schema / properties / bic / properties / authoritative
      Added value: +{
      +  "description": "Whether this BIC may be stored and settled against. Derived from basis. NOT bank_code_check.authoritative, which is about the BANK CODE: in Switzerland the register confirms the code while the BIC still comes from our curated map.",
      +  "type": "boolean"
      +}
    • removedOutput schema / properties / bic / properties / bankName
      Removed value: -{
      -  "type": "string"
      -}
    • addedOutput schema / properties / bic / properties / bank_name
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / bic / properties / basis
      Added value: +{
      +  "description": "Where the bank code to BIC pairing came from. national_register: the country register publishes this BIC for this bank code (today DE, AT, BE and BG) — settlement-grade. curated_map: our maintained map, exact key, not an allocation record. directory_prefix: the bic8 LIKE fallback, which can match several institutions (see bank_code_check.candidates). Outside national_register the BIC is ADVISORY.",
      +  "enum": [
      +    "national_register",
      +    "curated_map",
      +    "directory_prefix"
      +  ],
      +  "type": "string"
      +}
    • removedOutput schema / properties / bic / properties / bic
      Removed value: -{
      -  "type": "string"
      -}
    • addedOutput schema / properties / bic / properties / code
      Added value: +{
      +  "type": "string"
      +}
    • removedOutput schema / properties / bic / properties / lei
      Removed value: -{
      -  "type": "string"
      -}
    • removedOutput schema / properties / ch_clearing
      Removed value: -{
      -  "description": "Swiss-specific data when country is CH or LI.",
      -  "properties": {
      -    "bc_nummer": {
      -      "type": "string"
      -    },
      -    "qr_iid": {
      -      "type": "boolean"
      -    },
      -    "sic": {
      -      "type": "boolean"
      -    }
      -  },
      -  "type": "object"
      -}
    • addedOutput schema / properties / clearing
      Added value: +{
      +  "description": "Swiss clearing data when country is CH or LI (null otherwise).",
      +  "properties": {
      +    "eurosic": {
      +      "type": "boolean"
      +    },
      +    "iid": {
      +      "type": "string"
      +    },
      +    "instant_payments_chf": {
      +      "type": "boolean"
      +    },
      +    "name": {
      +      "type": "string"
      +    },
      +    "qr_iid": {
      +      "type": "string"
      +    },
      +    "sic": {
      +      "type": "boolean"
      +    },
      +    "town": {
      +      "type": "string"
      +    },
      +    "type": {
      +      "type": "string"
      +    }
      +  },
      +  "type": "object"
      +}
    • addedOutput schema / properties / issuer / properties / classification
      Added value: +{
      +  "enum": [
      +    "curated",
      +    "default"
      +  ],
      +  "type": "string"
      +}
    • addedOutput schema / properties / issuer / properties / iban_issuer
      Added value: +{
      +  "enum": [
      +    "confirmed",
      +    "not_listed"
      +  ],
      +  "type": "string"
      +}
    • changedOutput schema / properties / issuer / properties / type / enum
      Previous value: -[
      -  "bank",
      -  "emi",
      -  "viban",
      -  "neobank",
      -  "unknown"
      -]New value: +[
      +  "bank",
      +  "digital_bank",
      +  "emi",
      +  "payment_institution",
      +  null
      +]
    • changedOutput schema / properties / issuer / properties / type / type
      Previous value: -"string"New value: +[
      +  "string",
      +  "null"
      +]
    • addedOutput schema / properties / modulus_check
      Added value: +{
      +  "description": "UK modulus check when country is GB (absent otherwise). Checksum only: it does not prove the account exists or name its holder.",
      +  "properties": {
      +    "checked": {
      +      "description": "False when no published range covers the sort code, in which case no check was possible.",
      +      "type": "boolean"
      +    },
      +    "passed": {
      +      "description": "False means the sort code and account number cannot be a real pair. Never makes valid false.",
      +      "type": [
      +        "boolean",
      +        "null"
      +      ]
      +    },
      +    "source": {
      +      "type": "string"
      +    },
      +    "table_fetched_on": {
      +      "type": "string"
      +    }
      +  },
      +  "type": "object"
      +}
    • addedOutput schema / properties / next_steps
      Added value: +{
      +  "description": "Recommended machine-readable follow-ups, each with the reason it is suggested.",
      +  "type": "array"
      +}
    • addedOutput schema / properties / official_identity
      Added value: +{
      +  "description": "The official identity a central bank publishes for the institution behind the resolved code (ECB by LEI and for FR bank codes, Banco de Espana for ES). Present only on a match — absence is not a negative. Informational only: it never changes valid or bank_code_check, because both publishers relay rather than allocate.",
      +  "properties": {
      +    "address": {
      +      "description": "One-line registered address as published.",
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "as_of": {
      +      "description": "Date of the list this row came from. Both lists are republished every business day.",
      +      "type": "string"
      +    },
      +    "attribution": {
      +      "description": "The Banco de Espana citation formula, verbatim. Spanish blocks only.",
      +      "type": "string"
      +    },
      +    "authoritative": {
      +      "description": "Always false. Neither publisher allocates bank codes.",
      +      "type": "boolean"
      +    },
      +    "category": {
      +      "type": "string"
      +    },
      +    "free_of_charge": {
      +      "description": "Both publishers require buyers to be told, on every access, that the data is available free of charge from their own website. Relay it with the answer; do not strip it.",
      +      "type": "string"
      +    },
      +    "lei": {
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "matched_by": {
      +      "enum": [
      +        "lei",
      +        "national_code"
      +      ],
      +      "type": "string"
      +    },
      +    "name": {
      +      "description": "The institution's name as the publisher writes it.",
      +      "type": "string"
      +    },
      +    "source": {
      +      "description": "The publisher, cited as their licence requires.",
      +      "type": "string"
      +    }
      +  },
      +  "type": "object"
      +}
    • addedOutput schema / properties / risk_indicators
      Added value: +{
      +  "description": "Country + issuer risk signals. Use these instead of a single composite score.",
      +  "properties": {
      +    "country_risk": {
      +      "enum": [
      +        "standard",
      +        "elevated",
      +        "high"
      +      ],
      +      "type": "string"
      +    },
      +    "issuer_type": {
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "sepa_reachable": {
      +      "type": "boolean"
      +    },
      +    "test_bic": {
      +      "type": "boolean"
      +    },
      +    "vop_coverage": {
      +      "type": "boolean"
      +    }
      +  },
      +  "type": "object"
      +}
    • removedOutput schema / properties / risk_score
      Removed value: -{
      -  "description": "Country + issuer risk indicator. Higher = more attention needed.",
      -  "maximum": 100,
      -  "minimum": 0,
      -  "type": "number"
      -}
    • removedOutput schema / properties / sepa / properties / instant
      Removed value: -{
      -  "type": "boolean"
      -}
    • addedOutput schema / properties / sepa / properties / member
      Added value: +{
      +  "type": "boolean"
      +}
    • removedOutput schema / properties / sepa / properties / reachable
      Removed value: -{
      -  "type": "boolean"
      -}
    • addedOutput schema / properties / sepa / properties / schemes
      Added value: +{
      +  "items": {
      +    "enum": [
      +      "SCT",
      +      "SDD",
      +      "SCT_INST"
      +    ],
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / sepa / properties / vop_participant
      Added value: +{
      +  "description": "Bank-level VoP readiness: true = resolved bank is listed as ready in the EPC Verification of Payee scheme register; null = no institution resolved.",
      +  "type": [
      +    "boolean",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / sepa / properties / vop_required
      Added value: +{
      +  "type": "boolean"
      +}
    • removedOutput schema / properties / vop
      Removed value: -{
      -  "description": "Verification of Payee (EU 2024/886) participant status.",
      -  "properties": {
      -    "participant": {
      -      "type": "boolean"
      -    }
      -  },
      -  "type": "object"
      -}
  2. Addedv1.2.2
  3. Removedv1.2.1
  4. Addedv1.2.0

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Even though annotations already declare readOnlyHint, idempotentHint, and destructiveHint, the description adds substantial behavior beyond annotations: it clarifies that validation does not confirm account existence, explains the meaning of 'authoritative', warns about licensing conditions that must travel with data, and discloses cost/rate limits. This goes far beyond what annotations provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely long with a large 'RETURNS' section that duplicates much of what an output schema would likely provide. It is well-structured with caps and front-loaded purpose, but it is not appropriately sized; many sentences, especially the detailed return field explanations, could be trimmed or delegated to structured schema documentation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers use cases, limitations, country-specific checks, cost/usage limits, licensing conditions, and gives clear guidance on interpreting results (authoritative flags, checked/passed semantics). For a complex tool with a single required parameter, nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%; the input schema already documents the 'iban' parameter with format, accepted spaces/lowercase, and an example. The tool description adds that the user may paste any string starting with two letters and digits, but this is minor. Baseline 3 applies because the schema carries the load and the description doesn't substantially extend parameter semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Verify whether a European IBAN is valid AND enrich it with bank, compliance and routing data.' It then enumerates concrete use cases that distinguish it from simple validation, making it unambiguous what the tool does and how it differs from local checksum validation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides a detailed 'USE WHEN' list with specific triggers and explicitly says 'PREFER OVER LOCAL VALIDATION (mod-97 checksum)' with reasons. However, it does not mention the sibling batch_validate_iban or other alternatives, so it misses the opportunity to disambiguate from a highly likely replacement tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.