Home >Web Front-end >JS Tutorial >Stripe Subscription Integration in Node.js [ltimate Guide]

Stripe Subscription Integration in Node.js [ltimate Guide]

Barbara Streisand
Barbara StreisandOriginal
2024-11-22 15:57:37720browse

Stripe Subscription Integration in Node.js [ltimate Guide]

Getting Stripe subscriptions working with backend services can be tricky and often leads to what developers call the dreaded “brain split” - managing both Stripe's logic and your own backend data in sync.

At Vratix, we’ve tackled this problem head-on while building our Open Source Stripe Subscriptions API Module. Here's how we approach Stripe subscription billing in Node.js to keep things simple, scalable, and developer-friendly.

Core Principle: Let Stripe Be the Source of Truth

The key is to shift as much of the logic to Stripe while keeping your database minimal. We only store:

  • Customer ID
  • Subscription ID
  • Plan

This way, we avoid:

  • Overcomplicated backend logic
  • Error-prone webhook implementations for syncing dashboard changes
  • Data redundancy

With this approach, you still have a fully functional subscription billing system while relying on Stripe as the single source of truth.

Features of Our Implementation

By the end of this guide, you’ll have a subscription-based app supporting:

  • User subscription plans
  • Checkout sessions
  • Subscription upsells
  • Available plan listing

Tech Stack

  • PostgreSQL
  • Node.js Express.js
  • TypeScript

Step 1: Database Design

We start by designing a clean, minimal database table:

CREATE TABLE user_subscriptions (  
    "id" SERIAL PRIMARY KEY,  
    "plan" VARCHAR NOT NULL,  
    "user_id" INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,  
    "customer_id" VARCHAR,  
    "subscription_id" VARCHAR NOT NULL,  
    "is_owner" BOOLEAN NOT NULL DEFAULT TRUE,  
    "created_at" TIMESTAMP NOT NULL DEFAULT NOW(),  
    UNIQUE (user_id, subscription_id)  
);

Key points:

  • user_id: References your internal user table
  • plan: Tracks the subscription plan
  • subscription_id: The Stripe subscription ID
  • is_owner: Flags the primary subscription holder

Step 2: Controllers

We use a factory function to keep the business logic modular and testable. Here's a snippet from our Stripe Subscription Controller:

async getSubscriptions() {  
  const stripePrices = await stripe.prices.list({  
    active: true,  
    type: "recurring",  
    expand: ["data.product"],  
  });  

  return stripePrices.data.map((price) => {  
    const product = price.product as Stripe.Product;  
    return {  
      plan: price.lookup_key || product.name.toLowerCase().replaceAll(" ", "_"),  
      name: product.name,  
      priceId: price.id,  
      interval: price.recurring!.interval,  
      price: { currency: price.currency, amount: price.unit_amount },  
    };  
  });  
}  

Key highlights:

  • Custom subscription keys: Derived from the product name or lookup_key for clean plan checks (user.plan === 'pro_plan').
  • Stripe-first approach: We fetch subscription data directly from Stripe, avoiding the “brain split.”

Step 3: Streamlined Stripe Checkout

Our createCheckout function sets up a subscription checkout session:

const checkout = await stripe.checkout.sessions.create({  
  line_items: [  
    {  
      price: priceId,  
      adjustable_quantity: { enabled: true },  
      quantity: seats || 1,  
    },  
  ],  
  mode: "subscription",  
  subscription_data: { metadata: { userId } },  
  success_url: CHECKOUT_SUCCESS_URL,  
  cancel_url: CHECKOUT_CANCEL_URL,  
});  

return { url: checkout.url! };  

Want to Skip All This?

We’ve packaged everything into a ready-to-go Open Source module. In less than 30 seconds, you can set up:

  • Stripe integration
  • Authentication
  • Database configuration
  • Prebuilt routes and SQL queries

Run this:

CREATE TABLE user_subscriptions (  
    "id" SERIAL PRIMARY KEY,  
    "plan" VARCHAR NOT NULL,  
    "user_id" INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,  
    "customer_id" VARCHAR,  
    "subscription_id" VARCHAR NOT NULL,  
    "is_owner" BOOLEAN NOT NULL DEFAULT TRUE,  
    "created_at" TIMESTAMP NOT NULL DEFAULT NOW(),  
    UNIQUE (user_id, subscription_id)  
);

Check out our Stripe Subscriptions Module Docs for more details.

The full code is available on our GitHub repo.

See a demo video how to do all of this with a working UI here.

I’d love to hear your thoughts - does this make building subscription APIs easier? Let us know what features you’d like to see next!

The above is the detailed content of Stripe Subscription Integration in Node.js [ltimate Guide]. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn