/stripe-guides

How to create a subscription with Stripe API?

Learn how to create a subscription with the Stripe API, including setting up customers, products, prices, and handling payments. Step-by-step guide for developers.

Matt Graham, CEO of Rapid Developers

Book a call with an Expert

Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.

Book a free consultation

How to create a subscription with Stripe API?

How to Create a Subscription with Stripe API

 

Introduction

 

This tutorial will guide you through the process of creating a subscription using the Stripe API. Stripe is a popular payment processing platform that offers a robust API for handling subscriptions, payments, and more. By the end of this tutorial, you'll know how to set up customers, products, prices, and create subscriptions.

 

Step 1: Set Up Your Stripe Account

 

Before you can use the Stripe API, you need to create a Stripe account and get your API keys.

  1. Go to Stripe.com and sign up for an account
  2. Navigate to the Developers section
  3. Find your API keys (you'll have both test and live keys)

For development purposes, use the test API keys that start with sk_test_.

 

Step 2: Install the Stripe Library

 

Depending on your programming language, you'll need to install the appropriate Stripe library. Here are examples for popular languages:

For Node.js:

npm install stripe

For Python:

pip install stripe

For PHP:

composer require stripe/stripe-php

For Ruby:

gem install stripe

 

Step 3: Initialize the Stripe Client

 

After installing the library, you need to initialize the Stripe client with your API key.

Node.js:

const stripe = require('stripe')('sk_test_your_test_key');

Python:

import stripe
stripe.api_key = 'sk_test_your_test\_key'

PHP:

\Stripe\Stripe::setApiKey('sk_test_your_test_key');

Ruby:

require 'stripe'
Stripe.api_key = 'sk_test_your_test\_key'

 

Step 4: Create a Customer

 

Before creating a subscription, you need to create a customer and attach a payment method to them.

Node.js:

async function createCustomer() {
  const customer = await stripe.customers.create({
    email: '[email protected]',
    name: 'John Doe',
    description: 'Customer for subscription'
  });
  
  console.log('Created customer:', customer.id);
  return customer;
}

Python:

def create\_customer():
    customer = stripe.Customer.create(
        email='[email protected]',
        name='John Doe',
        description='Customer for subscription'
    )
    
    print(f"Created customer: {customer.id}")
    return customer

 

Step 5: Attach a Payment Method to the Customer

 

For a subscription to work, the customer needs a valid payment method.

Node.js:

async function attachPaymentMethod(customerId, paymentMethodId) {
  // Attach the payment method to the customer
  await stripe.paymentMethods.attach(paymentMethodId, {
    customer: customerId,
  });
  
  // Set it as the default payment method
  await stripe.customers.update(customerId, {
    invoice\_settings: {
      default_payment_method: paymentMethodId,
    },
  });
  
  console.log('Payment method attached and set as default');
}

Python:

def attach_payment_method(customer_id, payment_method\_id):
    # Attach the payment method to the customer
    stripe.PaymentMethod.attach(
        payment_method_id,
        customer=customer\_id,
    )
    
    # Set it as the default payment method
    stripe.Customer.modify(
        customer\_id,
        invoice\_settings={
            'default_payment_method': payment_method_id,
        },
    )
    
    print('Payment method attached and set as default')

 

Step 6: Create a Product

 

Products represent what you're selling. Each product can have multiple prices.

Node.js:

async function createProduct() {
  const product = await stripe.products.create({
    name: 'Premium Subscription',
    description: 'Monthly premium subscription with all features',
  });
  
  console.log('Created product:', product.id);
  return product;
}

Python:

def create\_product():
    product = stripe.Product.create(
        name='Premium Subscription',
        description='Monthly premium subscription with all features',
    )
    
    print(f"Created product: {product.id}")
    return product

 

Step 7: Create a Price for the Product

 

Prices define how much and how often to charge for products.

Node.js:

async function createPrice(productId) {
  const price = await stripe.prices.create({
    product: productId,
    unit\_amount: 1999, // $19.99
    currency: 'usd',
    recurring: {
      interval: 'month', // 'day', 'week', 'month', or 'year'
    },
  });
  
  console.log('Created price:', price.id);
  return price;
}

Python:

def create_price(product_id):
    price = stripe.Price.create(
        product=product\_id,
        unit\_amount=1999,  # $19.99
        currency='usd',
        recurring={
            'interval': 'month',  # 'day', 'week', 'month', or 'year'
        },
    )
    
    print(f"Created price: {price.id}")
    return price

 

Step 8: Create a Subscription

 

Now you can create a subscription by connecting the customer with the price.

Node.js:

async function createSubscription(customerId, priceId) {
  const subscription = await stripe.subscriptions.create({
    customer: customerId,
    items: [
      {
        price: priceId,
      },
    ],
    payment_behavior: 'default_incomplete',
    expand: ['latest_invoice.payment_intent'],
  });
  
  console.log('Created subscription:', subscription.id);
  return subscription;
}

Python:

def create_subscription(customer_id, price\_id):
    subscription = stripe.Subscription.create(
        customer=customer\_id,
        items=[
            {
                'price': price\_id,
            },
        ],
        payment_behavior='default_incomplete',
        expand=['latest_invoice.payment_intent'],
    )
    
    print(f"Created subscription: {subscription.id}")
    return subscription

 

Step 9: Handle the Subscription Status

 

After creating a subscription, you need to check its status and handle any required actions.

Node.js:

async function handleSubscriptionStatus(subscription) {
  const status = subscription.status;
  const clientSecret = subscription.latest_invoice.payment_intent.client\_secret;
  
  if (status === 'active') {
    console.log('Subscription is active!');
  } else if (status === 'incomplete') {
    console.log('Subscription requires additional action. Use this client secret with Stripe.js to complete the payment:', clientSecret);
  } else {
    console.log('Subscription status:', status);
  }
}

Python:

def handle_subscription_status(subscription):
    status = subscription.status
    client_secret = subscription.latest_invoice.payment_intent.client_secret
    
    if status == 'active':
        print('Subscription is active!')
    elif status == 'incomplete':
        print(f"Subscription requires additional action. Use this client secret with Stripe.js to complete the payment: {client\_secret}")
    else:
        print(f"Subscription status: {status}")

 

Step 10: Complete Flow Example

 

Here's a complete example that ties everything together:

Node.js:

async function createStripeSubscription() {
  try {
    // Create a customer
    const customer = await createCustomer();
    
    // For this example, we'll assume you've already collected and created a payment method
    // This would typically happen on your frontend using Stripe Elements or Checkout
    const paymentMethodId = 'pm_card_visa'; // In real scenarios, this comes from your frontend
    
    // Attach payment method to customer
    await attachPaymentMethod(customer.id, paymentMethodId);
    
    // Create a product
    const product = await createProduct();
    
    // Create a price
    const price = await createPrice(product.id);
    
    // Create a subscription
    const subscription = await createSubscription(customer.id, price.id);
    
    // Handle the subscription status
    await handleSubscriptionStatus(subscription);
    
    return subscription;
  } catch (error) {
    console.error('Error creating subscription:', error);
    throw error;
  }
}

// Execute the function
createStripeSubscription()
  .then(subscription => {
    console.log('Successfully set up subscription process!');
  })
  .catch(error => {
    console.error('Failed to set up subscription:', error);
  });

Python:

def create_stripe_subscription():
    try:
        # Create a customer
        customer = create\_customer()
        
        # For this example, we'll assume you've already collected and created a payment method
        # This would typically happen on your frontend using Stripe Elements or Checkout
        payment_method_id = 'pm_card_visa'  # In real scenarios, this comes from your frontend
        
        # Attach payment method to customer
        attach_payment_method(customer.id, payment_method_id)
        
        # Create a product
        product = create\_product()
        
        # Create a price
        price = create\_price(product.id)
        
        # Create a subscription
        subscription = create\_subscription(customer.id, price.id)
        
        # Handle the subscription status
        handle_subscription_status(subscription)
        
        return subscription
    except Exception as e:
        print(f"Error creating subscription: {str(e)}")
        raise

# Execute the function
try:
    subscription = create_stripe_subscription()
    print("Successfully set up subscription process!")
except Exception as e:
    print(f"Failed to set up subscription: {str(e)}")

 

Step 11: Set Up Webhook Handling

 

For a production environment, you should set up webhooks to receive notifications about subscription events like payments, renewals, and cancellations.

Node.js (with Express):

const express = require('express');
const app = express();

// This is your Stripe CLI webhook secret for testing
const endpointSecret = 'whsec_your_webhook\_secret';

app.post('/webhook', express.raw({type: 'application/json'}), (request, response) => {
  const sig = request.headers['stripe-signature'];

  let event;

  try {
    event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret);
  } catch (err) {
    response.status(400).send(`Webhook Error: ${err.message}`);
    return;
  }

  // Handle the event
  switch (event.type) {
    case 'customer.subscription.created':
      const subscriptionCreated = event.data.object;
      console.log('Subscription created:', subscriptionCreated.id);
      // Then define and call a function to handle the subscription creation
      break;
    case 'customer.subscription.updated':
      const subscriptionUpdated = event.data.object;
      console.log('Subscription updated:', subscriptionUpdated.id);
      // Then define and call a function to handle the subscription update
      break;
    case 'invoice.payment\_succeeded':
      const invoice = event.data.object;
      console.log('Invoice paid:', invoice.id);
      // Then define and call a function to handle the successful payment
      break;
    // ... handle other event types
    default:
      console.log(`Unhandled event type ${event.type}`);
  }

  // Return a 200 response to acknowledge receipt of the event
  response.send();
});

