piidetectionapi.com
Home
Solutions - Fundamentals
What Is PII Detection? NER vs Regex vs Rules Accuracy, Precision & Recall PII in Test Data
Solutions - Compliance
GDPR Personal Data HIPAA PHI Detection CCPA / CPRA PCI DSS Card Data
Solutions - AI & LLM Safety
LLM Guardrails Chatbot PII Filtering RAG Pipelines
Solutions - Data Discovery & DLP
Data Loss Prevention Log File Scanning Support Tickets Email Scanning Documents & PDFs Database Discovery ETL & Streaming Pipelines
Industries - Financial
Banking Fintech Insurance
Industries - Healthcare
Healthcare Pharma & Clinical Trials Telehealth
Industries - Public Sector & Legal
Government & FOIA Law Enforcement Law Firms & eDiscovery Education (FERPA)
Industries - Technology
SaaS Platforms Cybersecurity & IR Telecommunications Gaming & Platforms
Industries - Other
HR & Recruiting Retail & E-commerce Call Centers & BPO Real Estate Travel & Hospitality Marketing & AdTech
How-to Guides - Identity & Contact
Detect Names Detect Email Addresses Detect Phone Numbers Detect Physical Addresses Detect Dates of Birth
How-to Guides - IDs & Financial
Detect SSNs Detect Passport Numbers Detect Drivers Licenses Detect Credit Card Numbers Detect Bank Accounts & IBAN
How-to Guides - Technical & Health
Detect IP & Device IDs Detect Medical Records & PHI
Resources
Pricing API Docs Supported Entities Languages About Contact Sign In Try the Live Demo Get Started
How-To Guide

How to Detect Bank Accounts, IBAN & Routing Numbers

Learn how to automatically find, classify, and locate financial account numbers, IBANs, SWIFT/BIC codes, and ABA routing numbers hidden in text, documents, logs, and support conversations using PII Detection API — with character offsets, confidence scores, and optional masking.

12 min read
cURL, Python & JavaScript examples
Updated Aug 2026

Overview

Financial account identifiers are among the most consequential categories of personally identifiable information you can leak. A person's name embarrasses you when it escapes; a person's bank account number, paired with a routing number or IBAN, gives a fraudster everything needed to initiate unauthorized ACH debits, set up fake direct deposits, or execute authorized push payment scams. Yet these numbers turn up constantly in places they were never supposed to live: customer support tickets ("my salary went to the wrong account, it should be GB29 NWBK 6016 1331 9268 19"), chat transcripts, email threads with finance teams, exported CRM notes, application logs that captured a request payload, and free-text fields in loan or onboarding forms.

PII Detection API scans raw text and returns a structured list of every financial identifier it finds — the entity type, the exact matched string, the character offsets where it starts and ends, and a confidence score — so your pipeline can decide what to quarantine, mask, or alert on. Because the detection engine combines transformer-based named entity recognition with format validation (IBAN mod-97 arithmetic, ABA checksum verification, SWIFT/BIC structure rules), it distinguishes a genuine routing number from a nine-digit order ID far more reliably than a regular expression ever could.

Input Text
Refund the customer via IBAN DE89 3704 0044 0532 0130 00. For US wires use routing 021000021, account 4835261098.
Detected & Masked Output
Refund the customer via IBAN [IBAN_CODE]. For US wires use routing [ROUTING_NUMBER], account [FINANCIAL_ACCOUNT_NUMBER].
80+ IBAN Countries
Recognizes every registered IBAN country format, spaced or unspaced
Checksum Validation
Mod-97 and ABA check-digit math cuts false positives dramatically
Context-Aware
Transformer NER separates account numbers from invoice and order IDs

This guide walks through the four entity types involved, country-by-country IBAN structures, how the ABA routing checksum works, complete request examples in cURL, Python, and JavaScript, and the compliance backdrop — chiefly the Gramm-Leach-Bliley Act (GLBA) — that makes detection of financial account data a hard requirement for anyone handling US consumer financial records. If you want to see detection running on your own sample text before reading further, the interactive demo accepts pasted text and highlights every financial identifier in real time.

