Skip to main content

Building and Selling a Membership Subscription

In this guide, we're going to take you through the process of building and then selling a Membership type of Subscription.

Once you've gone through all the steps, you should have a good understanding of how to:

  1. Model a basic Membership Subscription with a Monthly and discounted Yearly plan
  2. Retrieve the details of this Subscription for your PDP
  3. Add the Subscription to the cart and select a plan
  4. Create an Elastic Path Account for your Subscription
  5. Check out and set up a recurring payment for the Subscription using Elastic Path Payments

Prerequisites

Store Setup

Make sure your store has the USD currency code set up as default, or adjust the Postman requests to use your selected currency instead.

Payment Provider Setup

As we are going through the checkout, we will be using Elastic Path Payments, however the steps will also work if you are just using Stripe by itself.

First, make sure you have Elastic Path Payments enabled for your store.

Second, you will need to create the following customer in Stripe Test mode, along with some dummy card information (you can use the card number 4242 4242 4242 4242 with any future expiry date and CVC):

  1. Will Wright

Make note of their Stripe Customer ID and associated Card ID.

note

We are setting up a customer in Stripe manually to make it easier to go through the Postman collection. In a production scenario, you would use something like Stripe Elements to set up the customer and collect the payment details securely.

Account Management Setup

We shall be creating an Elastic Path Account for the Subscriber using a password profile.

First, in Commerce Manager under Settings -> Authentication -> Authentication Management -> Account Management Realm, make sure you have a Password Profile set up called Subscriptions. You can specify either email or any for the username format, although we'll be using an emails as usernames in this guide.

Second, make sure you have the following settings enabled in Account Authentication Settings:

  • Self-Signup
  • Auto Create Account for Account Members
  • Account Member Self Management

Download the Assets

Download this zip file which contains the following:

FileDescription
collection.jsonA Postman Collection with all the API calls required for this guide
environment.jsonA Postman Environment you can set up to point to your store

Import the Postman Collection and Environment

Finally, let's set up the Postman Collection and Environment file.

Import collection.json and environment.json into Postman, and go to the Elastic Path Subscriptions - Building and Selling Membership Subscriptions environment.

Change the Current Value of the following variables to match your store, creating a new API key in Commerce Manager if you haven't already got one:

VariableValue
clientSecretThe Client Secret for your API key
clientIDThe Client ID for your API key
authURLThe API Base URL for your store
stripe_customer_idThe Stripe Customer ID for Will Wright
stripe_payment_methodThe Stripe Payment Method ID for Will Wright

To check everything is set up correctly, go to the Elastic Path Subscriptions - Building and Selling Membership Subscriptions collection, ensure that the Elastic Path Subscriptions - Building and Selling Membership Subscriptions environment is selected and run the first API request called Step 0 -> Authenticate.

You should see a 200 OK response and a new access token created in your environment for subsequent requests.

Our Fictional Business Problem

Let's start by outlining the problem we're going to solve with Elastic Path Subscriptions.

  • You own a fictional company called GameForge Academy that specialises in training material for budding game developers.
  • Subscribers can sign up for either a monthly or yearly pass to access the training content on your platform.
  • If a Subscriber pays monthly, it costs $10 a month, however if they sign up for a year, they get a 20% discount at just $96.
  • We don't need to worry about taxes as it's all included in the price of the Subscription.

Step 1 - Modelling the Subscription as an Offering

Before a Subscription becomes a Subscription, we refer to it as Offering.

There are two pieces of information that make up an Offering:

  • Products - The thing you want to sell and how much the base price is.
  • Plans - The rules that govern the lifecycle of the Subscription, including how often billing occurs, how long the Subscription lasts, and what happens when the Subscription ends.

With respect to our fictional business problem, we are going to need the following:

  • A Product that represents access to GameForge Academy, priced at $10 for a month.
  • Two Plans, one for the monthly billing with no discount, one for the yearly billing with a 20% discount.
  • An Offering that contains the product and both plans.

Later on, we'll add this Offering to the cart, where the Subscriber can then select which of the two plans they are signing up for.

Creating the Product

First let's create the product, which we're going to call Complete Access.

In the future, we might want to expand our business focussing on different types of content access, such as "Programming Essentials", "Game Design", and "Advanced Graphics", but to keep things simple, we'll focus on a single product that encompasses access to all content.

In your Postman collection, take a look at the body of the Create Complete Access Product request.

