Steps 1, 2 and 4 run in the customer’s browser. Steps 1 and 4 call Appstle’s Storefront API through Shopify’s App Proxy, so they need no API key; it isn’t Shopify’s Storefront GraphQL API. Step 3 and Save from your server instead use the Admin API from your server, with an API key. If the store changed its App Proxy path, replace
/apps/subscriptions with it. Read Build your own frontend first if you haven’t used the App Proxy before.What you’ll build
- A cart add that puts a fixed-price box in the cart with a selling plan, and carries the customer’s choices as line item properties.
- An account-page call that saves a changed selection on the customer’s existing subscription line.
Before you start
- A fixed-price box (a Fixed Pricing Bundle), enabled in the Build-A-Box section of the Appstle Subscriptions app. Note its reference: the box list shows it as Ref, and the API calls it
uniqueRef. - A selling plan attached to the box’s parent product.
- A signed-in customer for Step 4. Steps 1 and 2 also work for guests.
How a fixed-price box is stored
A fixed-price box is one ordinary line: the box’s parent product with a selling plan. The customer’s choices travel on that line as five line item properties, and they stay on the subscription line after checkout. That is why you can change the choices later by updating that line’s properties, without adding a line or a subscription.
Shopify doesn’t show properties whose names start with an underscore to the customer at checkout, so only
products appears on the order summary.
Step 1: Read the box
Get the box’s rules and its choices. The call goes through the App Proxy, so it needs no API key and works for guests as well as signed-in customers:/apps/subscriptions/cp/api/, which needs a signed-in customer. The call answers 204 with an empty body when no box has this reference or the box is disabled.
bundle.singleProductSettings is a JSON string. After parsing, it holds one entry per parent product, so a box with several parents has several entries. Use the entry whose sourceProduct is the parent you sell:
Read the rest from Shopify’s product JSON (
/products/<handle>.js). The parent product’s selling_plan_groups[].selling_plans[].id is the selling plan. For a PRODUCT choice, its variants[].id and variants[].sku go into __appstle-bb-variants and _appstle-bb-product-sku. For a VARIANT choice, read the product at its productHandle and use the variant whose id matches. Offer only these choices: Appstle’s box page refuses anything else, and your UI must too.
The same box is available to your server as
GET /api/external/v2/build-a-box/{handle} with an API key, where {handle} is the uniqueRef. It answers 404 while the box is disabled. See Retrieve Build-A-Box bundle details by handle.Step 2: Add the box to the cart
Add the parent variant with the selling plan and the five properties. This is Shopify’s Cart API, so no Appstle call is involved:minQuantity and maxQuantity. Shopify’s cart add doesn’t check it, but the save in Step 4 does.
Cart clearing
The Cart Clearing Behavior setting in the store’s Build-A-Box settings applies only to Appstle’s own box page. Your/cart/add.js call leaves the cart as it is. To start the customer with an empty cart, call Shopify’s POST /cart/clear.js before you add the box.
Step 3: Check the subscription after checkout
When the customer pays, Shopify creates the subscription, and the five properties are copied onto its line unchanged. Read the contract with the Admin API on your server to confirm:GET /apps/subscriptions/cp/api/subscription-customers-detail/valid/{customerId} (reference), where {customerId} is the customer’s numeric Shopify ID ({{ customer.id }} in Liquid). Each contract has a subscriptionContractId, and its contractDetailsJSON is a JSON string with one entry per line. Each entry has a lineId and the line’s customAttributes. The box line is the one whose customAttributes include _appstle-bb-id.
Step 4: Save a changed selection
To change what is in the box, send the new properties for the existing line. Don’t add a second line or a new subscription:
On success the call returns
200 with the updated contract, in the same shape as the Step 3 response, and the line carries the new properties. The line ID doesn’t change and the customer still has one subscription. See Edit custom attributes on a single line item.
What the save checks
The app runs these checks before it saves a customer’s change. A failed check answers400 with application/problem+json, and its title holds the message. The time-window and frozen-subscription messages are written for the customer: show them without the UserGeneratedError: prefix. The others point to a problem in your request or the customer’s picks, so show your own text for them, such as “Choose between 1 and 4 items.”
A customer can change only
products, __appstle-bb-variants and _appstle-bb-product-sku. Every other Appstle property keeps its old value, whether you send it or not. Properties that aren’t Appstle’s, such as a gift message from another app, work differently: the line keeps exactly the ones you send. Send each of them back unchanged. Adding, changing or leaving one out needs the store’s Allow customers to edit attribute values setting, and a property you leave out is then removed.
A call without a signed-in customer answers 401. Storefront calls are rate limited per customer: a call over the limit answers 429 with a Retry-After header, so wait that many seconds before you retry. Save once, when the customer confirms the new box, not on every change.
The time-window, frozen-subscription and edit-permission checks depend on the store’s customer portal settings. The other checks apply to every store.
Save from your server instead
The Admin API has an equivalent call for your own back office. It uses an API key and acts as the merchant, so none of the customer checks above run, including the box’s minimum and maximum. It replaces the line’s properties with exactly the list you send: send all five box properties and every other property the line should keep.Next steps
Build your own frontend
Selling plans, the cart and the customer portal from your own UI.
JavaScript hooks
Events the widget fires that your code can listen to.
Authentication
Admin API keys and how storefront calls are authenticated.
Integration guide
Server-side calls for subscriptions and contracts.