Skip to main content
Memberstack Docs
Dashboard

Plan Management

Implement and manage membership plans with Memberstack. All paid plans are processed through Stripe, ensuring secure and reliable payments.

/dom-package/plan-management.md

This guide covers everything you need to know about implementing and managing membership plans with Memberstack. All paid plans are processed through Stripe, ensuring secure and reliable payments.

Before You Start

Create and configure your plans in the Memberstack dashboard under "Plans" before implementing them in your code. Important:

  • Free plans use Plan IDs (starts with "pln_")
  • Paid plans use Price IDs (starts with "prc_")
  • Connect your Stripe account for paid plans
  • Create plans in the dashboard (Plans → Add plan)
Testing Your Plans

To test your plans without real charges:

  • Enable test mode in your Memberstack DevTools, then copy your public key (it starts with "pk_sb_").
  • Test mode has its own set of Plan IDs and Price IDs - make sure to use the correct ones
  • Use Stripe's test card: 4242 4242 4242 4242 (exp: any future date, CVC: any 3 digits)
  • Remember to switch back to live mode and update IDs for production

Free Plans

Free plans are a great way to offer basic access to your platform or provide a trial experience. They can be implemented without Stripe integration.

Fetching Available Plans

First, let's see how to retrieve all available plans:

// Get available plans
async function getAvailablePlans() {
  try {
    return await memberstack.getPlans();
  } catch (error) {
    console.error("Couldn't get plans:", error);
    return [];
  }
}

Fetching a Single Plan

Use getPlan() to look up one plan by its ID. This is a public read, no login required. It resolves to { data: plan }, and throws plan-not-found if the ID doesn't exist.

// Get details for one specific plan by ID
async function getPlanDetails(planId) {
  try {
    const { data: plan } = await memberstack.getPlan({ planId });

    console.log("Plan name:", plan.name);
    console.log("Description:", plan.description);
    // Paid plans include a prices array; free plans have an empty array
    plan.prices?.forEach((price) => {
      console.log(`Price ${price.id}: ${price.amount} ${price.currency}`);
    });

    return plan;
  } catch (error) {
    // Throws "plan-not-found" if the planId doesn't exist
    console.error("Couldn't get plan:", error.message);
    return null;
  }
}

Adding a Free Plan

Here's how to create a free plan signup button and handle enrollment:

// Add this HTML
<button onclick="startFreePlan()">Get Free Plan</button>

// Add this JavaScript
async function startFreePlan() {
  try {
    // Get the current member
    const { data: member } = await memberstack.getCurrentMember();

    if (!member) {
      // Not logged in - show signup with free plan
      await memberstack.openModal("SIGNUP", {
        signup: { plans: ["YOUR_FREE_PLAN_ID"] }
      });
    } else {
      // Logged in - add free plan
      await memberstack.addPlan({
        planId: "YOUR_FREE_PLAN_ID"
      });
      // Go to dashboard after success
      window.location.href = "/dashboard";
    }
  } catch (error) {
    alert("Couldn't add free plan. Please try again.");
  }
}
Free Plan Tips
  • Make sure to clearly list what's included in the free plan
  • Consider adding a trial of paid features to free plans
  • Show comparison tables to encourage upgrades
  • Test the signup flow both logged in and logged out

Paid plans use Stripe for secure payment processing. Before implementing paid plans, make sure you've connected Stripe in your Memberstack dashboard (Settings → Stripe Settings) and created your plans.

You can read more about the Stripe Customer Portal configuration here.

Adding a Paid Plan

Here's how to create a paid plan button and handle Stripe checkout:

// Add this HTML
<button onclick="startPaidPlan()">Get Pro Plan</button>

// Add this JavaScript
async function startPaidPlan() {
  try {
    const { data: member } = await memberstack.getCurrentMember();

    if (!member) {
      // Not logged in - sign them up first. The signup modal only attaches
      // FREE plans, so don't pass a priceId here; run checkout afterwards.
      const result = await memberstack.openModal("SIGNUP");
      if (result.type !== "SIGNUP") return; // member closed the modal
    }

    // Logged in (or just signed up) - start Stripe checkout for the paid plan.
    // autoRedirect defaults to true (the SDK navigates to Stripe for you);
    // pass autoRedirect: false to get the URL back instead.
    const checkout = await memberstack.purchasePlansWithCheckout({
      priceId: "prc_YOUR_PRICE_ID",
      successUrl: window.location.origin + "/dashboard",
      cancelUrl: window.location.origin + "/plans",
      autoRedirect: false
    });

    // Go to checkout, the URL is at checkout.data.url
    window.location.href = checkout.data.url;
  } catch (error) {
    alert("Couldn't start checkout. Please try again.");
  }
}

Required Setup

  • Connected Stripe account
  • Plans created in dashboard
  • Test mode for development
  • Plan IDs copied and ready

Plan Settings

  • Set prices and billing cycles
  • Define included features
  • Configure trial periods
  • Set member limits if needed

Plan Purchase Flow

Here's how to handle common plan management tasks like checking access, upgrades, and letting members manage their subscriptions:

// Check if member has a specific plan
async function hasPlan(planId) {
  const { data: member } = await memberstack.getCurrentMember();
  if (!member) return false;

  return member.planConnections?.some(plan =>
    plan.planId === planId &&
    plan.status === "ACTIVE"
  );
}

// Open billing portal for subscription management
async function openBilling() {
  try {
    const { data } = await memberstack.launchStripeCustomerPortal({
      returnUrl: window.location.origin + "/account"
    });
    window.location.href = data.url;
  } catch (error) {
    alert("Couldn't open billing. Please try again.");
  }
}

Removing a Plan

Use removePlan() to remove a plan from the logged-in member. For a paid plan this cancels the subscription. The call resolves to { data: { member } } with the member's updated planConnections, and Memberstack refreshes the persisted session for you (your onAuthChange listeners fire), so you don't need to re-fetch the member.

// Remove a plan from the current member.
// For a paid plan this cancels the subscription.
async function dropPlan(planId) {
  try {
    const { data } = await memberstack.removePlan({ planId });

    // The SDK returns the UPDATED member and refreshes the persisted
    // session for you (onAuthChange fires), no need to re-fetch.
    console.log("Remaining plans:", data.member.planConnections);
    return data.member;
  } catch (error) {
    // Throws if the member isn't logged in or doesn't have the plan
    alert("Couldn't remove plan. Please try again.");
  }
}
Note

The member must be logged in, and the call throws if they don't have the plan. To let members cancel or switch paid plans through Stripe's hosted UI instead, use launchStripeCustomerPortal() (shown above).

Common Questions

Free plans use Plan IDs (starts with "pln_") while paid plans use Price IDs (starts with "prc_"). You can find both in your Memberstack dashboard under the respective plan settings.

In your Memberstack dashboard: Plans → click on a plan → find the Plan ID for free plans or Price ID for paid plans in the settings

In your Memberstack dashboard: Plans → click on a plan → copy the ID from the URL or settings

Use memberstack.launchStripeCustomerPortal() to let them manage their subscription

Yes! Configure trial periods in your Memberstack dashboard when creating plans

Need help?
Can't find what you're looking for? Our team is here to help.