Refgrow
Back to blog

Stripe Test Card Reference Guide

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 4242 and CVC 400

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.

A diagram categorizing Stripe test cards into successful charges, generic declines, specific decline reasons, and 3D secure challenges.

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 4242 for normal success
  • 4000 0000 0000 0002 for generic decline
  • 4000 0000 0000 9995 for insufficient funds
  • 4000 0000 0000 0127 for incorrect CVC
  • 4000 0000 0000 0009 with a past date for expired card behavior
  • 4000 0027 6000 0004 for 3D Secure challenge
  • 4000 0076 0000 0001 for high-risk handling
  • 4000 0000 0000 0320 for 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.

Don’t start with the renewal event. Start earlier.

  1. Create a customer and Setup Intent
  2. Collect the payment method in test mode
  3. Complete the authentication step
  4. Attach the payment method to the customer
  5. Create the subscription or future off-session charge
  6. 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.

Screenshot from https://dashboard.stripe.com/test/payments

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:

  1. Start your app locally.
  2. Forward Stripe events to your webhook route.
  3. Trigger a test checkout in your frontend.
  4. 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.

A developer using a laptop to process live Stripe test events to their local server setup.

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

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:

  1. Load test-mode Stripe credentials from secure CI secrets.
  2. Spin up your app or API in a test environment.
  3. Create a Payment Intent or Setup Intent using the SDK.
  4. Trigger or forward webhook events to the test server.
  5. 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.

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:

  1. Dashboard object timeline
  2. webhook delivery and consumer logs
  3. test card behavior assumptions
  4. frontend confirmation path
  5. 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.

More from the blog

Ready to launch your affiliate program?

14-day free trial · No credit card required

Start Free Trial
Stripe Test Card Reference Guide — Refgrow Blog