Payments in your AI-built app: 7 checks before you switch them on
Seven checks to run before you switch on Stripe or another payment system in an app built with Lovable, Cursor or Bolt.
Author
G. Tempesta
Published
Reading
4 min
Updated
Written with AI assistance, reviewed by Giovanni Tempesta
Is your app built with Lovable, Cursor or Bolt about to switch on Stripe or another payment system? Then this is the right time to have the code reread. With payments, a mistake costs real money: yours or your customers'.
In one app I reviewed, the Pro plan could be unlocked from the browser: changing one variable was enough to use it without paying. On top of that, the payment webhook did not verify the signature. I fixed both: now the server verifies the subscription and the signature. Both are easy mistakes to make in AI-built apps, and you can check for them before launch.
The 7 checks to run before you switch on payments
1. The server decides who has paid
The browser can show the Pro plan, but it must not be the one deciding. Only the server records who has paid, when the confirmation arrives from the payment system.
Try this: sign in with a free user and change the plan value in the browser. If the app actually lets you use the paid features, not just see them, the check on the server is missing.
2. The webhook verifies the signature
The webhook is the message Stripe uses to tell your app that a payment has gone through. Stripe signs every message. The server must check the signature before trusting it: without this check, anyone can send a fake «paid».
3. Secret keys stay on the server
Stripe gives you a publishable key and a secret key. The publishable key can live in the browser. The secret key and the webhook secret must live only in the server's environment variables.
Search the code that reaches the browser and the repository. If you find a key starting with sk_ or rk_, or a secret starting with whsec_, roll it straight away from the Stripe dashboard.
4. Tests use a test environment
Stripe has a test mode, with keys different from the live ones. While you are testing, use the test keys and a test database. That way a test does not create real subscriptions and a mistake does not reach your customers.
5. Decide what happens when a payment fails
A card expires, a renewal fails, a user cancels. Decide in advance what the user sees and what happens to their access in each of these cases. Then test each case in test mode.
6. Each payment is recorded only once
Stripe can send the same webhook more than once. The server must recognise an event it has already received and record the payment only once. Otherwise a subscription can end up activated twice.
Notifications can also arrive out of order, for example the cancellation before the renewal. The server must check the current state of the subscription instead of trusting the last notification it received.
7. Refunds and logs are ready
Before the first payment, know how to issue a refund and where you see it in the app. Also keep a log of every payment event you receive. When a customer writes «I've paid, but I can't see anything», you will find the answer in that log.
What these checks do not cover
These checks find the most obvious mistakes, not all of them. If your app has several plans, coupons or free trials, the payment logic gets more complex and the mistakes hide in the details. Before you open payments to real customers, it is worth having the code reread by someone who did not write it.
With the AI Code Check-up I also check your app's payments: who decides whether a user has paid, the webhooks, the secret keys and the cases where something goes wrong. I tell you what to fix before you switch them on. The price is fixed. Before I see the code, we sign a confidentiality agreement together, and I read the code without changing it. The AI Code Check-up page