/stripe-guides

How to implement subscription trials with Stripe API?

Learn how to set up and manage subscription trials with Stripe API, including trial periods, handling trial ends, cancellations, and analytics. Step-by-step guide.

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 implement subscription trials with Stripe API?

How to Implement Subscription Trials with Stripe API

 

Step 1: Set Up Your Stripe Account

 

Before implementing subscription trials, you need to set up your Stripe account and install the Stripe library in your project.

  1. Create a Stripe account at https://dashboard.stripe.com/register
  2. Get your API keys from the Stripe Dashboard
  3. Install the Stripe SDK for your programming language

For Node.js, install the Stripe library:

npm install stripe

For PHP:

composer require stripe/stripe-php

For Python:

pip install stripe

 

Step 2: Initialize Stripe in Your Project

 

Initialize the Stripe client with your secret key.

For Node.js:

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

// For ES modules
// import Stripe from 'stripe';
// const stripe = new Stripe('sk_test_YourSecretKey');

For PHP:

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

For Python:

import stripe
stripe.api_key = 'sk_test\_YourSecretKey'

 

Step 3: Create Products and Prices with Trial Parameters

 

Before setting up subscriptions with trials, you need to create a product and a price.

For Node.js:

// Create a product
const product = await stripe.products.create({
  name: 'Premium Plan',
  description: 'Access to premium features',
});

// Create a price with recurring parameters
const price = await stripe.prices.create({
  product: product.id,
  unit\_amount: 1999, // Amount in cents (19.99 USD)
  currency: 'usd',
  recurring: {
    interval: 'month', // 'day', 'week', 'month' or 'year'
  },
});

 

Step 4: Create a Subscription with a Trial Period

 

There are two main ways to implement trials with Stripe:

  1. Using trial_period_days when creating a subscription
  2. Using trial_end with a specific timestamp

Method 1: Using trial_period_days

// Create a customer first
const customer = await stripe.customers.create({
  email: '[email protected]',
  name: 'Jenny Rosen',
  payment_method: 'pm_card\_visa', // Obtained from Stripe.js
});

// Set the payment method as the default
await stripe.customers.update(customer.id, {
  invoice\_settings: {
    default_payment_method: 'pm_card_visa',
  },
});

// Create a subscription with a 14-day trial
const subscription = await stripe.subscriptions.create({
  customer: customer.id,
  items: [
    {
      price: price.id,
    },
  ],
  trial_period_days: 14, // 14-day trial
  payment\_settings: {
    payment_method_types: ['card'],
    save_default_payment_method: 'on_subscription',
  },
  expand: ['latest_invoice.payment_intent'],
});

Method 2: Using trial_end with a specific timestamp

// Calculate trial end date (e.g., 30 days from now)
const trialEnd = Math.floor(Date.now() / 1000) + (30 _ 24 _ 60 \* 60); // 30 days in seconds

// Create a subscription with a specific trial end date
const subscription = await stripe.subscriptions.create({
  customer: customer.id,
  items: [
    {
      price: price.id,
    },
  ],
  trial\_end: trialEnd,
  payment\_settings: {
    payment_method_types: ['card'],
    save_default_payment_method: 'on_subscription',
  },
});

 

Step 5: Handle the Trial End

 

When a trial ends, Stripe automatically attempts to charge the customer. You should set up webhook handling to detect trial-related events.

// Express route handler for webhooks
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,
      'whsec\_YourWebhookSecret'
    );
  } catch (err) {
    response.status(400).send(`Webhook Error: ${err.message}`);
    return;
  }

  // Handle specific events
  switch (event.type) {
    case 'customer.subscription.trial_will_end':
      // Triggered 3 days before trial ends
      const subscription = event.data.object;
      console.log(`Trial for subscription ${subscription.id} will end soon.`);
      // Notify the customer that their trial will end soon
      break;
      
    case 'customer.subscription.updated':
      const updatedSubscription = event.data.object;
      // Check if the subscription has moved from trial to active
      if (event.data.previous\_attributes.status === 'trialing' && 
          updatedSubscription.status === 'active') {
        console.log(`Subscription ${updatedSubscription.id} has converted from trial to active.`);
        // Handle successful trial to paid conversion
      }
      break;
      
    case 'invoice.payment\_failed':
      // Handle failed payment at the end of the trial
      const invoice = event.data.object;
      console.log(`Payment failed for invoice ${invoice.id}`);
      // Notify the customer about the failed payment
      break;
  }

  response.send();
});

 

