Skip to main content
Many merchants love how Appstle Bundles calculates and applies discounts but want to design the customer-facing experience themselves so it matches their theme. Appstle fully supports this headless (or bring-your-own-UI) model for the three most common bundle types:
  • Fixed pricing bundle — a set of products sold for one fixed total price.
  • Dynamic pricing bundle — a build-your-own selection with a percentage or fixed-amount discount applied to the running total.
  • Volume discount bundle — tiered “buy more, save more” discounts based on quantity or spend.
The mental model in one sentence: you use the exact same Shopify metafields, cart-line attributes, and discount Functions that Appstle’s own bundle widgets use — the only thing you replace is the UI. Nothing about how the bundle is configured, priced, or discounted changes; you are simply rendering the experience yourself instead of letting Appstle’s widget render it.
This page explains the architecture that makes headless integrations possible. The per-bundle guides then walk through each type end to end.

Fixed pricing bundle

Sell a curated set for one fixed price.

Dynamic pricing bundle

Build-your-own with a percentage or amount discount.

Volume discount bundle

Tiered “buy more, save more” discounts.

Design principle: lean on Shopify, not on Appstle

Read configuration from Shopify metafields, fetch product data from Shopify’s own APIs, compute previews on the client, and let the discount apply through a Shopify Function. Treat calls to Appstle’s servers as a last resort, and cache them when you do make them. This is exactly how Appstle’s own storefront widgets are built — they read everything from a Shopify metafield and almost never call back to Appstle at render time. Following the same pattern keeps your storefront fast and resilient, and avoids putting storefront-scale traffic on Appstle’s API.
The key idea: you never calculate or apply the final discount yourself. The merchant configures the bundle once in the Appstle admin, and Appstle provisions a Shopify automatic discount backed by a Shopify Function in the store, and publishes the rules to a shop metafield. Your storefront reads the rules from that metafield, renders a selector, and adds the customer’s chosen line items to the cart with a small set of line-item attributes. The Appstle discount Function detects those attributes and applies the savings automatically — in the cart, in checkout, and on the final order. This design has three important consequences:

No discount codes

Discounts are automatic, not code-based. You do not request, generate, or apply a discount code anywhere in the flow.

The Function is authoritative

The Shopify Function decides the final discount at checkout. Any number you show in your UI is a preview — compute it from the same rule fields.

Attributes are mandatory

If the required _appstle-* line attributes are missing, the Function cannot recognize the line and no discount is applied.
The legacy PUT /bundles/bb/api/build-a-box/discount/{token} endpoint is deprecated and no longer returns a usable discount — discounting moved entirely to automatic Shopify Functions. Do not build a headless flow around it. Apply the line attributes described below instead.

Prerequisites

1

Install Appstle Bundles and keep it active

The discount Functions and the rules metafield only exist while the app is installed. Uninstalling removes the automatic discounts.
2

Create and activate the bundle in the Appstle admin

Configure the bundle (products, pricing, tiers) in the Appstle dashboard and set its status to Active. This provisions the Shopify automatic discount and publishes the rule to the shop metafield. Bundles are authored in the admin; there is no API to create them.
3

Add the Appstle app block once (themes)

On a Shopify theme, enable the Appstle Bundles app embed/block so the rules metafield is available to your code. You can hide Appstle’s default widget and render your own UI from the same data.

The integration model

Every headless bundle, regardless of type, follows the same shape — and most of it runs against Shopify, not Appstle:
1

Read the rules from the Shopify metafield

Appstle publishes active rules to the appstle_bundles.bundle_rules shop metafield. Read it the Shopify-native way — see Reading bundle configuration. No Appstle server call.
2

Render your own selector with Shopify data

Build UI from the rule fields: list eligible products, enforce the selection limits, and show a running total. Use Shopify’s own product/variant data (Liquid objects or the Storefront API) for titles, images, and prices.
3

Validate the selection, then add to cart

When the selection is valid, add the line items via Shopify’s Ajax Cart API (themes) or the Storefront API cartLinesAdd mutation (fully headless), attaching the bundle line attributes.
4

Let the discount apply automatically

Appstle’s discount Function reads the attributes and applies the savings in cart and checkout. You do nothing else. Optionally render a discount preview computed on the client from the same rule fields.

Reading bundle configuration

Pick the source closest to Shopify. The first option should cover almost every storefront.

Bundle type reference

