Patterns and conventions for implementing Stripe Checkout in this project. Use when creating or modifying payment flows, adding packages, or implementing webhooks.
stripe@^14 via CommonJS require('stripe')payment (one-time, not subscription)runetlify/functions/create-checkout.jsconst stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const session = await stripe.checkout.sessions.create({
mode: 'payment',
locale: 'ru',
line_items: [{ price: priceId, quantity: 1 }],
success_url: `${process.env.BASE_URL}/success.html`,
cancel_url: `${process.env.BASE_URL}/#pricing`,
// Optional enhancements:
allow_promotion_codes: true,
customer_email: customerEmail, // prefill email if known
metadata: { package: '4_sessions' },
payment_intent_data: { description: '4 psychology sessions — Ulyana Grau' },
});
return { statusCode: 200, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url: session.url }) };
const ALLOWED_PRICES = [
process.env.PRICE_4_SESSIONS,
process.env.PRICE_8_SESSIONS,
process.env.PRICE_12_SESSIONS,
];
if (!ALLOWED_PRICES.includes(priceId)) {
return { statusCode: 400, body: JSON.stringify({ error: 'Invalid price' }) };
}
// netlify/functions/stripe-webhook.js
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
exports.handler = async (event) => {
const sig = event.headers['stripe-signature'];
let stripeEvent;
try {
stripeEvent = stripe.webhooks.constructEvent(
event.body,
sig,
process.env.STRIPE_WEBHOOK_SECRET
);
} catch (err) {
return { statusCode: 400, body: `Webhook Error: ${err.message}` };
}
if (stripeEvent.type === 'checkout.session.completed') {
const session = stripeEvent.data.object;
// handle post-payment logic here
}
return { statusCode: 200, body: JSON.stringify({ received: true }) };
};
PRICE_X_SESSIONS in Netlify site settingsALLOWED_PRICES array in create-checkout.jsbuyPackage('...') button in index.htmlCLAUDE.md pricing tableasync function buyPackage(priceId) {
const res = await fetch('/.netlify/functions/create-checkout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ priceId }),
});
const data = await res.json();
if (data.url) window.location.href = data.url;
}
STRIPE_SECRET_KEY only in Netlify Function files — never in HTML/JSpriceId server-side against whiteliststripe-signature4242 4242 4242 42424000 0000 0000 00024000 0025 0000 3155