Stripe
Stripe Integration
Stripe Integration Checkout & Payments import Stripe from 'stripe'; const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { apiVersion: '2024-06-20', }); //…
Stripe Integration
Checkout & Payments
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: '2024-06-20',
});
// Create Checkout Session (hosted page)
// app/api/checkout/route.ts
export async function POST(req: Request) {
const { priceId, userId } = await req.json();
const session = await stripe.checkout.sessions.create({
mode: 'subscription', // or 'payment' for one-time
payment_method_types: ['card'],
line_items: [{ price: priceId, quantity: 1 }],
success_url: `${process.env.NEXT_PUBLIC_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.NEXT_PUBLIC_URL}/pricing`,
metadata: { userId }, // pass your own data through
customer_email: user.email, // pre-fill email
allow_promotion_codes: true,
});
return Response.json({ url: session.url });
}
// Client — redirect to Stripe
const { url } = await fetch('/api/checkout', {
method: 'POST',
body: JSON.stringify({ priceId: 'price_123' }),
}).then(r => r.json());
window.location.href = url;
// Payment Intent (custom UI with Stripe Elements)
const paymentIntent = await stripe.paymentIntents.create({
amount: 2000, // in smallest currency unit (cents for USD)
currency: 'usd',
automatic_payment_methods: { enabled: true },
metadata: { orderId: '123' },
});
// Return client_secret to frontend to complete paymentWebhooks
// app/api/webhooks/stripe/route.ts
import { headers } from 'next/headers';
export async function POST(req: Request) {
const body = await req.text();
const sig = headers().get('stripe-signature')!;
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(
body,
sig,
process.env.STRIPE_WEBHOOK_SECRET!
);
} catch (err) {
return new Response(`Webhook Error: ${err.message}`, { status: 400 });
}
switch (event.type) {
case 'checkout.session.completed': {
const session = event.data.object as Stripe.Checkout.Session;
const userId = session.metadata?.userId;
const subscriptionId = session.subscription as string;
await db.subscription.create({
data: { userId, stripeSubscriptionId: subscriptionId, status: 'active' },
});
break;
}
case 'customer.subscription.updated': {
const sub = event.data.object as Stripe.Subscription;
await db.subscription.update({
where: { stripeSubscriptionId: sub.id },
data: { status: sub.status },
});
break;
}
case 'customer.subscription.deleted': {
const sub = event.data.object as Stripe.Subscription;
await db.subscription.update({
where: { stripeSubscriptionId: sub.id },
data: { status: 'canceled' },
});
break;
}
case 'invoice.payment_failed': {
const invoice = event.data.object as Stripe.Invoice;
// notify user, retry logic
break;
}
}
return new Response(null, { status: 200 });
}
// Test webhooks locally
// stripe listen --forward-to localhost:3000/api/webhooks/stripeCustomer Portal & Subscriptions
// Customer portal — let users manage subscription themselves
const portalSession = await stripe.billingPortal.sessions.create({
customer: user.stripeCustomerId,
return_url: `${process.env.NEXT_PUBLIC_URL}/settings`,
});
return Response.json({ url: portalSession.url });
// Create/retrieve customer
const customer = await stripe.customers.create({
email: user.email,
name: user.name,
metadata: { userId: user.id },
});
// Retrieve subscription with items
const subscription = await stripe.subscriptions.retrieve(
subscriptionId,
{ expand: ['items.data.price.product'] }
);
const plan = (subscription.items.data[0].price.product as Stripe.Product).name;
// Prices & Products (retrieve from dashboard or API)
const prices = await stripe.prices.list({
product: 'prod_123',
active: true,
expand: ['data.product'],
});
// Stripe CLI shortcuts
// stripe login
// stripe listen --forward-to localhost:3000/api/webhooks/stripe
// stripe trigger checkout.session.completed
// stripe customers list
// stripe subscriptions list