Payments Preflight · Check 4 of 15
Keep test and live keys separate
Use sandbox keys (sk_test_, pk_test_) everywhere except production, and live keys (sk_live_, pk_live_) only in production env vars. Webhook secrets differ per endpoint and mode.
What it is
Stripe has sandbox (test) keys and live keys. Sandbox keys start with pk_test_, rk_test_ and sk_test_. Live keys start with pk_live_, rk_live_ and sk_live_.
Why it matters
Live keys in preview or local builds can charge real cards from a test run. Test keys in production mean real customers cannot pay. Each webhook endpoint has its own signing secret, so a mismatch breaks verification.
How to check
- In your host's env settings, confirm Production uses live keys and Preview and Development use sandbox keys.
- Search the repo for
sk_live_andsk_test_. Neither should be committed. - Confirm the webhook secret in each environment belongs to the endpoint for that environment.
How to fix it
- Store keys only in env vars, scoped per environment.
- Fail fast at boot if production starts with a key that is not
sk_live_, or a non-production build starts with one that is. - If a live secret key was ever committed or exposed, roll it in the Dashboard.
const key = process.env.STRIPE_SECRET_KEY ?? "";
const isProd = process.env.VERCEL_ENV === "production";
if (isProd !== key.startsWith("sk_live_")) throw new Error("Stripe key mode does not match environment");Prompt for your AI coding tool
Paste into Cursor, Claude Code, Lovable or similar. Review the diff before you accept it.
Audit how my app loads Stripe keys. Make sure no Stripe key is hardcoded or committed, that keys come from env vars, and add a startup check that throws if production is not using an sk_live_ key or a non-production environment is using one. List every place a Stripe key or webhook secret is read.
Sources
- API keys Stripe docs
- Receive Stripe events in your webhook endpoint Stripe docs
Related checks
Sponsor this page: get in touch.