---
title: Kits and Bundles
slug: oms/kits-and-bundles
docTags: 
createdAt: 2022-10-11T14:43:32.000Z
---

### Introduction

Chord's OMS platform supports two methods of selling a collection of products under a single price:

1\. Kit (static bundle)
2\. Bundle (dynamic bundle)

This document will review these two options to choose your best action.

### What are kits?

A kit is a \*\*pre-selected, fixed collection of products under a single **SKU**\*\*. Your customer cannot modify the products within a kit. However, you can create multiple kits which contain all the combinations of products they wish to sell.

:::hint{type="info"}
&#x20;Bundles offer the same functionality as kits but with more flexibility and less duplication.
:::

When a kit product is synced to the OMS, it creates multiple variants by permuting all possible combinations of these same variants for the products within the kit.

For example, consider a kit called Plants that consists of three products and their variants:

| **Product** | **Variants**   | **SKU**       |
| ----------- | -------------- | ------------- |
| Plant 1	    | Plant 1 Large	 | plant-1-large |
|             | Plant 1 Small  | plant-1-small |
| Plant 2     | Plant 2 Red    | plant-2-red   |
|             | Plant 2 Green	 | plant-2-green |
| Plant 3     | Plant 3        | plant-3       |

The OMS will generate a product called \*\***Plants**\*\* with the following variants:

1\. plant-1-large|plant-2-red|plant-3
2\. plant-1-large|plant-2-green|plant-3
3\. plant-1-small|plant-2-red|plant-3
4\. plant-1-small|plant-2-green|plant-3

The master SKU for the kit product is the combined SKUs of all parts separated by pipes. Using the example above, the **Plants** kit will have a master SKU of **plant-1|plant-2|plant-3**.

### &#x9;	&#xA;Create a kit

1. In the CMS, create a new entry of type **Kit.**
2. Set the store variable `SYNC_SKU_BASED_BUNDLES` to `enabled`. When OMS syncs the kits and bundles with the CMS, it will set the SKU of the bundle to the permutation of all products in the kit.

### What are bundles?

A bundle is a **dynamically selected collection of products**. The products within a bundle are not pre-defined within OMS like they are with kits. Instead, customers who add a bundle to their cart may then choose from a collection of variants (called **parts**) to add to the bundle.

A store can define what parts are within a bundle through the front end and prevent users from changing the bundle's contents. In this manner, a bundle can behave similarly to a kit *without* requiring OMS to create and manage multiple variants. 

This is useful if your store offers large numbers of possible parts within a bundle. Imagine maintaining distinct variants for every single combination of colors that a child can select in a pack of crayons.

The bundle has a single price regardless of which parts a customer adds. However, you can choose which parts may be added to a bundle.

A bundle is comprised of multiple parts. A part can be a product (including all its variants) or a specific variant.

### Create a bundle

In Contentful, create a new Content Model named **Bundle.**

Click on **Add Content Type**

::Image[]{src="https://api.archbee.com/api/optimize/TmutqdeXiIw-V3gBZXVjd/MZdaxvJWMiE6ccc6s8Mf5_image-5-19-2023-at-401-pm.jpg" size="62" width="3432" height="216" position="flex-start" showCaption="false"}

Name your new entry **Bundle,** and click **Create.**



::Image[]{src="https://api.archbee.com/api/optimize/TmutqdeXiIw-V3gBZXVjd/TIe6HjUH3nSc80LSTcqB0_image-5-19-2023-at-359-pm.jpg" size="66" width="1390" height="1130" position="flex-start" showCaption="false"}

Click **Add field**

&#x20;

::Image[]{src="https://api.archbee.com/api/optimize/TmutqdeXiIw-V3gBZXVjd/LmiBpEGlkMcoQcOlIFoKy_image-5-19-2023-at-421-pm.jpg" size="60" width="2418" height="1154" position="flex-start" showCaption="false"}

Add the following fields.



::Image[]{src="https://api.archbee.com/api/optimize/TmutqdeXiIw-V3gBZXVjd/cAN2VneS81lWN9J2eT_GO_image-5-19-2023-at-356-pm.jpg" size="72" width="1102" height="1300" position="flex-start" showCaption="false"}

Click on the **Content** tab and select Bundle in the dropdown, clic&#x6B;**&#x20;Add Entry&#x20;**&#x61;nd individually add each Product that is part of the bundle.&#x20;



::Image[]{src="https://api.archbee.com/api/optimize/TmutqdeXiIw-V3gBZXVjd/hefo_PfmTNwt0vfJh9t11_image-5-19-2023-at-430-pm.jpg" size="84" width="2956" height="256" position="flex-start" showCaption="false"}

Once done, **Publish** your entries.&#x20;

:::hint{type="danger"}
we strongly suggest creating and testing bundles in your staging environment first
:::





## Data model

### Product

A boolean `bundle` was added to the Product model to denote whether or not the product is a singular product or a bundle of products.

For example, the following products are bundles and will have `bundle: true`:

| Product ID | Name          |
| ---------- | ------------- |
| 1          | Plant Bouquet |
| 2          | Plant Bouquet |
| 3          | Plant Bouquet |

### BundlesPart

Used to define and validate what products may be added to a specific bundle. It also defines the maximum quantity of parts allowed within the bundle.

For example, consider the bundles defined above:

| Bundle ID | Part ID | Count |
| --------- | ------- | ----- |
| 1         |         | 1     |
| 2         |         | 4     |
| 3         |         | 6     |

## API

### Add a Bundle to the Cart

To add a bundle to the cart, the app calls `POST /api/orders/{order_number}/line_items`. The payload will include the `sku`, `variant_id`, and `id` of the bundle, along with the list of variants to include in the bundle within the `parts` array. Note that the `parts` array is within the `options` object.

The payload for adding a bundle to your cart:

```json
x{
   "line_item":{
      "sku":"KIT-1",
      "quantity":1,
      "options":{
         "parts":[
            {
               "sku":"PART-1",
               "quantity":1
            },
            {
               "sku":"PART-2",
               "quantity":1
            }
         ]
      }
   }
}
```

The `line_items` array in the order response will look like this:

```json
"line_items":[
	{
		"id":159,
		"quantity":1,
		"price":"65.0",
		"variant_id":329,
		"variant":{
		  "id":329,
		  "name":"Starter Kit",
		  "sku":"KIT",
		},
		"is_bundle":true,
		"parts":[
		  {
		     "id":170,
		     "sku":"PART-1",
		     "quantity":1
		  },
		  {
		     "id":171,
		     "sku":"PART-2",
		     "quantity":1
		  }
		]
	}
]
```

### Updating/Removing Parts from a Cart

Once a bundle is in a cart, parts can be added or removed using the `/api/orders/{order_number}/line_items/{line_item_number}`endpoint, where the `line_item_number` is the ID of the line item for the bundle.

The payload is:

```jsx
{
	line_item: {
		id: 1,
		part_line_items: [
			{
				id: 1
				sku: 'sku-1',
				_destroy: true
			}
		]
	}
}
```

# Misc Code Notes



Parts in the API payload are converted to `part_line_item_attributes` hash in the `normalize_part_params` method. The `part_line_item_attributes` hash is attached to the `line_item_attributes` in the `options` array.

The `part_line_item` is created when the `line_item` is created in the `Spree::OrderContents#after_add_or_remove`method. Uses some Rails magic to instantiate the `part_line_item`.