Why Detect Financial Account Data

Bank account details behave differently from most other PII categories, and that difference shapes how seriously you must treat them. Three characteristics matter.

Direct monetization

Unlike a name or an email address, a bank account number plus routing number is directly monetizable. In the United States, ACH debit fraud requires little more than an account/routing pair and a merchant willing to process the transaction. In the SEPA zone, an IBAN alone is enough to originate a direct debit under the SEPA Core Direct Debit scheme — the safeguards are largely reactive (the account holder can claw back an unauthorized debit within eight weeks) rather than preventive. That means every leaked account identifier is an open attack window, not merely a privacy concern.

Long identifier lifetime

People change email addresses and phone numbers; they very rarely change bank accounts. A checking account number leaked in a 2020 support ticket is very likely still valid today. This long shelf life is why financial regulators treat account numbers as sensitive even in aging archives, and why data-retention reviews and legacy log scans are common triggers for deploying automated detection. Scanning historical data stores for dormant financial identifiers is one of the most frequent first projects our banking customers run — see our banking industry guide for typical rollout patterns.

Regulatory classification

Account numbers sit in the strictest tier of virtually every data protection regime:

  • GLBA (US): account numbers are core "nonpublic personal information" (NPI); the Safeguards Rule requires financial institutions to know where NPI lives and protect it.
  • PCI DSS: while PCI focuses on card data, assessors routinely expect bank account data discovered alongside PANs to be governed by equivalent controls.
  • GDPR (EU): an IBAN is personal data whenever it is linkable to a natural person — which, for consumer accounts, is essentially always.
  • State breach laws (US): nearly every state's breach-notification statute explicitly lists "financial account number in combination with any required security code or access code" as notification-triggering data.

Where leaks actually happen: in our experience the highest-volume sources of stray account numbers are (1) customer support transcripts, (2) application logs that serialize full request bodies, (3) email attachments forwarded to shared inboxes, and (4) free-text "notes" fields in CRMs. Point your first scan at those four.

Detection is the prerequisite for every downstream control. You cannot encrypt, tokenize, redact, or delete account numbers you have not found. That is why the API is detection-first: it tells you precisely what was found, where it sits in the text (character offsets), and how confident the model is — and only optionally rewrites the text for you via mask_mode. Full request and response semantics are documented in the API documentation.

The Four Entity Types

PII Detection API models financial account data as four distinct entity types rather than one catch-all. Keeping them separate matters because they carry different risk profiles and different validation logic, and because most teams want to route them to different handling policies.

Entity type What it matches Validation applied Example
FINANCIAL_ACCOUNT_NUMBER Domestic bank account numbers: US checking/savings (4–17 digits), UK 8-digit account numbers, brokerage and loan account numbers Contextual NER (labels like "acct", "account no.", bank names, sort codes nearby) 4835261098
IBAN_CODE International Bank Account Numbers, spaced or compact, all 80+ registered countries Country prefix, exact per-country length, mod-97 check digits DE89 3704 0044 0532 0130 00
SWIFT_BIC SWIFT / BIC bank identifier codes (8 or 11 characters) Structure: 4-letter bank code + 2-letter country + location code + optional branch DEUTDEFF500
ROUTING_NUMBER US ABA routing transit numbers (9 digits) ABA weighted checksum (3-7-1 rule) + valid Federal Reserve district prefix 021000021

A subtle but important design point: a SWIFT/BIC code identifies a bank, not a person, so on its own it is comparatively low-risk. But a BIC co-occurring with an IBAN or account number in the same passage is the classic wire-instruction pattern, and the combination is exactly what invoice-fraud attackers harvest. Detecting all four types together lets you write policy rules such as "alert when IBAN_CODE and SWIFT_BIC appear within the same document" — the offsets in the response make proximity checks trivial. The full catalog of 150+ supported types is on the entities page.

Note that payment card numbers are handled by separate entity types (CREDIT_CARD_NUMBER, CVV_NUMBER); if your text may contain both card and bank data, request both families in one call — see the credit card detection guide for the card side.

Quick Start

One HTTPS POST is all it takes. Send your text plus the four financial entity types to the moderation endpoint and read back the structured results. The same request shape works from any language; here it is in cURL, Python, and Node.js.

curl -X POST https://piidetectionapi.com/api/moderate.php \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "YOUR_API_KEY",
    "api_type": "pii_detection",
    "text": "Wire funds to IBAN DE89 3704 0044 0532 0130 00 (BIC DEUTDEFF). US clients: routing 021000021, account 4835261098.",
    "entities": ["FINANCIAL_ACCOUNT_NUMBER", "IBAN_CODE", "SWIFT_BIC", "ROUTING_NUMBER"],
    "mask_mode": "replace"
  }'
import requests

resp = requests.post(
    "https://piidetectionapi.com/api/moderate.php",
    json={
        "api_key": "YOUR_API_KEY",
        "api_type": "pii_detection",
        "text": "Wire funds to IBAN DE89 3704 0044 0532 0130 00 (BIC DEUTDEFF). "
                "US clients: routing 021000021, account 4835261098.",
        "entities": ["FINANCIAL_ACCOUNT_NUMBER", "IBAN_CODE",
                     "SWIFT_BIC", "ROUTING_NUMBER"],
        "mask_mode": "replace",
    },
    timeout=30,
)
data = resp.json()
for e in data["detected_entities"]:
    print(e["type"], e["text"], e["start"], e["end"], e["confidence"])
const resp = await fetch("https://piidetectionapi.com/api/moderate.php", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    api_key: "YOUR_API_KEY",
    api_type: "pii_detection",
    text: "Wire funds to IBAN DE89 3704 0044 0532 0130 00 (BIC DEUTDEFF). " +
          "US clients: routing 021000021, account 4835261098.",
    entities: ["FINANCIAL_ACCOUNT_NUMBER", "IBAN_CODE",
               "SWIFT_BIC", "ROUTING_NUMBER"],
    mask_mode: "replace"
  })
});
const data = await resp.json();
data.detected_entities.forEach(e =>
  console.log(e.type, e.text, e.start, e.end, e.confidence));

The response gives you both the entity list and, because mask_mode was set, the rewritten text:

{
  "detected_entities": [
    {"type": "IBAN_CODE", "text": "DE89 3704 0044 0532 0130 00", "start": 19, "end": 46, "confidence": 0.99},
    {"type": "SWIFT_BIC", "text": "DEUTDEFF", "start": 52, "end": 60, "confidence": 0.97},
    {"type": "ROUTING_NUMBER", "text": "021000021", "start": 83, "end": 92, "confidence": 0.98},
    {"type": "FINANCIAL_ACCOUNT_NUMBER", "text": "4835261098", "start": 102, "end": 112, "confidence": 0.93}
  ],
  "anonymized_text": "Wire funds to IBAN [IBAN_CODE] (BIC [SWIFT_BIC]). US clients: routing [ROUTING_NUMBER], account [FINANCIAL_ACCOUNT_NUMBER].",
  "entities_detected": 4,
  "processing_time_ms": 142,
  "mask_mode_used": "replace",
  "status": 200
}

If you only need detection — for example, to raise a DLP alert without altering the document — simply omit mask_mode and ignore anonymized_text; the detected_entities array is always returned. Requests accept up to 50,000 characters of text each, so a typical support ticket, contract page, or log batch fits comfortably in one call.

IBAN Formats by Country

