Skip to content

Checking card numbers without storing them

4 min read API guides

card number validation

A card number validation pass with the Luhn algorithm catches most typos before the request reaches a payment provider. A mistyped number costs a failed payment and a support ticket. The check does not prove the card exists, has funds or belongs to the customer. It is a cheap first pass.

The PAN validator checks a number with the Luhn algorithm and returns a validity flag. The response masks the number.

curl "https://api2.globus.studio/v2/pan?number=4111111111111111&format=json"

What a card number validation checks

A card number validation pass with Luhn doubles every second digit from the right, subtracts nine from results above nine and sums the digits. A valid number produces a total divisible by ten. It catches single-digit errors and most adjacent transpositions. It cannot catch a valid number that was never issued.

The response

The card number validation response contains card_number with all but the last four digits masked, and validity with valid or invalid. The raw number is not returned. That keeps the number out of browser history and client logs.

Where to run it

Run the card number validation in the payment form before you create a token with the provider. If the number fails, show a field error and let the customer fix it. Do not send an invalid number to the provider and wait for a rejection.

Run it on the server when the form posts. A client-side check is useful for quick feedback, but the server decides what enters your system.

Do not store the number

Card number validation does not remove the need for a token. If you take card payments, the payment provider should receive the number and return a token. Store the token, the last four digits, the brand and the expiry. A full card number in your database expands the scope of PCI DSS and creates a target.

Do not log the number, not even in an error message. Mask it before it reaches the log. The API already masks it in the response, but your own code can still leak it if you log the request body.

Test numbers

Use the test numbers published by your payment provider. They pass card number validation and behave in predictable ways in the sandbox. Do not use a real card for testing, even your own. Keep one test number per brand so a failure points at the code and not at the input.

Limits

A card number validation result says nothing about the card brand, the issuing bank or the expiry date. It does not replace address verification, 3-D Secure or the provider’s fraud checks. It is one field validation, and it should stay that way.

Keep the check close to the form and return one message. "The card number is not valid" is enough. Do not echo the number or point at the failed digit. A user who mistypes four digits gets the same answer as a user who mistypes one, and the log stays clean. If the form posts to your server, validate again there; a client-side pass is a convenience, not a control.

Read the endpoint documentation for parameters and examples.

PCI scope in practice

If the card number reaches your server, the server is in scope for PCI DSS. If the payment provider’s form collects the number and returns a token, the number never touches your code. The second design is simpler to audit. A Luhn check can run in the provider’s form or on the token flow without storing the number.

Brand and length

Card brands have different lengths and prefixes. A Luhn-valid number with the wrong length for the brand is still invalid. Check the length and the prefix in the form, then let the provider confirm the brand. Do not reject a new brand because your list is old.

# A test number from a payment provider sandbox.
curl "https://api2.globus.studio/v2/pan?number=4111111111111111&format=json"

Expiry and CVV are separate fields

The Luhn check covers the number only. The expiry date and the security code have their own validation. Check that the expiry is in the future and that the code has the expected length for the brand. The payment provider performs the final check.

Related reading

Pair the check with email validation at signup. For a WordPress site, see generating WordPress salts after a security change.

Further reading: PCI Security Standards Council.

Custom work

Need an API that does not exist yet?

Describe the task and the response format. We will estimate the endpoint, the integration and the maintenance.

Start a conversation