Short answer
Check the key your production server actually sends. It must be a secret key (sk_live_) or a restricted key (rk_live_) from the Stripe account you mean, copied whole, and not one that was rolled or deleted. Copy the current key from the Dashboard into your host’s production environment variables, redeploy, and never put it in front-end code.
Which key is wrong, most common first
01
The production environment variable is missing or stale
“If a request doesn’t include a valid key, Stripe returns an invalid request error.” Stripe, API keys
The most common case: the key is set on your machine or a preview deploy but empty, truncated or out of date in production. Check the variable your server reads in your host’s production settings, look for a stray space or quote mark, then redeploy so the new value is used.
02
A publishable key where the secret key belongs
“The API key provided is a publishable key, but a secret key is required.” Stripe, Error codes
The server needs a secret or restricted key, and the publishable key belongs only in the browser or mobile app. Stripe reports a pk_ key on the server with its own code, secret_key_required, so if your logs show that code, the server variable holds the publishable key. Check the two variables weren’t swapped.
03
The key was rolled or deleted
“Code that uses the expired key can no longer make API calls.” Stripe, API keys
If someone rolled the key in the Dashboard, the old one stops working, after a grace period if one was set. Put the replacement key in every place that used the old one, including background jobs and other servers. An expired key shows a different code, api_key_expired, so if your logs show that code, this is the cause too.
04
A test key on live data, or the other way round
“When you’re ready to accept real payments: Switch to your live mode keys, which start with pk_live_, rk_live_, and sk_live_.” Stripe, API keys
Going live means switching to the live keys, and live mode starts without your test customers, prices and webhook endpoints. Our page on test mode working but live failing covers the rest of that switch.
05
The secret key is in front-end code
“Don’t embed secret or restricted API keys in source code or client-side applications.” Stripe, Authentication
AI builders sometimes put the secret key in the browser bundle, or in a variable with a public prefix such as VITE_ or NEXT_PUBLIC_. Move every call that needs it to the server. If the secret key was ever public, roll it in the Dashboard.
Checked against the vendor’s docs on : Stripe docs: API keys; Stripe docs: Error codes; Stripe API reference: Authentication.
Rather hand it over?
Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.
- $950Stripe Billing Fix and SetupSubscriptions, webhooks, customer portal and failed payments set up or fixed, tested in Stripe test mode.See scope and start
- from $450App Fix TicketOne reproducible bug in an existing mobile or web app, diagnosed and fixed.See scope and start
- from $450AI-Built App RescueA Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way.See scope and start
Related: Stripe works in test mode, not live · Stripe webhook signature error · Vercel environment variables undefined · Stripe PaymentIntent already succeeded