Stripe is not working in my Lovable app. What do I check?
When Stripe is not working in a Lovable app, the cause is almost always one of five things: the app is still on test keys or test prices, the go-live steps were never finished, the webhook is missing or rejected, your app's record of who paid has drifted from Stripe's, or the backend function that talks to Stripe is failing. You can check all five from Stripe's dashboard and Lovable's payment settings without reading code.
Which one it is depends on how payments were set up. Lovable has two ways: built-in payments, where Lovable provisions the account and the webhooks for you, and your own Stripe account connected with a secret key, where by default there are no webhooks at all and the app asks Stripe directly. Find out which you have before changing anything.
The silent failures matter most: a customer who cancelled and kept access, or a payment that went through and never unlocked anything. Nothing tells you about either. The check at the end of this page finds both in about ten minutes.
In founders’ words
“Like the customer payed, but wasn't connected properly so they still ended up with no access. Or they cancelled, but still retained access.”
“Agent ships it, looks fine, breaks on a real webhook, and you pay again to fix what you already paid to build.”
“My existing published site is still live, but I can't republish updates.”
First, which Stripe setup does your Lovable app use?
Open Payments from the project's More menu. If it shows a Self-managed Stripe badge, you connected your own Stripe account with a key. Otherwise you are on built-in payments, which Lovable recommends for most projects and which needs a Pro plan or higher. A project uses one or the other, never both.
- Built-in payments: Lovable manages keys, webhooks, and separate test and live environments. The preview always runs in test mode and the published app in live mode.
- Your own Stripe key: Lovable writes backend functions that call Stripe with your key, stored as a secret named STRIPE_SECRET_KEY. By default the app checks payment and subscription status with Stripe directly, and matches subscriptions to users by email address. Webhooks exist only if you asked Lovable to add them and set them up in Stripe yourself.
- Code you or another agent added: if someone wrote a payment flow by prompt outside these two, treat it as your own Stripe key with webhooks, and check everything below.
Stripe works in the preview but not on the live app
- Test keys or test prices in production. Stripe keeps test and live data completely apart: a product in test mode does not exist in live mode, and price IDs differ. Lovable's docs say to switch the key and then ask Lovable to switch the app to the live price IDs. Half-switched is a common state.
- Go-live not finished. On built-in payments, "Until all go-live steps are completed, live checkout will not work", and that includes the provider's identity and business verification. Open the go-live checklist in the Payments tab.
- The opposite problem. With your own Stripe key there is no separate test environment: Lovable's docs say that "with a live key, payments made from the preview are real". If you have been testing with a real card on a live key, those were real charges.
- Checkout does not open. It opens in a new tab, and a popup blocker can stop it. The customer portal also needs activating once in Stripe, and it does not work inside Lovable's preview panel; test it in a normal browser tab or on the published app.
- The published app is behind. Lovable publishes a snapshot; if you fixed payments in the editor and did not publish again, the live app still has the old code.
Lovable Stripe webhook not working
A webhook is a message Stripe sends to your app when something happens: a payment succeeded, a subscription renewed, changed or ended, a card failed. If those messages do not arrive, or arrive and are refused, Stripe and your app stop agreeing about who has paid. These are the ways it fails:
- No endpoint, or the wrong one. On built-in payments, Lovable registers two endpoints per environment, and Lovable warns that deleting your app's endpoint "silently stops payment events": purchases succeed, subscriptions never activate. A duplicate pointing at the same address delivers events the app cannot verify; remove the one you made.
- Invalid signature. Your app checks each message with a signing secret. Stripe says the most common error is using the wrong one, and test and live endpoints have different secrets. A test secret on the live endpoint fails every live event. The check also fails if the code changes the message before checking it, because Stripe needs the raw body.
- Refused before your code runs. Lovable's backend functions run on Supabase, which by default rejects calls without a logged-in user's token with a 401 error, "and your code never executes". Stripe has no user token, so Supabase's docs say a Stripe webhook function needs JWT verification turned off and must check Stripe's signature itself.
- Not listening for the right events. A handler written for the first purchase only (checkout.session.completed) never hears about renewals, changes or cancellations (customer.subscription.updated and customer.subscription.deleted) or failed payments (invoice.payment_failed).
- The handler errors. Any error response or a redirect counts as a failure. Stripe retries live events for up to three days, and test events three times over a few hours, so a broken deploy can stay hidden for days.
Where to look: in Stripe, open Workbench, then Webhooks, select the endpoint and open Event deliveries. Each event shows Delivered, Pending or Failed with the response code. A 401 points at the Supabase setting, a 400 usually at the signing secret, a 500 at the handler. Once fixed, you can resend an event from the Dashboard for up to 15 days. If a subscription webhook keeps failing, Stripe also emails you, so check the inbox on your Stripe account.
Cancelled customers still have access
There are two records of who is paying: Stripe's, and a field in your own database (often called plan, is_pro or subscribed). The app unlocks features from its own record. If cancellations, refunds and failed payments never reach that record, it keeps saying yes. Nobody complains, because the people getting it free are not going to tell you.
The usual causes: the webhook only handles the first purchase; access is granted by the "payment successful" page instead of a message from Stripe, so anyone who opens that page gets access; or, with Lovable's own-key setup, a user signed up with one email and paid with another, so the match by email fails in one direction or the other.
Also decide what should happen. Stripe cancels immediately by default, unless the cancellation is set for the end of the paid period. Lovable's advice for built-in payments is not to remove access the moment someone cancels, because they have paid through the end of the period. And subscriptions whose payments keep failing are cancelled automatically after up to eight attempts. Your app should follow the subscription's status, not guess.
Check it in Stripe without touching code
- In Stripe, open Billing, Subscriptions, filter by Canceled, and note the customers' emails.
- In your database (Lovable Cloud's database view or the Supabase table editor), find those people in the table that stores access. Anyone cancelled who still has access is the bug.
- Do the reverse with active subscriptions: every active subscriber should have access.
- Open your webhook endpoint's Event deliveries and look for anything that is not Delivered.
- Check the events the endpoint listens to: at least checkout.session.completed, customer.subscription.updated, customer.subscription.deleted and invoice.payment_failed.
- In Lovable, confirm the key mode matches the app: a live key (sk_live_ or rk_live_) on the published app, and live price IDs.
- Run one real purchase on the published app, then cancel and refund it in Stripe and confirm access ends when it should.
Stripe in Replit, Bolt and other AI-built apps
The same five causes apply everywhere, with different switches. On Replit, the Stripe integration is for paid plans; the Agent starts on a Stripe sandbox, which Replit calls "not production-ready", and going live means installing the Replit Integrated Payments app on your live Stripe account and choosing the live account, not a sandbox. Founders report Replit blocking a republish with "Connect a live Stripe account before publishing" until that is done, and in at least one case Replit support had to clear an integration stuck as "Connected by: Unknown". If your Replit app is down for other reasons, there is a separate page for that.
Apps built with Bolt, Cursor, Claude Code or by hand on Supabase hit the webhook problems above most often, especially the Supabase 401 and the test signing secret on a live endpoint. The checks are the same.
When you may not need help, and when you do
If the cause was a test key, an unfinished go-live step, a popup blocker or a missing published update, you have fixed it, and the check above came back clean, you do not need anyone. Run that check once a month.
Bring someone in when money and access disagree and you cannot find why, when webhooks fail and the fix keeps breaking something else, when you need to move between built-in payments and your own Stripe account with paying customers in place, or when the app also has to take Apple's in-app purchase. Getting payments right is worth a second pair of eyes, and the free call is a fair place to start.
| What you see | Usual cause | Where to check |
|---|---|---|
| Checkout works in the preview, fails live | Test key or test price IDs, or go-live not finished | Lovable Payments go-live checklist; the key mode; live price IDs |
| Payment succeeds, nothing unlocks | Webhook missing, deleted or rejected | Stripe Workbench, Webhooks, Event deliveries |
| Webhook fails with 401 | Supabase rejected Stripe's call before your code ran | JWT verification on the webhook function |
| Webhook fails with 400 or a signature error | Wrong signing secret, often test on live | The secret stored in Lovable against the live endpoint's secret |
| Cancelled customers keep access | Only the first purchase is handled, or access set by the success page | Canceled subscriptions in Stripe against your access table |
| A subscriber shows as not paid | Signed up and paid with different emails | The Stripe customer's email against the app account's email |
| Customer portal errors | Portal not activated, or opened inside the preview panel | Stripe customer portal settings; test in a normal tab |
Questions
Does Lovable use webhooks for Stripe?
On built-in payments, yes: Lovable registers and manages them. With your own Stripe key, not by default; the app checks status with Stripe directly. You can ask Lovable to add webhooks, and then you create the endpoint and manage the signing secret in your Stripe dashboard.
Why does my Stripe webhook return 401 from Supabase?
Supabase checks every call to a backend function for a logged-in user's token by default, and Stripe does not send one, so the call is refused before your code runs. Supabase's docs say to turn JWT verification off for the webhook function and verify Stripe's signature in the code instead.
Is it safe to test with a real card?
Only if you mean to be charged. Use Stripe's test card on a test key. With your own Stripe key in Lovable, the preview uses whatever key is set, so a live key means real charges even in the preview.
Will disconnecting Stripe in Lovable stop charges?
Not necessarily. Lovable says disconnecting does not cancel customers' subscriptions, and on a project using your own Supabase the payment functions keep working, and keep charging, as long as the secret exists there. Cancel subscriptions in Stripe and remove the secret if you mean to stop.
Can I take Stripe payments in my iOS app?
Not for purchases made inside the app. Apple requires in-app purchase for subscriptions and unlocked features bought in the app, and an app that runs Stripe checkout for them is rejected. Apple's guidelines do let apps on the United States storefront link out to your website, where Stripe checkout is fine; in other regions that link needs an entitlement from Apple. Either way, Apple and Stripe should update the same subscription record your app checks.
First look, $750. After a free call, we read your whole product and tell you what is finished, what is not, and what to do first.
Setup, $3,000 fixed. We make it ready for real customers, in accounts you own.
Partner, $2,500 a month. We review what your coding agent writes and keep the checks and tests current. Month to month.
