Stripe Test Mode to Live Mode: The Pre-Launch Checklist for AI-Built Apps
22 checks before you flip Stripe to live mode. Webhook endpoints, test cards, tax, legal pages, invoice branding, refund policy, dispute handling.
The Stripe dashboard has a little toggle in the top left that switches between test mode and live mode. For most vibe coders, that toggle is the most expensive single click of the entire build. Everything that worked during development, the card that always succeeded, the webhook that fired instantly, the receipt that landed in Mailtrap, is suddenly touching real money and real customers with real card issuers who genuinely do not care that your AI agent wrote the integration in an afternoon.
The painful part is not that Stripe is hard. The painful part is that test mode and live mode are almost separate systems that happen to share a dashboard. Products, prices, webhooks, coupons, customers, tax rates, Radar rules, none of it carries over. If your build assistant scaffolded everything against test keys, you are about to ship into a fresh empty account with no webhook endpoint, no products, no receipts, and no dispute flow. The first real customer charge either succeeds silently and fails to fulfil, or fails loudly and refunds through a chargeback six weeks later with a fifteen dollar fee attached.
This is the checklist we run before a WitsCode client flips the switch. Twenty two checks, grouped into the five places they actually live. No fluff, no screenshots of obvious buttons, just the ones that bite.
Before you start, open two browser tabs. One on the Stripe dashboard in test mode, one in live mode. You are going to be translating state from left to right for the next hour or two, and the muscle memory of which tab is which will prevent the worst class of mistake: creating a production customer with real billing details while you thought you were still poking around in test. The top-left toggle colour is your only visual cue and it is not as obvious as it should be, so verify every single time you click a create button.
Account, Identity and Brand Surface
Start where Stripe starts. Your account activation is not complete just because you can see the dashboard. Stripe wants your legal entity, registered address, date of birth for the responsible person, last four of a social security number or the national equivalent, business tax ID, a live website URL, and a bank account in the same country as the entity. That is the first check. The second is your business profile, which is separate: legal name, trading name, support email, support phone, and a short description that actually matches what you sell. Stripe manually reviews a slice of new accounts, and a mismatch between your website copy and the description you typed into the profile is one of the most common reasons activation gets paused for extra documentation.
The third check is the statement descriptor. Open Settings, Public details, and set the descriptor to something a human would recognise on their bank statement. If you leave the default, charges show up as a string like STRIPE ACCT12345, and your dispute rate will climb inside a week because customers do not remember buying from a random acronym. The descriptor has a hard twenty two character limit and must match the brand the customer saw at checkout.
Fourth, invoice and receipt branding. Settings, Branding. Upload a square logo, upload an icon, set the primary brand colour, set the accent colour. This is what appears on the PDF invoice, the hosted receipt page, and the Checkout page header. Default unbranded PDFs look exactly like a phishing email, which is another reason disputes spike. Fifth, inside the same area, set your support email and a short footer line for invoices. The footer is where you put your company number, VAT number, and registered address if your jurisdiction requires them on invoices.
Keys, Products and Webhook Plumbing
Now the plumbing. Sixth check is the key swap. Your environment variables currently contain pk_test_ and sk_test_ values. Live mode uses pk_live_ and sk_live_, and the secret key is shown exactly once when you reveal it. Swap both in your production environment, whether that is Vercel, Fly, Railway or a self-hosted server, and redeploy. Never commit live keys to git. If your AI assistant baked them into a config file, revoke them in the dashboard and reissue.
Seventh, recreate your product catalogue. This is the one that surprises almost every vibe coder. A product with ID prod_Abc123 in test mode does not exist in live mode at all. Neither do its prices. If your checkout code references a hardcoded price ID, it will throw a no such price error the moment you hit production. Either recreate every product and price by hand in the live dashboard and update your code with the new IDs, or build a small migration script that reads your test catalogue and recreates it via the live API. While you are in there, recreate coupons, promotion codes, and any tax rates you configured manually.
Eighth, and this is the single most skipped check in every AI-built Stripe integration we audit, is the webhook endpoint. Webhook endpoints registered in test mode are completely invisible to live mode. Go to Developers, Webhooks, flip into live mode, click Add endpoint, paste your production URL, and select the exact same events your test endpoint subscribed to. Ninth, take the new signing secret that Stripe shows you on that screen and put it in your production environment as STRIPE_WEBHOOK_SECRET. The test signing secret will not verify live events and every webhook will return 400. Tenth, pin your API version. In Developers, API version, you will see the version your account currently defaults to. Lock it to the version you developed against so that a silent Stripe upgrade does not reshape the objects your code parses.
Customer-Facing Settings and Payment Methods
Eleventh, turn on email receipts. Settings, Emails, and enable successful payment receipts, refund receipts, and failed payment notifications. Many newer account types ship with these off by default because Stripe assumes you want to send your own transactional mail, which is fine if you actually built that, and fatal if you did not. Twelfth, configure the Customer Portal. Settings, Billing, Customer portal. Enable it, choose which actions customers can take, cancel subscription, update payment method, download invoices, update billing address, and crucially grab the portal URL from the settings page. Your app needs to link to this URL, or customers who want to cancel will cancel through their bank as a dispute instead, and every dispute costs you fifteen dollars and a point on your chargeback ratio.
Thirteenth, Stripe Tax. If you sell to customers outside your home jurisdiction or across US state lines, you probably have a tax obligation somewhere. Open Tax, Registrations, add the regions you are registered in, and turn on Stripe Tax for your Checkout sessions or PaymentIntents. If you have decided you are below nexus thresholds and not registering yet, still turn on the monitoring view so Stripe warns you when you cross a threshold. Fourteenth, payment methods. Settings, Payment methods. Even if test mode showed Link, Apple Pay, Google Pay, SEPA, iDEAL and Bancontact all enabled, live mode requires you to enable each one and some of them, specifically SEPA Direct Debit, BACS, and a few local methods, require extra KYC documents or a domain verification file before they activate. Apple Pay needs the domain association file served at /.well-known/apple-developer-merchantid-domain-association on your live domain.
Fifteenth, Strong Customer Authentication. In Europe, UK and increasingly elsewhere, issuers will challenge a percentage of transactions with 3D Secure. The PaymentIntent lifecycle includes a requires_action status where you must redirect the customer through Stripe.js to complete the challenge. Test mode rarely exercises this path because the standard success card does not trigger it. Before launch, use Stripe's test card 4000 0025 0000 3155 in test mode to force a challenge and confirm your code handles the status correctly. Then repeat the smoke with a real European card in live mode.
Sixteenth, Radar. Stripe Radar ships with default rules that are tuned for a mature merchant. On a brand new account with no transaction history, the default block rules can reject legitimate customers in higher-risk countries, customers on mobile networks, or anyone using a prepaid card. Open Radar, Rules, review the default block and review rules, and soften the ones that do not fit your product. For a digital SaaS selling globally, blocking all prepaid cards will cost you more than the fraud it prevents. Revisit this at thirty days in.
Disputes, Legal and Policy
Seventeenth is the one that catches founders off guard. The first chargeback on a new Stripe account is a trigger event. If you receive a dispute before you have completed the business verification, or before you have enabled the dispute response flow, Stripe can extend your payout schedule from the standard T+2 to T+7 or T+14, and on higher-risk accounts can place a rolling reserve on incoming funds. Before launch, open Disputes, set a notification email that a human actually reads, and draft a short evidence template: order confirmation, delivery confirmation or login logs, customer correspondence, refund policy, and terms of service. Stripe lets you upload evidence for each dispute and wins the defensible ones for you, but only if you respond inside the window, which is usually seven to twenty one days depending on the card network.
Eighteenth, your Terms of Service URL and Privacy Policy URL must be live, must resolve, and must be submitted in the business profile. Stripe will reject activation if these 404. If you generated them with a template, read them once and make sure the entity name and jurisdiction match what you put on the activation form. Nineteenth, publish a refund policy page on your marketing site and link it from the footer and from the checkout page itself. Stripe does not require this, but every card network treats a visible refund policy as primary evidence when you contest a dispute under the product not as described reason code. A linked refund policy at checkout wins more disputes than any other single piece of evidence.
The Pre-Flight Smoke Test
Twentieth, scrub test fixtures out of your production build. Search your codebase for 4242 4242 4242 4242, for any test@example.com hardcoded as a recipient, for any mock customer objects that seeded your development database, and for any Cypress or Playwright specs that post real API calls to checkout. These sneak into production bundles more often than you would think, especially when an AI assistant copies an earlier file as a starting point for a new one. Twenty first, confirm your server-side Stripe calls use idempotency keys. Every create PaymentIntent, create Customer, create Subscription call should pass an Idempotency-Key header with a stable unique value, usually your internal order ID. Without it, a retry after a network blip becomes a duplicate charge.
Twenty second, the end-to-end smoke. Put a real card, a real personal one, into your live checkout. Charge yourself one currency unit, the minimum allowed. Watch the webhook land in your production logs. Confirm the receipt email arrives at the customer email address, not the Stripe account email. Confirm the charge appears in the dashboard with the correct statement descriptor. Then issue a full refund from the dashboard and watch the refund webhook fire. Then open the Customer Portal URL as the customer and confirm you can cancel, update the card, and download the invoice. If any single step fails, fix it before you tell a paying customer to visit the pricing page. If all twenty two pass, you are actually ready for live traffic.
One more note on the smoke. Do the refund loop from two directions. Refund once from the Stripe dashboard, which simulates a support agent pressing the button, and once from your own admin UI if you built one, which exercises the refund API path and the webhook handler that should unlock whatever your product locked when the charge succeeded. These are two different code paths. Vibe-coded apps almost always get the charge-succeeded path right because it is the happy one, and almost always leave the refund-succeeded path silently broken because no one tests it before launch. The customer who asks for a refund is already unhappy. Do not compound it by leaving their account in the paid state for a week.
Where Vibe Coders Usually Break
The pattern we see at WitsCode across dozens of Stripe go-lives is that the code itself is fine. AI assistants write serviceable integrations. The damage lives in the configuration layer that the assistant cannot see and therefore cannot check: the webhook endpoint that was never recreated in live mode, the customer portal that was never turned on, the statement descriptor that still says the default, the Radar rules that silently reject a third of African and South Asian cards, the invoice PDF that looks like a phishing attempt. These are dashboard settings, not code, and no AI pair-programmer will flag them because they cannot read your account state.
If you want a human to walk the full twenty two with you, stage a one pound smoke charge on your live integration, and hand back a production-ready Stripe account with clean webhooks, tuned Radar, a branded portal, and a dispute response flow already loaded, that is the WitsCode Stripe go-live engagement. We do it as a fixed-scope two-day pass so you launch on schedule with the financial plumbing that your roadmap assumed was already there.
> Ready to flip the switch without the post-launch refund storm? Book a WitsCode Stripe go-live and we will take you from test mode to first real charge, clean.
Get weekly field notes.
Practical writing on shipping products, straight to your inbox. No spam.
Need help with this?
MVP Development
We design and build web apps, MVPs, and SaaS products. Talk to us about what you are working on.
Talk to usWant to discuss vibe coders for your business?
Start a project and we'll talk through where you are, what's working, and the highest-leverage moves for the next 90 days.