Updated 2 min read By Namso Gen
Understanding BIN Numbers: A Developer's Guide

Understanding BIN Numbers: A Developer's Guide

What is a BIN/IIN Number?

A Bank Identification Number (BIN), formally the Issuer Identification Number (IIN), is the first 6 or 8 digits of a payment card number. It identifies the card network and the institution that issued the card. Payment systems use it to route transactions, apply fraud rules and decide which validation rules apply.

The IIN was historically 6 digits. Since the 2017 revision of ISO/IEC 7812-1, new IINs are 8 digits, and Visa and Mastercard have been issuing 8-digit BINs since April 2022. Older 6-digit BINs are still in circulation, so your code has to handle both.

BIN Number Structure

Standard Format Breakdown

Position Length Purpose Example
1 1 digit Major Industry Identifier (MII) 4 (banking and financial)
1–6 or 1–8 6 or 8 digits Issuer Identification Number (BIN/IIN), including the MII 453201 or 45320151
After the BIN, up to the second-to-last digit Variable Individual account identifier 5112830
Last 1 digit Luhn check digit 6

Major Industry Identifier (MII) Values

These are the ISO/IEC 7812-1 categories for the first digit:

MII Digit Industry
0 ISO/TC 68 and other industry assignments
1 Airlines
2 Airlines, financial and other future industry assignments
3 Travel and entertainment
4 Banking and financial
5 Banking and financial
6 Merchandising and banking/financial
7 Petroleum and other future industry assignments
8 Healthcare, telecommunications and other future industry assignments
9 For assignment by national standards bodies
Interactive

BIN anatomy explorer

Paste a card number to see what each part of it means.

Common BIN Ranges by Card Network

Primary BIN Ranges

These are the main published ranges. Each network also has smaller ranges, so treat this as a classification aid, not a complete register.

bin_ranges = {
    'Visa': ['4'],
    'Mastercard': ['51-55', '2221-2720'],
    'American Express': ['34', '37'],
    'Discover': ['6011', '644-649', '65'],
    'JCB': ['3528-3589'],
    'Diners Club': ['300-305', '3095', '36', '38-39'],
    'UnionPay': ['62', '8100-8171'],
}

Discover's network also accepts UnionPay cards (including the 622126–622925 range) and Diners Club cards in the US, but those cards still belong to their own networks.

BIN Lookup Implementation

import re

NETWORK_LENGTHS = {
    'Visa': {13, 16, 19},
    'Mastercard': {16},
    'American Express': {15},
    'Discover': {16, 17, 18, 19},
    'JCB': {16, 17, 18, 19},
    'Diners Club': {14, 15, 16, 17, 18, 19},
    'UnionPay': {16, 17, 18, 19},
}


def detect_network(number: str) -> str:
    first2, first4 = int(number[:2]), int(number[:4])
    if number.startswith(('34', '37')):
        return 'American Express'
    if number.startswith(('300', '301', '302', '303', '304', '305', '3095', '36', '38', '39')):
        return 'Diners Club'
    if 3528 <= first4 <= 3589:
        return 'JCB'
    if number.startswith(('6011', '65')) or 644 <= int(number[:3]) <= 649:
        return 'Discover'
    if number.startswith('62') or 8100 <= first4 <= 8171:
        return 'UnionPay'
    if 51 <= first2 <= 55 or 2221 <= first4 <= 2720:
        return 'Mastercard'
    if number.startswith('4'):
        return 'Visa'
    return 'Unknown'


def validate_bin(card_number: str) -> dict:
    number = re.sub(r'\D', '', card_number)
    if len(number) < 6:
        return {'valid': False, 'error': 'Enter at least 6 digits'}

    network = detect_network(number)
    return {
        'bin': number[:8] if len(number) >= 16 else number[:6],
        'network': network,
        'length': len(number),
        'valid_length': len(number) in NETWORK_LENGTHS.get(network, set(range(12, 20))),
    }

Whether the BIN is 6 or 8 digits depends on the issuer, so the snippet keeps the first 8 digits for full-length numbers. Lookup services accept either.

BIN Data Properties

Typical BIN Lookup Fields

There is no standard schema: these are the fields most commercial and open BIN lookup services return, and the names vary by provider.

Field Description Example
scheme Card network "visa"
country Issuing country "US"
type Card type "credit"
category Card level or product "platinum"
issuer Issuing bank "CHASE"
length Card number length 16

BIN-Based Validation Rules

Card Number Length by Network

Network Valid Lengths
Visa 13, 16, 19
Mastercard 16
American Express 15
Discover 16–19
JCB 16–19
Diners Club 14–19 (36), 16–19 (other ranges)
UnionPay 16–19

Integration Example

const NETWORK_LENGTHS = {
  visa: [13, 16, 19],
  mastercard: [16],
  amex: [15],
  discover: [16, 17, 18, 19],
  jcb: [16, 17, 18, 19],
  diners: [14, 15, 16, 17, 18, 19],
  unionpay: [16, 17, 18, 19],
};

const binValidator = {
  checkBIN(cardNumber) {
    const digits = cardNumber.replace(/\D/g, '');

    if (digits.length < 6) {
      return { valid: false, error: 'Enter at least 6 digits' };
    }

    const network = this.detectNetwork(digits);
    const lengths = NETWORK_LENGTHS[network] || [];

    return {
      valid: lengths.includes(digits.length),
      network,
      bin: digits.slice(0, digits.length >= 16 ? 8 : 6),
      cardLength: digits.length,
    };
  },

  detectNetwork(digits) {
    const first4 = Number(digits.slice(0, 4));
    if (/^3[47]/.test(digits)) return 'amex';
    if (/^(30[0-5]|3095|36|3[89])/.test(digits)) return 'diners';
    if (first4 >= 3528 && first4 <= 3589) return 'jcb';
    if (/^(6011|64[4-9]|65)/.test(digits)) return 'discover';
    if (/^62/.test(digits) || (first4 >= 8100 && first4 <= 8171)) return 'unionpay';
    if (/^5[1-5]/.test(digits) || (first4 >= 2221 && first4 <= 2720)) return 'mastercard';
    if (/^4/.test(digits)) return 'visa';
    return 'unknown';
  },
};

Security Considerations

  1. Data protection

    • A BIN on its own is not cardholder data, but a full card number (PAN) is. Avoid storing full PANs; if you must, PCI DSS Requirement 3 requires them to be rendered unreadable (strong cryptography, truncation, tokenization or keyed hashing).
    • If you keep a truncated number, stay within the PCI SSC truncation limits: at most the first 8 and any other 4 digits for 16-digit PANs, and the first 6 and last 4 for 15-digit Amex numbers.
    • Encrypt full card numbers in transit (TLS) and restrict who can access them.
  2. Compliance

    • Storing or processing full PANs brings your systems into PCI DSS scope; tokenization through your payment provider keeps most of it out.
    • Define retention periods for anything derived from card data, including logs.
  3. Performance

    • Cache BIN lookup results; BIN data changes slowly.
    • Respect your lookup provider's rate limits and use bulk endpoints where available.

Best Practices for BIN Processing

Practice Purpose Implementation
Caching Reduce API calls Store BIN data in memory or a local table
Validation Prevent errors Check format, length and Luhn before calling an API
Monitoring Detect issues Log lookup failures and unknown BINs
8-digit support Stay accurate Match on 8 digits first, then fall back to 6

BIN data is a classification aid, not proof that a card exists or will be approved. Combine it with the Luhn check, length rules and, for real payments, the authorization result from your gateway.

Related articles