GET /iban/resolve

Resolves an IBAN in a single call: structural validity (all ISO 13616 countries), issuing bank, BIC and reachability (countries covered by the local bank registry) — including SEPA reachability per scheme (SCT, SCT Inst, SDD Core/B2B) from the EPC register when the bank’s BIC is known. Purely local lookup → response in milliseconds.

x402 golden rule: the agent pays for the answer to its question. “This IBAN is invalid” is a successful answer → 200 with valid: false. The 4xx range is reserved for requests the service cannot answer.

Parameters

ParameterTypeRequiredDescription
ibanstringyesIBAN to resolve; spaces and dashes tolerated, any case

200 response — UnifiedResponse

{
  "data": { ... },
  "provenance": {
    "source": "national-bank-registries",
    "fetched_at": "2026-06-12T09:30:00Z",
    "freshness": { "kind": "snapshot", "as_of": "2026-06-11T00:00:00Z" }
  }
}
  • provenance.source: stable identifier of the bank registry.
  • freshness.as_of: date of the registry snapshot (meta.json).

A single provenance block describes the whole answer. SEPA reachability comes from a second snapshot (the EPC register); its own freshness is exposed by the gateway’s /health (data.reachability.as_of) rather than a second provenance block here.

Fields of data

FieldTypeDescription
ibanstringElectronic form if valid, otherwise the input as received
validboolStructural validity (country format + mod-97 checksum)
countrystring | nullISO 3166-1 alpha-2 country code, if extracted
bank_codestring | nullBank code, if the country defines its position
branch_codestring | nullBranch code, if the country defines its position
bankobject | null{ "name": string, "bic": string | null }
reachablebool | nullWhether the bank exists; null if unknowable (see coverage)
coveragestring | null"full" | "partial" | "structure_only"; null if the IBAN is invalid (see below)
issuestring | nullDiagnostic code when valid: false
sepa_reachabilityobject | nullSEPA reachability per scheme; null when unknowable (see below)

sepa_reachability

Present only when the bank’s BIC is known and the EPC register answers for it — either directly, or through the institution-level fallback described below. Otherwise it is null (unknowable) — never a false false, exactly like reachable.

FieldTypeDescription
sctboolReachable for SEPA Credit Transfer
sct_instboolReachable for SEPA Instant Credit Transfer (SCT Inst)
sdd_coreboolReachable for SEPA Direct Debit Core
sdd_b2bboolReachable for SEPA Direct Debit B2B
schemesstring[]Canonical list of reachable schemes, e.g. ["SCT", "SCT_INST", "SDD_CORE"]
matchstringHow the reading was obtained: "exact" or "institution" (see below)
"sepa_reachability": {
  "sct": true,
  "sct_inst": true,
  "sdd_core": true,
  "sdd_b2b": false,
  "schemes": ["SCT", "SCT_INST", "SDD_CORE"],
  "match": "exact"
}

This answers the payout question — will a SEPA Instant transfer go through before I send? — at the PSP level.

match — a reading or an inference

National bank registries frequently carry a branch BIC where the EPC register only indexes the institution’s main one. Deutsche Bank retail (DE bank code 10070000) is the emblematic case: its registry BIC DEUTDEBB is absent from the EPC register, DEUTDEFF is present. Reporting null there withheld an answer that in fact existed.

So when the 8-character BIC is not listed, the service falls back to the (institution, country) pair — the first 6 characters of the BIC — and reports that pair’s schemes. match says which of the two happened, so the agent can tell a reading from an inference:

ValueMeaning
"exact"The bank’s 8-character BIC is listed in the EPC register — a direct reading
"institution"The BIC is absent; every EPC entry for its (institution, country) pair agrees on the same set of schemes, and that set is what is reported — an inference

That same Deutsche Bank IBAN, which used to answer null, now answers:

"sepa_reachability": {
  "sct": true,
  "sct_inst": true,
  "sdd_core": true,
  "sdd_b2b": true,
  "schemes": ["SCT", "SCT_INST", "SDD_B2B", "SDD_CORE"],
  "match": "institution"
}

What the fallback deliberately does not do:

  • No arbitration. If the entries of the pair disagree on their schemes, no majority is taken and no set is invented: the block stays null.
  • No country crossing. An institution’s scheme adhesion differs from one country to the next, so the pair is always country-bound — the same institution in another country is never used as evidence.

Reference-BIC caveat. The EPC register lists reference BICs. The block reports reachability at the PSP level for each scheme; it is not a routing guarantee for a specific account. Treat it as a decision-support signal, not a settlement promise — and, on match: "institution", as a signal about the institution rather than about that BIC itself.

