Most credit card numbers are 16 digits. American Express uses 15. Diners Club Classic uses 14. Visa has issued 13-digit and 19-digit numbers. Maestro ranges from 12 to 19. The ISO/IEC 7812 standard permits any length up to 19 digits, and card networks use most of that range.
If your payment form assumes 16, it rejects real cards.
Length by network
| Network | Digits | Prefix | Security code |
|---|---|---|---|
| American Express | 15 | 34, 37 | 4 |
| Diners Club (classic) | 14 | 300–305, 3095, 36, 38, 39 | 3 |
| Diners Club (newer) | 16, 19 | 36, 38, 39 | 3 |
| Discover | 16, 19 | 6011, 622126–622925, 644–649, 65 | 3 |
| JCB | 16–19 | 3528–3589 | 3 |
| Maestro | 12–19 | 50, 56–69 | 3 |
| Mastercard | 16 | 51–55, 2221–2720 | 3 |
| Troy | 16 | 9792 | 3 |
| UnionPay | 16–19 | 62, 81 | 3 |
| V PAY | 16 | 4 | 3 |
| Visa | 13, 16, 19 | 4 | 3 |
| Visa Electron | 16 | 4026, 417500, 4405, 4508, 4844, 4913, 4917 | 3 |
Two notes on reading this table. The prefix column is the published range, not a guarantee that every number in it has been issued — what a prefix identifies is an institution, not a card. And where a network lists several lengths, all of them are current; the shorter ones are not deprecated, merely less common.
Why lengths vary at all
ISO/IEC 7812 defines a maximum of 19 digits for a Primary Account Number. It does not mandate a fixed length, and that single design choice is the source of everything on this page.
Within the ceiling, each network built its own numbering plan, and the total falls out of three components: the issuer identification number, the account identifier the issuer assigns inside it, and one check digit. Change the width of the middle component and the total changes with it — the structure guide works through how the three fit together.
The arithmetic is worth seeing once, because it explains why lengths cluster the way they do. A 16-digit card with a six-digit issuer identifier leaves 16 − 6 − 1 = 9 digits for the account, or a billion cards per issuer identifier. A 15-digit Amex leaves 8, or a hundred million. Once an issuer approaches that ceiling it needs either another identifier or a longer number, and both routes have been taken: the eight-digit IIN migration subdivided the existing space, while the 19-digit ranges extended it. Neither changed the check digit, which has occupied the final position throughout.
Historical decisions then became permanent. American Express settled on 15 and Diners Club on 14 before 16 became the norm, and by the time it did, changing meant reissuing every card and updating every terminal in the world. Later, as networks exhausted their available account space, some extended upward rather than sideways — which is where 19-digit Visa, Discover, and UnionPay numbers come from.
The lengths that break forms
Five lengths cause essentially all the bugs.
15 digits — American Express. A maxlength="16" attribute is harmless, but a check for
length === 16 rejects every Amex card. The display grouping is 4-6-5 rather than 4-4-4-4,
and the security code field has to widen to four digits — which means the code field’s
validation depends on the number field’s brand detection, a coupling that is easy to miss.
The Amex generator produces cards for exactly this
test.
14 digits — Diners Club Classic. The shortest PAN in common circulation. A
minlength="15" rule excludes it entirely, and these cards are still in wallets.
13 digits — legacy Visa. Rare, valid, and killed by the most popular Visa regex on the
internet: ^4\d{15}$ matches 16 digits and nothing else.
19 digits — Visa, Discover, JCB, UnionPay, Maestro. The one that does real damage,
because it fails silently. An input capped at 16 characters truncates on entry; a
VARCHAR(16) column truncates on write with no error raised. The row saves, the stored
number is wrong, and the symptom appears weeks later as declines affecting one subset of
customers. Size inputs at maxlength="23" if you keep the spaces, and columns at
VARCHAR(19) minimum.
12 digits — Maestro. The floor. Maestro’s 12-to-19 span defeats any fixed-length rule by itself, which is why the Maestro generator is the quickest way to find out whether your form has one.
How to validate length correctly
Validate against the brand’s permitted set, not against a single number:
const LENGTHS = {
amex: [15],
diners: [14, 16, 19],
discover: [16, 19],
jcb: [16, 17, 18, 19],
maestro: [12, 13, 14, 15, 16, 17, 18, 19],
mastercard: [16],
troy: [16],
unionpay: [16, 17, 18, 19],
visa: [13, 16, 19],
};
function lengthIsValid(brand, pan) {
const digits = pan.replace(/\D/g, '');
const allowed = LENGTHS[brand];
if (!allowed) return digits.length >= 12 && digits.length <= 19;
return allowed.includes(digits.length);
}
The fallback branch is the important line. When the brand is unrecognised, accept anything from 12 to 19 digits and let the payment provider decide. New BIN ranges appear — the 2-series Mastercard range is the obvious recent example — and a hard reject on an unknown prefix loses real customers, while the provider’s check is authoritative anyway.
The same reasoning applies to the Luhn test on UnionPay: some UnionPay ranges are not
Luhn-valid, so a checksum failure on 62 or 81 should warn
rather than block.
Length alone cannot identify a network
A related mistake is running the inference backwards — treating length as a brand signal. It is not one. Sixteen digits covers Visa, Mastercard, Discover, JCB, UnionPay, Troy, Maestro, newer Diners Club, V PAY, and Visa Electron; the length narrows nothing. Fifteen digits is nearly always American Express, but Maestro reaches 15 as well.
The prefix identifies the network and the length then constrains what is acceptable for that network. Doing it in the other order produces code that misroutes cards whenever a network adds a length — which is precisely what happened to systems that inferred brands before the 19-digit ranges appeared.
Testing for length problems
Length bugs are cheap to catch and expensive to discover in production, because the failures are partial: everything works except one brand, or one product within a brand.
The minimum set of fixtures worth having, one card each:
- 15 digits — Amex, for the
=== 16check and the four-digit security code branch - 14 digits — Diners Club Classic, for minimum-length rules
- 13 digits — legacy Visa, for regexes pinned to 16
- 19 digits — for input truncation, column truncation, and the 4-4-4-4-3 grouping
- 12 digits — Maestro, for the floor
- A 2-series Mastercard — not a length case, but it fails alongside these for the same reason: a rule written before the range existed
Assert on the stored value, not on the form’s acceptance. A 19-digit number that the form accepts and the database truncates passes any test that only checks whether submission succeeded, which is why this specific bug survives so long — the test suite and the bug are looking at different ends of the same request.
Input field configuration
| Setting | Value | Note |
|---|---|---|
maxlength | 23 | 19 digits plus four spaces |
inputmode | numeric | Numeric keypad on mobile |
autocomplete | cc-number | Enables browser and password-manager autofill |
pattern | [0-9\s]* | Digits and spaces |
| Type | text, never number |
That last row causes more grief than its length suggests. type="number" strips leading
zeros, renders spinner arrows on a card field, allows e and + in several browsers, and
on some platforms silently applies locale formatting. A card number is a string of digits,
not a quantity — treat it as text from the input element through to the database column.
Grouping by length
Display grouping follows the length, not the brand:
| Length | Grouping | Example |
|---|---|---|
| 14 | 4-6-4 | 3056 930902 5904 |
| 15 | 4-6-5 | 3782 822463 10005 |
| 16 | 4-4-4-4 | 4539 1488 0343 6467 |
| 19 | 4-4-4-4-3 | 4532 0151 1283 0366 187 |
Every example above is a synthetic, Luhn-valid number produced by the generator and checked before publication — paste any of them into the validator to confirm. None of them belongs to an account.
Get the grouping wrong and nothing breaks technically, but the field stops matching the card in the user’s hand, which measurably increases mistyping on exactly the input where a typo costs you the sale. Brand detection is what tells your formatter which grouping to apply, and the form testing checklist covers asserting all of this before it reaches production.