What Stripe testing cards actually are
Stripe publishes a set of card numbers that exist only in test mode. They behave like real cards in the sense that they run through the same authorization flow, return the same response objects, and trigger the same webhooks. They are not linked to any bank account. Nothing settles. No money moves.
You can only use them with a test mode API key (the ones starting with sk_test_). Paste one into a live checkout and it will be rejected by the network. That is the point. A test PAN is a fixture, not a credential.
I keep a short list pinned in my editor and reach for the same four or five numbers over and over. Most of the rest exist to trigger a specific failure so you can watch your error handling do its job.
Stripe CC Test Guide for Selling CVV Online
The numbers I actually use
For a plain successful charge, use 4242 4242 4242 4242. It is a Visa, it always approves, and it never asks for authentication. If you need a different brand for a routing or icon test, 5555 5555 5555 4444 is Mastercard, 3782 822463 10005 is Amex, and 6011 1111 1111 1117 is Discover.
The Ultimate Guide to Choosing the Best Stripe Card Checker
Everything else on the card form is yours to invent. Any future expiry date works. Any three or four digit CVC works. Any postal code works. Stripe does check the format of those fields, so a two-digit year or a missing CVC will still fail client side validation before it ever reaches the API.
Cards that fail on purpose
These are the ones worth memorizing, because they let you test the unhappy path without editing your code.
- 4000 0000 0000 0002 returns a generic decline. Good for a catch-all error message.
- 4000 0000 0000 9995 returns insufficient funds.
- 4000 0000 0000 0069 returns an expired card.
- 4000 0000 0000 0127 returns an incorrect CVC.
- 4000 0000 0000 0119 returns a processing error, which is the one that usually means retry later.
- 4100 0000 0000 0019 is blocked outright, which is what a fraud rule looks like from the client side.
Each one maps to a decline_code on the charge or PaymentIntent. Print that field while you are building. The generic card_declined message tells your user nothing useful, and the specific code is what lets you decide between "try another card" and "call your bank."
3D Secure and authentication flows
Authentication is the part people forget to test until launch week. Stripe ships test cards that force a 3DS challenge so you can watch the modal appear and the redirect come back. They come in pairs: one that authenticates successfully and one that fails or errors out. Wire both into your test suite, because a PaymentIntent that needs action is a different code path from one that succeeded inline.
The handling rule is simple. If the intent comes back with a status of requires_action, hand the client secret to Stripe.js and let it run the challenge. Then listen for the webhook rather than trusting the browser redirect. Users close tabs.
Testing beyond a single charge
A one-off payment is the easy case. The awkward parts show up later.
- Subscriptions and trials. Stripe has test clocks that let you advance time and watch invoices generate, retries fire, and dunning emails send without waiting a month.
- Webhook handlers. Use the CLI to trigger events on demand instead of hunting for a card that produces the right one.
- Refunds and disputes. Test cards can produce dispute states so you can build the notification path before a real chargeback finds you.
One habit that saves me time: keep test keys out of your production config entirely, and never let a test number reach a live endpoint. If you see a 4242 in a live dashboard, something is wrong with your environment switching, not with the card.