coverage

coverage is a property of the data, not of your IBAN — it says how much the local registry knows about that country. It has three levels:

LevelMeaningreachable when bank is unknown
"full"Complete national routing register — an unknown bank code really means the bank is unknownfalse (strong signal)
"partial"Curated, incomplete register — an unknown bank code is simply not in our subsetnull (honest “don’t know”)
"structure_only"Country outside the registry — only the ISO 13616 structure is guaranteednull (unknowable)

The distinction matters for reachable: under partial coverage a bank we don’t recognise yields reachable: null, never a false false — we don’t have the whole register, so absence is not evidence of non-existence.

Country coverage today:

  • full — national routing registers, incl. DE, NL, PL (PL resolves via an 8-digit routing fallback on branch_code), among others.
  • partialFR, GB, PT, served from curated manual_* registers (the complete national registers — FIB/FGD, EISCD — are not freely licensable). A known code resolves its bank and canonical BIC (e.g. FR 20041La Banque Postale, PSSTFRPP); an unknown code returns reachable: null.
  • structure_only — every other ISO 13616 country: structure validated, bank not resolved.

This subset is deliberately conservative and announced as such — partial is a curated slice, not full national coverage.

Case 1 — valid IBAN, bank found

coverage: "full", reachable: true.

{
  "iban": "DE41500105170123456789",
  "valid": true,
  "country": "DE",
  "bank_code": "50010517",
  "branch_code": null,
  "bank": { "name": "ING-DiBa", "bic": "INGDDEFFXXX" },
  "reachable": true,
  "coverage": "full",
  "issue": null,
  "sepa_reachability": {
    "sct": true,
    "sct_inst": true,
    "sdd_core": true,
    "sdd_b2b": true,
    "schemes": ["SCT", "SCT_INST", "SDD_B2B", "SDD_CORE"],
    "match": "exact"
  }
}

When the BIC is unknown, or absent from the EPC register with no unanimous (institution, country) pair to fall back on (the cases below where bank.bic is null or unlisted), sepa_reachability is null.

Case 2 — valid IBAN, country covered but bank unknown

Strong signal: the account is probably unreachable.

{
  "iban": "DE36000000000000000000",
  "valid": true,
  "country": "DE",
  "bank_code": "00000000",
  "branch_code": null,
  "bank": null,
  "reachable": false,
  "coverage": "full",
  "issue": null
}

Case 3 — valid IBAN, partial coverage, bank found

FR/GB/PT are served from curated registers. A known code resolves its bank and canonical BIC — here FR 20041La Banque Postale (PSSTFRPP).

{
  "iban": "FR1420041010050500013M02606",
  "valid": true,
  "country": "FR",
  "bank_code": "20041",
  "branch_code": null,
  "bank": { "name": "La Banque Postale", "bic": "PSSTFRPP" },
  "reachable": true,
  "coverage": "partial",
  "issue": null
}

Case 4 — valid IBAN, partial coverage, bank unknown

Under partial coverage a code we don’t recognise is honestly reachable: null — not in our curated subset, not evidence the bank does not exist.

{
  "iban": "FR7630000000000000000000000",
  "valid": true,
  "country": "FR",
  "bank_code": "30000",
  "branch_code": null,
  "bank": null,
  "reachable": null,
  "coverage": "partial",
  "issue": null
}

Case 5 — valid IBAN, country outside the registry

Only the structure is guaranteed: reachable is unknowable.

{
  "iban": "NO9386011117947",
  "valid": true,
  "country": "NO",
  "bank_code": "8601",
  "branch_code": null,
  "bank": null,
  "reachable": null,
  "coverage": "structure_only",
  "issue": null
}

Case 6 — invalid IBAN (successful answer → 200)

country/bank_code are filled in if they could be extracted before the failure (e.g. INVALID_BBAN), otherwise null.

{
  "iban": "DE89370400440532013001",
  "valid": false,
  "country": null,
  "bank_code": null,
  "branch_code": null,
  "bank": null,
  "reachable": null,
  "coverage": null,
  "issue": "BAD_CHECKSUM"
}

Possible issue codes: BAD_CHARACTERS, BAD_LENGTH, BAD_FORMAT, BAD_CHECKSUM, UNKNOWN_COUNTRY, INVALID_BBAN.

Errors

StatuscodeCase
400MISSING_PARAMETERiban parameter missing or empty
500INTERNALInternal error (detail logged, not exposed)
{ "error": "missing or empty required parameter: iban", "code": "MISSING_PARAMETER" }