How to Set Up Stripe Subscriptions with MedusaJS using Low-Code

Authors: Matthew Lal, Lucas Pham

Introduction

Running a subscription-based business requires robust infrastructure that can handle recurring payments, product management, and customer relationships seamlessly. While Stripe excels at payment processing and subscription management, and Medusa provides powerful e-commerce capabilities, combining these platforms traditionally requires significant development effort and custom integration work.
Enter Buildship – a solution that bridges this gap, allowing you to harness the power of both platforms without the complexity of building custom integrations from scratch.
This comprehensive guide will walk you through the process of integrating Medusa with Stripe's subscription functionality using Buildship.
Whether you're already using Medusa and want to add subscription capabilities, or you're evaluating platforms for your subscription-based business, this tutorial provides everything you need to get started. With just a few hours of setup time, you'll have a fully functional subscription system that leverages the best of both Medusa and Stripe.

What You'll Learn

In this guide, we'll cover:
How to integrate Medusa with Stripe using Buildship
How to set up Stripe subscription products to be sold through Medusa
Automate the subscription lifecycle from purchase to fulfillment
Customizing your subscription workflows in Buildship

Who This Tutorial Is For

This guide is perfect for:
People that use Medusa for their ecommerce who want to create subscriptions through Stripe
People who are considering migrating over to Medusa

What You’ll Need

Buildship account (free)
A hosted and deployed instance of Medusa (free)
Medusa account with admin permissions (free)
Stripe account (free)
A developer or development experience
Though the project requires some development skills, either low code or code approaches will work. We provide you all the necessary code snippets to complete the project. For a basic implementation (no customizations), the only necessary code edits will be to input your Buildship endpoint URLs.
For more details about Medusa product architecture and concepts, check out the .

Install the Medusa Stripe Plugin

To get started, we will install the .
Here’s how we’ve configured our Stripe Plugin for reference:
Screenshot 2024-10-21 at 6.41.05 PM.png

Duplicate the Buildship Workflows

Next let’s load , which includes the necessary flows to connect Stripe and Medusa.
Throughout the code provided, be sure to fill in the variables. You can learn more about each variable in the sections below.

Connect Medusa Product to Stripe Product

Step 1—Create product.created event listener

To create a Medusa subscriber that listens for the product.created event, you can place the subscriber in the file path src/subscribers/product-created-event.ts. This subscriber will listen for the event when a new product is created in Medusa. Upon detecting the product.created event, the subscriber will capture the relevant data of the newly created product. It will then send this product data to the Buildship platform, specifically calling the "Create Stripe Product" workflow. This integration allows the newly created Medusa product to be synchronized with Stripe, automating the product creation process between the two platforms.
\\\ Send the data of the created product to the Buildship Create Stripe Product workflow (src/subscribers/product-created-event.ts )
import {
ProductService,
type SubscriberConfig,
type SubscriberArgs,
} from "@medusajs/medusa"

type ProductCreatedEvent = {
id: string,
}

export default async function handleCreateStripeProduct({
data, eventName, container, pluginOptions,
}: SubscriberArgs<ProductCreatedEvent>) {
console.log('Product created event fired', data)
const endpoint = process.env.BUILDSHIP_CREATE_STRIPE_PRODUCT_ENDPOINT_URL //Insert Buildship create stripe product remix endpoint`
try {
const response = await fetch(endpoint, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
}
});
const responseData = await response.json()
console.log('API response:', responseData)
return responseData
} catch (error) {
console.error('Error:', error)
throw error
}
}

export const config: SubscriberConfig = {
event: ProductService.Events.CREATED,
}

Step 2—Remix Buildship workflow to create a Stripe Product

