Stripe Test Card Reference Guide

You’re probably in one of two spots right now. Either your Stripe integration works for the happy path and you’re trying to avoid ugly surprises in production, or your first subscription tests passed and trouble started when SCA, webhooks, retries, and off-session renewals entered the picture.
That’s where a good stripe test card workflow matters. Not just a list of card numbers, but a way to test the exact paths your users and background jobs will take. The basic success card is useful. It’s also the easiest way to miss the failures that break launches.
The teams that ship reliable billing flows usually do three things well. They separate test mode from live mode without exceptions, they map cards to real product scenarios instead of random manual checks, and they run the same payment cases repeatedly through local dev, staging, and CI.
Understanding stripe test card fundamentals
The fastest way to create payment bugs is to test with live credentials too early. A real checkout can charge someone, trigger real receipts, create accounting noise, and leave you debugging business fallout instead of code.
A stripe test card exists to prevent that. Stripe provides simulated credit and debit card numbers that work only in test mode, so you can exercise payment flows without moving real money or exposing yourself to financial risk. Common examples include 4242 4242 4242 4242 for a successful Visa payment and 5555 5555 5555 4444 for a successful Mastercard payment, along with cards for Visa debit, Mastercard 2-series, co-branded cards, declines, insufficient funds, and invalid CVC behavior, as summarized by Synder’s overview of Stripe test cards.
What test mode actually protects
Test mode isn’t just fake card numbers. It’s a separate environment.
That separation matters because it lets you:
- Try destructive scenarios safely like repeated failed renewals, invalid CVC entries, and decline handling.
- Inspect logs cleanly without mixing development traffic with production activity.
- Build release confidence before your app ever sees a real customer payment method.
Real cards don’t belong in test mode. That creates confusion fast, especially when someone on the team starts comparing Dashboard records from the wrong environment.
Practical rule: treat test mode and live mode like different systems, not just different API keys.
The first cards most teams need
If you’re starting fresh, use a small baseline set:
- Successful payment with
4242 4242 4242 4242 - Generic decline with
4000 0000 0000 0002 - Insufficient funds with
4000 0000 0000 9995 - Invalid CVC by using
4242 4242 4242 4242and CVC400
That small set already covers the most common UI and backend branches.
If you’re still comparing processors or planning billing architecture before implementation, this overview of best payment processing software for small business is useful context for understanding where Stripe fits and why its test tooling is so developer-friendly.
Categorizing stripe test cards
Most payment teams make the same early mistake. They collect a long list of card numbers, paste a few into a checkout form, and call it testing.
That approach breaks down because card numbers aren’t just samples. They represent behavior categories. Once you sort them that way, your test matrix gets much easier to maintain.

The four categories that matter most
Here’s the mental model I recommend.
| Category | What it simulates | Why you need it |
|---|---|---|
| Successful charges | Clean approvals | Verifies your default checkout, receipts, and post-payment state |
| Generic declines | Broad failures | Confirms your app doesn’t treat all failures like transient errors |
| Specific decline reasons | Targeted error conditions | Tests copy, retries, and user guidance for known failure types |
| 3D Secure challenges | Authentication steps | Validates SCA flows, modal handling, redirects, and off-session setup |
How to map categories to product behavior
A card category should correspond to a product outcome, not just an API response.
- Successful charges belong in tests that verify account upgrades, invoice creation, analytics events, and entitlement changes.
- Generic declines should prove your app doesn’t grant access to features, doesn’t double-submit, and shows a useful retry path.
- Specific decline reasons belong where support burden appears. Incorrect CVC, insufficient funds, and expired card produce different user actions.
- 3D Secure challenges matter whenever authentication state changes what happens next, especially in subscriptions and cross-border flows.
What developers often miss
The failure path isn’t one thing. A generic decline, a risk block, and a timeout are operationally different.
A clean matrix usually has one representative card for each of these buckets:
- Approval
- Customer-correctable decline
- Merchant-side risk or fraud block
- Authentication required
- Transport or network-style failure
If your test plan has five success cases and one decline case, it isn’t a billing test plan. It’s a demo.
The practical win from categorizing stripe test cards is speed. When someone changes checkout copy, retries, webhook consumers, or subscription logic, you immediately know which cards to rerun.
Detailed stripe test card reference list
Once your categories are clear, the next step is building a short reference that developers can use. You don’t need a giant internal wiki page. You need a compact set of cards tied to scenarios your app cares about.
Core success and decline cards
Start with these common entries.
| Card number | Expected behavior | CVC and expiry guidance | Good use case |
|---|---|---|---|
4242 4242 4242 4242 |
Successful Visa payment | Any 3-digit CVC, future expiry | Baseline checkout success |
5555 5555 5555 4444 |
Successful Mastercard payment | Standard test entry in test mode | Brand coverage for card form validation |
4000 0566 5566 5556 |
Visa debit simulation | Standard test entry in test mode | Debit-specific paths |
2223 0031 2200 3222 |
Mastercard 2-series simulation | Standard test entry in test mode | BIN handling and UI brand detection |
4000 0025 0000 1001 |
Cartes Bancaires/Visa co-branded | Standard test entry in test mode | Regional card behavior |
4000 0000 0000 0002 |
Generic decline | Use in normal test checkout flow | Failure handling |
4000 0000 0000 9995 |
Insufficient funds decline | Use in normal test checkout flow | Retry prompts and alternative payment method flows |
Cards for edge cases and risk handling
These are the cards that save you from production surprises.
According to Stripe testing use cases, 4000 0027 6000 0004 triggers a 3D Secure flow that requires action, 4000 0000 0000 0320 simulates a network timeout, 4000 0076 0000 0001 simulates a high-risk block, 4000 0015 0000 0000 is useful for EU-specific failure testing, 4000 0000 0000 0127 simulates incorrect CVC, and 4000 0000 0000 0009 should be used with a past date to simulate an expiry decline. The same Stripe reference also notes that physical Terminal test cards are Stripe-branded, sandbox-only, support chip and contactless, and use PIN 1234, while Interac test cards are Canada-only and ordered through the Dashboard.
Example request patterns
You don’t need a custom code path for every test card. Keep your request shape stable and vary only the payment method details.
Payment Intent confirmation example
const paymentIntent = await stripe.paymentIntents.create({
amount: 5000,
currency: 'usd',
payment_method: 'pm_card_visa',
confirm: true,
});
That example is useful for API flow discussions, but in real testing you’ll often create the Payment Intent server-side and confirm it from Stripe Elements or the Payment Element so you can exercise SCA and UI states correctly.
Setup flow example for future usage
const setupIntent = await stripe.setupIntents.create({
customer: customerId,
payment_method_types: ['card'],
usage: 'off_session',
});
That pattern matters more than many teams realize. If your app bills later, saves a card for subscription renewals, or triggers usage-based charges after onboarding, you should test with Setup Intents early.
A practical reference set for daily work
For most SaaS billing implementations, I keep these in easy reach:
4242 4242 4242 4242for normal success4000 0000 0000 0002for generic decline4000 0000 0000 9995for insufficient funds4000 0000 0000 0127for incorrect CVC4000 0000 0000 0009with a past date for expired card behavior4000 0027 6000 0004for 3D Secure challenge4000 0076 0000 0001for high-risk handling4000 0000 0000 0320for timeout-oriented resilience tests
That list covers most bugs I see in subscription products. Not because it’s exhaustive, but because it maps to real states your code has to survive.
Testing SCA and 3DS payment flows
SCA and 3DS are where many Stripe integrations stop being straightforward. A one-time charge that succeeds in local testing can still fail in production once you save a card for future use and try to charge it off-session.
The main mistake is using the wrong card for the wrong authentication pattern.
One-time setup versus every-charge authentication
Stripe’s support guidance is unusually important here. For recurring-payment testing, the card ending in 3184 triggers 3D Secure on every charge, while the card ending in 3155 is the recommended choice when you want to simulate a one-time authentication during a Setup Intent for SCA-compliant recurring flows, according to Stripe support on 3D Secure test card behavior.
That distinction changes how you should test subscriptions:
- Use the 3184-ending card when you want to stress-test repeated authentication handling.
- Use the 3155-ending card when you want to model a more realistic recurring setup where the customer authenticates once and later off-session charges can proceed.
If you’re building recurring billing logic, this walkthrough on setting up recurring payments is a helpful companion to the payment-side test cases.
Recommended test sequence
Don’t start with the renewal event. Start earlier.
- Create a customer and Setup Intent
- Collect the payment method in test mode
- Complete the authentication step
- Attach the payment method to the customer
- Create the subscription or future off-session charge
- Verify what happens on the next charge attempt
The outcome you’re looking for is not just “payment succeeded.” You need to know whether your app correctly stores the payment method, records mandate-like consent state for the flow you use, and handles later charges without accidentally re-prompting the customer in impossible contexts.
A minimal handling pattern
try {
const result = await stripe.confirmCardSetup(clientSecret, {
payment_method: {
card: cardElement,
billing_details: { email: customerEmail },
},
});
if (result.error) {
// show auth or validation error
} else {
// save result.setupIntent.payment_method
}
} catch (err) {
// log unexpected failure
}
That code is intentionally plain. The important part is where you branch on the result.
A successful Setup Intent doesn’t guarantee your recurring flow is modeled correctly. It only proves the first authentication step completed.
What works and what doesn’t
What works
- Testing a Setup Intent and the follow-up invoice or off-session charge as separate steps
- Keeping logs for both frontend authentication state and backend invoice state
- Verifying webhook order instead of assuming it
What doesn’t
- Using a 3DS card that challenges every transaction to represent normal recurring behavior
- Treating all SCA cards as interchangeable
- Marking subscriptions “done” after the first successful setup without testing renewal logic
Simulating stripe test card errors
Error simulation is where billing quality becomes visible. A polished checkout doesn’t matter much if your application collapses into generic “something went wrong” messages the first time a bank declines a charge or Radar blocks a suspicious payment.
Customer-correctable versus system-level failures
Keep these two classes separate in your code and UI.
Customer-correctable errors include:
- insufficient funds
- incorrect CVC
- expired card
- authentication needed
These should lead to specific guidance. Ask for a corrected CVC, another card, or completion of authentication.
System-level or platform-side failures include:
- network timeout simulations
- high-risk or fraud-oriented blocks
- webhook delivery problems
- temporary internal processing issues
These usually need retries, queueing, or a support-oriented fallback path rather than more aggressive prompts to the customer.
Fraud simulation matters for resilience
Card testing fraud isn’t theoretical. During the card testing surge from February to August 2022, Stripe Radar peaked at blocking over 20 million card testing attempts per day, then later introduced changes including model updates in 1 hour instead of 1 to 2 days, plus API rate limiters that blocked nearly 40 million attempts in 2023. Stripe also reported an 80% decrease in successful card testing attacks while global fraud rose 11%, as described in Stripe’s newsroom post on the card testing surge.
Those numbers matter to application developers because they explain why your own app should treat unusual request bursts, repeated low-value attempts, and rapid-fire card changes as operational signals.
How to handle simulated failures cleanly
A simple handling model works well:
| Scenario | What your app should do |
|---|---|
| Insufficient funds | Ask for another card or retry later |
| Incorrect CVC | Keep context, prompt for corrected details |
| Expired card | Force card update path |
| Risk block | Avoid automatic retries, log for review |
| Timeout | Retry carefully and guard against duplicate state changes |
Don’t map every failed payment to “try again.” Some failures need a new card. Some need authentication. Some should stop immediately.
Logging that actually helps
When a stripe test card produces an error, capture:
- Payment Intent or Setup Intent ID
- Customer ID
- UI state at failure
- Webhook events received afterward
- Whether your app already granted access
That last point matters more than teams expect. The hardest payment bugs aren’t “charge failed.” They’re “charge failed, but the user still got premium access.”
Using stripe test cards with Dashboard CLI and SDKs
You should be able to run the same payment scenario three ways. Interactively in the Dashboard, locally with the Stripe CLI, and in application code through your SDK. If one path works and the others don’t, your integration still has blind spots.
A visual pass in the Dashboard is often the fastest sanity check.