{
"data": {
"type": "subscription_product",
"attributes": {
"name": "Complete Access",
"external_ref": "product_complete_access",
"description": "Complete Access – Your Ultimate Game Dev Toolkit\n\nUnlock Complete Access and gain unlimited entry to our full library of game development training materials. Whether you're a beginner or leveling up your skills, you'll get:\n\n✅ Expert-Led Courses – Learn coding, design, and mechanics from industry pros.\n✅ Project-Based Learning – Hands-on tutorials to build real games.\n✅ Exclusive Resources – Access assets, templates, and source code.\n✅ Community & Support – Connect with fellow devs and get expert guidance.\n\nStart your journey today—Master game development, one level at a time! 🎮🚀",
"price": {
"USD": {
"amount": 1000,
"includes_tax": true
}
},
"price_units": {
"unit": "month",
"amount": 1
}
}
}
}

Before running it, let us break down what we've put in here:

FieldRequiredDescription
nametrueThe name of our product, in this case "Complete Access" to indicate that a Subscriber would have complete access to all material.
external_reffalseA unique identifier that we can use to reference this product in the future, rather than using the random UUID that the API generates.
descriptionfalseA description of our product, detailing what the Subscriber will get when they sign up.
pricefalseThe price in USD that the Subscriber will pay for the product, in this case $10. We also specify whether or not the tax is included in the price or not.
price_unitsfalseA rate at which the price of the product is against. For example, here we say the base price is $10 a month
note

If you specify includes_tax as false, this will mean you have to add tax to the invoice once it's been generated before payment can be successfully taken.

We cover this in greater detail as part of Invoices, Taxes and Payments.

For this guide, we'll set it as true to keep things simple, indicating no additional tax is required.

info

While price_units are not required, they help if you want to express discounts between plans of different lengths of time.

For example, if you have two plans, one is set up with month intervals and the other with year, you will need to express the base price

We'll cover more of how this used in calculating a Plans price in the next section. TODO - Add link to section

Now we've gone through our Product, run the Create Complete Access Product request in Postman followed by the List Products request.

You should now see that you have a Product called "Complete Access" in your store.

Creating the Plans

Next, we need to create two plans:

  • A monthly Subscription plan that a Subscriber pays the full base rate of $10 a month.
  • A yearly Subscription plan that a Subscriber pays a lump sum for the year, but with a 20% discount off the base price.

Let's start with our Monthly Plan.

Take a look at the body for the request Create a Monthly Plan in your Postman collection.

{
"data": {
"type": "subscription_plan",
"attributes": {
"external_ref": "plan_monthly",
"name": "Monthly Billing",
"description": "Our basic monthly subscription, allowing you to cancel at any time",
"billing_interval_type": "month",
"billing_frequency": 1,
"plan_length": 1,
"end_behavior": "roll",
"can_pause": true,
"can_resume": true,
"can_cancel": true,
"base_price_percentage": 100
}
}
}
FieldRequiredDescription
external_reffalseA unique identifier that we can use to reference this product in the future, rather than using the random UUID that the API generates.
nametrueThe name representing this plan, in this case "Monthly Billing" to indicate that the Subscriber will be billed monthly.
descriptionfalseA description of the plan.
billing_interval_typetrueThe unit of time we're going to represent billing with. In this case we'll be using months.
billing_frequencytrueHow often the Subscriber will be billed. Combined with the billing_interval_type this represents how often an invoice will be generated for a Subscriber, otherwise known as a Billing Cycle.
plan_lengthtrueHow many Billing Cycles the plan will last for. In this case, the plan will end after one month.
end_behaviortrueWhat should happen to the Subscription once the number of billing cycles have reached the end of the plan. In this case, the plan will roll over and continue month to month.
can_pausetrueWhether the Subscriber can pause the Subscription.
can_resumetrueWhether the Subscriber can resume the Subscription.
can_canceltrueWhether the Subscriber can cancel the Subscription.
base_price_percentagetrue if fixed_price is not setThe percentage of the base price that the plan will cost. In this case, we want to offer no discount, so it's 100% of the base price.
info

In the above example, we've set base_price_percentage, but an alternative is to used fixed_price instead. This allows you to set a fixed price for the plan which will override whatever base price rules you've put onto the product. This might fit your business model better if you have fixed prices in mind for each plan, and don't need to dynamically calculate the discount between different plans.

