6 min read

What Is Subscription Management in Stripe

Recurring revenue requires tracking customers, billing cycles, and payment methods—all of which Stripe handles through subscriptions. Rather than building custom logic for when to charge, how much to charge, and what happens when payments fail, Stripe's subscription system automates these workflows. If you're running a SaaS or membership business, understanding subscriptions is essential.

How to Set Up a Basic Subscription

A subscription in Stripe connects a customer, a product/price, and a payment method. Here's how the pieces fit together.

Create or retrieve a customer

Every subscription needs a customer. Use stripe.customers.create() to add a new customer to Stripe, or fetch an existing one with stripe.customers.retrieve(). Store the customer ID—you'll need it for the subscription.

javascript
const customer = await stripe.customers.create({
  email: '[email protected]',
  name: 'Jane Doe',
  metadata: { user_id: '12345' }
});
Create a new customer in Stripe

Attach a payment method to the customer

Before Stripe can charge the customer, you need to attach a payment method (credit card, bank account, etc.). Use stripe.paymentMethods.attach() to link the payment method to the customer.

javascript
await stripe.paymentMethods.attach(
  'pm_card_visa',
  { customer: customer.id }
);

await stripe.customers.update(
  customer.id,
  { invoice_settings: { default_payment_method: 'pm_card_visa' } }
);
Attach a payment method and set it as the default

Create a subscription

Now create the subscription by specifying the customer, the price, and the billing cycle. Stripe will charge on the interval you set (monthly, annual, etc.). Use stripe.subscriptions.create() to start the subscription.

javascript
const subscription = await stripe.subscriptions.create({
  customer: customer.id,
  items: [{
    price: 'price_1234567890',
  }],
  payment_behavior: 'error_if_incomplete'
});
Create a subscription with automatic billing
Tip: Set payment_behavior: 'error_if_incomplete' to prevent subscriptions from starting if the first payment fails. This avoids creating a subscription with a failed payment.

Modifying Subscriptions

After a customer subscribes, you'll often need to change the quantity, upgrade to a different price, or adjust the billing amount. Stripe handles proration automatically.

Update the subscription price or quantity

Use stripe.subscriptions.update() to change what the customer is paying for. You can change the quantity, the price, or both. Stripe calculates the prorated amount based on the remaining billing period.

javascript
const updated = await stripe.subscriptions.update(
  subscription.id,
  {
    items: [{
      id: subscription.items.data[0].id,
      price: 'price_upgraded_plan',
    }],
    proration_behavior: 'create_prorations'
  }
);
Upgrade a customer to a more expensive plan mid-cycle

Handle proration and billing

When you update a subscription mid-cycle, Stripe calculates the difference between what the customer already paid and what they owe. Set proration_behavior: 'create_prorations' to bill the difference immediately, or use 'none' to skip the charge and wait until the next billing cycle.

javascript
await stripe.subscriptions.update(
  subscription.id,
  {
    items: [{ id: item.id, quantity: 5 }],
    proration_behavior: 'create_prorations',
    billing_cycle_anchor: 'unchanged'
  }
);
Apply proration and bill the difference on the next invoice
Watch out: Proration only applies when you change the price or quantity mid-cycle. If you're changing payment_settings, the new terms apply at the next renewal, not immediately.

Canceling and Ending Subscriptions

Subscriptions end in two ways: immediate cancellation (customer stops being charged) or at the end of the current billing period (grace period).

Cancel a subscription immediately

Use stripe.subscriptions.del() to stop a subscription right away. The customer won't be charged again, but they'll lose access when your app revokes it. This is the standard for when a customer cancels.

javascript
const canceled = await stripe.subscriptions.del(
  subscription.id
);
Cancel a subscription immediately

Set a cancellation date instead

To give customers a grace period (e.g., they lose access at the end of the month), use stripe.subscriptions.update() with cancel_at set to a future timestamp. The subscription cancels automatically at that time.

javascript
const gracePeriod = Math.floor(Date.now() / 1000) + (30 * 24 * 60 * 60);

await stripe.subscriptions.update(
  subscription.id,
  { cancel_at: gracePeriod }
);
Cancel at the end of the billing period (give a 30-day grace period)
Tip: Monitor the customer.subscription.deleted webhook to detect when subscriptions end, so you can sync your app and revoke access at the right time.

Common Pitfalls

  • Forgetting to set a default payment method before creating a subscription—Stripe will create it, but it won't charge until you attach one.
  • Not handling proration correctly when upgrading mid-cycle—use proration_behavior: 'create_prorations' to bill the difference immediately, or 'none' to defer.
  • Relying on subscription status from the API instead of webhooks—your app can drift out of sync if you don't listen for customer.subscription.updated and customer.subscription.deleted events.
  • Canceling a subscription without immediately revoking access in your app—the subscription stops, but the customer can still use the product until you remove access.

Wrapping Up

Subscription management in Stripe automates the complexity of recurring billing—you define the product, customer, and payment method, and Stripe handles the rest. Proration, retries, and dunning are built-in. If you want to track this automatically across tools, Product Analyst can help.

Track these metrics automatically

Product Analyst connects to your stack and surfaces the insights that matter.

Try Product Analyst — Free