Subscription Management

Learn how to handle subscriptions, upgrades, downgrades, and cancellations in your application.

Creating Subscriptions

Create a subscription when a customer selects a plan:

// Create a subscription
const subscription = await stripe.subscriptions.create({
customer: customerId,
items: [{ price: priceId }],
payment_behavior: "default_incomplete",
payment_settings: {
save_default_payment_method: "on_subscription",
},
expand: ["latest_invoice.payment_intent"],
});
// Return the client secret for payment confirmation
const clientSecret = subscription.latest_invoice.payment_intent.client_secret;

Managing Subscriptions

Handle common subscription operations:

// Update subscription (e.g., change plan)
const updatedSubscription = await stripe.subscriptions.update(subscriptionId, {
items: [
{
id: subscriptionItemId,
price: newPriceId,
},
],
proration_behavior: "always_invoice",
});
// Cancel subscription
const canceledSubscription = await stripe.subscriptions.update(subscriptionId, {
cancel_at_period_end: true,
});
// Reactivate subscription
const reactivatedSubscription = await stripe.subscriptions.update(
subscriptionId,
{
cancel_at_period_end: false,
}
);
// Add usage record (for metered billing)
await stripe.subscriptionItems.createUsageRecord(subscriptionItemId, {
quantity: 10,
timestamp: "now",
action: "increment",
});

Handling Subscription Status

Track and respond to subscription status changes:

// Get subscription status
export async function getSubscriptionStatus(subscriptionId: string) {
const subscription = await stripe.subscriptions.retrieve(subscriptionId);
return {
status: subscription.status,
cancelAtPeriodEnd: subscription.cancel_at_period_end,
currentPeriodEnd: subscription.current_period_end,
trialEnd: subscription.trial_end,
};
}
// Check if subscription is active
export function isSubscriptionActive(subscription: Stripe.Subscription) {
return (
subscription.status === "active" ||
subscription.status === "trialing"
);
}

Customer Portal

Let customers manage their subscriptions through the Stripe Customer Portal:

// Create a portal session
export async function createPortalSession(customerId: string) {
const session = await stripe.billingPortal.sessions.create({
customer: customerId,
return_url: `${process.env.NEXT_PUBLIC_SITE_URL}/settings/billing`,
});
return session.url;
}
// Configure portal features in Stripe Dashboard:
// - Subscription management
// - Payment method updates
// - Billing history
// - Customer information updates

Best Practices

  • Always handle webhooks for subscription status changes
  • Implement proper error handling for failed payments
  • Consider offering a trial period for new subscriptions
  • Use metadata to store additional subscription information
  • Sync subscription data with your database

Next Steps