Set up company-specific Products, Pricing, and Discounts

B2B commerce use cases are generally more complex compared to a standard B2C online retail setup. B2B companies need flexibility to model their catalogs the way their business model requires it. For instance, B2B products often have many variations and can be highly configurable. Similarly, B2B pricing is usually complex and customer-specific.

In this tutorial, we will demonstrate the process of setting up company-specific products, pricing, and discounts in Composable Commerce using Business Units and Stores.

Business Units represent companies or divisions within a company. In our use case, a Business Unit is a customer who wants to purchase from our business.

Stores are a flexible concept in Composable Commerce. They can be used to model, for instance, physical retail locations, brand stores, regions, and more. They are useful for our use case because they allow us to define what subset of resources within a Project are available in the context of the Store. With the help of Stores, we will assign Channels and Product Selections to a Business Unit, thereby ensuring the correct Products and Prices are in place. In addition, you can create Cart Discounts and Carts that are only available within a specific Store.

The following table provides a summary of the Composable Commerce APIs used in this tutorial, along with their purpose for our use case.

Composable Commerce APIUse it to represent
Business Unitscompanies as customers
Storesa logical grouping of Products and Prices
Product Selectionsa set of Products offered to a company
Channelsa set of Prices specific to a company
Cart Discountsa Price reduction to items of a Cart

Prerequisites

We recommend reading the getting started guide to learn how to set up a Project and understand the fundamental concepts of the Composable Commerce API.

In this tutorial, we'll use the example of an electronics wholesaler based in the United States. To ensure the code examples work as expected, you'll need to first setup a Project with the following:

To follow along with the tutorial, you'll need to replace placeholder values in code examples with IDs and keys of existing resources in your Project.

Goal

In this tutorial, we'll configure our Project to offer a customer a selection of Products with specific prices. Our goal is to place an Order for the customer, which includes a Product from the selection at a specific price and with a discount applied.

At a high level, these are the steps we will follow:

  1. Create a Channel to represent a specific set of Prices.
  2. Create a Product and assign it a different Price inside the new Channel.
  3. Create a Product Selection and add the Product to it.
  4. Create a Store and assign the Channel and Product Selection to it.
  5. Assign the Store to the Business Unit that represents the customer.
  6. Create a Cart Discount in the Store.
  7. Create a Cart in the Store and add the Product.
  8. Place an Order for the customer.

Let's get started!

Steps

Create a Channel

In our use case, a Channel represents a set of Prices assigned to a specific Business Unit.

Let's start by creating a Channel named distribution-customer-1. We'll designate it as a distribution Channel by assigning the ProductDistribution role to it. This allows us to manage and distribute Products through the Channel.

{
"key": "distribution-customer-1",
"roles": ["ProductDistribution"]
}

Create a Product

Now, let's create a new Product and assign a specific Price to the distribution-customer-1 Channel.

{
"name": {
"en": "A0 Large Format Printer - Type C Plug"
},
"key": "a0-printer-type-c",
"productType": {
"typeId": "product-type",
"key": "large-format-printers"
},
"slug": {
"en": "a0-printer-type-c"
},
"masterVariant": {
"sku": "sku-a0-printer-type-c",
"prices": [
{
"value": {
"currencyCode": "USD",
"centAmount": 300000
}
},
{
"channel": {
"type": "channel",
"key": "distribution-customer-1"
},
"value": {
"type": "centPrecision",
"currencyCode": "USD",
"centAmount": 250000
}
}
],
"attributes": []
},
"variants": [],
"publish": true,
"taxCategory": {
"typeId": "tax-category",
"key": "electronics-tax"
}
}

In our example, the default Price of the printer Product is 3000 USD, but the Channel distribution-customer-1 is assigned a reduced Price of 2500 USD.

Create a Product Selection

For our use case, we want to make a specific set of Products available to a particular Business Unit. We will use a Product Selection to achieve this.

Let's create a Product Selection named selection-customer-1:

{
"key": "selection-customer-1",
"name": {
"en": "selection-customer-1"
}
}

After the Product Selection is created, we can begin to add Products to it. Let's add the previously created A0 printer with the key a0-printer-type-c to our Product Selection by using the Add Product update action.

{
"version": 1,
"actions": [
{
"action": "addProduct",
"product": {
"typeId": "product",
"key": "a0-printer-type-c"
}
}
]
}

Create a Store

Next, let's create a Store named store-customer-1 and assign the Product Selection and Channel to it.

{
"key": "store-customer-1",
"productSelections": [
{
"productSelection": {
"key": "selection-customer-1"
},
"active": true
}
],
"distributionChannels": [
{
"typeId": "channel",
"key": "distribution-customer-1"
}
]
}

Now, we need to assign our Store to the Business Unit by using the Add Store update action.

{
"version": 2,
"actions": [
{
"action": "addStore",
"store": {
"key": "store-customer-1",
"typeId": "store"
}
}
]
}

With the help of our Store, the Business Unit can now access only the Products assigned to the Product Selection selection-customer-1, and the specific Prices defined in our Channel distribution-customer-1.

When a Store has one or more Channels, the Business Unit is restricted to using only the Channels assigned to that Store.

Create a Cart Discount

Next, use the create Cart Discount in Store endpoint to create a discount that applies to all Carts within our Store. This discount targets the total price of each Cart.

For in-store endpoints, such as this one, you'll need to specify the Store key in the URL path.

