Production checklist
Stripe production checklist: 7 checks before launch
7 checks for running Stripe in production: 2 must-dos, 3 should-dos and 2 good-to-haves. Each one says why it matters, how to verify it and where the docs are.
Updated . Every check links the vendor’s own docs.
Must do (2)
Verify webhook signatures
Without the signature check anyone can POST a fake "payment succeeded" event to your endpoint.
Verify from the command line
Send your webhook endpoint a request without a valid Stripe-Signature header; it must be rejected (400). Then use the Stripe CLI to send a real signed event and check it’s accepted.
curl -i -X POST https://<your-app>/api/webhooks/stripe -H "Content-Type: application/json" -d '{"type":"checkout.session.completed"}' stripe listen --forward-to localhost:3000/api/webhooks/stripe stripe trigger payment_intent.succeededSet prices and amounts on the server, never from the client
A tampered request can otherwise buy anything at any price. Send product or price ids from the browser and look the amount up on your server.
Check the code
Your checkout endpoint takes product or price ids from the browser and builds line items from Price ids on the server. A pass: no amount or price is read from the request body.
line_items: [{ price: '<price_id>', quantity: 1 }]
Should do (3)
Send idempotency keys on create requests
A retried request after a timeout otherwise charges the customer twice.
Check the code
Every create call passes an idempotency key derived from your own record (order or cart id), so a retry can’t charge twice.
await stripe.paymentIntents.create(params, { idempotencyKey: `order-${order.id}` });Handle duplicate and out-of-order webhook events
Stripe delivers at least once; record processed event ids and don’t assume ordering.
Verify from the command line
Resend an event that was already processed. Your handler should recognise its id (stored in a processed-events table) and do nothing the second time.
stripe events resend <evt_id>
Collect card details with Stripe Checkout or Elements, not your own form
Card numbers then never touch your servers, which keeps your PCI DSS scope as small as it gets.
Verify from the command line
Search your frontend for your own card inputs; a pass finds none, because payment forms use Stripe Checkout or the Payment Element.
grep -rniE "card.?number|cvc|cvv" --include=*.tsx --include=*.jsx --exclude-dir=node_modules .
Good to have (2)
Use restricted API keys per service
Limits the blast radius if one key leaks.
How to verify
In the Stripe Dashboard under Developers → API keys, each service should use its own restricted key (rk_live_…) with only the permissions it needs, and the full secret key shouldn’t be deployed where it isn’t needed.
Work through Stripe’s go-live checklist
Covers live keys, webhooks in live mode, receipts, statement descriptors and handling failed payments before real money moves.
How to verify
Tick off each item on the checklist before switching to live keys, then make one real low-value payment and refund it.
Get the checklist for your whole stack
Design your stack or map your repo in StackPrism, and the Improve panel lists the checks for every technology on it and keeps track of what you’ve done. Building with an AI app builder? Start with the vibe coding checklist.