import Stripe from "stripe";
import express from "express";
// ============================================
// Configuration
// ============================================
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: "2023-10-16", // Update to latest
});
const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET!;
// ============================================
// Services
// ============================================
export const stripeService = {
// Create Checkout Session
async createCheckoutSession(priceId: string, customerId?: string) {
const session = await stripe.checkout.sessions.create({
mode: "subscription", // or 'payment'
payment_method_types: ["card"],
line_items: [
{
price: priceId,
quantity: 1,
},
],
customer: customerId,
success_url: `${process.env.DOMAIN}/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.DOMAIN}/cancel`,
});
return session;
},
// Create Customer Portal Session
async createPortalSession(customerId: string) {
const session = await stripe.billingPortal.sessions.create({
customer: customerId,
return_url: `${process.env.DOMAIN}/account`,
});
return session;
},
// Get Customer Subscription
async getSubscription(customerId: string) {
const subscriptions = await stripe.subscriptions.list({
customer: customerId,
status: "active",
limit: 1,
});
return subscriptions.data[0] || null;
},
};
// ============================================
// Webhook Handler
// ============================================
export const webhookHandler = async (
req: express.Request,
res: express.Response,
) => {
const sig = req.headers["stripe-signature"];
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(
req.body, // Must be raw buffer
sig!,
endpointSecret,
);
} catch (err: any) {
console.error(`Webhook Error: ${err.message}`);
return res.status(400).send(`Webhook Error: ${err.message}`);
}
// Handle the event
try {
switch (event.type) {
case "checkout.session.completed": {
const session = event.data.object as Stripe.Checkout.Session;
// Provision access, update database, send email
console.log("Payment successful for session:", session.id);
break;
}
case "customer.subscription.updated": {
const subscription = event.data.object as Stripe.Subscription;
// Update subscription status in DB
console.log("Subscription updated:", subscription.id);
break;
}
case "customer.subscription.deleted": {
const subscription = event.data.object as Stripe.Subscription;
// Revoke access
console.log("Subscription canceled:", subscription.id);
break;
}
default:
console.log(`Unhandled event type ${event.type}`);
}
} catch (error) {
console.error("Error processing webhook:", error);
return res.status(500).send("Error processing webhook");
}
res.json({ received: true });
};