{
"name": {
"en": "5% off total price"
},
"value": {
"type": "relative",
"permyriad": 500
},
"cartPredicate": "1=1",
"target": {
"type": "totalPrice",
"predicate": "1=1"
},
"sortOrder": "0.1",
"isActive": true,
"requiresDiscountCode": false
}

Create a Cart

Now, let's create a Cart using Create Cart in Store. For in-store endpoints, such as this one, you'll need to specify the Store key in the URL path.

You'll also need to update the following example with values from your own Project:

  • The customerId of the Associate that belongs to your Business Unit.
  • The key of Business Unit.
{
"country": "US",
"customerId": "{your-associate-id}",
"shippingAddress": {
"country": "US"
},
"businessUnit": {
"key": "{your-business-unit-key}"
},
"currency": "USD"
}

Now that our Cart is created, we can add a Product by using the Add LineItem update action.

To ensure the customer receives the correct price of 2500 USD, we need to specify the Channel distribution-customer-1. If a Channel is not specified, the customer would receive the default price of 3000 USD. If you specify a Channel that has not been assigned to the Store, the action will fail.

{
"version": 1,
"actions": [
{
"action": "addLineItem",
"sku": "sku-a0-printer-type-c",
"quantity": 1,
"distributionChannel": {
"typeId": "channel",
"key": "distribution-customer-1"
}
}
]
}

In the response, we can verify that the Cart contains a single Product a0-printer-type-c with the correct Price of 2500 USD, derived from our Channel. In addition, we can also see that the Discount of 5% off the total price of the Cart has been applied.

Create Cart in Store responsejson
{
"type": "Cart",
[...]
"lineItems": [
{
"id": "1e8fcf0a-7e89-4d04-aacd-8bc7f59b008b",
"productId": "1c05d09c-0eef-44b0-8b1e-9a5abd606836",
"productKey": "a0-printer-type-c",
"name": {
"en": "A0 Large Format Printer - Type C Plug"
},
[...]
},
"price": {
"id": "4df7d142-e18d-4c2a-8f4c-dd3a8260516d",
"value": {
"type": "centPrecision",
"currencyCode": "USD",
"centAmount": 250000,
"fractionDigits": 2
},
"channel": {
"typeId": "channel",
"id": "64b68d7c-f3a4-4e55-99e1-6419e79a7c4d"
}
},
"quantity": 1,
[...]
],
"priceMode": "Platform",
"lineItemMode": "Standard",
"totalPrice": {
"type": "centPrecision",
"currencyCode": "USD",
"centAmount": 250000,
"fractionDigits": 2
},
[...]
"taxedPricePortions": []
}
],
"cartState": "Active",
"totalPrice": {
"type": "centPrecision",
"currencyCode": "USD",
"centAmount": 237500,
"fractionDigits": 2
},
[...]
"country": "US",
"discountOnTotalPrice": {
"discountedAmount": {
"type": "centPrecision",
"currencyCode": "USD",
"centAmount": 12500,
"fractionDigits": 2
},
"includedDiscounts": [
{
"discount": {
"typeId": "cart-discount",
"id": "9f7799cd-203c-43c0-b410-3f03bd29864b"
},
"discountedAmount": {
"type": "centPrecision",
"currencyCode": "USD",
"centAmount": 12500,
"fractionDigits": 2
}
}
],
"discountedNetAmount": {
"type": "centPrecision",
"currencyCode": "USD",
"centAmount": 10870,
"fractionDigits": 2
},
"discountedGrossAmount": {
"type": "centPrecision",
"currencyCode": "USD",
"centAmount": 12500,
"fractionDigits": 2
}
},
[...]
"store": {
"typeId": "store",
"key": "store-customer-1"
},
"totalLineItemQuantity": 1
}

Create an Order

Finally, we are ready to create an Order. Let's use the Create Order in Store from Cart endpoint.

In the following example, you'll need to add the id of your Cart.

{
"version": 4,
"id": "{your-cart-id}",
"orderNumber": "2024010100"
}

With the Order created, let's check the response to verify that the Order price is as expected. Under totalPrice, we can see that the price of 2500 USD has been reduced by 125 USD, due to the 5% discount. The total price is now 2375 USD, which is the correct price for this customer. Congratulations!

Create Order responsejson
{
"type": "Order",
"id": "c3f39e52-d63b-4158-88ed-9393098c55fe",
"version": 1,
"createdAt": "2023-06-24T10:58:31.131Z",
"lastModifiedAt": "2023-06-24T10:58:31.131Z",
"lastModifiedBy": {
"clientId": "8ZaxKuGxvrQlnIP2dHdXJI2A",
"isPlatformClient": false
},
"createdBy": {
"clientId": "8ZaxKuGxvrQlnIP2dHdXJI2A",
"isPlatformClient": false
},
"orderNumber": "2023060600",
"customerId": "56b9bf16-71ec-427a-bd67-8c0424eb1e83",
"totalPrice": {
"type": "centPrecision",
"currencyCode": "USD",
"centAmount": 237500,
"fractionDigits": 2
}
[...]
}

Conclusion

In this tutorial, you've learned how to use Channels, Product Selections, Cart Discounts, and Stores together to enable company-specific products, pricing, and discounts.

To achieve the level of flexibility that our use case required, we chose to use Channels and Product Selections. Depending on your business needs and individual use case, you may choose to model your Project differently to accomplish your goals.

To learn more about the concepts presented in this tutorial, see Channels, Product Selections, Stores, and Business Units in the Composable Commerce API documentation.