Creating a dynamically-prcied bundle using the API
Add custom line item properties during checkout to enable Recharge to identify and process dynamically priced bundles.
This guide explains how to create a dynamically-priced bundle using the Recharge API.
Requirements
Data needed
You need the following values to build the line item properties:
- From the bundle product:
handle
- Product ID
- Variant ID
- From the line item
- Collection ID
Properties to add
Each line item must include the following properties:
Property | Description |
---|---|
|
|
| The product handle |
| The bundle product variant |
| The Collection ID associated with the line item |
Set-up instructions
Step 1 - Retrieve the bundle product data
Use the following script to fetch the required product data from Shopify:
const fetch = require('node-fetch');
// Replace with your actual store info and access token
const SHOPIFY_STORE = 'your-store-name.myshopify.com';
const ACCESS_TOKEN = 'your-admin-api-access-token';
const PRODUCT_ID = 'gid://shopify/Product/1234567890';
async function getProductDetails(productGID) {
const query = `
query getProduct($id: ID!) {
product(id: $id) {
id
handle
variants(first: 1) {
edges {
node {
id
}
}
}
}
}
`;
const response = await fetch(`https://${SHOPIFY_STORE}/admin/api/2024-01/graphql.json`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Shopify-Access-Token': ACCESS_TOKEN,
},
body: JSON.stringify({
query,
variables: { id: productGID }
}),
});
const result = await response.json();
if (result.errors) {
console.error('GraphQL errors:', result.errors);
return null;
}
const product = result.data.product;
return {
id: product.id,
handle: product.handle,
variants: product.variants.edges.map(edge => edge.node),
};
}
// Run the function
getProductDetails(PRODUCT_ID).then(product => {
if (product) {
console.log(JSON.stringify(product, null, 2));
} else {
console.log('Product not found or error occurred.');
}
});
Step 2 - Build line item properties
Use the function below to generate the correct property format for each line item:
import { nanoid } from 'nanoid';
function buildLineItemProperties(productId, productVariantId, productHandle, lineItemCollectionId, lineItemVariantId) {
let itemData = {
id: lineItemVariantId,
quantity: 1,
properties: {
"_rc_bundle": `${nanoid(9)}:${productId}`,
"_rc_bundle_parent": productHandle,
"_rc_bundle_variant": productVariantId, // Important, this is the active variant ID for the bundle
"_rc_bundle_collection_id": lineItemCollectionId,
}
};
return itemData;
}
Step 3 - Update the cart
Use this script to post the updated line items to Shopify's cart endpoint:
queue = [];
const productId = "{productId}";
const productVariantId = "{productVariantId}";
const productHandle = "{product-handle}";
const lineItemCollectionId = "{lineItemCollectionId}";
const lineItems = buildLineItemProperties()
const lineItemVariantId = "{lineItemVariantId}";
const linetItemProperties = buildLineItemProperties(productId, productVariantId, productHandle, lineItemCollectionId, lineItemVariantId);
queue.push(lineItemProperties);
try {
await dispatch('postToCart', { items: queue });
} catch (error) {
console.log("error");
}
const postToCart = (data) => {
return fetch('/cart/add.js', {
headers: { 'Content-Type': 'application/json' },
method: 'POST',
body: JSON.stringify(data),
});
};
Note
This example updates the cart within the storefront context. If using a different context (e.g., headless implementation or server-side processing), adjust the script accordingly to ensure correct behavior.
Example results
The example below illustrates the expected structure for line item:

Updated about 24 hours ago