The International Bank Account Number standard (ISO 13616) wraps each country's domestic account structure in a uniform envelope: a two-letter country code, two check digits, and then a country-defined Basic Bank Account Number (BBAN). What trips up naive detectors is that the total length varies by country — from 15 characters in Norway to 33 in Russia — and the BBAN may be purely numeric (Germany) or mix letters and digits (UK, Netherlands, Italy). A detector that only knows "two letters plus digits" will both miss valid IBANs and flag random reference codes.

PII Detection API validates the country prefix against the official IBAN registry, enforces the exact length for that country, and runs the ISO 7064 mod-97 check: move the first four characters to the end, convert letters to numbers (A=10 … Z=35), and the resulting large integer modulo 97 must equal 1. A 26-character string with a Polish PL prefix that fails mod-97 is almost certainly not an IBAN, and the engine scores it accordingly.

Country Length BBAN structure Example (spaced)
Germany (DE)228-digit bank code + 10-digit accountDE89 3704 0044 0532 0130 00
United Kingdom (GB)224-letter bank code + 6-digit sort code + 8-digit accountGB29 NWBK 6016 1331 9268 19
France (FR)275-digit bank + 5-digit branch + 11-char account + 2-digit keyFR14 2004 1010 0505 0001 3M02 606
Netherlands (NL)184-letter bank code + 10-digit accountNL91 ABNA 0417 1643 00
Spain (ES)244-digit bank + 4-digit branch + 2 check + 10-digit accountES91 2100 0418 4502 0005 1332
Italy (IT)271 check letter + 5-digit ABI + 5-digit CAB + 12-char accountIT60 X054 2811 1010 0000 0123 456
Poland (PL)288-digit bank/branch + 16-digit accountPL61 1090 1014 0000 0712 1981 2874
Switzerland (CH)215-digit bank code + 12-char accountCH93 0076 2011 6238 5295 7
Norway (NO)154-digit bank + 6-digit account + 1 check digit (shortest IBAN)NO93 8601 1117 947
United Arab Emirates (AE)233-digit bank code + 16-digit accountAE07 0331 2345 6789 0123 456
Brazil (BR)298-digit bank + 5-digit branch + 10-digit account + type + ownerBR18 0036 0305 0000 1000 9795 493C 1
Saudi Arabia (SA)242-digit bank code + 18-char accountSA03 8000 0000 6080 1016 7519

Real-world text rarely presents IBANs in tidy four-character groups. People type them compact (DE89370400440532013000), with inconsistent spacing, in lowercase, split across line breaks in emails, or prefixed with labels in local languages ("Kontonummer", "N° de compte"). The detection model normalizes all of these before validating, and the returned start/end offsets always reference the original, unnormalized text so your masking or highlighting stays byte-accurate.

Watch out: The United States, Canada, Australia, and most of Asia do not use IBANs. Text from those regions carries domestic account formats instead — which is exactly why you should request FINANCIAL_ACCOUNT_NUMBER and ROUTING_NUMBER alongside IBAN_CODE rather than relying on IBAN detection alone for global coverage.

Routing Numbers & the ABA Checksum

A US ABA routing transit number is nine digits identifying the financial institution in a transaction. Its first two digits historically encode the Federal Reserve district (00–12 for banks, 21–32 for thrifts, 61–72 for electronic transactions), and its final digit is a checksum. The checksum uses a 3-7-1 weighting: multiply digits 1, 4, 7 by 3; digits 2, 5, 8 by 7; digits 3, 6, 9 by 1; the sum must be divisible by 10. For 021000021: (0×3 + 2×7 + 1×1) + (0×3 + 0×7 + 0×1) + (0×3 + 2×7 + 1×1) = 15 + 0 + 15 = 30 — divisible by 10, so structurally valid.

This math matters because nine-digit numbers are everywhere in business text: ZIP+4 codes without hyphens, order numbers, tax IDs, and Social Security numbers are all nine digits. Roughly 10% of random nine-digit strings pass the ABA checksum by chance, so the checksum alone is not sufficient either — which is where context modeling earns its keep. The engine weighs surrounding tokens ("routing", "ABA", "RTN", bank names, the co-occurrence of an account number) and the prefix-validity rule before committing to a ROUTING_NUMBER label. A nine-digit number following "SSN:" will be classified as SSN instead, even if it happens to pass the ABA checksum; our SSN detection guide covers that boundary in detail.

