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:
- Model a basic Membership Subscription with a Monthly and discounted Yearly plan
- Retrieve the details of this Subscription for your PDP
- Add the Subscription to the cart and select a plan
- Create an Elastic Path Account for your Subscription
- 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):
- Will Wright
Make note of their Stripe Customer ID and associated Card ID.
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:
File | Description |
---|---|
collection.json | A Postman Collection with all the API calls required for this guide |
environment.json | A 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:
Variable | Value |
---|---|
clientSecret | The Client Secret for your API key |
clientID | The Client ID for your API key |
authURL | The API Base URL for your store |
stripe_customer_id | The Stripe Customer ID for Will Wright |
stripe_payment_method | The 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:
Field | Required | Description |
---|---|---|
name | true | The name of our product, in this case "Complete Access" to indicate that a Subscriber would have complete access to all material. |
external_ref | false | A unique identifier that we can use to reference this product in the future, rather than using the random UUID that the API generates. |
description | false | A description of our product, detailing what the Subscriber will get when they sign up. |
price | false | The 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_units | false | A rate at which the price of the product is against. For example, here we say the base price is $10 a month |
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.
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
}
}
}
Field | Required | Description |
---|---|---|
external_ref | false | A unique identifier that we can use to reference this product in the future, rather than using the random UUID that the API generates. |
name | true | The name representing this plan, in this case "Monthly Billing" to indicate that the Subscriber will be billed monthly. |
description | false | A description of the plan. |
billing_interval_type | true | The unit of time we're going to represent billing with. In this case we'll be using months. |
billing_frequency | true | How 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_length | true | How many Billing Cycles the plan will last for. In this case, the plan will end after one month. |
end_behavior | true | What 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_pause | true | Whether the Subscriber can pause the Subscription. |
can_resume | true | Whether the Subscriber can resume the Subscription. |
can_cancel | true | Whether the Subscriber can cancel the Subscription. |
base_price_percentage | true if fixed_price is not set | The 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. |
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:
Field | Difference |
---|---|
billing_frequency | We 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_percentage | We 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"
]
}
}
Field | Required | Description |
---|---|---|
external_ref | false | A unique identifier that we can use to reference this product in the future, rather than using the random UUID that the API generates. |
name | true | The 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. |
description | false | A description of the Offering. |
products | true | A list of Products to include in the offering, here using the external_ref of the Product we created earlier. |
plans | true | A list of Plans to include in the offering, here using the external_ref of the Plans we created earlier. |
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.
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 theplan
and set it to theid
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.
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.
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:
- Create a Customer in Stripe, taking note of it's ID
- 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
Field | Description |
---|---|
data.payment | The ID of the payment method assigned to the Stripe customer you'll be using for recurring payments |
data.options.customer | The ID of the Stripe Customer that payment method is associated with |
data.options.setup_future_usage | This must be set to off_session to indicate that the payment method can be used for future payments |
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.
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.