Skip to content
Kitenzo Headless is invite-only. To enable it on your store, email support@kitenzo.com.

Endpoints

All paths are relative to https://live.bb.eight-cdn.com/api/headless/v1 and require Authorization: Bearer kit_live_….


GET /bundles

Returns published bundles (capped at 100). Lightweight — no sections or product data.

Response 200

[
{
"id": 42,
"name": "Build your own box",
"description": "Pick any 3 items",
"imageUrl": "https://cdn.shopify.com/…",
"type": "native",
"bundlingOption": "bundles",
"published": true
}
]
FieldTypeDescription
idnumberBundle ID.
namestringDisplay name.
descriptionstringMerchant description (may be empty).
imageUrlstringBundle image (may be empty).
typestringsingle-product | multiple-products | native.
bundlingOptionstringNormally bundles. Legacy upsells bundles are still returned — handle defensively.
publishedbooleanAlways true here.

GET /bundles/:id

Full configuration: sections, discount, limit rules, required products and the conditions-engine graph. Product/variant detail comes from the products endpoint.

Response 200

{
"id": 42,
"name": "Build your own box",
"description": "Pick any 3 items",
"imageUrl": "https://cdn.shopify.com/…",
"type": "native",
"bundlingOption": "bundles",
"layout": "multiple-sections",
"published": true,
"discount": {
"type": "percentage",
"value": "10.00",
"flatOrTiered": "flat",
"minimum": null,
"operator": "max",
"tiers": []
},
"sections": [
{
"id": 1,
"name": "Choose a shirt",
"description": "",
"imageUrl": "",
"order": 0,
"autoNextSection": true,
"products": [
{ "bundleItemId": 7, "shopifyProductId": "111", "variantIds": ["1001", "1002"] }
]
}
],
"requiredProducts": [
{ "shopifyProductId": "222", "variantIds": [], "quantity": 1 }
],
"limitRules": [
{ "type": "total-number-of-products", "operation": "gte", "value": "3", "sectionId": null }
],
"weightUnit": "kg",
"conditionsEngineEnabled": false,
"conditionsEngineNodes": [],
"conditionsPartial": false
}
FieldTypeDescription
layoutstringsingle-page | multiple-sections.
discountobject | nullTiers carry type, value, operation, discount and customText (merchant copy override, null when unset). See Discounts.
sections[]arrayid, name, description, imageUrl, order, autoNextSection, products[].
sections[].autoNextSectionbooleanThe merchant’s “advance to the next step once this one is satisfied” setting. Mirror it rather than hardcoding the behaviour.
sections[].products[]arraybundleItemId, shopifyProductId, variantIds[] (empty = all variants allowed).
requiredProducts[]arrayshopifyProductId, variantIds[], quantity.
limitRules[]arraytype, operation, value, sectionId. See Limit rules.
weightUnitstringShop weight unit (g/kg/oz/lb) for the amount-of-weight rule.
conditionsEngineEnabledbooleanWhether the bundle has conditions-engine logic.
conditionsEngineNodes[]arraySerialised rule graph (present when the shop’s conditions feature is on). The SDK evaluates it client-side.
conditionsPartialbooleantrue when the bundle uses conditions the headless evaluator can’t run yet (cascade-variant) and they were stripped.
sellingPlans[]?arrayLive Kitenzo Subscriptions plans — present only for shops in the subscriptions beta with live programs on this bundle. See Conditions & subscriptions.
personalisation?objectPer-product personalisation field definitions, keyed by Shopify product ID. Present only when the shop’s personalisation feature is on.

GET /bundles/:id/products

Full product and variant data for the bundle — live pricing, SKU, availability, inventory, options and content fields.

Query parameters

ParamTypeDescription
countryCodestringOptional ISO 3166-1 alpha-2 country. Adds Shopify Markets presentment pricing + market availability per variant.

Response 200

{
"products": [
{
"shopifyProductId": "111",
"shopifyProductGid": "gid://shopify/Product/111",
"title": "Classic Tee",
"handle": "classic-tee",
"imageUrl": "https://cdn.shopify.com/…",
"status": "ACTIVE",
"tags": ["summer", "tees"],
"descriptionHtml": "<p>Our classic tee…</p>",
"options": [
{ "name": "Size", "position": 1, "values": ["Small", "Medium"], "swatches": {} }
],
"variants": [
{
"shopifyVariantId": "1001",
"shopifyVariantGid": "gid://shopify/ProductVariant/1001",
"title": "Small / Black",
"price": "29.99",
"compareAtPrice": null,
"sku": "TEE-S-BLK",
"available": true,
"inventoryQuantity": 42,
"grams": 180,
"optionValues": ["Small", "Black"]
}
]
}
]
}

Product fields