Account numbers: the hardest of the four

Domestic account numbers have no checksum and no fixed length — US accounts run anywhere from 4 to 17 digits at the bank's discretion. Pure pattern matching is hopeless here; classification is driven almost entirely by context. The model looks for account-labeling vocabulary, bank names, routing numbers or sort codes nearby, and transactional phrasing ("deposit to", "debit from", "beneficiary account"). This is also where the threshold parameter becomes your main tuning lever: in high-recall audit scans, drop it to 0.35–0.4 and accept more borderline candidates; in inline masking of customer-visible text, keep it at 0.6+ so an order number is not mangled into [FINANCIAL_ACCOUNT_NUMBER].

More Code Examples

High-recall audit scan with a lowered threshold

When sweeping a legacy data store you generally prefer false positives over misses. Lower the confidence threshold and route everything to human review:

import requests

def audit_scan(text):
    resp = requests.post(
        "https://piidetectionapi.com/api/moderate.php",
        json={
            "api_key": "YOUR_API_KEY",
            "api_type": "pii_detection",
            "text": text,
            "entities": ["FINANCIAL_ACCOUNT_NUMBER", "IBAN_CODE",
                         "SWIFT_BIC", "ROUTING_NUMBER",
                         "CREDIT_CARD_NUMBER"],
            "threshold": 0.35,  # favor recall over precision
        },
        timeout=30,
    )
    return [
        e for e in resp.json()["detected_entities"]
    ]

hits = audit_scan(open("exported_tickets.txt").read()[:50000])
for e in hits:
    flag = "REVIEW" if e["confidence"] < 0.6 else "CONFIRMED"
    print(f"{flag}: {e['type']} '{e['text']}' at {e['start']}-{e['end']}")

Consistent hashing for analytics pipelines

Sometimes you must remove account numbers but still need to join records that reference the same account — reconciliation logs, fraud analytics, dispute threads. mask_mode: "hash" replaces each value with a stable hash, so the same account number always produces the same token without ever exposing the number itself:

// Sanitize payment-ops log lines before they reach the data warehouse
async function sanitizeLogBatch(lines) {
  const resp = await fetch("https://piidetectionapi.com/api/moderate.php", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      api_key: process.env.PII_API_KEY,
      api_type: "pii_detection",
      text: lines.join("\n"),
      entities: ["FINANCIAL_ACCOUNT_NUMBER", "IBAN_CODE",
                 "SWIFT_BIC", "ROUTING_NUMBER"],
      mask_mode: "hash"   // same account => same token, joins still work
    })
  });
  const data = await resp.json();
  console.log(`masked ${data.entities_detected} identifiers in ${data.processing_time_ms}ms`);
  return data.anonymized_text.split("\n");
}

Excluding known test accounts with custom_instruction

Payment teams often have well-known sandbox values (test IBANs, dummy routing numbers) that would otherwise clutter every scan. Use custom_instruction to state exclusions in plain English, or exclude_entities to drop a whole type:

curl -X POST https://piidetectionapi.com/api/moderate.php \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "YOUR_API_KEY",
    "api_type": "pii_detection",
    "text": "Test with IBAN DE75512108001245126199 then pay the customer at NL91 ABNA 0417 1643 00.",
    "entities": ["IBAN_CODE", "FINANCIAL_ACCOUNT_NUMBER", "ROUTING_NUMBER"],
    "mask_mode": "replace",
    "custom_instruction": "Ignore the documented sandbox test IBAN DE75512108001245126199 and any account labeled as a test fixture."
  }'

Only the genuine Dutch IBAN comes back in detected_entities; the sandbox value is left untouched in the masked output.

GLBA & the Regulatory Context

