[{"data":1,"prerenderedAt":284},["ShallowReactive",2],{"blog-blueprints/lovable-stripe":3},{"id":4,"title":5,"body":6,"category":264,"date":265,"dateModified":265,"description":266,"draft":267,"extension":268,"faq":269,"featured":267,"headerVariant":270,"image":269,"keywords":269,"meta":271,"navigation":272,"ogDescription":273,"ogTitle":269,"path":274,"readTime":275,"schemaOrg":276,"schemaType":277,"seo":278,"sitemap":279,"stem":280,"tags":281,"twitterCard":282,"__hash__":283},"blog/blog/blueprints/lovable-stripe.md","Lovable + Stripe Security Blueprint",{"type":7,"value":8,"toc":254},"minimark",[9,20,24,30,35,91,95,110,119,123,132,136,145,149,154,157,160,163,166,169,172,175,178,194,230,242],[10,11,12],"blueprint-summary",{},[13,14,15,19],"p",{},[16,17,18],"strong",{},"To secure a Lovable + Stripe stack,"," you need to: (1) keep Secret Keys server-side only, (2) verify webhook signatures on every event, (3) use Stripe Checkout or Elements for PCI compliance, and (4) create payment intents on the server. This blueprint covers key management, webhook security, and payment flow best practices.",[21,22],"blueprint-meta",{"time":23},"1-2 hours",[25,26,27],"tldr",{},[13,28,29],{},"Stripe integration requires careful key management and webhook verification. Key rules: never expose the Secret Key (sk_*) in client code, always verify webhook signatures, use Stripe Checkout or Elements for PCI compliance, and create payment intents on the server only. Test with Stripe's test mode before going live.",[31,32,34],"h2",{"id":33},"stripe-key-management","Stripe Key Management",[36,37,38,54],"table",{},[39,40,41],"thead",{},[42,43,44,48,51],"tr",{},[45,46,47],"th",{},"Key Type",[45,49,50],{},"Prefix",[45,52,53],{},"Where to Use",[55,56,57,69,80],"tbody",{},[42,58,59,63,66],{},[60,61,62],"td",{},"Publishable Key",[60,64,65],{},"pk_test_ / pk_live_",[60,67,68],{},"Client-side (safe to expose)",[42,70,71,74,77],{},[60,72,73],{},"Secret Key",[60,75,76],{},"sk_test_ / sk_live_",[60,78,79],{},"Server-side only (NEVER expose)",[42,81,82,85,88],{},[60,83,84],{},"Webhook Secret",[60,86,87],{},"whsec_",[60,89,90],{},"Server-side only",[31,92,94],{"id":93},"part-1-stripe-environment-variables","Part 1: Stripe Environment Variables",[96,97,99],"code-block",{"label":98},"Environment configuration",[100,101,106],"pre",{"className":102,"code":104,"language":105},[103],"language-text","# Client-side (safe)\nVITE_STRIPE_PUBLISHABLE_KEY=pk_test_xxx\n\n# Server-side only (NEVER in client code)\nSTRIPE_SECRET_KEY=sk_test_xxx\nSTRIPE_WEBHOOK_SECRET=whsec_xxx\n","text",[107,108,104],"code",{"__ignoreMap":109},"",[111,112,113],"warning-box",{},[13,114,115,118],{},[16,116,117],{},"Critical:"," If the Secret Key (sk_*) is ever exposed, rotate it immediately in the Stripe dashboard. An exposed key allows full access to your Stripe account.",[31,120,122],{"id":121},"part-2-stripe-webhook-verification","Part 2: Stripe Webhook Verification",[96,124,126],{"label":125},"Verify webhook signatures",[100,127,130],{"className":128,"code":129,"language":105},[103],"import Stripe from 'stripe';\n\nconst stripe = new Stripe(process.env.STRIPE_SECRET_KEY);\n\nexport async function handleWebhook(request: Request) {\n  const body = await request.text();\n  const signature = request.headers.get('stripe-signature');\n\n  let event: Stripe.Event;\n\n  try {\n    event = stripe.webhooks.constructEvent(\n      body,\n      signature!,\n      process.env.STRIPE_WEBHOOK_SECRET!\n    );\n  } catch (err) {\n    console.error('Webhook signature verification failed');\n    return new Response('Invalid signature', { status: 400 });\n  }\n\n  // Handle the verified event\n  switch (event.type) {\n    case 'checkout.session.completed':\n      // Fulfill the purchase\n      break;\n    case 'payment_intent.succeeded':\n      // Handle successful payment\n      break;\n  }\n\n  return new Response('OK', { status: 200 });\n}\n",[107,131,129],{"__ignoreMap":109},[31,133,135],{"id":134},"part-3-stripe-payment-flow","Part 3: Stripe Payment Flow",[96,137,139],{"label":138},"Create checkout session (server-side)",[100,140,143],{"className":141,"code":142,"language":105},[103],"// This must run on the server, not the client\nexport async function createCheckoutSession(userId: string, priceId: string) {\n  const session = await stripe.checkout.sessions.create({\n    customer_email: userEmail,  // Or use customer ID\n    line_items: [{ price: priceId, quantity: 1 }],\n    mode: 'subscription',\n    success_url: `${process.env.APP_URL}/success?session_id={CHECKOUT_SESSION_ID}`,\n    cancel_url: `${process.env.APP_URL}/cancel`,\n    metadata: { userId },  // For webhook processing\n  });\n\n  return session.url;\n}\n",[107,144,142],{"__ignoreMap":109},[31,146,148],{"id":147},"security-checklist","Security Checklist",[150,151,153],"h4",{"id":152},"pre-launch-checklist-for-lovable-stripe","Pre-Launch Checklist for Lovable + Stripe",[13,155,156],{},"Secret Key only in server-side code",[13,158,159],{},"Webhook signature verification implemented",[13,161,162],{},"Using Stripe Checkout or Elements (PCI compliance)",[13,164,165],{},"Payment intents created server-side only",[13,167,168],{},"Test mode used for development",[13,170,171],{},"Live keys in production environment only",[13,173,174],{},"Webhook endpoint secured (HTTPS)",[13,176,177],{},"Idempotency keys used for retries",[179,180,181,188],"faq-section",{},[182,183,185],"faq-item",{"question":184},"Is the publishable key safe to expose?",[13,186,187],{},"Yes, the publishable key (pk_*) is designed for client-side use. It can only be used to create tokens or confirm payments, not to read data or make charges.",[182,189,191],{"question":190},"Why verify webhook signatures?",[13,192,193],{},"Without verification, attackers could send fake webhook events to your endpoint, potentially granting free access or disrupting your service. Always verify the signature.",[195,196,197,201,204],"stack-comparison",{},[31,198,200],{"id":199},"alternative-stack-options","Alternative Stack Options",[13,202,203],{},"Consider these related blueprints for different stack combinations:",[205,206,207,216,223],"ul",{},[208,209,210,215],"li",{},[211,212,214],"a",{"href":213},"/blog/blueprints/lovable-supabase","Lovable + Supabase"," - Store Stripe metadata in Supabase",[208,217,218,222],{},[211,219,221],{"href":220},"/blog/blueprints/lovable-firebase","Lovable + Firebase"," - Firebase for payment webhooks",[208,224,225,229],{},[211,226,228],{"href":227},"/blog/blueprints/lovable-vercel","Lovable + Vercel"," - Deploy Stripe webhooks on Vercel",[231,232,233,237],"related-articles",{},[234,235],"related-card",{"description":236,"href":213,"title":214},"Database for Stripe metadata",[234,238],{"description":239,"href":240,"title":241},"Deep dive into Stripe","/blog/guides/stripe","Stripe Security Guide",[243,244,247,251],"cta-box",{"href":245,"label":246},"/","Start Free Scan",[31,248,250],{"id":249},"integrating-stripe-with-lovable","Integrating Stripe with Lovable?",[13,252,253],{},"Scan for key exposure and webhook issues.",{"title":109,"searchDepth":255,"depth":255,"links":256},2,[257,258,259,260,261,262,263],{"id":33,"depth":255,"text":34},{"id":93,"depth":255,"text":94},{"id":121,"depth":255,"text":122},{"id":134,"depth":255,"text":135},{"id":147,"depth":255,"text":148},{"id":199,"depth":255,"text":200},{"id":249,"depth":255,"text":250},"blueprints","2026-02-04","Security guide for Lovable + Stripe integration. Protect API keys, verify webhooks, handle PCI compliance, and secure payment flows in your Lovable app.",false,"md",null,"purple",{},true,"Complete security configuration for Stripe integration in Lovable apps.","/blog/blueprints/lovable-stripe","10 min read","[object Object]","Article",{"title":5,"description":266},{"loc":274},"blog/blueprints/lovable-stripe",[],"summary_large_image","_j3sT8qrY1qiKmK5_n6of9PHi5lS0SWKtlgW-0RX9-k",1775843932353]