Skip to content

My Stripe payments work but no real money shows up, test mode vs live mode

5 min read

Your Stripe checkout worked, the success page showed up, and yet no real money landed in your bank. Almost certainly, your app is still in Stripe test mode. Test mode uses separate keys and a separate ledger, so every "payment" was fake and no card was ever charged. The fix is to swap your test keys for live keys and confirm a real charge goes through.

Why this happens

Stripe gives you two completely separate worlds: test and live. Each has its own API keys, its own customers, its own payments, and its own dashboard view. Test mode exists so you can build and click through checkout with fake card numbers like 4242 4242 4242 4242 without moving a penny. Nothing you do in test mode ever touches a real bank.

When an AI agent wires up Stripe for you, it uses whatever keys were handy, and those are almost always the test keys, because they are the ones Stripe shows you first. The agent built exactly what you asked, "add Stripe checkout," and it works perfectly. It just works in the sandbox, because you never told it to go live, and it will not warn you.

How to check

  1. Open your Stripe Dashboard and look at the top for the Test mode toggle. If it is on, the payments you are seeing are test payments.
  2. Look at the keys your app is using. Open your .env file or your hosting provider's environment variables and find the Stripe keys:
    • sk_test_... and pk_test_... mean test mode. Fake money.
    • sk_live_... and pk_live_... mean live mode. Real money.
  3. Check the dashboard ledger. In test mode you will see your payments under Payments only while the Test mode toggle is on. Flip the toggle off and the live side is empty. That empty live side is your missing money.

If your keys say test, that is the whole answer.

The fix

  1. Get your live keys. In the Stripe Dashboard, turn the Test mode toggle off, go to Developers → API keys, and copy the live publishable key (pk_live_...) and reveal the live secret key (sk_live_...).
  2. Swap the keys in your environment variables, not in your code. Replace the test values with the live ones wherever they live: your .env file locally, and your host's dashboard for production (Vercel, Netlify, Railway, and so on). The secret key belongs only on the server, never in the browser bundle.
  3. Recreate any Stripe objects for live mode. Products, prices, and payment links created in test mode do not exist in live mode. If your checkout uses a price ID (price_...), create the product again with the Test toggle off and use the new live price ID.
  4. Re-point your webhook. Test and live webhooks are separate. Add your endpoint again under the live side and copy the new signing secret into your environment. If you skip this, real payments succeed but your app never hears about them.
  5. Redeploy, then make one real payment with an actual card, ideally your own, for a small amount. Confirm it appears on the live side of the dashboard and that the money reaches your bank. Refund yourself afterwards.

The trap to avoid

The common mistake is flipping the dashboard toggle and assuming the app followed. It did not. The toggle only changes what you see in Stripe; your app keeps using whatever keys are in its environment. Another version of the same trap is switching the secret key to live but leaving the publishable key, the price ID, or the webhook on test. Payments then fail in confusing, half-broken ways. Move all of it together: both keys, the prices, and the webhook.

Where this fits

Going live is one of the last things to get right before real users, and it is easy to ship a demo that quietly charges no one. Before you flip the switch, walk through how to test Stripe payments before launch, and make sure your app actually reacts when a real payment lands, which is a separate failure covered in paid but nothing happened. The free Readiness Report checks whether your app is running live Stripe keys with a working webhook, and the Finishing Pass hands you the go-live steps in order so the first real card is the one that works.