For US financial institutions, the Gramm-Leach-Bliley Act is the primary reason account-number detection moves from "nice to have" to "control objective". GLBA's Safeguards Rule (16 CFR Part 314, substantially strengthened in the 2021–2023 revisions) requires covered institutions — banks, but also mortgage brokers, payday lenders, tax preparers, auto dealers extending credit, and fintechs — to maintain a written information security program built on a risk assessment of where customer NPI is collected, stored, and transmitted.

Two Safeguards Rule elements map directly onto automated detection:

  • Data inventory (§314.4(c)(1)): you must know where customer information resides. Unstructured stores — ticket systems, chat logs, shared drives, email — cannot be inventoried by schema inspection; they must be scanned. Running detection across those stores is how the inventory gets built and kept current. Our DLP guide shows how teams wire the API into scheduled discovery jobs.
  • Access and disposal controls (§314.4(c)(6)): NPI must be disposed of when no longer needed. Detection with offsets lets you surgically redact account numbers from records you otherwise must retain — masking the identifier while preserving the ticket or transcript for its operational value.

Outside the US, the same detection output serves GDPR Article 32 (security of processing) and Article 30 records-of-processing obligations for IBAN data, and supports PSD2-era operational-risk expectations on European payment institutions. Because the API can be deployed on-premise as well as consumed as a cloud service, institutions with data-residency constraints can keep the entire scan pipeline inside their own network boundary; contact us about on-premise licensing, or review pricing for the hosted tiers.

Practical framing for auditors: "We scan all unstructured customer-facing text stores weekly for FINANCIAL_ACCOUNT_NUMBER, IBAN_CODE, SWIFT_BIC and ROUTING_NUMBER entities at threshold 0.4; hits above 0.6 are auto-masked, hits between 0.4 and 0.6 are human-reviewed within 48 hours" is a control statement assessors can test. Detection APIs make it cheap to operate.

Best Practices

1. Always request the full financial family together

Account data travels in convoys: an IBAN is usually near a BIC, a routing number near an account number, and card numbers near all of them. Requesting a single type creates blind spots. A sensible default entity list for financial text is FINANCIAL_ACCOUNT_NUMBER, IBAN_CODE, SWIFT_BIC, ROUTING_NUMBER, CREDIT_CARD_NUMBER, plus PERSON_NAME — because an account number tied to a name is the combination regulators actually care about.

2. Tune threshold per use case, not globally

Run inline chat masking at 0.6+, batch archive audits at 0.35–0.4, and alerting somewhere between. The confidence score exists so different consumers of the same API can make different precision/recall trade-offs; hard-coding one threshold for every pipeline wastes that flexibility.

3. Use offsets, not string replacement

When you post-process results yourself, always cut on the returned start/end offsets rather than searching for the matched text. Account numbers can appear multiple times with different roles, and naive find-and-replace will happily rewrite an unrelated occurrence — or a substring of a longer number.

4. Scan before storage, not after

The cheapest place to catch an account number is at the ingestion boundary: the support-ticket webhook, the log shipper, the ETL step. Retrofit scans of data lakes are possible (and often required once), but a 150ms synchronous check at write time keeps the store clean permanently. Median processing time is well under 200ms for typical payloads, which fits inside most ingestion budgets.

5. Keep an eye on partial and obfuscated numbers

Users self-redact ("account ending 1098") and support agents paste last-four references constantly. Decide explicitly whether last-four fragments are in scope for your policy. The model does not flag bare last-four fragments as full account numbers — that is deliberate, since masking "ending 1098" usually destroys utility without reducing real risk — but combining fragments with custom_instruction lets you widen the net when a stricter policy demands it.

Edge Cases

Numbers that collide across types

Nine digits might be a routing number, an SSN, or a ZIP+4. Twenty-two alphanumeric characters might be a German IBAN or a shipping container reference. The engine resolves collisions with three signals in order: format validation (checksums are strong evidence), labeled context (the token before the number), and discourse context (what the passage is about). When two labels remain plausible, the higher-confidence one wins and the score reflects the ambiguity — another reason to route mid-confidence hits to review rather than dropping them.

