Data

Stripe Test Data Generator

Create realistic testing data to integrate Stripe without touching real accounts. Cover success cases, declines, 3D Secure and edge cases in seconds.

Instant🔒In your browserNo signup
Live
    View as text

    Anatomy of Stripe test data

    Stripe provides test card numbers that simulate real behaviors without touching money. '4242424242424242' is the success wildcard: always works, useful for smoke tests. '4000000000009995' simulates generic decline. The difference is in the check digit: Stripe validates it with Luhn algorithm, so random numbers fail.

    Tokens like 'tok_visa' are shortcuts for quick testing in Stripe dashboard, but in real code you should use Stripe.js to tokenize. Payment Methods ('pm_card_visa') are the modern API; tokens are legacy but still valid for backward compatibility.

    Resource IDs (cus_, ch_, pi_) follow patterns: prefix + underscore + alphanumeric string. In test mode, any string after the prefix is valid ('cus_123', 'cus_fake') as long as the prefix matches the resource type. In production, Stripe generates real 24-28 character IDs.

    Testing strategy: beyond the happy path

    The most common error: only testing '4242424242424242' and assuming everything works. Your code must handle at least 5 scenarios: success, generic decline, requires_action (3DS), processing error, insufficient funds. Each returns different response structures.

    For 3D Secure (SCA), use '4000002760003184'. This card number triggers the complete flow: your frontend must show the auth modal, user 'approves', and only then the payment succeeds. If your test passes without modal, you didn't implement SCA correctly and will fail in European production.

    Webhooks are pain point #1. In local dev, use Stripe CLI ('stripe listen --forward-to localhost:3000/webhook') to receive real events. Test idempotency: Stripe can send the same webhook multiple times; your endpoint must be idempotent (check 'event.id' before processing).

    Edge cases that break integrations

    Decimal amounts: Stripe uses integers, not floats. $10.00 = 1000 (in USD). Yen has no decimals, ¥1000 = 1000. If you pass '10.00' as a number, Stripe rejects it. Correct conversion: Math.round(amount * 100) for currencies with 2 decimals.

    Metadata limits: you can pass up to 50 metadata keys, each value max 500 characters. Useful for internal tracking, but if you try to pass a giant serialized JSON, it silently fails. Test with excessive metadata to catch this edge case.

    Out-of-order webhooks: you can receive 'payment_intent.succeeded' BEFORE 'payment_intent.created'. Stripe doesn't guarantee order. Your logic must be stateless or check current resource state with a GET before processing. Classic bug: assuming 'created' always arrives first and setting flags that don't update later.

    Robust test environment setup

    Key separation: use different environment variables for test/prod. Common pattern: STRIPE_SECRET_KEY in prod, STRIPE_TEST_SECRET_KEY in dev. Never commit keys to git. Use local .env and secrets management in production (AWS Secrets Manager, Doppler, etc).

    For CI/CD, create a separate Stripe test account (don't use your personal account). This allows multiple devs and pipelines to run tests without collisions. Each PR can create ephemeral resources (customers, subscriptions) that clean up automatically after.

    Test data factories: instead of hardcoding '4242424242424242' in each test, create helpers: createSuccessfulCard(), createDeclinedCard(), create3DSCard(). This centralizes test data and makes updating easier if Stripe changes numbers. Example: when 3DS2 replaced 3DS1, you only had to update one function instead of 50 tests.

    FAQ

    Can I use test cards in production?

    No. Test numbers only work with keys starting with 'sk_test_' or 'pk_test_'. In production with 'sk_live_' keys, those cards are automatically rejected.

    How do I test recurring subscriptions without waiting a month?

    Use the 'billing_cycle_anchor' parameter to force dates, or create 1-day trial periods. You can also use Stripe CLI to simulate time passing: 'stripe trigger invoice.payment_succeeded'.

    Do test webhooks reach my localhost?

    Only with Stripe CLI. Install 'stripe-cli', run 'stripe listen --forward-to http://localhost:3000/webhook', and copy the webhook secret it gives you. Without this, webhooks only reach public URLs.

    What if my test passes locally but fails in CI?

    Probably timing issues with async webhooks. In CI, add delays or polling: after creating a PaymentIntent, wait 2-3 seconds or do GET until status changes before asserting.

    Was this generator useful?