openapi: 3.1.0 info: title: Ibanforge IBAN API version: 1.4.3 contact: url: https://ibanforge.com description: 'Operations tagged IBAN across 2 of this provider''s published API definitions: ibanforge-iban-api-openapi.yml, ibanforge-openapi.yml. Each path carries the servers of the definition it was published in.' servers: - url: https://api.ibanforge.com description: Production - url: http://localhost:3000 description: Local development tags: - name: IBAN description: IBAN validation endpoints (paid via x402) paths: /v1/iban/validate: post: operationId: validateIBAN summary: Validate a single IBAN description: Validates an IBAN and returns parsed components including country, check digits, BBAN, and optional BIC lookup. Costs 0.005 USDC via x402. tags: - IBAN security: - x402Payment: [] - apiKey: [] requestBody: required: true content: application/json: schema: type: object required: - iban properties: iban: type: string description: IBAN to validate (spaces allowed, will be normalized) example: GB29NWBK60161331926819 responses: '200': description: Validation result content: application/json: schema: $ref: '#/components/schemas/IBANValidationResult' '400': description: Missing or malformed request body '402': description: Payment required (x402) servers: - url: https://api.ibanforge.com description: Production - url: http://localhost:3000 description: Local development /v1/iban/batch: post: operationId: batchValidateIBAN summary: Validate up to 100 IBANs in one request description: Validates a list of IBANs and returns results for each. Costs $0.002 USDC per IBAN via x402 (e.g. 10 IBANs = $0.020, 100 IBANs = $0.200). On API keys, a batch debits 1 request/credit per IBAN — free tier and prepaid packs alike. tags: - IBAN security: - x402Payment: [] - apiKey: [] requestBody: required: true content: application/json: schema: type: object required: - ibans properties: ibans: type: array items: type: string minItems: 1 maxItems: 100 description: List of IBANs to validate example: - GB29NWBK60161331926819 - DE89370400440532013000 responses: '200': description: Batch validation results content: application/json: schema: type: object properties: results: type: array items: $ref: '#/components/schemas/IBANValidationResult' count: type: integer description: Total IBANs processed valid_count: type: integer description: Number of valid IBANs cost_usdc: type: number description: Total cost in USDC required: - results - count - valid_count - cost_usdc '400': description: Missing or malformed request body '402': description: Payment required (x402) servers: - url: https://api.ibanforge.com description: Production - url: http://localhost:3000 description: Local development components: schemas: IBANValidationResult: type: object required: - iban - valid - cost_usdc properties: iban: type: string description: The IBAN as provided (normalized) valid: type: boolean country: type: object properties: code: type: string example: GB name: type: string example: United Kingdom required: - code - name check_digits: type: string example: '29' bban: type: object properties: bank_code: type: string branch_code: type: string account_number: type: string required: - bank_code - account_number bic: type: object nullable: true properties: code: type: string example: NWBKGB2L bank_name: type: string nullable: true city: type: string nullable: true required: - code - bank_name - city formatted: type: string description: IBAN formatted in groups of 4 example: GB29 NWBK 6016 1331 9268 19 clearing: type: object nullable: true 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 example: '00230' name: type: string example: UBS Switzerland AG type: type: string enum: - bank - cantonal_bank - postfinance - raiffeisen - central_bank - foreign_participant town: type: string example: Zürich 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 nullable: true description: QR-IID allocation for QR-bill reference, null when the institution has none error: type: string enum: - invalid_format - unsupported_country - wrong_length - checksum_failed error_detail: type: string cost_usdc: type: number example: 0.005 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 the institution supports (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 EU Instant Payments Regulation for this institution vop_participant: type: boolean nullable: true 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. Listing means the bank answers VoP requests — it does not run the name check for you.' required: - member - schemes - vop_required issuer: type: object description: Issuer classification for the institution behind the IBAN. Useful for vIBAN detection and KYC enrichment. Only present when the IBAN is valid and the BIC is resolved. properties: type: type: string nullable: true 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 - default description: Whether the type was established or assumed. curated = the BIC8 is in the issuer set, so this is an identification. 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 only curated. 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 risk_indicators: type: object description: 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. properties: issuer_type: type: string nullable: true enum: - bank - digital_bank - emi - payment_institution - null description: Type of the issuing institution (mirrors issuer.type for convenience). Null when the bank code resolved no institution — it used to default to "bank", which typed an institution that had not been found. Read bank_code_check to tell an unresolved code from a genuine bank. country_risk: type: string enum: - standard - elevated - high description: Country-level risk classification based on FATF grey/black lists and EU high-risk third countries test_bic: type: boolean description: Whether the resolved BIC is a test/sandbox code (position 8 = 0) sepa_reachable: type: boolean description: 'Whether SEPA Credit Transfers reach this COUNTRY. Derived from the country, not from the account: it stays true on an IBAN whose bank code resolved nothing. See sepa_reachable_scope.' sepa_reachable_scope: type: string enum: - country description: The scope sepa_reachable holds at. Present so the field cannot be read as an account-level assertion. vop_coverage: type: boolean description: Whether the institution is covered by Verification of Payee, reducing payee impersonation risk required: - issuer_type - country_risk - test_bic - sepa_reachable - sepa_reachable_scope - vop_coverage bank_code_check: type: object description: 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 much weight the answer carries. Present only when the IBAN is valid. properties: value: type: string description: 'The bank code that was actually checked. Normally identical to bban.bank_code. It differs in Finland, where the monetary institution code is 1 to 4 characters depending on its leading digits while bban.bank_code stays the fixed positional slice: a Nordea IBAN carries bban.bank_code "123" and value "1". When they differ, this field is the one the verdict is about.' status: type: string enum: - verified - not_in_register - unavailable description: 'verified: resolves to an institution we can name. not_in_register: it does not, in reference data we do hold for this country — actionable as non-existence ONLY when authoritative is true. unavailable: we hold no reference data for this country, so no opinion.' match: type: string nullable: true enum: - register - prefix - null description: 'register: exact key in the reference set, deterministic. prefix: the bic8 LIKE fallback, reachable only in the 30 countries whose bank code may open on a letter (a BIC8 always does) — check candidates.' register: type: string nullable: true description: Name of the reference set consulted. authoritative: type: boolean description: 'True only where that reference set is the national register: today CH and LI against the SIX BankMaster, DE against the Bundesbank Bankleitzahlendatei, FI against the Finance Finland monetary institution list, AT against the Oesterreichische Nationalbank SEPA-Zahlungsverkehrs-Verzeichnis, and BE against the Banque nationale de Belgique bank identification codes. This is the flag to branch on: everywhere else an absence is evidence of absence from our data, not of non-existence. One asymmetry worth knowing: CH, LI, DE, AT and BE allocate codes to individual institutions, while FI allocates prefixes to banking groups, so a Finnish verified confirms the group and its BIC rather than one specific bank. The negative direction carries full weight in all six.' candidates: type: integer description: BIC8 the prefix search matched. Present only for match=prefix. Greater than 1 means the returned BIC is one of several and may belong to a different institution than the account does. retired: type: boolean description: 'Present and true when an authoritative register marks the code for deletion: the institution is being retired. The code WAS allocated, so this is a verified result, not a denial. See superseded_by.' superseded_by: type: string description: The bank code that takes over, when the register names one. Re-paper the beneficiary against it. institution: type: object description: 'What the national register publishes about the allocated institution. Present only on an authoritative answer — composite-map hits stay bare (naming a BIC holder is the bic block, and its address would imply a register that was not consulted). Depth varies by register: SIX (CH/LI) and the OeNB (AT) publish the full seat address, the Bundesbank (DE) publishes postal code and town only, the BNB (BE) publishes names alone; Finland stays without this block, its codes belong to banking groups. Absent fields are null, never guessed. This is the institution allocated the BANK CODE — not a branch, and not proof of any account.' properties: name: type: string street: type: string nullable: true description: One line, house number included, matching the GLEIF shape. Null where the register publishes none (DE, BE). post_code: type: string nullable: true town: type: string nullable: true country: type: string lei: type: string nullable: true description: Legal Entity Identifier, where the register publishes one (the OeNB does, 99% of entries). required: - name - street - post_code - town - country as_of: type: string description: Year-month the consulted reference set was last refreshed. required: - value - status - match - register - authoritative - as_of next_steps: type: array description: '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 error already says what to do.' items: type: object properties: code: type: string description: 'Stable identifier. Today: bank_code_not_allocated (the national register denies the code, do not send), bank_code_retired (allocated but being withdrawn, re-paper against superseded_by), verify_payee_name (we cannot confirm it, treat as unavailable and let a name check decide), bic_is_advisory (the BIC was picked from several candidates), issuer_not_a_known_iban_issuer (the code resolves to a BIC, but its holder is not among the providers known to issue IBANs in that country), test_bic, expect_virtual_iban (curated non-bank issuer, account holder and IBAN holder often differ), screen_compliance.' do: type: string description: The instruction, in one sentence an agent can relay to a person. because: type: string description: The field of this response that produced the step, so the advice is auditable. action: type: string description: An IBANforge call that performs the step, when one exists. required: - code - do - because IBANValidationResult_2: type: object required: - iban - valid - cost_usdc properties: iban: type: string description: The IBAN as provided (normalized) valid: type: boolean country: type: object properties: code: type: string example: GB name: type: string example: United Kingdom required: - code - name check_digits: type: string example: '29' 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 example: NWBKGB2L bank_name: type: - string - 'null' city: type: - string - 'null' required: - code - bank_name - city formatted: type: string description: IBAN formatted in groups of 4 example: GB29 NWBK 6016 1331 9268 19 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 example: '00230' name: type: string example: UBS Switzerland AG type: type: string enum: - bank - cantonal_bank - postfinance - raiffeisen - central_bank - foreign_participant town: type: string example: Zürich 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 - checksum_failed error_detail: type: string cost_usdc: type: number example: 0.005 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 the institution supports (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 EU Instant Payments Regulation for this institution 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. Listing means the bank answers VoP requests — it does not run the name check for you.' required: - member - schemes - vop_required issuer: type: object description: Issuer classification for the institution behind the IBAN. Useful for vIBAN detection and KYC enrichment. Only present when the IBAN is valid and the BIC is resolved. 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 - default description: Whether the type was established or assumed. curated = the BIC8 is in the issuer set, so this is an identification. 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 only curated. 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 risk_indicators: type: object description: 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. properties: issuer_type: type: - string - 'null' enum: - bank - digital_bank - emi - payment_institution - null description: Type of the issuing institution (mirrors issuer.type for convenience). Null when the bank code resolved no institution — it used to default to "bank", which typed an institution that had not been found. Read bank_code_check to tell an unresolved code from a genuine bank. country_risk: type: string enum: - standard - elevated - high description: Country-level risk classification based on FATF grey/black lists and EU high-risk third countries test_bic: type: boolean description: Whether the resolved BIC is a test/sandbox code (position 8 = 0) sepa_reachable: type: boolean description: 'Whether SEPA Credit Transfers reach this COUNTRY. Derived from the country, not from the account: it stays true on an IBAN whose bank code resolved nothing. See sepa_reachable_scope.' sepa_reachable_scope: type: string enum: - country description: The scope sepa_reachable holds at. Present so the field cannot be read as an account-level assertion. vop_coverage: type: boolean description: Whether the institution is covered by Verification of Payee, reducing payee impersonation risk required: - issuer_type - country_risk - test_bic - sepa_reachable - sepa_reachable_scope - vop_coverage bank_code_check: type: object description: 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 much weight the answer carries. Present only when the IBAN is valid. properties: value: type: string description: 'The bank code that was actually checked. Normally identical to bban.bank_code. It differs in Finland, where the monetary institution code is 1 to 4 characters depending on its leading digits while bban.bank_code stays the fixed positional slice: a Nordea IBAN carries bban.bank_code "123" and value "1". When they differ, this field is the one the verdict is about.' status: type: string enum: - verified - not_in_register - unavailable description: 'verified: resolves to an institution we can name. not_in_register: it does not, in reference data we do hold for this country — actionable as non-existence ONLY when authoritative is true. unavailable: we hold no reference data for this country, so no opinion.' match: type: - string - 'null' enum: - register - prefix - null description: 'register: exact key in the reference set, deterministic. prefix: the bic8 LIKE fallback, reachable only in the 30 countries whose bank code may open on a letter (a BIC8 always does) — check candidates.' register: type: - string - 'null' description: Name of the reference set consulted. authoritative: type: boolean description: 'True only where that reference set is the national register: today CH and LI against the SIX BankMaster, DE against the Bundesbank Bankleitzahlendatei, FI against the Finance Finland monetary institution list, AT against the Oesterreichische Nationalbank SEPA-Zahlungsverkehrs-Verzeichnis, and BE against the Banque nationale de Belgique bank identification codes. This is the flag to branch on: everywhere else an absence is evidence of absence from our data, not of non-existence. One asymmetry worth knowing: CH, LI, DE, AT and BE allocate codes to individual institutions, while FI allocates prefixes to banking groups, so a Finnish verified confirms the group and its BIC rather than one specific bank. The negative direction carries full weight in all six.' candidates: type: integer description: BIC8 the prefix search matched. Present only for match=prefix. Greater than 1 means the returned BIC is one of several and may belong to a different institution than the account does. retired: type: boolean description: 'Present and true when an authoritative register marks the code for deletion: the institution is being retired. The code WAS allocated, so this is a verified result, not a denial. See superseded_by.' superseded_by: type: string description: The bank code that takes over, when the register names one. Re-paper the beneficiary against it. institution: type: object description: 'What the national register publishes about the allocated institution. Present only on an authoritative answer — composite-map hits stay bare (naming a BIC holder is the bic block, and its address would imply a register that was not consulted). Depth varies by register: SIX (CH/LI) and the OeNB (AT) publish the full seat address, the Bundesbank (DE) publishes postal code and town only, the BNB (BE) publishes names alone; Finland stays without this block, its codes belong to banking groups. Absent fields are null, never guessed. This is the institution allocated the BANK CODE — not a branch, and not proof of any account.' properties: name: type: string street: type: - string - 'null' description: One line, house number included, matching the GLEIF shape. Null where the register publishes none (DE, BE). post_code: type: - string - 'null' town: type: - string - 'null' country: type: string lei: type: - string - 'null' description: Legal Entity Identifier, where the register publishes one (the OeNB does, 99% of entries). required: - name - street - post_code - town - country as_of: type: string description: Year-month the consulted reference set was last refreshed. required: - value - status - match - register - authoritative - as_of next_steps: type: array description: '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 error already says what to do.' items: type: object properties: code: type: string description: 'Stable identifier. Today: bank_code_not_allocated (the national register denies the code, do not send), bank_code_retired (allocated but being withdrawn, re-paper against superseded_by), verify_payee_name (we cannot confirm it, treat as unavailable and let a name check decide), bic_is_advisory (the BIC was picked from several candidates), issuer_not_a_known_iban_issuer (the code resolves to a BIC, but its holder is not among the providers known to issue IBANs in that country), test_bic, expect_virtual_iban (curated non-bank issuer, account holder and IBAN holder often differ), screen_compliance, generate_payment_qr (partner handoff to PayQR on a register-confirmed SEPA account: generate and self-check a SPAYD or EPC/GiroCode payment QR).' do: type: string description: The instruction, in one sentence an agent can relay to a person. because: type: string description: The field of this response that produced the step, so the advice is auditable. action: type: string description: 'The call that performs the step, when one exists: an IBANforge endpoint, or the partner site for a partner handoff.' required: - code - do - because securitySchemes: x402Payment: type: apiKey in: header name: X-Payment description: x402 USDC micropayment token apiKey: type: http scheme: bearer description: API key (Bearer ifk_xxx) — 200 free requests/month, or custom quota for paid keys externalDocs: description: Agent-oriented overview (llms.txt) with copy-paste examples url: https://api.ibanforge.com/llms.txt x-refined-from: - ibanforge-iban-api-openapi.yml - ibanforge-openapi.yml