FIX-06 · STRIPE · GO-LIVE CHECKLIST

Works in Stripe test mode, breaks in live mode: why

Test mode and live mode are two parallel universes that share a login page. Every key, webhook, product and price exists in only one of them — and go-live means recreating, not flipping a switch.

Updated July 2026 · 5 min read · free self-serve checks inside

Everything worked. Test cards sailed through, access unlocked, webhooks landed. You switched to live keys, shared the link — and real customers get errors, or pay and receive nothing. Nothing about your code changed. What changed is which Stripe you're talking to.

The mental model: two parallel universes

Test mode (Stripe now calls these sandboxes) and live mode behave like two separate Stripe accounts that happen to share a dashboard login. Each has its own API keys, its own webhook endpoints, its own signing secrets, its own products and prices, its own customers. Nothing crosses over automatically. "Works in test, breaks in live" almost always means one of those five things still points at the test universe.

The Dashboard has a mode toggle (sandbox/test vs live). Every check below assumes you're looking at live mode — a flipped toggle is exactly how these bugs stay hidden.

1. Both API keys must be live — as a pair

There are two keys: the publishable key (pk_...) in your frontend and the secret key (sk_...) on your server. Both must be the _live_ versions, together. The sneaky failure is the mismatched pair — pk_live_ in the browser with sk_test_ still in the server's env vars — which produces confusing errors about missing sessions or unknown objects. Check your hosting dashboard's environment variables, not your code: that's where a stale test key usually survives. And after changing env vars, redeploy — existing builds keep the old values.

2. The live webhook endpoint doesn't exist yet

This is the big one behind "paid but nothing happened, but only in live mode". Webhook endpoints registered in test mode do not exist in live mode. Toggle the Dashboard to live, open Workbench → Webhooks, and look. If the list is empty, no live payment has ever been announced to your app. Register the same URL, subscribed to the same event types, in live mode.

3. …and it has a brand-new signing secret

The moment you create the live endpoint, it gets its own whsec_... signing secret — different from the test one. Your webhook function is still holding the test secret, so every live delivery fails with a 400 until you update it. For Supabase Edge Functions that means updating the STRIPE_WEBHOOK_SECRET secret and redeploying the function. This step bites nearly everyone, precisely because the code is identical and was working an hour ago.

4. Live prices are different objects with different IDs

Products and prices created in test mode exist only there. If your code or env vars contain a hardcoded price_... ID from test mode, live checkout fails instantly with the refreshingly clear error No such price: 'price_...'. Recreate the products in live mode — many Dashboard product pages offer a "copy to live mode" button — then update every place the old ID appears: code, env vars, pricing config.

5. Customers and subscriptions don't come along either

Test-mode customers, subscriptions and saved cards stay in test mode. Anyone who "subscribed" during testing does not exist in live mode. If your database has rows pointing at cus_... or sub_... IDs created in test mode, live-mode code that looks them up will error — those IDs reference objects in the other universe. Clean those rows out, or mark them clearly as test data.

The only test that counts

Once every item above points at the live universe, run one real transaction: buy your own product with a real card, watch the event deliver in the live Events log, confirm the database row changes and access unlocks, then refund yourself in the Dashboard — refunding takes one click, and you lose only the small processor fee. Five minutes, and it's the difference between believing your checkout works and knowing it does.

That recorded, end-to-end live transaction is — not coincidentally — exactly how we prove every fix we deliver: money in, webhook delivered, access unlocked, on video. If you'd rather have someone who does this daily walk your go-live, the diagnosis below is free.

STILL BROKEN? THAT'S THE HARD VERSION

Diagnosed free. Fixed for a flat $250. Proven live.

01 · FREE HEALTH CHECK

Describe the symptom in two minutes. You get a plain-English root cause within hours — yours to keep even if you fix it yourself. No call, no strings.

02 · THE $250 FLAT FIX

One broken flow, fixed within 48 hours of access — proven with a recorded live test transaction you watch, and covered by a 30-day warranty. Miss the deadline, pay nothing.