Skip to content

pametan/card-validator

Repository files navigation

card-validator

Luhn checksum, card-network detection and number / CVV / expiry validation for Visa, Mastercard, American Express, Discover, Diners Club, JCB, Maestro and UnionPay — with explainable, typed results.

TypeScript-first, zero runtime dependencies, and built for regulated/audited contexts: it validates format only, never logs or stores the card number, and makes no network calls.

import { validateCardNumber, validateCard } from '@pametan/card-validator';

validateCardNumber('4242 4242 4242 4242').valid; // true
validateCard({ number: '3782 822463 10005', cvv: '1234', expiry: '11/30' }).valid; // true (Amex)

Why

Most card mistakes are caught before a payment processor is ever called: a mistyped digit (Luhn), the wrong number of digits for the network, a 3-digit code where Amex wants 4, or an expired date. This library does those checks with the two awkward networks — Amex (15 digits, 4-digit code, 4-6-5 grouping) and Discover (scattered IIN ranges incl. 622126–622925) — handled correctly, and returns a result object you can log or audit.

Scope: this is structural validation, not a BIN lookup and not proof that a card exists or has funds. A valid result means "this looks like a well-formed card number for this network."

Install

npm install @pametan/card-validator

Requires Node 24+. Ships ESM with bundled type declarations.

Usage

Validate a number

import { validateCardNumber } from '@pametan/card-validator';

validateCardNumber('6011 0009 9013 9424');
// {
//   valid: true,
//   network: 'discover',
//   luhnValid: true,
//   lengthValid: true,
//   normalized: '6011000990139424',
// }

valid is true only for a recognised network with a passing Luhn checksum and a valid length. The sub-flags are exposed so you can apply your own policy — for example, accepting a luhnValid number whose network is 'unknown'.

CVV and expiry

import { validateCvv, validateExpiry } from '@pametan/card-validator';

validateCvv('1234', 'amex').valid;  // true  (Amex uses 4 digits)
validateCvv('123', 'visa').valid;   // true  (others use 3)

// Valid through the last day of the expiry month (industry norm).
validateExpiry('05/26', { now: new Date(2026, 4, 26) }).valid; // true
// graceDays extends the window past end of month:
validateExpiry('05/26', { now: new Date(2026, 5, 3), graceDays: 5 }).valid; // true

now is injectable so expiry checks are deterministic in tests.

Validate a full entry

import { validateCard } from '@pametan/card-validator';

const result = validateCard({
  number: '3782 822463 10005',
  cvv: '1234',
  expiry: '11/30',
});
// result.valid === true, and result.number / result.cvv / result.expiry hold the detail.

The CVV is checked against the network detected from the number, so Amex's 4-digit code is handled automatically.

Detection and formatting

import { detectNetwork, formatCardNumber, getLast4 } from '@pametan/card-validator';

detectNetwork('2223 0031 2200 3222'); // 'mastercard' (2-series)
formatCardNumber('378282246310005');  // '3782 822463 10005'
getLast4('4242 4242 4242 4242');       // '4242'

API

Export Description
validateCardNumber(pan) CardNumberResult — network, Luhn, length, overall.
detectNetwork(pan) One of visa, mastercard, amex, discover, diners, jcb, maestro, unionpay, or unknown.
validateCvv(cvv, network) CvvResult — checks length per network.
validateExpiry(input, opts?) ExpiryResultMM/YY or MM/YYYY, configurable grace.
validateCard({ number, cvv, expiry }, opts?) CardResult — composite.
formatCardNumber(pan) / getLast4(pan) Display helpers.
luhnCheck(input) The raw Luhn checksum.
NETWORKS, networkRule(id) The underlying network rule table.

All result and option types are exported.

Supported networks

Network IIN / prefix Lengths Security code
Visa 4 13, 16, 19 3
Mastercard 51–55, 2221–2720 16 3
American Express 34, 37 15 4
Discover 6011, 644–649, 65, 622126–622925 16, 19 3
Diners Club 300–305, 309, 36, 38, 39 14, 16, 19 3
JCB 3528–3589 16–19 3
Maestro 5018, 5020, 5038, 5893, 6304, 6759, 6761–6763, 6390, 0604 12–19 3
UnionPay 62, 81 16–19 3

Ranges follow ISO/IEC 7812 and each network's published documentation.

Overlap and precedence. Several networks share the 6x IIN space. Discover's specific ranges — including the co-branded 622126–622925 block — are matched first, so those BINs route to Discover; UnionPay's broad 62/81 and Maestro's IIN list only catch what Discover does not. If your acquirer routes a particular BIN differently, treat the detected network as a hint and confirm with your processor.

Handling card data responsibly

This library never logs, stores or transmits the card number — it only inspects it in memory. To keep it that way in your own code:

  • Don't log full card numbers. Use getLast4() for display, and mask PANs in logs (e.g. with @pametan/pii-redact).
  • Validation is not a substitute for your payment processor's own checks, and does not reduce or remove your PCI DSS obligations.

Non-goals: real-time BIN lookup, tokenization, storage, and fraud scoring.

Development

npm install
npm run typecheck
npm test          # 43 tests: published test PANs + edge cases
npm run build     # emit dist/

Test card numbers are the standard published synthetic numbers (Stripe / network docs) — they are designed for testing and are not real accounts.

Disclaimer

Provided as an engineering aid, not financial, security or compliance advice. Verify network rules against current documentation for production use. MIT licensed — see LICENSE.


Need the production version of this?

We're Pametan — a specialist fintech/regtech engineering agency working across UK, US and Canadian rails (FCA · CFPB · FCAC). We build the regulated, audited, in-market version of tools like this: card and payment validation, PCI-scoped checkout flows, and the systems around them.

Talk to us →

About

Luhn check, card-network detection (Visa, Mastercard, Amex, Discover, Diners, JCB, Maestro, UnionPay) and CVV/expiry validation. TypeScript, zero-dependency, PCI-conscious.

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors