This UnionPay card generator produces Luhn-valid test numbers on the network’s published ranges. UnionPay is the largest card network in the world by cards issued and by transaction volume, and it is also the network that produced the most useful counterexample in card validation — the reason a failed checksum should never be a hard block.
Test card only
Credit Card Number Generator
Generate dummy card details for development and QA. Nothing is stored or sent to a server.
UnionPay card number format
| Property | Value |
|---|---|
| Primary BIN range | 62 |
| Additional ranges | reported in BIN references, including 81 |
| Length | 16–19 digits |
| Check digit | Luhn (mod 10) |
| Security code | CVN2, 3 digits, on the back |
| Grouping | 4-4-4-4 or 4-4-4-4-3 |
The Luhn exception
Almost every piece of card-handling advice, including ours, says the same thing: a valid card number satisfies the Luhn checksum. UnionPay is where that sentence acquired an asterisk.
Some UnionPay cards issued in the mid-2010s did not carry a valid check digit. This was not a data-entry problem or a myth passed around in forums — it was documented behaviour in a domestic range, and it broke validation libraries that treated Luhn as a hard gate. Current UnionPay cards do carry a valid check digit, so the exception is largely historical.
The lesson is not. Here is why it still matters even though the specific case has closed:
Luhn is a typo filter, not an authority. It was designed in the 1950s to catch mistyped and transposed digits. It has never been a statement about whether an account exists, and it was never guaranteed to hold across every range every network would ever allocate.
Hard blocks convert edge cases into lost revenue. A client-side check that refuses to submit turns any unforeseen case — a new range, an unusual product, a network doing something its predecessor did not — into an abandoned checkout with no server-side record. You do not find out. You just have a slightly worse conversion rate forever.
The processor is the actual authority. It has the issuer relationship and the current range data. Your form has a checksum from 1954.
So: warn, allow submission, and let the authorisation answer. That is the right shape for every network, and UnionPay is simply the evidence that the shape matters. Our card validator takes the same position — it reports a failed check digit and tells you which digit was expected, rather than declaring the number invalid.
The same reasoning applies to ranges. A great deal of code checks ^62 and stops. UnionPay’s
allocations are not confined to that block, and additional ranges including 81 appear in
industry BIN references. Treat any hard-coded single-prefix check as a thing that will be
wrong later, and prefer a lookup where the answer actually matters — the
BIN lookup page covers what maintained data can tell you that the digits
cannot.
Where UnionPay is accepted
Domestically in mainland China, UnionPay was for years effectively the only card network, and its issued-card base is larger than any other scheme’s by a wide margin. That base travels: Chinese cardholders abroad carry UnionPay cards, which is why acceptance has spread through tourist-heavy merchant categories worldwide well ahead of general acceptance.
Internationally, UnionPay reaches much of the world through partner arrangements rather than
its own acceptance footprint everywhere — including a reciprocal relationship with
Discover, whose 622126–622925 block is a shared co-brand
range. JCB sits in a comparable web of partnerships.
For a merchant the decision is straightforward. Selling to Chinese customers, including travellers and diaspora, means supporting UnionPay or losing those transactions silently. Selling entirely elsewhere makes it lower priority — but the detection still has to be right, because a mis-detected card produces a confusing failure rather than a clean decline.
Warn without being useless
“Warn, do not block” is easy to state and easy to implement badly. A warning nobody reads is the same as no warning, and a warning that looks like an error is the same as a block.
Three things make the difference:
- Say what to check, not what failed. “Please check your card number” points at the input. “Invalid checksum” points at your implementation and tells the customer nothing they can act on.
- Keep the submit button live. The warning is advice. If the button is disabled, you have built a block with extra steps, and the customer with the unusual card is stuck exactly as before.
- Log it server-side. A checksum failure that proceeds to authorisation and then succeeds is the most valuable signal you can collect here: it means your validation was wrong about a real card. Without the log you never learn that, because the payment worked and nobody complained.
That third point is how the original UnionPay exception was found in the first place — not by reading a specification, but by noticing that numbers failing a local check were authorising fine.
Brand detection regex
const UNIONPAY = /^(62|81)\d{14,17}$/;
UNIONPAY.test('6200000000000000'); // true — 16 digits
UNIONPAY.test('6200000000000000000'); // true — 19 digits
UNIONPAY.test('620000000000000'); // false — 15 digits, too short
UNIONPAY.test('6300000000000000'); // false — outside the range
Detection order matters here as much as it does for Maestro, whose
56–69 block contains 62 entirely. Check UnionPay’s specific range before Maestro’s broad
one, or every UnionPay card in your traffic is labelled Maestro — and since both are commonly
debit products, the mistake is easy to miss in testing.
Testing scenarios
- Both lengths. Generate sixteen and nineteen digit numbers and confirm the form, the API and the database all handle each without truncation.
- Detection order. Run a
62number through the full brand-detection chain and assert UnionPay, not Maestro. - Failed checksum handling. Feed a number with a deliberately wrong check digit and confirm your form warns rather than blocking submission. This is the behaviour the whole page argues for, and it deserves an explicit test.
- Range assumptions. Grep your codebase for hard-coded
62checks and decide, deliberately, what happens to a UnionPay card outside them. - Grouping. Nineteen digits do not divide into groups of four; confirm the mask handles the trailing group rather than dropping it.
Official test numbers
For processor behaviour, use the gateway’s own sandbox numbers. Stripe publishes
6200 0000 0000 0005 and 6200 0000 0000 0047 for UnionPay, PayPal documents
6200 6800 0000 0004, and Adyen uses 8171 9999 2766 0000 — which is itself a useful
demonstration that the network is not confined to 62. The
test card numbers reference collects them by gateway.
UnionPay International’s own material is published at UnionPay International, the authoritative source for the network’s acceptance and range information.
Related tools and guides
The Luhn algorithm guide works through the checksum itself and why it was never designed to carry the weight validation code puts on it — worth reading if this page’s argument was new to you. The brand detection guide sets out the ordering problem across all nine networks at once. The other generators are in the tool directory, and the FAQ answers the same question this page opens with, in one paragraph.