/** * Stripe payment integration * * Configured via STRIPE_SECRET_KEY env var. * STRIPE_PUBLISHABLE_KEY is exposed to the frontend via /api/config. * * Stripe is available as a secondary payment processor. * Authorize.net is recommended as the primary for seamless checkout. */ import Stripe from "stripe"; let _stripe: Stripe | null = null; function getStripe(): Stripe { if (!_stripe) { if (!process.env.STRIPE_SECRET_KEY) { throw new Error("STRIPE_SECRET_KEY is not configured"); } _stripe = new Stripe(process.env.STRIPE_SECRET_KEY, { apiVersion: "2024-06-20" as any, }); } return _stripe; } export function isStripeConfigured(): boolean { return !!process.env.STRIPE_SECRET_KEY; } export interface StripePaymentIntentResult { success: boolean; clientSecret?: string; paymentIntentId?: string; error?: string; } /** * Create a PaymentIntent for use with Stripe Elements on the frontend. */ export async function createPaymentIntent(params: { amountCents: number; currency?: string; email: string; metadata?: Record; }): Promise { try { const stripe = getStripe(); const intent = await stripe.paymentIntents.create({ amount: params.amountCents, currency: params.currency || "usd", receipt_email: params.email, metadata: params.metadata, }); return { success: true, clientSecret: intent.client_secret!, paymentIntentId: intent.id, }; } catch (err: any) { return { success: false, error: err.message }; } } /** * Retrieve a PaymentIntent by ID and check if it succeeded. */ export async function verifyPaymentIntent( paymentIntentId: string ): Promise<{ success: boolean; status?: string; error?: string }> { try { const stripe = getStripe(); const intent = await stripe.paymentIntents.retrieve(paymentIntentId); return { success: intent.status === "succeeded", status: intent.status }; } catch (err: any) { return { success: false, error: err.message }; } } /** * Issue a refund against a PaymentIntent. */ export async function refundPaymentIntent(params: { paymentIntentId: string; amountCents?: number; }): Promise<{ success: boolean; refundId?: string; error?: string }> { try { const stripe = getStripe(); const refund = await stripe.refunds.create({ payment_intent: params.paymentIntentId, ...(params.amountCents && { amount: params.amountCents }), }); return { success: refund.status === "succeeded", refundId: refund.id }; } catch (err: any) { return { success: false, error: err.message }; } }