Pick up two payment cards from different networks and the numbers do not look alike. One may be sixteen digits grouped in fours, another fifteen digits grouped four, six and five, and the closing digits obey the same checksum while the lengths do not match at all. Building test card numbers by network means working with those differences deliberately, because an integration that only ever sees one brand is an integration that has never run most of its own code.
This article sets out the differences that matter, shows how to read the published ranges, and explains why a number with the right prefix still belongs to nobody.
Every network has its own numbering plan
A card network registers the ranges of issuer prefixes it will recognise and the number of digits a card in each range will carry. That registration is what lets a payment terminal decide, with no network call, which brand a card belongs to and whether the number is even plausible.
The result is a small set of families rather than one universal shape. Some networks use one length almost exclusively; others support several lengths for different product tiers or regions. Security codes differ too, both in how many digits they contain and in which side of the card they are printed. A test set that ignores those differences will pass review and fail in production.
How do you choose a prefix for a test case?
Work backwards from the branch you want to exercise. If your form changes its layout based on the detected brand, you need at least one number per brand that triggers a distinct layout. If your validation has a branch for a fifteen-digit number, you need a number of that length. If your checkout handles a four-digit security code, you need a card whose network uses one.
Then check that the prefix you chose is published rather than invented. Using a range that no network has registered produces a number that your own prefix detection will reject, which makes the test look like a failure of the detection logic rather than of the fixture.
A practical shortcut is to generate one number for each brand you support and keep the whole set together as a named fixture, so that the set can be regenerated whenever a brand is added or a length rule changes.
The published ranges at a glance
The following table summarises the publicly documented prefix ranges and the shapes that go with them. It describes numbering plans, not specific products or issuers.
| Network | Published prefix ranges | Typical length | Security code |
|---|---|---|---|
| Visa | begins with 4 | 16 digits, with 13 and longer forms also registered | 3 digits, back |
| Mastercard | 51 to 55, and 2221 to 2720 | 16 digits | 3 digits, back |
| American Express | 34 and 37 | 15 digits | 4 digits, front |
| Discover | 6011, 65, 644 to 649, and 622126 to 622925 | 16 digits, longer forms registered | 3 digits, back |
| JCB | 3528 to 3589 | 16 digits, longer forms registered | 3 digits, back |
| Diners Club | 300 to 305, 36, and 38 to 39 | 14 digits, with 16 also used | 3 digits, back |
| UnionPay | 62 | 16 digits, longer forms registered | 3 digits, back |
| Maestro | 50, and 56 to 69 | variable within the standard’s limit | 3 digits, back |
Two caveats belong beside the table. Ranges are registered by networks and occasionally change, so a detector should be written to tolerate additions rather than to treat the list as final. And length is a property of the range, not of the brand as a whole: a rule that says a particular network always has sixteen digits will eventually be wrong.
Why does the security code length differ too?
American Express using four digits is not a security upgrade over three; it is simply how that network’s specification is written. The practical effect lands on the form, which has to know how many characters to accept.
If your interface offers a single field with a fixed maximum of three characters, an American Express code will be silently truncated, and the customer will see a failure that makes no sense to them. The robust approach is to accept the network’s expected length once the brand is known, and to allow a slightly generous maximum when it is not, so that a paste never loses a character the user will need back.
Does a matching prefix mean the number is real?
No. The prefix tells you which range a number claims to belong to, and nothing more. Any digit string starting with a registered range can be completed with arbitrary middle digits and a computed closing digit, producing something that every local check will accept.
The same applies to generated data: a number is structurally valid and was never issued to anyone. That is a property worth relying on rather than a limitation, because it means the value can be used in a demo or a fixture without any risk of it resolving to a real account. It also means a passed format check should never be described to a user as confirmation that their card exists.
For developers: building a network test matrix
A test matrix turns a list of brands into a list of decisions, and it is worth writing down in a table with four columns: the brand, the prefix range used, the expected detection result, and the form behaviour you expect as a consequence.
From there, three rules keep the matrix useful. Include exactly one number per distinct behaviour rather than many numbers per brand, because redundant fixtures add maintenance without adding coverage. Record the expected length for each entry, so that a change to a length rule shows up as a failing test rather than as an unnoticed relaxation. And keep at least one number whose prefix belongs to no range you support, so that the unknown-brand path is exercised rather than assumed.
Watch out for the detection function itself. Implementations that match on the first digit alone lump every banking card together, and ones that test ranges in the wrong order can let a narrower range be swallowed by a broader one. Both bugs are invisible until a specific card arrives, which is exactly what the matrix exists to prevent.
Finally, remember that format detection is not authorisation. A test matrix is a statement about your own code, and no arrangement of prefixes will tell you whether a card is valid for a payment. The validation walkthrough covers where detection belongs in the sequence of checks, and the format guide explains how the prefix relates to the rest of the number.
Producing one card per network
To build the fixture set, open the card number generator, pick a network, and copy the result; repeat for each brand you support, then store the collection together with a note about which behaviour each entry is meant to trigger. Generating rather than copying ranges out of documentation keeps the batch internally consistent and gives you a quantity that can be extended whenever a new payment method is added.
The PCI DSS notes are worth reading before that set is committed anywhere shared, and the provider test card guide explains when a scripted sandbox number is a better choice than a synthetic one.
Next steps
Draw up the matrix, generate one card per distinct behaviour, and add a fixture for a range you deliberately do not support so the unknown path stays covered. Then review the detection function against the table, starting with the narrowest ranges, to confirm that no branch is unreachable.