Fraud prevention for merchants
How to spot a fake credit card number
Fake credit card detection is a layered job. Some checks run instantly in the browser, some need a BIN lookup, and only the issuing bank can confirm that an account really exists. This guide walks through each layer from a merchant’s and developer’s point of view.
Key takeaways
- Format checks (prefix, length, Luhn, expiry, CVV length) catch typos and random digits instantly, but anyone can produce numbers that pass them.
- A BIN lookup tells you the network, issuer country and card type, so you can spot mismatches with the customer’s IP address or billing country.
- Only an authorization or a $0 account verification proves that an account exists; CVV, AVS and 3-D Secure results add evidence about the person using it.
- Stolen real cards pass every format check, so velocity rules and behavior signals matter as much as validating the number.
On this page
- What “fake” means at a checkout
- Layer 1: format checks you can run instantly
- What the Luhn check can and can’t prove
- Layer 2: BIN lookup consistency
- Layer 3: let the issuer answer
- Red flags at checkout
- Physical cards at the counter
- Test your checks without real cards
- Putting the layers together
- Frequently asked questions
When merchants talk about a “fake” card number, they usually mean one of four very different things. Each one is caught by a different check, and treating them as one problem is how checkouts end up either rejecting good customers or letting fraud through. This guide separates them, then shows which signals you can collect at each stage of a payment.
What “fake” means at a checkout
| Type | Example | Caught by |
|---|---|---|
| Typo in a real number | Two digits swapped while typing | Luhn check in the form |
| Random or made-up digits | Someone mashes the keyboard | Prefix, length and Luhn checks |
| Generated, format-valid number | Output of a test card generator | The issuer’s authorization response |
| Stolen real card | Details taken in a data breach or phishing | CVV, AVS, 3-D Secure, velocity and behavior signals |
The first two are honest mistakes or low-effort junk, and your form should catch them before any request leaves the browser. A generated number passes every format rule by design, so only the bank can reject it. The fourth is the case that costs merchants money: the number is perfectly real, and the question becomes whether the person typing it is the cardholder.
Layer 1: format checks you can run instantly
Format validation is free, fast and private. It runs in the browser before submission and catches most typing errors. Use it to give helpful messages, not as a fraud verdict.
Brand prefix and length
The first digits of a card number, the issuer identification number (IIN), identify the network. Each network also has a fixed set of lengths. A number that starts with 34 but has 16 digits is not a valid American Express number, whatever else is true about it.
| Brand | Starts with | Length | Security code |
|---|---|---|---|
| Visa | 4 | 13, 16 or 19 | 3 digits |
| Mastercard | 51–55, 2221–2720 | 16 | 3 digits |
| American Express | 34, 37 | 15 | 4 digits (front) |
| Discover | 6011, 644–649, 65 | 16–19 | 3 digits |
| JCB | 3528–3589 | 16–19 | 3 digits |
| Diners Club | 300–305, 36, 38–39 | 14–19 | 3 digits |
| UnionPay | 62 | 16–19 | 3 digits |
The full list, including Maestro and spacing rules, is on our card number format page. Keep these tables in one place in your code: ranges do change (Mastercard’s 2-series range is a relatively recent addition), and a stale list rejects real customers.
Luhn checksum
The last digit of every major card number is a check digit calculated with the Luhn algorithm. If a customer mistypes one digit, or swaps most pairs of neighboring digits, the checksum fails and you can ask them to check the number before they press “Pay”.
Expiry date
Reject months outside 01–12 and dates in the past. A card is normally valid until the last day of the printed month, so 10/26 is still good on 31 October 2026. Also cap how far ahead you accept: cards are rarely issued for more than a handful of years, and a year like 2099 is almost always a typo or a test value.
Security code length
American Express uses a four-digit code printed on the front; the other major brands use three digits on the back. Validate the length for the detected brand. You cannot check whether the code is correct — only the issuer can, because the value is derived from secret keys (see our guide to CVV, CVC and CID).
A compact browser-side check looks like this. It returns a reason you can show to the customer, not a fraud score:
function luhnOk(num) {
let sum = 0, dbl = false;
for (let i = num.length - 1; i >= 0; i--) {
let d = num.charCodeAt(i) - 48;
if (dbl) { d *= 2; if (d > 9) d -= 9; }
sum += d; dbl = !dbl;
}
return sum % 10 === 0;
}
const BRANDS = [
{ name: 'amex', re: /^3[47]/, lengths: [15], cvc: 4 },
{ name: 'visa', re: /^4/, lengths: [13, 16, 19], cvc: 3 },
{ name: 'mastercard', re: /^(5[1-5]|222[1-9]|22[3-9]\d|2[3-6]\d\d|27[01]\d|2720)/, lengths: [16], cvc: 3 },
];
function checkCard(raw, cvc) {
const num = raw.replace(/[\s-]/g, '');
if (!/^\d{12,19}$/.test(num)) return 'Card number must be 12–19 digits';
const brand = BRANDS.find(b => b.re.test(num));
if (!brand) return 'Card type not accepted';
if (!brand.lengths.includes(num.length)) return 'Wrong length for ' + brand.name;
if (!luhnOk(num)) return 'Please check the card number';
if (!new RegExp('^\\d{' + brand.cvc + '}$').test(cvc)) return 'Security code must be ' + brand.cvc + ' digits';
return null; // well formed – the issuer still decides
}For the full set of brand patterns, tested in three languages, see our credit card regex guide. You can also paste any number into the credit card validator to see each check step by step.
What the Luhn check can and can’t prove
The Luhn check is the most misunderstood part of fake credit card detection. It is an error-detection code from the 1950s, not a security feature, and the arithmetic is public.
| Question | Can Luhn answer it? |
|---|---|
| Did the customer mistype one digit? | Yes — every single-digit error changes the checksum |
| Did they swap two neighboring digits? | Almost always (the swap 09 ↔ 90 is the exception) |
| Is this number issued to a real account? | No |
| Is the card active, unexpired and not blocked? | No |
| Is the person typing it the cardholder? | No |
| Was this number generated rather than typed from a card? | No — about one in ten random strings pass, and generators always pass |
So a Luhn failure is a strong reason to stop and ask the customer to retype. A Luhn pass tells you almost nothing about fraud.
Layer 2: BIN lookup consistency
The first six or eight digits — the BIN — identify the issuer’s range. A BIN lookup returns the network, the issuing bank, the country and often whether the card is credit, debit or prepaid. That data does not prove a card is real, but it lets you test whether the story of the order hangs together.
Signals worth comparing
- Issuer country vs. IP country and billing country. A card issued in one country, a billing address in a second and an IP address in a third is worth a closer look, especially for high-value or digital goods.
- Prepaid cards. Prepaid cards are legitimate payment methods, but some businesses — subscriptions with free trials, rentals, high-risk goods — choose to review or decline them.
- Unknown or unassigned BINs. A prefix that no BIN database knows may be a new range, but it can also point to random digits.
- Brand mismatch. If the BIN data says the range belongs to a different network than your prefix rules detected, check your brand table first — it may be out of date.
Mismatches are signals, not verdicts
Travellers, expats, cross-border shoppers and VPN users all create honest mismatches. Use BIN data to decide how much verification to ask for — for example, triggering 3-D Secure or a manual review — rather than to decline outright.
Layer 3: let the issuer answer
Everything above happens without contacting the bank. The only way to learn whether an account exists, is open and belongs to the person paying is to ask the issuer through the card network.
Authorization and account verification
A normal authorization asks the issuer to approve a specific amount. When you want to check a card without charging it — for example when saving it for later — most gateways offer an account verification: a zero-amount (or very small) authorization that returns approved or declined plus the result of the CVV and address checks. A generated number is declined at this step because the issuer has no such account.
CVV and AVS results
When you send the security code and billing address, the issuer compares them with its records. Gateways report the outcome in normalized fields. Stripe, for example, reports cvc_check, address_line1_check and address_postal_code_check on the card:
| Result | Meaning | Typical action |
|---|---|---|
pass | The value matches the issuer’s records | Proceed |
fail | The value does not match | Decline or ask the customer to correct it |
unavailable | The issuer did not check (common for address checks outside a few countries) | Weigh with other signals |
unchecked | No value was sent, or the check has not run yet | Collect the field if you rely on it |
Visa’s merchant guidance on enumeration recommends requiring CVV2 and AVS on card-not-present transactions, because together they make guessing card details far more expensive. PCI DSS allows you to collect the security code for authorization but not to store it afterwards.
3-D Secure
3-D Secure asks the issuer to authenticate the cardholder directly — with a banking app, a one-time code or biometrics — and is required for many payments in Europe under Strong Customer Authentication. It is the strongest signal that the person paying controls the account, and it can shift liability for fraud chargebacks away from the merchant. Our 3-D Secure testing guide covers how to build and test it.
Red flags at checkout
Stolen real cards pass the format checks and often the issuer checks too, so the best fraud signals are about behavior, not the number itself. Watch for:
- Many different card numbers tried from one device, IP address, email address or account in a short time.
- Several declines followed by a success, especially with different cards or slightly different expiry dates.
- Card numbers in a session that share the same first digits and differ only at the end.
- Lots of very small orders or donations, or zero-value card saves, from new accounts.
- Nonsensical names and email addresses, or the same billing address used with many cards.
- Rush shipping to a freight forwarder or an address that does not match the billing details.
Patterns like these often indicate an automated attack rather than one fraudulent purchase. Our guide to card-testing fraud explains how to detect and stop them.
Physical cards at the counter
For card-present payments, the chip does most of the work: an EMV chip produces a cryptogram for each transaction that a copied magnetic stripe cannot reproduce. If staff handle cards, the classic checks still help — the card number on the front matches the receipt’s last four digits, the printing and hologram look right, and the card is not visibly altered. Insist on chip or contactless rather than swiping whenever the terminal allows it.
Test your checks without real cards
Never use real card numbers to test fraud rules. Use generated numbers for the format layer and your gateway’s documented test cards for the issuer layer. In Stripe test mode, for instance:
| Stripe test card | Simulated result |
|---|---|
4000 0000 0000 0101 | CVC check fails (send a CVC value, or the check is skipped) |
4000 0000 0000 0036 | Postal code check fails |
4000 0000 0000 0028 | Address line 1 check fails |
4100 0000 0000 0019 | Always blocked by Radar as highest risk |
The complete list for each gateway is on our Stripe test cards page and its siblings for other gateways.
Putting the layers together
- In the browser: brand prefix, length, Luhn, expiry and CVV length — clear error messages, no fraud decisions.
- Before authorization: BIN country and card type compared with IP and billing data; velocity limits per device, IP, email and account.
- At authorization: require CVV and postal code, read the check results, and use 3-D Secure where it is required or the risk is elevated.
- After authorization: monitor decline rates and early fraud warnings, and refund suspicious orders before they turn into disputes.
No single layer is enough. Format checks stop typos, issuer checks stop invented numbers, and behavior signals are what catch real cards in the wrong hands.
Frequently asked questions
Can I tell if a credit card number is real just by looking at it?
No. You can tell whether it is well formed: right prefix for the brand, right length, valid Luhn check digit. Whether an account exists behind it is only known to the issuing bank, which answers through an authorization.
Does passing the Luhn check mean a card is valid?
No. The Luhn check only proves that the digits are internally consistent, which catches typing mistakes. Roughly one in ten random digit strings passes it by chance, and generators produce passing numbers on purpose.
What is the best way to detect a fake card online?
Combine layers: validate the format in the browser, compare the BIN’s country and card type with the order, require the CVV and billing postal code, use 3-D Secure where available, and watch for velocity patterns such as many cards from one device.
Is a card from a different country than the customer’s IP a fake?
Not necessarily. Travellers, expats and VPN users create legitimate mismatches. Treat it as one risk signal to weigh with others, for example by asking for 3-D Secure or reviewing the order manually.
Sources
Tools used in this guide
Related guides
Written for developers, QA teams and merchants. Generated card numbers are test data: they are not real cards and cannot pay for anything.