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 |
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
-
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.
-
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.
-
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.