Webhooks & Integration
Learn how to integrate Stripe’s payment features, webhooks, subscription management, and pricing section in your app.
Stripe’s webhooks notify your app of payment events (e.g., successful payments, subscription updates), and the integration supports checkout sessions, subscription management, and pricing displays, all tied to your Next.js structure and Supabase database via Prisma.
Implementing Payments and Webhooks
Set Up Checkout Sessions
- Use Stripe’s Checkout in app or components for payments. Example:
import { SignIn } from '@clerk/nextjs';
export default function PricingCard(props) {
return (
<form action="/api/stripe/checkout" method="POST" className="w-full">
<input type="hidden" name="priceId" value={defaultPriceId} />
{discountedPrice && (
<input type="hidden" name="couponId" value={couponId} />
)}
<Button size={'lg'} className="w-full" type="submit">
{cta?.text}
</Button>
</form>
);
}import { stripe } from '@/lib/stripe/stripe';
import { NextRequest, NextResponse } from 'next/server';
export async function POST(req: NextRequest) {
const formData = await req.formData();
const priceId = formData.get('priceId')?.toString();
const couponId = formData.get('couponId')?.toString();
try {
const session = await stripe.checkout.sessions.create({
line_items: [
{
price: priceId,
quantity: 1,
},
],
discounts: [
{
coupon: couponId,
},
],
mode: 'payment',
success_url: `${process.env.SITE_URL}/order?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.SITE_URL}`,
automatic_tax: {
enabled: true,
},
custom_text: {
after_submit: {
message: `By continuing, you agree to Plainform's [Terms of Service](${process.env.SITE_URL}/terms-of-service) and [Privacy Policy](${process.env.SITE_URL}/privacy-policy), and to receive periodic emails with updates.`,
},
},
custom_fields: [
{
key: 'github',
label: {
type: 'custom',
custom: 'GitHub Username',
},
optional: false,
type: 'text',
},
],
payment_intent_data: {
capture_method: 'manual',
},
});
if (!session.url) {
return NextResponse.json({
message: 'Failed to create checkout session.',
status: 500,
});
}
return NextResponse.redirect(session.url!, { status: 303 });
} catch (error) {
return Response.json({ message: 'Server Error', error, status: 500 });
}
}Manage Subscriptions
- Create subscription plans in the Stripe dashboard and integrate them in Checkout. Example:
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
line_items: [{ price: 'price_123', quantity: 1 }],
success_url: `${process.env.NEXT_PUBLIC_SITE_URL}/success`,
cancel_url: `${process.env.NEXT_PUBLIC_SITE_URL}/cancel`,
});- Allow users to manage subscriptions via Stripe’s Customer Portal. Example:
import { stripe } from '@/lib/stripe';
export async function createPortalSession(customerId: string) {
const portalSession = await stripe.billingPortal.sessions.create({
customer: customerId,
return_url: `${process.env.NEXT_PUBLIC_SITE_URL}/account`,
});
return portalSession.url;
}Display Pricing Section
- Fetch products/prices with
getProductsfunction and render in a pricing component (e.g., components/Pricing.tsx):
export async function getProducts() {
try {
const res = await fetch(`${process.env.SITE_URL}/api/stripe/products`, {
cache: 'force-cache',
next: { tags: ['stripe/products'] },
});
if (!res.ok) {
throw new Error('Failed to fetch products!');
}
return res.json();
} catch (error) {
return error;
}
}import locale from '@/locales/en.json';
import { getProducts } from '@/lib/stripe/getProducts';
import { getCoupons } from '@/lib/stripe/getCoupons';
import { PricingCard } from '@/components/pricing/PricingCard';
export async function Pricing() {
const pricingLocale = locale?.homePage?.pricingSection;
const data = await getProducts();
const couponData = await getCoupons();
if (!data) {
return null;
}
return (
<div className=" flex items-center justify-center w-full gap-20 ">
{/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
{data?.products?.map((product: any) => (
<PricingCard
key={product?.id}
name={product?.name}
description={product?.description}
imgSrc={product?.images[0]}
currency={product?.default_price?.currency}
unitAmount={product?.default_price?.unit_amount}
defaultPriceId={product?.default_price?.id}
marketingFeatures={product?.marketing_features}
priceType={product?.default_price?.type}
couponId={couponData?.coupon?.id || null}
amountOff={couponData?.coupon?.amount_off || null}
percentOff={couponData?.coupon?.percent_off || null}
isCouponValid={couponData?.coupon?.valid || null}
perks={pricingLocale?.perks}
cta={pricingLocale?.cta}
/>
))}
</div>
);
}Configure Webhooks
- In the Stripe dashboard, add a webhook URL (e.g.,
https://yourapp.com/api/webhooks/stripe) and select events likecheckout.session.completed,invoice.paid, andcustomer.subscription.updated
switch (event.type) {
case 'coupon.created':
revalidateTag('stripe/coupons');
break;
case 'coupon.deleted':
await recordEvent({
type: 'coupon',
clear: true,
});
revalidateTag('stripe/coupons');
revalidateTag('event');
break;
case 'product.created':
case 'product.updated':
case 'product.deleted':
revalidateTag('stripe/products');
break;
case 'checkout.session.completed':
revalidateTag('stripe/coupons');
revalidateTag('stripe/orders');
await handleCheckoutSessionCompleted(
event.data.object as Stripe.Checkout.Session
);
break;
default:
break;Testing Payments and Webhooks
- Use Stripe’s test mode (test keys) and run
npm run devto test Checkout and subscriptions. - Simulate webhook events in the Stripe dashboard (e.g.,
checkout.session.completed). - Verify the pricing section displays correctly with product data.
- Test Customer Portal and subscription management flows.
Important Notes
- Environment Variables: Ensure
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY,STRIPE_SECRET_KEY, andSTRIPE_WEBHOOK_SECRETare valid, ort3-envwill block startup. - Customization: Configure Stripe’s Checkout UI or Customer Portal in the dashboard to match your app’s branding.
- Security: Keep
STRIPE_SECRET_KEYandSTRIPE_WEBHOOK_SECRETout of client-side code and version control.
For advanced features like multi-currency support, consult the Stripe Documentation.
How is this guide ?
Last updated on