Each Appstle bundle type maps to a bundleType value in the rules data. These three are supported for headless storefronts:
Merchant labelbundleTypebundleSubType
Fixed pricing bundleSINGLE_PRODUCT_BUILD_A_BOXFIXED_BUNDLE
Dynamic pricing bundleCLASSIC_BUILD_A_BOX
Volume discount bundleVOLUME_DISCOUNT
Other values exist in the bundleType enum (for example DISCOUNTED_PRICING, BUY_X_GET_Y, SECTIONED_BUNDLE, COMBO_BUNDLE). This documentation covers the three types above; the same metafield-plus-attributes model extends to the others.

Discount fields on a rule

The relevant pricing fields on each rule object:
FieldTypeUsed byMeaning
uniqueRefstringallStable reference for the bundle. You attach this to every cart line as _appstle-bb-id.
discountTypeenumdynamic, volumeOne of PERCENTAGE, FIXED_AMOUNT, FIXED_BUNDLE_AMOUNT, TIERED_DISCOUNT, NO_DISCOUNT, FREE_GIFT.
discountValuenumberdynamicThe percentage (e.g. 15 = 15%) or fixed amount, depending on discountType.
pricenumberfixedThe fixed total price the customer pays for the bundle.
tieredDiscountstring (JSON)volumeJSON array of tier objects (see the Volume discount guide).
minProductCount / maxProductCountintegerdynamic, fixedMin / max number of items the customer must select.
minOrderAmount / maxOrderAmountnumberdynamicMin / max selection value required for the discount to apply.
products / variantsstring (JSON)allEligible products and variants configured for the bundle.
statusstringallThe bundle is only live when ACTIVE.

Required cart line attributes

This is the contract between your storefront and Appstle’s discount Function. When you add a bundle line item to the cart, attach these attributes. On a Shopify theme they are passed as line-item properties; through the Storefront API they are line attributes. Both surface to the Function as cart-line attributes.
Attribute keyRequiredValuePurpose
_appstle-bb-idYesThe rule’s uniqueRefLinks the line to a specific bundle so the Function knows which rule to apply.
_appstle_bundles_typeYesThe bundleType value (e.g. VOLUME_DISCOUNT)Tells the Function which discount logic to run.
__appstle-bb-nameRecommendedThe bundle’s nameHuman-readable label shown in cart/order line items.
_appstle_bundle_combo_idVolume only (tier restriction)The selected tier’s identifierPins the line to a specific tier when tier restriction is enabled.
_appstle-bb-childFixed only (child items)"true"Marks component lines added alongside the parent in certain inventory modes.
Attribute keys are matched exactly, including the leading underscore and the mix of hyphens and underscores (_appstle-bb-id vs. _appstle_bundles_type). Copy them verbatim. Keys beginning with _ are hidden from the customer in standard Shopify cart/checkout UIs.

Adding to cart on a Shopify theme (Ajax Cart API)

await fetch(`${Shopify.routes.root}cart/add.js`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    items: [
      {
        id: variantId,          // numeric Shopify variant ID
        quantity: 2,
        properties: {
          '_appstle-bb-id': bundle.uniqueRef,
          '_appstle_bundles_type': bundle.bundleType,
          '__appstle-bb-name': bundle.name,
        },
      },
    ],
  }),
});

Adding to cart on a fully headless stack (Storefront API)

mutation AddBundleLines($cartId: ID!) {
  cartLinesAdd(
    cartId: $cartId
    lines: [
      {
        merchandiseId: "gid://shopify/ProductVariant/123456789"
        quantity: 2
        attributes: [
          { key: "_appstle-bb-id", value: "your-bundle-uniqueRef" }
          { key: "_appstle_bundles_type", value: "VOLUME_DISCOUNT" }
          { key: "__appstle-bb-name", value: "Summer Skincare Set" }
        ]
      }
    ]
  ) {
    cart { id }
    userErrors { field message }
  }
}

Previewing the discount

Because the Shopify Function applies the authoritative discount at checkout, any amount you display beforehand is a preview — and you compute it on the client, from the same rule fields, with no server call. (Appstle’s own widget does the same, and even exposes a window._ABConfig.getProductDiscountedPricing(...) helper on theme storefronts.) The formula differs per type — see each guide:
All monetary values in the Shopify cart are expressed in the minor unit (cents). A total_price of 5000 means $50.00. Account for this when computing previews.

Next steps

Fixed pricing bundle guide

End-to-end headless walkthrough for fixed-price sets.

Dynamic pricing bundle guide

End-to-end headless walkthrough for build-your-own discounts.

Volume discount bundle guide

End-to-end headless walkthrough for tiered savings.

Authentication

For backend-only reads — never used from a storefront.