app.listen(4242, () => console.log('Running on port 4242'));

Python (with Flask):

from flask import Flask, request, jsonify
import stripe

app = Flask(**name**)

# This is your Stripe CLI webhook secret for testing
endpoint_secret = 'whsec_your_webhook_secret'

@app.route('/webhook', methods=['POST'])
def webhook():
    payload = request.get_data(as_text=True)
    sig\_header = request.headers.get('Stripe-Signature')

    try:
        event = stripe.Webhook.construct\_event(
            payload, sig_header, endpoint_secret
        )
    except ValueError as e:
        # Invalid payload
        return jsonify(success=False), 400
    except stripe.error.SignatureVerificationError as e:
        # Invalid signature
        return jsonify(success=False), 400

    # Handle the event
    if event['type'] == 'customer.subscription.created':
        subscription = event\['data']\['object']
        print(f"Subscription created: {subscription['id']}")
        # Handle the subscription creation
    elif event['type'] == 'customer.subscription.updated':
        subscription = event\['data']\['object']
        print(f"Subscription updated: {subscription['id']}")
        # Handle the subscription update
    elif event['type'] == 'invoice.payment\_succeeded':
        invoice = event\['data']\['object']
        print(f"Invoice paid: {invoice['id']}")
        # Handle the successful payment
    # ... handle other event types
    else:
        print(f"Unhandled event type {event['type']}")

    return jsonify(success=True)