Before running the request, take a look at the Create a Yearly Plan request body as well.

{
"data": {
"type": "subscription_plan",
"attributes": {
"external_ref": "plan_yearly",
"name": "Yearly Billing",
"description": "Sign up to GameForge Academy for a year and get a 10% discount on the price",
"billing_interval_type": "month",
"billing_frequency": 12,
"plan_length": 1,
"end_behavior": "roll",
"can_pause": true,
"can_resume": true,
"can_cancel": true,
"base_price_percentage": 80
}
}
}

Let's take a look at the main differing fields (beyond name, description, and external_ref) and note some of their differences:

FieldDifference
billing_frequencyWe have changed this to 12 to indicate a billing cycle of 12 months, generating an invoice once per year. Alternatively, we could have kept this at 1 and changed billing_interval_type to year.
base_price_percentageWe have set this to 80 to indicate that the plan will only cost 80% of the base price representing our 20% discount.

Now run both requests in Postman, followed by the List Plans request.

You should see that you have two plans, one for Monthly Billing and one for Yearly Billing.

Building the Offering

Now that we have our Product and Plans, we can create our Offering.

Take a look at the Build an Offering request body in Postman.

{
"data": {
"external_ref": "offering_membership",
"name": "GameForge Academy Membership",
"description": "Sign up to one of our amazing membership plans and get access to all of our training materials",
"products": [
"product_complete_access"
],
"plans": [
"plan_monthly",
"plan_yearly"
]
}
}
FieldRequiredDescription
external_reffalseA unique identifier that we can use to reference this product in the future, rather than using the random UUID that the API generates.
nametrueThe name of our Offering, in this case "GameForge Academy Membership" to indicate that the Subscriber will be signing up for a membership to GameForge Academy.
descriptionfalseA description of the Offering.
productstrueA list of Products to include in the offering, here using the external_ref of the Product we created earlier.
planstrueA list of Plans to include in the offering, here using the external_ref of the Plans we created earlier.
info

We are using external_ref here in our products and plans field, but you can also use the id field that the API will generate for you for both products and plans.

Run the request to create the Offering followed by List Offerings to confirm that is now in your store.

note

When you build an Offering, the Products and Plans that are used to create it are copied into the Offering. This means that when you make a chance to your base Product and Plans, it won't affect any Offerings you've created.

This concept carries on when your offering is converted to a Subscription, where that contains a copy of the Offering, including the Plans and Products within it.

This is useful for when you need to make changes to what you're selling to new customers without affecting all current Subscribers who will be signed up on different terms.

Step 2 - Displaying the Offering and Adding to Cart

Displaying the Offering

Now that we have our Offering, let's go through how you can fetch all the details you'll need for your site, and how a Subscriber can add it to a cart.

Take a look at the Display Offering, Products, and Plans request in Postman.

You'll notice that we're fetching the Offering using its external_ref and a filter.

However, an Offerings name and description aren't particularly useful on their own, which is why we also have an include query parameter to fetch the Product and Plans that make up that offering.

Run the request, and you'll see all the information you'll need to display on your site to market your Offering.

For pricing information, you can see the calculated price for each plan in included.plans.meta.display_price where:

  • Our Monthly Plan has a display price of $10.00
  • Our Yearly Plan has a display price of $96.00

Adding to Cart

Next, let's add the Offering to the cart.

This is no different to adding any other item to your cart besides:

  • The type must be a subscription_item.
  • You must specify the subscription_configuration with the plan and set it to the id of the plan the Subscriber has chosen (e.g., either our Monthly or Yearly Plan).

If you open up the request body of Add Offering to Cart you'll see we specify both the id of the Offering we're adding, and the id of the Yearly plan in our Offering.

Run the request, followed by List Items in the Cart and you should see your Offering with the Yearly plan selected.

Step 3 - Creating an Account for the Subscriber

Accounts within Elastic Path can be used to allow a Subscriber to make change to their Subscription by using their email and password.

info

While we will go over each step you'll need to execute to set up an Account for your Susbcriber, we won't go into any of the details behind them.

However, if you need more a more detailed overview, please take a look through the following resources.

First, run both Fetch Authentication Realm ID and Fetch Password Profile ID requests in Postman. Both of these requests are fetching and setting some values in our Postman environment that we'll need to create an Account for our Subscriber. You can see these being set under account_management_realm_id and password_profile_id respectively.