Step 6: Implement a Free Trial Without Requiring Payment Information

 

If you want to offer a trial without collecting payment information upfront, you can use Stripe Checkout with a trial and collect payment information later.

// Create a Checkout Session with a trial
const session = await stripe.checkout.sessions.create({
  payment_method_types: ['card'],
  line\_items: [
    {
      price: price.id,
      quantity: 1,
    },
  ],
  mode: 'subscription',
  subscription\_data: {
    trial_period_days: 14,
  },
  success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
  cancel\_url: 'https://example.com/cancel',
});

Alternatively, you can create a subscription with a trial without requiring immediate payment:

// Create a customer
const customer = await stripe.customers.create({
  email: '[email protected]',
  name: 'Jenny Rosen',
});

// Create a subscription with trial but no payment method yet
const subscription = await stripe.subscriptions.create({
  customer: customer.id,
  items: [
    {
      price: price.id,
    },
  ],
  trial_period_days: 14,
  payment\_settings: {
    save_default_payment_method: 'on_subscription',
  },
  collection_method: 'send_invoice', // This prevents automatic charge attempts
  days_until_due: 14, // Number of days before the invoice is due
});

 

Step 7: Handle Trial Cancellations

 

Allow customers to cancel during the trial period without being charged.

// Cancel a subscription immediately
const canceledSubscription = await stripe.subscriptions.del(
  'sub\_1234567890'
);

// Cancel at the end of the trial period
const subscription = await stripe.subscriptions.update(
  'sub\_1234567890',
  {
    cancel_at_period\_end: true,
  }
);

 

Step 8: Extend a Trial Period

 

Sometimes you may want to extend a customer's trial:

// Extend trial by updating the trial\_end timestamp
const extendedTrialTimestamp = Math.floor(Date.now() / 1000) + (30 _ 24 _ 60 \* 60); // 30 more days

const subscription = await stripe.subscriptions.update(
  'sub\_1234567890',
  {
    trial\_end: extendedTrialTimestamp,
    proration\_behavior: 'none', // Don't create prorations for this change
  }
);

 

Step 9: Track Trial Conversions and Analytics

 

To track how well your trials convert to paid subscriptions, use Stripe's Analytics or implement custom tracking:

// Get all subscriptions that were on trial and are now active
const subscriptions = await stripe.subscriptions.list({
  status: 'active',
  limit: 100,
});

// Filter subscriptions that converted from trial
const convertedSubscriptions = subscriptions.data.filter(
  sub => sub.trial_start && sub.trial_end && Date.now() / 1000 > sub.trial\_end
);

console.log(`Trial conversion rate: ${convertedSubscriptions.length / subscriptions.data.length * 100}%`);

 

Step 10: Implement Trial-Specific User Interfaces

 

Create front-end elements to show trial status to users:

// Client-side JavaScript to display trial information
async function displayTrialInfo() {
  // Fetch subscription data from your backend
  const response = await fetch('/api/subscription-status');
  const subscription = await response.json();
  
  const trialEndDate = new Date(subscription.trial\_end \* 1000);
  const today = new Date();
  const daysRemaining = Math.ceil((trialEndDate - today) / (1000 _ 60 _ 60 \* 24));
  
  if (subscription.status === 'trialing') {
    document.getElementById('trial-banner').innerHTML = \`
      
Your trial ends in ${daysRemaining} days on ${trialEndDate.toLocaleDateString()}.
\`; } }

 

Conclusion

 

Implementing subscription trials with Stripe involves creating products and prices, setting up subscriptions with trial parameters, and handling the end of the trial period. By using Stripe's robust API and webhook system, you can offer flexible trial options to your customers while ensuring a smooth transition to paid subscriptions when the trial ends.

Remember to test thoroughly in Stripe's test mode before moving to production. Additionally, make sure to handle edge cases such as failed payments at the end of trials and provide clear communication to your users about their trial status and expiration.

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