This workflow automates the creation of a Stripe Product only if the Medusa product's type matches a specified intended type. When a match occurs, it creates a corresponding Stripe Product, storing the Medusa Product ID in the Stripe Product's metadata. Additionally, it updates the Medusa product's metadata to include the Stripe Product ID, ensuring both systems stay in sync. The typeValue input represents the product type for which Stripe Products will be created, and it is recommended to make this a variable in Buildship so it can be easily reused across other workflow nodes that require the same type value. Similarly, input your base Medusa URL as a Buildship variable, allowing for easy reference and reuse in other nodes requiring the Medusa URL.

Note: The Medusa JWT Auth Node serves as the master service role and should be kept secure on the server side in Buildship, utilizing secret keys. It must not be used in any other way. Be sure to input the Medusa email and password into the appropriate fields. To simplify filling out other related inputs, it's recommended to set both the email and URL as Buildship variables for easier reuse across various nodes.
Screenshot 2024-10-12 at 1.11.09 AM.png

Step 3—Create Product on Medusa UI

Next we’ll use the Medusa Admin UI to create new Products. Upon creation, the product.created event will fire for the custom listener created in the Medusa backend, which in turns calls on the “Create Stripe Product” workflow in Buildship.
Screenshot 2024-10-11 at 3.20.25 AM.png
Assign the product type during the creation of a Medusa product, which will be used to determine whether a corresponding Stripe product should be created.
Screenshot 2024-10-11 at 3.21.34 AM.png

Step 4—Create product.deleted event listener

Create a Medusa subscriber to listen for product.deleted events and place it in the file path src/subscribers/product-deleted-event.ts. When a product is deleted in Medusa, this subscriber will trigger and send the relevant product data to the "Delete Stripe Product" workflow in Buildship.
import {
ProductService,
type SubscriberConfig,
type SubscriberArgs,
} from "@medusajs/medusa"

type ProductDeletedEvent = {
id: string,
object: string,
deleted: boolean
}

export default async function handleDeleteStripeProduct({
data, eventName, container, pluginOptions,
}: SubscriberArgs<ProductDeletedEvent>) {
console.log('Delete subscriber ran', data)
const endpoint = process.env.BUILDSHIP_DELETE_STRIPE_PRODUCT_ENDPOINT_URL //Insert Buildship delete stripe product endpoint
try {
const response = await fetch(endpoint, {
method: 'DELETE',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
}
});
const responseData = await response.json()
console.log('API response:', responseData)
return responseData
} catch (error) {
console.error('Error:', error)
throw error
}
}

export const config: SubscriberConfig = {
event: ProductService.Events.DELETED,
}

Step 5—Remix Buildship workflow to delete Stripe Product

This workflow locates the Stripe Product associated with the deleted Medusa product by searching for the Medusa Product ID stored in the Stripe Product's metadata. Once found, it updates the Stripe Product's status to inactive, effectively disabling it.
Screenshot 2024-10-11 at 4.01.39 AM.png

Connect Medusa Product Variant to Stripe Plan

Step 1—Create product-variant.updated event listener

Create a Medusa subscriber to listen for the product-variant.updated event. When a Product Variant is updated, this subscriber will capture the data and send it to the Buildship “Create/Update Stripe Price” workflow. This allows the corresponding Stripe Price to be created or updated based on the variant changes in Medusa. Place this subscriber in the file path src/subscribers/product-variant-updated-event.ts.
import {
type SubscriberConfig,
type SubscriberArgs,
} from "@medusajs/medusa"

type ProductVariantUpdatedEvent = {
id: string,
product_id: string,
fields: []
}

export default async function handleCreateUpdateStripePrice({
data, eventName, container, pluginOptions,
}: SubscriberArgs<ProductVariantUpdatedEvent>) {
console.log('Product Variant Updated event fired',data)
const endpoint = process.env.BUILDSHIP_CREATE_STRIPE_PRICE_ENDPOINT_URL //Insert Buildship stripe price endpoint
try {
const response = await fetch(endpoint, {
method: 'POST',
body: JSON.stringify(data),
headers: {
Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.