FieldTypeDescription
statusstringACTIVE | ARCHIVED | DRAFT. Archived/draft products can’t be added to the cart — don’t render them as pickable.
tagsstring[]Product tags (Kitenzo’s internal bundle-builder-* control tags are stripped).
descriptionHtmlstringRaw Shopify product HTML — sanitise before rendering.
options[]arrayOption definitions (name, position, values[], swatches) in Shopify’s order, aligned with each variant’s optionValues.

Variant fields

FieldTypeDescription
pricestringShop-currency price, 2 decimals.
compareAtPricestring | nullThe variant’s own compare-at price, when set.
gramsnumberWeight in grams (what the amount-of-weight rule measures).
optionValuesstring[]Option values in the same order as the product’s options.
imagestring?Variant-level image — present only when the variant has one of its own; fall back to the product image.
availablebooleanBase-store purchasability (see availability rules).
presentmentPrice / presentmentCurrency / priceInShopCurrency / availableForSalePresent only when countryCode was supplied. availableForSale: false means “not sold in that market” — distinct from available.

See Sections, products & variants for the full semantics.


POST /bundles/:id/configure

Validates a customer’s selection, creates a configured bundle, and returns the data needed to add it to the Shopify cart — including, for native bundles, a cart-ready payload any HTTP client can write straight to a cart (this is what the TapCart guide uses).

Request body

{
"type": "native",
"products": [
{ "variant": "1001", "product": "111", "section": 1 },
{ "variant": "1002", "product": "111", "section": 1 }
],
"countryCode": "US"
}
FieldTypeRequiredDescription
typestringYesnative | multiple-products | single-product.
productsarrayYesNon-empty list; each item needs variant, product, section. Max 200.
countryCodestringNoFor market-aware pricing.
subscriptionobjectNoid (recurring group), email, frequency, unit — creates a pending subscription.
bundleContentobjectNoConditions-engine discount override (conditionsDiscount) — sent automatically by the SDK; the server validates and signs it.

Response 200

{
"configured_bundle_id": 9876,
"variant_id": "44556677",
"product_id": "111",
"discount": "<encrypted-discount-string>",
"subscription_id": null,
"pricing": {
"originalPrice": "59.98",
"discountedPrice": "53.98",
"discountType": "percentage",
"discountValue": "10.00",
"currency": "USD"
},
"cart": {
"line_items": [
{ "id": 1001, "quantity": 1, "properties": { "_bundle_data": "9876#44556677#<uuid>" } },
{ "id": 1002, "quantity": 1, "properties": { "_bundle_data": "9876#44556677#<uuid>" } }
],
"attributes": {
"_bundles": "{\"9876\": {\"configuredBundleId\": 9876, \"discount\": \"…\", \"title\": \"…\", \"items\": [{\"variantId\": 1001, \"count\": 1}], \"image\": null, \"note\": null, \"id\": 42}}"
}
}
}
FieldTypeDescription
configured_bundle_idnumberThe configured bundle’s ID.
variant_idstringShopify variant to add to cart (the bundle’s ghost variant, for non-native paths).
product_idstringShopify product for the bundle.
discountstringEncrypted, server-signed discount string (what the Cart Transform decrypts).
subscription_idnumber | nullSet when a recurring subscription option was chosen.
pricingobjectSame shape as the price endpoint.
cartobject | nullCart-ready payload — native bundles only; null for other types (their discount is in the variant price).
cart.line_items[]arrayShopify /cart/add.js-shaped items (id, quantity, properties). Each carries _bundle_data = configuredBundleId#parentVariantId#uniqueId; all entries of one call share the same uniqueId.
cart.attributes._bundlesstringStringified one-entry map for the _bundles cart attribute, keyed by configuredBundleId. Merge it into any existing _bundles value — don’t overwrite.

POST /bundles/:id/price

Calculates pricing for a selection without creating a configured bundle. Same request body as /configure (minus type): products, plus optional countryCode and bundleContent.

Response 200

{
"originalPrice": "59.98",
"discountedPrice": "53.98",
"discountType": "percentage",
"discountValue": "10.00",
"currency": "USD"
}

Amounts are always in the shop’s base currency — countryCode makes the discount maths market-correct but doesn’t change the response currency. For displaying localised prices, use the SDK’s presentment helpers.


GET /settings

Response 200

{
"activeFeatures": ["headless_api", "subscriptions"],
"currency": "USD",
"moneyFormat": "${{amount}}",
"weightUnit": "kg"
}
FieldTypeDescription
activeFeaturesstring[]Enabled Kitenzo features for the shop.
currencystringShop currency code.
moneyFormatstringShopify money format string (used by formatMoney).
weightUnitstringShop weight unit (g/kg/oz/lb).