Next, let's create some initial user_authentication_info to represent our Subscriber by running Create User Authentication Info in Postman.

Once that's done, you'll next need to create a Username and Password for the Subscriber by running Add Username and Password. We've added a dummy email and password for the Subscriber in the postman environment which you can see under account_email and account_password.

Finally, run Authentciate as Account, which will create an access token that you can use to make requests on behalf of the account holder when checking out the account.

info

As we have set up our Authentication Realm to automatically create accounts when creating a User, we need to make sure we can find the ID of that Account when it's created.

This can be found in the response body when running Authenticate as Account in Postman, but if you need these details without having the user enter their username and password you can run Fetch the Account ID in Postman.

When fetching the account membership details for the user, you can include any associated accounts with that user by passing include=account as a query parameter.

Step 4 - Checking Out and Setting Up a Recurring Payment

If you've followed all the steps above, we now have all the information we need to check the order out before we can add payment details to the order which the Subscription will use.

Checking out the Cart

Take a look at the Check Out Cart request in Postman.

All the standard Order fields are set in this request, but you'll also see that we've set the header EP-Account-Management-Authentication-Token as the account token we created when authenticating as the user in the previous step.

This will allow the Subscription to be associated with the Account that the Subscriber has set up.

Adding Payment Details

Finally, we need to add the payment details to the order so that the Subscription can be paid for.

At this point, you would want to use the Stripe checkout flow to collect the payment details securely.

As part of that journey, you would need to do the following:

  1. Create a Customer in Stripe, taking note of it's ID
  2. Assign a payment method to that customer, taking note of it's ID

For the purposes of this guide, we've already created a customer in Stripe called Will Wright, and have assigned a dummy payment method to them.

Take a look at the Take Payment for Order request in Postman.

Like any other Order, you pass in your payment information as part of the purchase flow. However, for a Subscription you must also make sure you set the payment up for long term usage, otherwise when the Subscription renews, Elastic Path will not be able to use the same payment method to automatically take payment.

To do this with Elastic Path Subscriptions, you need to pass in the following body when taking payment:

{
"data": {
"gateway": "elastic_path_payments_stripe",
"method": "purchase",
"payment": "{{stripe_payment_method}}",
"options": {
"customer": "{{stripe_customer_id}}",
"setup_future_usage": "off_session"
}
}
}

The three key pieces of information you need to add are

FieldDescription
data.paymentThe ID of the payment method assigned to the Stripe customer you'll be using for recurring payments
data.options.customerThe ID of the Stripe Customer that payment method is associated with
data.options.setup_future_usageThis must be set to off_session to indicate that the payment method can be used for future payments
warning

If you don't set setup_future_usage to off_session, the payment method will be used for a single payment only and future payments will fail for your Subscription.

You can see more about this in Stripes documentation.

info

While in most cases the Subscription will be created successfully, there are some edge cases where something might be amiss:

  • An unsupported Payment Gateway is used
  • The offering has been removed from your store after the Subscription is created

In these scenarios, the Subscription will fail to be created and a specific event called create-failed will be emitted that you can listen and react to within your system.

Step 5 - Seeing your Subscriptions

Once payment is complete, let's take a look and see if any Subscriptions have been created.

Run the List Subscriptions request in Postman, and you should see a Subscription with the status active.

If you then run List Subscribers, you'll see that a Subscriber has also been created for you, with the account_id matching up with the Account we created earlier.

Finally, if you run List Invoices, you'll see that an initial invoice has been created for the Subscription you have just set up.

For future invoices, Billing and Payment Runs will be used to generate and pay your invoices, but when you go through the checkout process (or specify first_invoice_paid when creating a Subscription), a paid invoice is generated to represent that the first payment has already been taken by an external process.

What Have We Learned?

In this guide, we've covered the basic workflow of how to create, sell, and checkout a Membership Subscription in Elastic Path Subscriptions using Elastic Path Payments.

You should know what an Offering is, how Products represent our base price, and Plans can be used to set up the Billing Rules for a Subscription.

You should understand how you can fetch that Offering and display it on your site, and how a Subscriber can add it to a cart.

You should also know how to set up an Account for your Subscriber, and how to use that to check the order out.

Finally, you should know what additional payment information you need to capture at checkout, and how once the order has been successfully paid, an active Subscription and Subscriber will appear in the system.