Dashboard for fast manual verification
The Dashboard is where I start when a product manager or founder wants to verify a billing edge case without running local code.
Use it for:
- Quick Payment Intent checks when you want to confirm a card behavior
- Visual inspection of status changes after confirmation or failure
- Reviewing event timelines before digging into logs
This is especially useful when someone says “checkout failed” but the bug could live in webhook handling, entitlement logic, or analytics.
CLI for local event flow testing
The Stripe CLI is the bridge between local development and webhook realism. It lets you forward events to your local server and replay scenarios without opening up a public endpoint.
A practical local workflow looks like this:
- Start your app locally.
- Forward Stripe events to your webhook route.
- Trigger a test checkout in your frontend.
- Confirm that your local logs and Stripe event timeline match.
Use the CLI when you need to test side effects, not just payment outcomes.
SDK examples across stacks
The exact language doesn’t matter much. The pattern does.
Node.js
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const intent = await stripe.paymentIntents.create({
amount: 2500,
currency: 'usd',
automatic_payment_methods: { enabled: true },
});
Python
import stripe
stripe.api_key = os.environ["STRIPE_SECRET_KEY"]
intent = stripe.PaymentIntent.create(
amount=2500,
currency="usd",
automatic_payment_methods={"enabled": True},
)
Ruby
Stripe.api_key = ENV["STRIPE_SECRET_KEY"]
intent = Stripe::PaymentIntent.create(
amount: 2500,
currency: 'usd',
automatic_payment_methods: { enabled: true }
)
These examples are intentionally close. Your real complexity usually isn’t in creating the intent. It’s in handling what happens after.
One tool reference worth keeping nearby
If you want a product-side integration reference for connecting Stripe revenue events into affiliate or referral workflows, the Stripe integration docs at https://refgrow.com/docs/stripe are a useful implementation reference alongside Stripe’s own docs.
Simulating webhooks and verifying events
Webhook testing is where many “working” Stripe integrations fail. The charge succeeds, but your app doesn’t activate the account. Or the UI says payment failed, while the webhook later marks the invoice paid and upgrades the customer anyway.
Those bugs happen because developers test API requests but not event delivery and event consumption.

What test mode does correctly
Test cards trigger webhooks the same way live mode does for core event flows such as payment_intent.succeeded with 4242 4242 4242 4242, while higher-risk simulation can require specific risk parameters or cards like 4000000000000341. A later update noted by Memberstack says Stripe test mode supports ephemeral Link tokens for faster auth testing, with a reported 40% reduction in setup time for subscription flows in that context, as described in Memberstack’s Stripe test card guide.
The key takeaway is simple. If your local webhook handling doesn’t behave in test mode, don’t expect production to save it.
A webhook verification checklist
Use a checklist, not memory:
- Verify signatures before parsing payloads into business actions
- Store Stripe event IDs so retries don’t create duplicate side effects
- Log event order because payment-related events often arrive as a sequence, not a single confirmation
- Decouple UI success from final provisioning when your app depends on webhook confirmation
- Replay events when debugging so you test consumers, not guesses
Radar and risk-related testing
Risk simulation is where many guides stay too shallow. A high-risk card or risk parameter should trigger a path in your app that is visibly different from a normal decline.
That usually means:
| Event condition | App response |
|---|---|
| Normal success | Grant access and record payment |
| Standard decline | Show corrective UI |
| Risk-oriented block | Hold state, log review context, avoid automatic retries |
If your product tracks downstream effects such as commissions or referral-attributed purchases, make sure those jobs run only after the right event state. The webhook documentation at https://refgrow.com/docs/webhooks is a good example of the kind of event-first integration pattern worth copying.
Your source of truth should be the event stream your backend accepts and verifies, not the frontend’s optimistic state.
Integrating stripe test cards into CI pipelines
Payment regressions are expensive because they often hide in ordinary refactors. A checkout button rename doesn’t matter. A serializer change that drops setup_future_usage does.
That’s why a stripe test card should show up in CI, not just in manual QA.
What belongs in CI
A useful CI billing suite doesn’t try to reproduce every interactive path. It focuses on deterministic checks:
- Happy path payment creation
- One representative decline
- Webhook consumer execution
- Idempotency-safe retries
- Subscription setup path for saved cards
Keep your suite narrow enough to run on every pull request, but meaningful enough to catch breaking changes.
Practical CI structure
A solid pattern looks like this:
- Load test-mode Stripe credentials from secure CI secrets.
- Spin up your app or API in a test environment.
- Create a Payment Intent or Setup Intent using the SDK.
- Trigger or forward webhook events to the test server.
- Assert on application state, not just Stripe API responses.
For 3DS-heavy flows, don’t try to fake browser interaction in every pipeline job unless you need end-to-end coverage. An effective approach involves two layers:
- API-level CI tests for intent creation, event handling, and database state
- Browser-based scheduled tests for modal or redirect flows
Common CI mistakes
These are the ones I see most often:
- Mixing live and test secrets in shared environment files
- Running too many payment tests in parallel without pacing requests
- Asserting only on returned status instead of checking internal access state
- Skipping webhook simulation and assuming direct API success is enough
A small amount of request pacing goes a long way here, especially because production-grade anti-abuse patterns can shape how repeated payment attempts behave.
A simple pass-fail rule
CI should fail if any payment scenario leaves your application in an ambiguous state.
That includes cases where:
- payment failed but access was granted
- payment succeeded but downstream jobs didn’t run
- duplicate events created duplicate records
- a saved-card setup flow stopped being reusable off-session
If your billing tests can detect those states before merge, they’re already doing valuable work.
Quick stripe test card reference cheat sheet
This is the version to keep beside your editor. It’s not exhaustive. It’s the shortest useful set for daily development.
If you want a copyable lookup tool, https://refgrow.com/tools/stripe-test-cards is a convenient reference for grabbing common test numbers quickly.
Stripe Test Card Cheat Sheet
| Card number | Behavior | Use case |
|---|---|---|
4242 4242 4242 4242 |
Successful payment | Baseline checkout success |
5555 5555 5555 4444 |
Successful Mastercard payment | Brand-specific success path |
4000 0000 0000 0002 |
Generic decline | General failure UI and retry logic |
4000 0000 0000 9995 |
Insufficient funds | Prompt for another payment method |
4000 0000 0000 0127 |
Incorrect CVC | Card detail correction flow |
4000 0000 0000 0009 with past date |
Expired card decline | Card update flow |
4000 0027 6000 0004 |
3D Secure requires action | SCA and challenge flow |
4000 0076 0000 0001 |
High-risk block | Fraud handling path |
4000 0000 0000 0320 |
Network timeout simulation | Retry and resilience logic |
card ending in 3184 |
3D Secure on every charge | Repeated auth stress test |
card ending in 3155 |
Better fit for one-time Setup Intent auth | Recurring off-session setup testing |
The shortest usable matrix
Five cases typically catch the majority of integration bugs:
- success
- generic decline
- insufficient funds
- 3DS required
- webhook-confirmed post-payment side effect
That’s the minimum set I’d insist on before launch.
Related resources and cross references
A good stripe test card workflow depends on checking the right resource at the right moment. Don’t use one document for everything.
Where to look depending on the problem
- Stripe official testing docs when you need exact card behavior, payment method simulation, or product-specific test cases.
- Stripe support articles when the issue is nuanced behavior, especially around SCA, Setup Intents, and recurring charging patterns.
- Stripe Dashboard event logs when the API result and the webhook outcome disagree.
- Stripe CLI documentation when your local consumer logic needs event forwarding and replay.
- Your application integration docs when payment success has downstream effects like provisioning, access, analytics, or partner attribution.
A practical reading order
If something breaks, I’d check in this order:
- Dashboard object timeline
- webhook delivery and consumer logs
- test card behavior assumptions
- frontend confirmation path
- subscription or off-session charge setup
That order avoids a lot of wasted debugging time.
Glossary of stripe testing terms
Key terms you’ll keep seeing
Test mode
Stripe’s sandbox environment for simulated transactions.Live mode
The production environment that processes real payments.Payment Intent
A Stripe object that tracks a payment attempt through confirmation and completion.Setup Intent
A Stripe object used to save and authenticate a payment method for later use.SCA
Strong Customer Authentication. Regulatory authentication requirements that affect many card payments.3DS
3D Secure. An authentication step often used to satisfy SCA.Webhook
An event Stripe sends to your server when payment state changes.Radar
Stripe’s fraud tooling for evaluating payment risk and blocking suspicious activity.Off-session payment
A charge attempted when the customer isn’t actively in the checkout flow.Link tokens
Test-mode auth helpers referenced in newer Stripe-related testing workflows.
Frequently asked questions
Can I mix test and live API keys in one environment
You can, but you shouldn’t. It creates object mismatches, confusing logs, and accidental live actions. Keep environments separate.
What should CI do with 3DS flows
Use CI for deterministic backend checks and event handling. Keep fully interactive browser-based 3DS tests in a separate end-to-end layer.
Should I test refunds with the same rigor as charges
Yes. Refunds often trigger the same webhook, ledger, and entitlement consistency problems that payments do.
Why did the payment succeed but my app didn’t update
Usually because the webhook consumer failed, arrived later than expected, or your app granted access based on frontend state alone.
How many stripe test card scenarios are enough before launch
Enough to cover success, one decline, one corrective decline, one authentication flow, and your key webhook-driven side effect. More than that depends on your product’s billing complexity.
If you’re building a SaaS product and need referral or affiliate tracking tied to Stripe revenue events, Refgrow is one option to look at. It embeds an in-app affiliate program, connects revenue through Stripe and other billing platforms, and supports API and webhook-based workflows for payouts, attribution, and commission rules.