--- title: "Get Bundle Recommendations" slug: "get-bundle-recommendations" description: "Use the Insider One /v2/bundle endpoint to serve Bundle Strategy products by trigger, with pinned, catalog, and algorithm slots and fallback logic." updated: 2026-11-03T10:09:55Z published: 2026-11-03T10:09:55Z canonical: "academy.insiderone.com/get-bundle-recommendations" --- > ## Documentation Index > Fetch the complete documentation index at: https://academy.insiderone.com/llms.txt > Use this file to discover all available pages before exploring further. # Get Bundle Recommendations The Bundle endpoint returns products from a Bundle Strategy saved in InOne. - Each slot uses a pinned product, a catalog filter, or an available algorithm. - Trigger rules choose the bundle for the current product or category. A configured fallback is used when none matches. - Send the strategy ID and the product, category, or user context your setup needs. > [!NOTE] > For setup and details, see [Create a Bundle Strategy](https://academy.insiderone.com/docs/create-a-bundle-strategy). > [!NOTE] > Bundle Strategy availability varies by the Smart Recommender package. ## Algorithm-Based or Bundle? Two strategy types are available. See [Smart Recommender Recommendation Strategies](https://academy.insiderone.com/docs/smart-recommender-recommendation-strategies) for details. | You want to... | Use | Endpoint | | --- | --- | --- | | Fill all positions with one algorithm (e.g., Top Sellers, Viewed Together) | Algorithm-Based | /v2/{algorithm-name} (see [Algorithm Descriptions](https://academy.insiderone.com/docs/algorithm-descriptions)) | | Put specific products in fixed positions, mix pinned, catalog-filtered, and algorithm products, or show different products depending on the viewed product or category | Bundle | /v2/bundle | For advanced mixed-algorithm or pinned-product setups, we recommend Bundle Strategies when available in your account. See Building Mixed Strategy or Manual Merchandising setups as a Bundle below. ## Before you start - An [API token](https://academy.insiderone.com/docs/api-authentication-tokens), sent in the X-Auth-Token header. Call the endpoint from your server; never put the token in a URL or in client-side code. - A saved Bundle Strategy and its ID. To find the ID, go to Campaigns > Recommendation > Recommendation Strategies, click the info icon of your Bundle Strategy, and copy the Bundle ID. Send this value as bundleStrategyId. - Your partner name and locale, as in [Get Recommendations](https://academy.insiderone.com/docs/get-recommendations). ## Endpoint > **GET** https://recommendation.api.useinsider.com/v2/bundle ## Query Parameters Required parameters are listed below. Additional context depends on your strategy; see Which Context to Send. | Parameter | Sample Value | Description | Data Type | Required | | --- | --- | --- | --- | --- | | partnerName | mybrand | Partner identifier assigned by Insider One. You can use the Partner ID as well. | String | Yes | | locale | en_US | Locale of the requested product catalog. | String | Yes | | bundleStrategyId | 123 | ID of the saved Bundle Strategy. | String | Yes | | productId | JACKET-01 | Product the shopper is viewing. Used for product triggers, item-based slots and filters that use the viewed product's values. Separate several IDs with commas (for example, cart items). | String | No | | categoryList | ["Jackets"] | Category of the current page. Used for category triggers and "of the Category" slots. Send as a URL-encoded JSON array. | Array (of string) | No | | userId | testUser | User identifier assigned by Insider One. Needed for personalized slots and for personalization settings. | String | No | | currency | USD | Currency code used for currency-specific pricing. Required for Highest Discounted algorithm slots; these slots return no products if currency is omitted. On Stock & Revenue Based feeds, providing currency excludes products without a price above 0 in that currency. If omitted, this automatic price filter is not applied. | String | No | | size | 20 | Maximum number of products in the response. | Integer | No | | minSize | 4 | Minimum total product count used to try the configured fallback. This is not a guaranteed response size. See How the Endpoint Picks the Products. | Integer | No | | details | true | Adds product details and the slot of each product to the response. | Boolean | No | | filter | [price.USD][<][100] | Applied to every slot, including pinned products, on top of the filters saved in the strategy. There can be more than one filter parameter. See [Filtering Recommendation Responses](https://academy.insiderone.com/docs/recommendation-api-filtering-responses). | String | No | | hp | true | Enables attribute affinity for algorithm slots. Not needed if Attribute Affinity is already on in the bundle's personalization settings. | Boolean | No | | excludeViewDay, excludeViewItem, excludePurchaseDay, excludePurchaseItem | 30, 10, 30, 10 | Exclude viewed or purchased products. Requires userId. Request-level viewed exclusions override saved viewed exclusions; purchased exclusions are overridden independently. | Integer | No | | getGroupProducts, groupProductsFields | true, price,in_stock | Returns variant products. Requires details=true. | Boolean / String | No | | country, city | TR, Istanbul | Shopper's location, for Location Based Top Sellers slots. country is required for those slots; with city, only that city's list is used. | String | No | | platform | web | Requested platform. Web is the default. | Enum | No | ## Which context to send Omitting context can leave a trigger unmatched or a slot empty without failing the request. Invalid parameters and explicit exclusion parameters without userId can still return an error. | If your strategy has | Send | If you don't | | --- | --- | --- | | A trigger on specific products or a product attribute (brand, price, ...) | productId | The trigger does not match. The fallback bundle is served, or nothing. | | A trigger on category | categoryList | Same as above. | | An item-based slot (Viewed Together, Purchased Together, Substitute, Complementary, Similar, Visually Similar, Checkout Recommendation) or a contextual custom algorithm slot, based on the viewed product | productId | That slot is empty. | | An item-based slot using the user's recent activity as its source (e.g. last viewed or last added to cart) | userId | If the activity source cannot be resolved, the slot tries the request productId. It is empty if neither provides a usable product anchor. | | A Most Popular or Most Valuable "of the Category" slot | categoryList | No category restriction; the slot returns products from the whole catalog. | | A User-Based, User Engagement, Recently Viewed or Purchased with Last Purchased slot, or a personalized custom algorithm slot | userId | That slot is empty. | | A Location-Based Top Sellers slot | country (city optional) | That slot is empty. | | A Highest Discounted slot | currency | That slot is empty. | | Personalization settings that exclude viewed, purchased, or in-cart products, or Attribute Affinity | userId | The setting is skipped. | | A personalization setting that hides the currently viewed product | productId | The setting is skipped. | | Exclusion parameters in your request | userId | 400 error. | | Only pinned products, catalog filter slots, or non-personalized algorithm slots, with no trigger | Nothing extra | - | > [!NOTE] > **Tip**: When testing, check that **bundle_id** is the bundle you expect and that total is not lower than planned. ## How the endpoint picks the products 1. It checks each bundle's trigger against **productId** or **categoryList**, in the bundle order in InOne. A bundle without a trigger always matches. 2. It fills the first matching bundle and returns products in slot order, without duplicates. An unfilled slot adds no placeholder to data; **use __context.bundle_slot_id** with **details=true** to identify each product's slot. 3. It applies the bundle's personalization settings (see Settings saved in the strategy below). 4. If the selected bundle is below minSize or fails completely, the configured fallback is tried directly; other matching bundles are not tried. If the fallback returns no products but the first bundle had products, the first result is kept. 5. If no bundle matches, the fallback bundle is served. With no fallback, the response is successful with no products. ## Settings saved in the strategy - Saved slot filters and Advanced Personalization Criteria are applied automatically; do not repeat them in the request. - Send userId for user-based settings and productId for settings based on the viewed product. - Request-level viewed exclusions override saved viewed exclusions. Purchased exclusions are overridden independently. ## Sample Request Strategy 123 has two bundles: - Complete the look (bundle ID 101): - triggers on selected jackets. - 1 pinned trouser + 3 Purchased Together products. - Best sellers (bundle ID 102): - triggers on selected sneakers. - 4 Top Sellers products. - Also this bundle selected as the fallback. A shopper views JACKET-01: **cURL** ```bash curl -X GET "https://recommendation.api.useinsider.com/v2/bundle?partnerName=mybrand&locale=en_US¤cy=USD&bundleStrategyId=123&productId=JACKET-01&size=4&details=true" \ -H "X-Auth-Token: YOUR_API_TOKEN" ``` **JavaScript (server-side)** ```javascript const apiToken = 'YOUR_API_TOKEN'; const endpoint = 'https://recommendation.api.useinsider.com/v2/bundle'; const params = {  partnerName: 'mybrand',  locale: 'en_US',  currency: 'USD',  bundleStrategyId: '123',  productId: 'JACKET-01',  size: 4,  details: true }; const queryString = new URLSearchParams(params).toString(); fetch(`${endpoint}?${queryString}`, {  method: 'GET',  headers: {    'X-Auth-Token': apiToken  } }) .then(response => response.json()) ``` **Python** ```python import requests api_token = 'YOUR_API_TOKEN' endpoint = 'https://recommendation.api.useinsider.com/v2/bundle' params = { 'partnerName': 'mybrand', 'locale': 'en_US', 'currency': 'USD', 'bundleStrategyId': '123', 'productId': 'JACKET-01', 'size': 4, 'details': True } headers = { 'X-Auth-Token': api_token } response = requests.get(endpoint, params=params, headers=headers) data = response.json() print(data) ``` ## Sample Response Bundle 101 matched. All IDs and products are illustrative. ```json {    "success": true,    "total": 4,    "types": {        "pd": 1,        "btb": 3    },    "data": [        {            "item_id": "TROUSER-07",            "name": "Slim Fit Trousers",            "url": "https://www.mybrand.com/product/trouser-07",            "image_url": "https://www.mybrand.com/images/trouser-07.jpg",            "in_stock": 1,            "price": { "USD": 59.0 },            "category": ["Trousers"],            "locale": "en_US",            "__context": { "bundle_slot_id": 7001, "source": "static" }        },        {            "item_id": "BELT-02",            "name": "Leather Belt",            "url": "https://www.mybrand.com/product/belt-02",            "image_url": "https://www.mybrand.com/images/belt-02.jpg",            "in_stock": 1,            "price": { "USD": 25.0 },            "category": ["Accessories"],            "locale": "en_US",            "__context": { "bundle_slot_id": 7002, "source": "algorithm", "type": "btb" }        },        {            "item_id": "SHIRT-11",            "name": "Oxford Shirt",            "url": "https://www.mybrand.com/product/shirt-11",            "image_url": "https://www.mybrand.com/images/shirt-11.jpg",            "in_stock": 1,            "price": { "USD": 45.0 },            "category": ["Shirts"],            "locale": "en_US",            "__context": { "bundle_slot_id": 7002, "source": "algorithm", "type": "btb" }        },        {            "item_id": "SCARF-04",            "name": "Wool Scarf",            "url": "https://www.mybrand.com/product/scarf-04",            "image_url": "https://www.mybrand.com/images/scarf-04.jpg",            "in_stock": 1,            "price": { "USD": 30.0 },            "category": ["Accessories"],            "locale": "en_US",            "__context": { "bundle_slot_id": 7002, "source": "algorithm", "type": "btb" }        }    ],    "bundle_id": 101 } ``` | Field | Meaning | | --- | --- | | bundle_id | ID of the served bundle, not the strategy ID. Omitted when no bundle is served. | | types | Number of products per source: pd = pinned product, cat = catalog filter, other codes = the algorithm (e.g. btb = Purchased Together). See [Algorithm Descriptions](https://academy.insiderone.com/docs/algorithm-descriptions). | | data | Products in slot order. Product IDs only, unless details=true. | | __context.source | static = pinned product, catalog = catalog filter, algorithm = algorithm slot. Only with details=true. | | __context.bundle_slot_id | The slot the product filled. | | __context.type | The algorithm that produced the product. Only on algorithm slot products. | The same request on other pages: - A sneaker in bundle 102's trigger list: "bundle_id": 102 - A bag in neither trigger list: bundle 102 is served as the fallback, "bundle_id": 102 With no matching bundle and no fallback: ```plaintext { "success": true, "total": 0, "data": [] } ``` ## Good to know - Pinned products are never replaced. A pinned product that is out of stock, passive, or does not match your filter leaves its slot empty. - If an algorithm slot finds too few products, its standard fallback fills the rest; **types** and **__context.type** then show the fallback's code. - Direct API calls are not reported in Smart Recommender analytics. To track impressions, clicks, and revenue with your own design, assign the Bundle Strategy to a JavaScript SDK-based campaign and complete the analytics-enabled integration steps in Track 2 of Integrate the JavaScript SDK-Based Smart Recommender. Assigning the strategy alone does not enable analytics tracking. - **size** caps the final combined list and can remove products from later slots. **minSize** can trigger fallback; it does not guarantee a minimum number of returned products. - Saved changes in InOne are not reflected immediately. Recheck the API result after an update before using it in your integration. - Variant exclusion is set in InOne, not in the request. Go to **Components** > **Recommendation Algorithms** > **Recommendation Settings** and turn on Product Variant Exclusion. See [Recommendation and Algorithm Settings](https://academy.insiderone.com/docs/recommendation-and-algorithm-settings). The **excludeVariants** request parameter is not supported on this endpoint. Pinned products are not affected. ## Errors The endpoint uses the standard status codes. Common cases for this endpoint: | Status | Message | When | | --- | --- | --- | | 400 | Missing parameter: | partnerName, locale or bundleStrategyId is missing | | 400 | Bundle strategy not found. | The ID does not exist or belongs to another partner | | 400 | Size can not be greater than and lower than 1. | size is out of range | | 400 | Malformed parameter: minSize. ... | minSize is not a number | | 400 | userId required for exclude products. | Exclusion parameters sent without userId | | 400 | Parameters `productId` and `locale` must be provided when dynamic value is used. | A request filter uses ${value} without productId | | 401 | Authentication failed | The X-Auth-Token header is missing or not valid | | 429 | Rate exceeded. | More calls than your rate limit allows | | 504 | All recommendation sources timed out | All sources of the served bundle failed and no products could be returned, after any configured fallback was considered | ## Building Mixed Strategy or Manual Merchandising setups as a Bundle | You send today | In a Bundle Strategy | | --- | --- | | /v2/manual-merchandising?productId=A,B,C | One bundle with three pinned product slots: A, B and C | | includeOutOfStockItems=true on Manual Merchandising | Not available. Pinned products that are out of stock are not shown; their slot stays empty. | | /v2/mixed?strategy=[{"recommendationType":"ub","size":2},{"recommendationType":"btb","size":2}] | One bundle with an algorithm slot per entry, each with its size | | filters on a strategy entry | A filter on that slot | | Page-specific logic in your own code | One bundle per case, each with its own trigger, and one of them as the fallback | Then call **/v2/bundle?bundleStrategyId=** and send the context your strategy needs.