if **name** == '**main**':
    app.run(port=4242)

 

Conclusion

 

You've now learned how to create a subscription with the Stripe API. This includes setting up customers, products, prices, and handling the subscription lifecycle. Remember to test thoroughly in the Stripe test environment before going to production.

For a complete implementation, you'll also need to:

  1. Implement a frontend to collect payment information using Stripe Elements or Checkout
  2. Set up proper error handling
  3. Create a webhook endpoint to handle subscription events
  4. Implement subscription management features (cancellations, upgrades, etc.)

Always refer to the official Stripe documentation for the most up-to-date information:
https://stripe.com/docs/api

Want to explore opportunities to work with us?

Connect with our team to unlock the full potential of no-code solutions with a no-commitment consultation!

Book a Free Consultation

Client trust and success are our top priorities

When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.

Rapid Dev was an exceptional project management organization and the best development collaborators I've had the pleasure of working with. They do complex work on extremely fast timelines and effectively manage the testing and pre-launch process to deliver the best possible product. I'm extremely impressed with their execution ability.

CPO, Praction - Arkady Sokolov

May 2, 2023

Working with Matt was comparable to having another co-founder on the team, but without the commitment or cost. He has a strategic mindset and willing to change the scope of the project in real time based on the needs of the client. A true strategic thought partner!

Co-Founder, Arc - Donald Muir

Dec 27, 2022

Rapid Dev are 10/10, excellent communicators - the best I've ever encountered in the tech dev space. They always go the extra mile, they genuinely care, they respond quickly, they're flexible, adaptable and their enthusiasm is amazing.

Co-CEO, Grantify - Mat Westergreen-Thorne

Oct 15, 2022

Rapid Dev is an excellent developer for no-code and low-code solutions.
We’ve had great success since launching the platform in November 2023. In a few months, we’ve gained over 1,000 new active users. We’ve also secured several dozen bookings on the platform and seen about 70% new user month-over-month growth since the launch.

Co-Founder, Church Real Estate Marketplace - Emmanuel Brown

May 1, 2024 

Matt’s dedication to executing our vision and his commitment to the project deadline were impressive. 
This was such a specific project, and Matt really delivered. We worked with a really fast turnaround, and he always delivered. The site was a perfect prop for us!

Production Manager, Media Production Company - Samantha Fekete

Sep 23, 2022