Stripe works in test mode but not live? The go-live checklist for Lovable and Bolt
Published October 21, 2026 · About 7 minutes
Everything worked with the 4242 test card. Then you switched to live, and the first real customer got an error at checkout, or paid and never got access. The cause is usually something left over from testing. Stripe keeps test and live mode fully separate, so most things you set up in test mode need to be set up again in live mode.
This checklist shows what is different in live mode, where to change it in a Lovable or Bolt app, and how to test the live setup before your customers do.
The short version
- Keys: replace every test key with its live version, on the backend and in the browser.
- Prices: create your products in live mode and use the live price IDs. Test IDs don't exist in live mode.
- Webhooks: add a live endpoint and copy its own signing secret. The test secret won't verify live events.
- Customer portal and saved IDs: save the portal settings in live mode too, and don't reuse customer IDs saved during testing.
- Test it: make one real purchase on your published app and check your database, not just Stripe.
What is separate in test and live mode
According to Stripe's API keys docs, every API request runs either in a sandbox (test mode) or in live mode. Each mode has its own keys, and one mode can't see the other mode's objects. So each of these has a test version and a live version:
- API keys. Test keys start with
pk_test_,sk_test_orrk_test_; live keys withpk_live_,sk_live_orrk_live_. - Products and prices, and with them every
price_…ID in your code or settings. - Customers, subscriptions and payments. Nothing you bought while testing exists in live mode.
- Webhook endpoints, each with its own
whsec_…signing secret. - Customer portal settings. You set these separately for sandboxes and for live mode.
Stripe also needs your account set up for real payments, with your business and payout details. Until then you can't accept real payments.
Step 1: Swap every key
Your backend key creates the checkout sessions. Where you change it depends on how you built the app:
- Lovable (your own Stripe account): the key is stored as a backend secret called
STRIPE_SECRET_KEY. Lovable's Stripe docs say to ask Lovable to update your Stripe key, then enter the live key in the Update Stripe secret key form. Never paste a key into the chat as a message. - Bolt: the key goes in the project's Stripe settings (the gear icon, then Stripe), per Bolt's Stripe docs. Their setup steps use a test key. When you switch, add your live key in the same place.
- Your own Supabase project: also check the edge function secrets in the Supabase dashboard. That's where the deployed functions read the key from.
If your app also uses a publishable key in the browser (for example, for an embedded payment form), change it to pk_live_… too. A live secret key with a test publishable key, or the other way around, causes confusing errors. If your host has separate preview and production settings, change the production ones.
Stripe's go-live checklist also says to rotate your keys before launch, in case one was saved somewhere outside your code, and to make sure no key is written in the code itself. Stripe also recommends restricted keys (rk_live_…) with only the permissions your app needs, instead of full secret keys.
Step 2: Use live products and price IDs
A live payment can't use a test price. If your app still sends one, Stripe returns an error like this:
No such price: 'price_…'; a similar object exists in test mode,
but a live mode key was used to make this request.To fix it, create the products in live mode. If you made them in the Stripe Dashboard, open each product in your sandbox and click Copy to live mode. Stripe copies the product and its prices. The live copies get new IDs, so point your app at them:
- Lovable: Lovable's docs say price IDs are different in each mode. Ask Lovable to switch your app to the live price IDs.
- Bolt: Bolt imports products from your Stripe account when you click Retrieve my products. After switching to the live key, make sure the products you select are the live ones.
- Any app: search your code and settings for
price_and confirm each ID exists in live mode in your Dashboard.
Step 3: Set up live webhooks
If your app learns about payments from webhooks (for example, to mark a user as paid in your database), a missing live endpoint is a common reason people pay but never get access. Each webhook endpoint belongs to one mode and has its own signing secret.
- In live mode, open Webhooks in the Stripe Dashboard and check whether a live endpoint exists for your published app's webhook URL (not a preview or localhost address).
- Subscribe it to the same events your test endpoint uses, such as
checkout.session.completed,customer.subscription.updatedandcustomer.subscription.deleted. - Copy the live endpoint's signing secret into your backend secrets, replacing the test one.
Bolt's docs say Bolt registers the webhook endpoint and checks signatures for you. Lovable's own-account integration doesn't use webhooks unless you asked for them. Either way, the live Webhooks page shows you what exists. If live webhooks arrive but fail, our guide to fixing a Stripe webhook that isn't working covers each error.
Step 4: Things people often miss
- Customer portal. If your app has a "Manage subscription" button, save the customer portal settings in live mode too. Lovable's docs say the portal doesn't work inside the Lovable preview panel, so test it in a normal browser tab.
- Customer IDs saved during testing. If your database saved a Stripe customer ID for your own test account, that ID doesn't exist in live mode. Reusing it gives the same "similar object exists in test mode" error. Clear test IDs before launch.
- Success and cancel URLs. Make sure checkout sends people back to your published domain, not a preview address.
- Payments from the preview are real. Lovable's docs say that with your own Stripe account, the preview has no separate test environment. Once the live key is in, a purchase in the preview charges a real card.
Step 5: Test with one real purchase
Stripe's test cards don't work in live mode, so the final check is a real payment:
- On your published app, sign up with a fresh account and buy your cheapest plan with a real card.
- In the Stripe Dashboard (live mode), check the payment and, if you use webhooks, that the delivery shows a 2xx status.
- In your database, check that the user's plan actually changed. Stripe can show a successful payment even when your app didn't update.
- Open the customer portal, cancel, and check that access goes away when it should. You can then refund the payment from the Dashboard.
Before you switch, also test what happens when a payment fails. Bolt's docs list test cards for a successful payment (4242 4242 4242 4242), a declined payment (4000 0000 0000 0002) and one that requires authentication (4000 0025 0000 3155).
Instructions you can paste into Lovable or Bolt
I'm switching Stripe from test mode to live mode. Please check:
1. No Stripe key is written in the code. The secret/restricted key is
read from backend secrets, and any publishable key from an
environment variable.
2. List every Stripe price ID the app uses and where it's set, so I
can replace them with the live price IDs.
3. Checkout success and cancel URLs use my published domain.
4. The webhook function (if any) reads its signing secret from a
secret, so I can replace it with the live endpoint's secret.
5. Stripe customer IDs saved during testing aren't reused for live
checkouts.
Don't change the keys yourself; I'll update them in the secure form.Questions people ask
Why does Stripe say "a similar object exists in test mode, but a live mode key was used"?
Your app sent a live key with the ID of something created in test mode, usually a price and sometimes a customer or product. Test and live mode don't share objects, so the live API can't find it. Put the live price IDs in your production settings, and make sure your app doesn't reuse customer IDs saved during testing.
Do my test customers and subscriptions carry over to live mode?
No. Customers, subscriptions and payments made in a sandbox exist only there. Anyone who "subscribed" with a test card has no live subscription. If you saved Stripe customer or subscription IDs in your database during testing, clear them or keep them apart from live ones.
Can I put my Stripe publishable key in the frontend?
Yes. Publishable keys (pk_test_ and pk_live_) are made for browser code. Secret keys (sk_) and restricted keys (rk_) are not. Keep those in your backend secrets and never in code that runs in the browser.
Does this apply to Lovable's built-in payments?
No. With built-in payments, Lovable manages the keys, webhooks and test and live environments for you. This checklist is for apps that connect your own Stripe account, in Lovable, Bolt, Replit or another builder.
Check your live site for free
PaidPath's free checker loads your live app from the outside. It flags a Stripe test publishable key (pk_test_…) in your public code, an exposed secret key, and signup, login or pricing pages that return an error. Paid plans also check your Stripe account every hour with a read-only key. If you connect your app's user data too, they flag customers who paid but weren't upgraded, so you don't have to wait for the customer to tell you.