Skip to main content
This guide is for frontend developers who start a membership purchase from their own page: a custom plan picker, a landing page, a team or seat plan with a quantity picker, or a link in an email. You don’t call an Appstle API to sell a membership. Shopify’s cart and checkout take the order, and Appstle creates the membership once checkout completes.
The cart calls on this page are Shopify’s Ajax Cart API. They run on pages of the store’s Online Store theme and need no Appstle API key. The only Appstle call, looking up a plan’s IDs, is an Admin API call from your server with an API key in the X-API-Key header (see Authentication). Never put an API key in browser code. A headless storefront builds its cart with Shopify’s Storefront GraphQL API instead. There, each cart line takes the selling plan as sellingPlanId, in the form gid://shopify/SellingPlan/690000000001. See cartCreate.

How a membership purchase works

A membership is a Shopify product that the customer buys on a selling plan. A cart line becomes a membership only when it carries that plan’s selling plan ID. Your page does three things:
  1. Look up the variant ID and the selling plan ID.
  2. Add the variant to the cart with selling_plan and a quantity.
  3. Send the customer to checkout.
When the customer completes checkout, Shopify creates a subscription contract, and Appstle turns it into a membership for that customer. It usually appears in the contract list within a few seconds, and the membership.created webhook fires.

Find the variant ID and the selling plan ID

Pick the place that matches where your code runs.

From the product’s .js endpoint

The response holds the IDs you need (trimmed):
A plan with more than one renewal option has one entry in selling_plan_allocations for each. The names are in product.selling_plan_groups[].selling_plans[], so match on id to let the customer choose. If the product also sells through another app’s selling plans, use only the groups whose app_id is appstle-memberships.

From the Admin API

Call this from your server only. Take the plan’s id from the list call GET /api/external/v2/subscription-groups, then get the plan by that ID. The list itself can’t give you either ID: it leaves subscriptionPlans empty and variantIds null.
variantIds is a JSON-encoded string, so parse it before you read it. The selling plan ID is the number after gid://shopify/SellingPlan/.

Add the membership to the cart

Post the variant, the selling plan and the quantity to /cart/add.js:
A successful call returns 200 with one cart line (trimmed). The selling_plan_allocation is what makes the line a membership:
Always send selling_plan. In the Appstle plan editor, merchants are told to make the membership product subscription only in Shopify. On a product set that way, a cart add without a selling plan fails with 422:
On a product that isn’t subscription only, the same call adds a one-time purchase, and the order doesn’t create a membership.

If the cart already has the membership

If the cart already has a line with the same variant and selling plan, /cart/add.js adds your quantity to that line. A customer who picks 3 seats, comes back and picks 2 checks out with 5. To send only the seats the customer just picked, clear the cart first, as a Quick Checkout link does. This also removes everything else in the cart:

Errors

/cart/add.js answers a bad request with a JSON body whose description says what went wrong. The helper above throws that text: Send the number after gid://shopify/SellingPlan/, not the whole string.

Quantity

quantity works like it does for any cart line. A cart add with quantity: 3 on a 9.99 plan creates one membership with one line at quantity: 3. In the contract that GET /api/external/v2/subscription-contract-details returns, that line’s currentPrice is the price of one seat (9.99) and its discountedPrice is the line total (29.97). The contract’s orderAmount and contractAmount are both 29.97 (trimmed):
Appstle creates one membership, owned by the customer who checked out, not one per seat. To give the extra seats meaning, read the line’s quantity from contractDetailsJSON in your own system. If every person on a team needs their own membership, each of them has to buy one.

Send the customer to checkout

Redirect to /checkout once the cart add succeeds, as in the example above. To start the same purchase from a link, such as a button in an email, build a cart link the way the app’s Quick Checkout link does. The link clears the cart, adds the item and continues to checkout:
Merchants can create these links without code under More → Subscriber Acquisition & Automation → Quick Checkout, in the Quick Checkout Link card with its Copy button. A Quick Checkout link carries the quantity the merchant chose when they created it. For a quantity the customer picks, build the link with membershipLink, use the cart call above, or use the form below.

Using a form

A plain theme form is the simplest seat picker, because a quantity input carries the customer’s choice and no JavaScript is needed. The form adds the item and return_to sends the customer to checkout:
Like the cart call, the form adds to a line that is already in the cart, so a returning customer’s seats add up.

The checkout rule that can refuse the cart

Appstle adds a Shopify checkout rule, Membership Validations, that can refuse a cart with memberships in it. It refuses carts only when both of these are true:
  • The merchant has activated the rule in Shopify admin: under Settings → Checkout, Membership Validations by Appstle Memberships shows as Active.
  • The merchant has turned on Allow membership per customer in Appstle under More → General Settings → Shop Settings, in Member Settings.
When both are on, the rule refuses any cart that holds more than one membership in total, whoever the customer is: two lines on membership plans, or one line with a quantity above 1. So a seat picker that sends a quantity above 1 works only on a store where Allow membership per customer is off. The setting’s four options also refuse customers who already have a membership. If the merchant never picked an option, One Overall applies. When the rule refuses a cart, /cart/add.js still returns 200, because the rule runs when the customer reaches checkout. Checkout then shows the merchant’s Duplicate membership checkout validation message, or Duplicate membership purchases are not allowed. when that field is empty. The customer can’t pay until the cart changes.

Next steps

Webhooks

React to membership.created and the other membership events on your server.

Integration guide

Find members and manage memberships with the Admin API.

Metafields & tags

Read plan and membership data in Liquid.