---
title: "IBAN validator: length, mod-97 check digits, bank/branch/account breakdown (89 countries)"
method: GET
path: "/v1/id/iban"
tags: ["deterministic", "no-api-key", "id", "identifiers", "banking", "validation"]
---

# IBAN validator: length, mod-97 check digits, bank/branch/account breakdown (89 countries)

`GET /v1/id/iban`

## Request

- Base URL: `https://api.duoleads.com`
- URL: `https://api.duoleads.com/v1/id/iban`
- Auth: none declared

IBAN validator: validate an IBAN's length for its country, permitted character classes per field, and the ISO 7064 mod-97-10 check digits. Returns the verdict with a specific failure reason, the electronic and print formats, and the decomposed bank code, branch code and account number according to that country's registered layout. Covers the 89 countries of the SWIFT IBAN registry. Structure and checksum only, it does not confirm the account exists.

**Output (`data`):** valid (boolean), iban (electronic format, no spaces, uppercase), iban_print (grouped in fours), country (first two characters), check_digits, bban, parts ({bank, branch, account}, each string|null per the registry layout for the country; all null when the length, structure or country is wrong), length (actual), expected_length (registry length, null for an unknown country), reason (null | country_unknown | length | charset | structure | checksum, checked in that order), algorithm (always mod-97-10). A failed verdict is a 200, never a 400.

Deterministic: identical input returns identical output, so the response is served with `Cache-Control: private, max-age=31536000, immutable` (the paying client may cache it indefinitely; shared caches must not, because the response is paid).

Sources: iban-registry ibantools 4.5.4, field layout schwifty 2026.7.3 (published 2026-04-10, MIT). Echoed in `meta.sources`.

Price: $0.05 USDC per call (x402, Base). Route contract version 1.0.0. Docs: https://api.duoleads.com/docs#id-iban

## Query parameters

- `iban` string, required

## Response `200`

Paid and settled. `data` is route-specific; a route that judges its input returns 200 with `data.valid: false` for a bad value.

- object
  - `ok` unknown, required
  - `route` '/v1/id/iban', required
  - `version` '1.0.0', required
  - `data` object, required: valid (boolean), iban (electronic format, no spaces, uppercase), iban_print (grouped in fours), country (first two characters), check_digits, bban, parts ({bank, branch, account}, each string|null per the registry layout for the country; all null when the length, structure or country is wrong), length (actual), expected_length (registry length, null for an unknown country), reason (null | country_unknown | length | charset | structure | checksum, checked in that order), algorithm (always mod-97-10). A failed verdict is a 200, never a 400.
    - `valid` boolean, required
    - `iban` string, required
    - `iban_print` string, required
    - `country` string, required
    - `check_digits` string, required
    - `bban` string, required
    - `parts` object, required
      - `bank` string, nullable, required
      - `branch` string, nullable, required
      - `account` string, nullable, required
    - `length` integer, required
    - `expected_length` integer, nullable, required
    - `reason` string, nullable, required
    - `algorithm` string, required
  - `meta` Meta, required
    - `disclaimer` string, required: Legal short disclaimer, identical on every response.
    - `request_id` string, required: ULID.
    - `computed_at` string, date-time, required: RFC 3339 UTC with milliseconds.
    - `price_usd` string, required: Decimal string, "0.05".
    - `deterministic` boolean, required
    - `sources` object[]: Present only on routes that read a vendored dataset: the exact edition that answered.
      - `id` string, required
      - `version` string, required
      - `published` string, required
      - `attribution` string
      - `licence` string

## Other responses

- `400`: MISSING_PARAM, INVALID_PARAM or UNSUPPORTED_VALUE. Not charged: validation runs before the paywall.
- `402`: Payment required. No valid PAYMENT-SIGNATURE was supplied: read the base64 PAYMENT-REQUIRED header (or this body) for the price ($0.05 = 50000 atomic USDC on eip155:8453), sign an EIP-3009 authorization and retry. Also returned when settlement is declined (PAYMENT_FAILED). Nothing is charged on a 402.
- `404`: NOT_FOUND: unknown path. Not charged.
- `405`: METHOD_NOT_ALLOWED: only GET and HEAD are served. Not charged.
- `413`: INPUT_TOO_LARGE: a parameter exceeded its documented maximum length. Not charged.
- `500`: INTERNAL: a server bug. Not charged.

---

[API](https://skmtc.dev/duoleads/apis/duo-data-utilities-iban-isin-vat-tax-id-barcode-timezone-geo.md) · [All operations](https://skmtc.dev/duoleads/apis/duo-data-utilities-iban-isin-vat-tax-id-barcode-timezone-geo/llms.txt) · [OpenAPI document](https://skmtc.dev/duoleads/apis/duo-data-utilities-iban-isin-vat-tax-id-barcode-timezone-geo/revisions/18790d59615e?raw)