OCR and transcription noise

Account data arriving from scanned remittance advice or call transcripts brings substitution errors: O for 0, l for 1, S for 5, and spoken digits ("zero two one, zero zero zero, zero two one"). The model tolerates common OCR confusions inside otherwise well-formed IBANs, and detects digit-sequence account references in conversational transcripts. For voice-channel pipelines, pair this page's entity set with the patterns in our call center guide.

Sort codes, BSBs, and transit numbers

Several countries pair a short branch code with the account number: UK sort codes (6 digits, often written 60-16-13), Australian BSBs (6 digits), Canadian transit numbers (5 digits + 3-digit institution). These are detected under FINANCIAL_ACCOUNT_NUMBER context handling when adjacent to an account, since a bare six-digit number in isolation is rarely classifiable — or attackable — on its own.

Multilingual labels

Detection works across 60+ languages, which matters most here for the labels around the numbers: "Kontonummer", "numéro de compte", "número de cuenta", "口座番号". A German email whose only English content is the IBAN itself is still parsed correctly because the surrounding German context feeds the model. The full list is on the supported languages page.

Do not build a regex fallback. Teams sometimes bolt a regex layer "for safety" on top of model output. In practice this reintroduces every false positive the validation logic was built to remove — flagging invoice numbers, timestamps, and tracking codes — and trains downstream reviewers to ignore alerts. If recall worries you, lower threshold instead; that keeps the checksum and context machinery in the loop.

Frequently Asked Questions

Does the API validate that an IBAN's check digits are correct?

Yes. Every IBAN candidate is checked against the country registry for prefix and length and against the ISO 7064 mod-97 rule. Strings that fail validation are either suppressed or returned with sharply reduced confidence, depending on how strong the surrounding context is. This is the main reason IBAN detection precision is materially higher than for unformatted account numbers.

Can it tell a routing number apart from an SSN? Both are nine digits.

In almost all real text, yes. The classifier uses the ABA checksum, the valid-prefix rule, and — most decisively — context: "routing"/"ABA"/bank names versus "SSN"/"social" and personal-record context. If your text genuinely contains both, request both entity types in one call and each number is labeled independently.

What happens with account numbers of unusual length?

US account numbers from 4 to 17 digits are in scope, as are longer international domestic formats. Very short numeric strings (under 4 digits) are never flagged as accounts. Because there is no universal checksum, unusual-length candidates lean heavily on context, so their confidence scores tend to sit in the middle of the range — plan your threshold accordingly.

Can I detect bank data in languages other than English?

Yes — detection is trained across 60+ languages, and financial-label vocabulary ("Kontonummer", "IBAN", "compte", "cuenta") is covered in each. The numbers themselves are language-neutral; it is the context words that vary, and those are modeled natively rather than translated.

Does masking change the character offsets in the response?

No. The start and end offsets in detected_entities always refer to the original input text, regardless of mask_mode. The masked string is returned separately in anonymized_text. If you need to map entities onto the masked text, apply replacements from the end of the string backwards using the original offsets.

Is this enough for PCI DSS scope reduction?

PCI DSS concerns cardholder data, which is covered by the separate CREDIT_CARD_NUMBER, CREDIT_CARD_EXPIRATION_DATE, and CVV_NUMBER entities — include them alongside the bank entities when scanning payment environments. For the discovery obligations specifically, see the PCI DSS cardholder data discovery guide.

How do I try it before integrating?

Paste any sample text into the live demo — it runs the same production models and highlights each detected entity with its type and confidence. When you are ready to integrate, create an API key and check pricing; the free tier is enough to validate accuracy on your own data.

Start Detecting Financial Account Data Today

Test IBAN, routing number, and account detection on your own text in seconds — then integrate with three lines of code.

Try the Live Demo View Pricing