🐍 PythonFintech / Payments

Fintech Onboarding Validation

Validate IBAN, BIC/SWIFT, credit card numbers, and UK sort codes in Python using asyncio.gather for parallel API calls. Covers SEPA eligibility, bank identity matching, and card network detection.

Also available in Node.js

1. Payment identifiers covered

IdentifierEndpointUse case
IBAN/v0/ibanEU/international bank account numbers
BIC/SWIFT/v0/bicBank identifier codes for wire transfers
Credit Card/v0/credit-cardCard numbers — network, type, issuer
Sort Code/v0/sort-codeUK domestic bank routing codes

2. Validate IBAN

Use await iv.iban(value) (SDK) or GET /v0/iban?value=….

{
  "valid": true,
  "countryCode": "DE",
  "countryName": "Germany",
  "bban": "370400440532013000",
  "isEU": true,
  "isSEPA": true,
  "bankCode": "37040044",
  "bankName": "Commerzbank",
  "bankBic": "COBADEFFXXX"
}
  1. Check valid — structural + checksum pass
  2. Check isSEPA for Euro payments eligibility
  3. Use bankBic to pre-fill or verify BIC field
  4. Surface countryName for user confirmation

3. Validate BIC / SWIFT

Use await iv.bic(value) (SDK) or GET /v0/bic?value=….

{
  "valid": true,
  "bic": "COBADEFFXXX",
  "bankCode": "COBA",
  "countryCode": "DE",
  "locationCode": "FF",
  "branchCode": "XXX",
  "bank": "Commerzbank",
  "city": "Frankfurt am Main"
}
  1. Verify valid (format + ISO 9362 structure)
  2. Confirm countryCode matches IBAN country
  3. Show bank and city for user confirmation

4. Validate credit card number

Use await iv.credit_card(value) (SDK) or GET /v0/credit-card?value=….

{
  "valid": true,
  "number": "4111111111111111",
  "network": "Visa",
  "cardType": "debit",
  "issuer": "Chase",
  "country": "US",
  "luhn": true
}
  1. Gate on valid and luhn
  2. Check cardType — block prepaid if required by compliance
  3. Log network and country for fraud scoring

5. Validate UK sort code

Use await iv.sort_code(value) (SDK) or GET /v0/sort-code?value=….

{
  "valid": true,
  "sortCode": "200000",
  "formatted": "20-00-00"
}
  1. Check valid — format and known UK sort code range
  2. Display formatted (XX-XX-XX) in UI

6. Parallel validation with asyncio.gather

Run all relevant checks concurrently — only the APIs needed for the payment method and region are called.

import asyncio
from isvalid_sdk import IsValidConfig, create_client

config = IsValidConfig(api_key="YOUR_API_KEY")
iv = create_client(config)

async def validate_payment_method(account_type: str, region: str, data: dict):
    tasks = {}

    if account_type == "bank_transfer":
        if region == "uk":
            tasks["sort_code"] = iv.sort_code(data["sort_code"])
        else:
            tasks["iban"]      = iv.iban(data["iban"])
            tasks["bic"]       = iv.bic(data["bic"])
    elif account_type == "card":
        tasks["card"] = iv.credit_card(data["card_number"])

    results = dict(zip(tasks.keys(), await asyncio.gather(*tasks.values())))

    if "iban" in results and "bic" in results:
        iban_r = results["iban"]
        bic_r  = results["bic"]
        if (iban_r.bank_bic and bic_r.valid
                and iban_r.bank_bic[:6] != bic_r.bic[:6]):
            raise ValueError(
                f"BIC country mismatch: IBAN bank BIC {iban_r.bank_bic} "
                f"vs provided {bic_r.bic}"
            )

    return results

# Example usage
async def main():
    result = await validate_payment_method(
        "bank_transfer",
        "eu",
        {"iban": "DE89370400440532013000", "bic": "COBADEFFXXX"}
    )
    for key, val in result.items():
        print(f"{key}: valid={val.valid}")

asyncio.run(main())

7. Edge cases

IBAN + BIC country mismatch

⚠️Always cross-check iban.bank_bic[:6] with the user-supplied BIC prefix. A German IBAN paired with a French BIC signals either user error or fraud.
if iban_r.bank_bic and bic_r.valid:
    if iban_r.bank_bic[:6] != bic_r.bic[:6]:
        raise ValueError("IBAN/BIC bank mismatch")

Prepaid card detection

card = await iv.credit_card(card_number)
if card.card_type == "prepaid":
    # block or flag for manual review
    raise ValueError("Prepaid cards not accepted")

IBAN valid but not SEPA

ℹ️Structurally valid IBANs from non-SEPA countries (e.g. US, AE) cannot receive SEPA Credit Transfers. Check is_sepa before routing through SEPA rails.
iban = await iv.iban(value)
if iban.valid and not iban.is_sepa:
    use_swift_transfer()   # fall back to SWIFT/correspondent banking

8. Summary checklist

Run IBAN + BIC in parallel with asyncio.gather
Cross-check IBAN bankBic vs user-supplied BIC
Gate SEPA transfers on isSEPA flag
Route UK users through sort_code endpoint
Block prepaid cards when required
Log card network + country for fraud scoring
Use ThreadPoolExecutor for sync requests fallback
Return 422 on validation failures with field-level messages

See also

Ready to integrate?

Free tier — 1,000 requests/month. No credit card required.

Get your API key →