Subscription Cart Lines
Add, change and address subscription lines in the storefront cart with the SDK.
Updated
On this page
Overview
A storefront cart can hold subscription lines next to one-time lines. A subscription line starts a recurring delivery instead of shipping once, and at checkout the cart becomes a buy-once order and a subscription order. Merchant setup is covered in Product Subscriptions.
Reading The Plans
Plans live on each size. dash.products.getOptions(slug) returns size.subscription_plans, one entry per frequency on offer for that size:
{
id: "subplan__...", // pass this as subscriptionPlanId
name: string,
subscription_id: string,
interval_length: number, // e.g. 14
interval_unit: "days" | "months",
discount_percent: string, // e.g. "15.00"
price: string | null, // per delivery; null means priced off discount_percent
features: string[], // perk lines to show
}
Product list endpoints also return subscription_savings ({ min, max } whole percents, or null) on each product, for a "Subscribe & Save" badge.
Adding A Subscription Line
await dash.cart.add({
productId,
sizeId,
quantity: 1,
subscriptionPlanId: plan.id, // omit for a one-time purchase
})
A subscription line never merges with a one-time line for the same size, and two frequencies of the same size stay separate lines. The same frequency does merge, as one subscription with a higher quantity.
Address Lines By Item Id
Because one size can sit in the cart more than once (bought once, and on subscription), a size id no longer identifies a line. Pass the line's itemId:
await dash.cart.update(sizeId, 2, { itemId: line.id })
await dash.cart.remove(sizeId, { itemId: line.id })
A call with only a size id reaches the one-time line for that size, and fails with "Item not found" for a subscription line.
Changing A Line In Place
dash.cart.changeItem(itemId, changes) moves one line to a different size, frequency or both, keeping its id, position and quantity:
// switch strength or pack; the frequency carries over to the new size
await dash.cart.changeItem(line.id, { sizeId: otherSizeId })
// switch frequency
await dash.cart.changeItem(line.id, { subscriptionPlanId: otherPlanId })
// turn the line into a one-time purchase
await dash.cart.changeItem(line.id, { subscriptionPlanId: "" })
sizeId must be another size of the same product. Plans are per size, so their ids differ between sizes; moving the size alone maps the frequency to the equivalent plan on the new size.
Line Fields
A subscription line in dash.cart.get() carries is_subscription: true and a subscription object (plan_id, subscription_id, interval_length, interval_unit, label such as "Every 4 weeks", discount_percent). One-time lines have subscription: null. Subscription lines also carry change_options.sizes, each with strength, pack and its live plans, which is everything a cart drawer needs to render its dropdowns for changeItem.
Checkout
When the cart contains a subscription, saving the card is required, and the checkout creates two orders. Show subscription lines clearly (frequency and free shipping) and label both orders on the success screen.
Customer Account
The dash.subscriptions module manages a signed-in customer's subscriptions: list(), create(), pause(id), resume(id), cancel(id), updatePayment(id, paymentProfileId) and changePlan(id, { planId, quantity }). Saved cards come from dash.paymentMethods.list().
Skipping the next delivery and subscribing again after cancelling are storefront API endpoints (no SDK method yet), called with the customer's token:
POST /api/storefront/customer/subscriptions/<sub_id>/skip/
POST /api/storefront/customer/subscriptions/<sub_id>/resubscribe/