Cart Tutorial

How to create a new cart

1

To create a new cart, you need to send a request to the Creating a new cart endpoint.

curl -i -X POST \
  'https://api.emporix.io/cart/{tenant}/carts' 
  -H 'Authorization: Bearer <YOUR_TOKEN_HERE>' 
  -H 'Content-Type: application/json' 
  -H 'saas-token: string' 
  -H 'session-id: string' 
  -d '{
    "siteCode": "main",
    "currency": "EUR",
    "type": "shopping",
    "channel": {
      "name": "storefront",
      "source": "https://your-storefront.com/"
    },
    "sessionValidated": true
  }'
API Reference

How to add custom attributes to a cart

You can define custom attributes for a cart through mixins.

1

Define your custom attributes schema

First, define your custom attributes schema in the form of a JSON schema.

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "properties": {
      "cartInstructions": {
        "type": "object",
        "properties": {
          "instruction": {
            "type": "string"
            }
          }
      }
    }
}
2

Upload schema

Upload your schema to a hosting service and save its URL.

3

Update a cart with custom attributes

To add custom attributes to a cart, you need to send a request to the Updating a cart endpoint.

curl -i -X PUT \
  'https://api.emporix.io/cart/{tenant}/carts/{cartId}' 
  -H 'Authorization: Bearer <YOUR_TOKEN_HERE>' 
  -H 'Content-Type: application/json' 
  -d '{
  "customerId": "87413250",
  "currency": "EUR",
  "deliveryWindowId": "60006da77ec20a807cd6f065",
  "type": "wishlist",
  "zipCode": "10115",
  "countryCode": "DE",
  "status": "OPEN",
  "deliveryWindow": {
    "id": "5b5572a61cf31a000f31eee4",
    "deliveryDate": "2023-06-06T12:00:00.000Z",
    "slotId": "5678-8756-3321-1234"
  },
  "channel": {
    "name": "storefront",
    "source": "https://your-storefront.com/"
  },
  "metadata": {
    "mixins": {
      "generalAttributes": "https://res.cloudinary.com/saas-ag/raw/upload/schemata/orderGeneralAttributesMixIn.v9.json",
      "deliveryTime": "https://res.cloudinary.com/saas-ag/raw/upload/schemata/deliveryTimeMixIn.v2.json",
      "cartInstructions": "https://res.cloudinary.com/saas-ag/raw/upload/v1635253083/schemata/CAAS/cartInstructions_schema.json"
    }
  },
  "mixins": {
    "deliveryTime": {
      "deliveryDate": "2021-06-08T12:00:00.000Z",
      "deliveryTimeId": "5f5a3da02d48b9000d39798c"
    },
    "cartInstructions": {
      "instruction": "It would be nice if you could deliver the order after 5 PM."
    }
  }
}'
API Reference

How to merge carts

1

To merge an anonymous cart with a customer cart, you need to send a request to the Merging carts endpoint. Provide the customer cart's ID in the cartId path parameter and the anonymous cart's ID in the request body.

curl -i -X POST \
  'https://api.emporix.io/cart/{tenant}/carts/{cartId}/merge' 
  -H 'Accept-Language: string' 
  -H 'Authorization: Bearer <YOUR_TOKEN_HERE>' 
  -H 'Content-Language: string' 
  -H 'Content-Type: application/json' 
  -H 'languages: string' 
  -d '{
  "carts": [
    " "
  ]
}'
API Reference

How to use external sources to modify a cart

Learn the ways to use external sources, like for example ERP systems, for modifying carts. It's possible to source externally price calculations, products, fees, or discounts.

How to source pricing information from an external price calculation tool

For B2B scenarios, you might want to integrate an external application for price calculation for your products. Usually, the systems, such as ERPs, store all the relevant customer-specific pricing information needed for customer-specific pricing. The external system then can communicate with the Cart Service directly to overwrite the price of the product added to the cart.

1

After enabling the external application to update carts with calculated prices, to add a product that is available within Commerce Engine, but with an external price, you need to send the request to the Adding a product to cart endpoint. Provide the customer cart's ID in the cartId path parameter.

curl -i -X POST \
  'https://api.emporix.io/cart/{tenant}/carts/{cartId}/items?siteCode=string' 
  -H 'Authorization: Bearer <YOUR_TOKEN_HERE>' 
  -H 'Content-Type: application/json' 
  -d '{
    "itemYrn": "urn:yaas:saasag:caasproduct:product:mytenant;1600A016BF",
    "price": {
      "priceId": "{priceId}",
      "effectiveAmount": 2,
      "originalAmount": 2,
      "currency": "EUR"
    },
    "quantity": 1,
    "itemType": "EXTERNAL",
    "tax": {
      "name": "STANDARD",
      "rate": 10,
      "grossValue": 2,
      "netValue": 1.82
    }
  }'
API Reference

Notice the "itemType": "EXTERNAL" definition which allows the Cart Service to overwrite the pricing from Commerce Engine. The payload must include the price and tax information.

How to add a product from an external source to a cart

For some cases, you might want to allow adding products from an external system to cart, and not only from your online store. The products from external product management sources can be added directly to the customer's cart, bypassing the standard product catalog.

1

To add a product outside Commerce Engine, you need to send the request to the Adding a product to cart endpoint. Provide the customer cart's ID in the cartId path parameter. The payload has to include the "itemType" : "EXTERNAL" parameter, as well as the price and tax information.

curl -i -X POST \
  'https://api.emporix.io/cart/{tenant}/carts/{cartId}/items?siteCode=string' 
  -H 'Authorization: Bearer <YOUR_TOKEN_HERE>' 
  -H 'Content-Type: application/json' 
  -d '{
    "itemYrn": "{productYrn}",
    "price": {
      "priceId": "{priceId}",
      "effectiveAmount": 1239,
      "originalAmount": 1239,
      "currency": "EUR"
    },
    "quantity": 1,
    "itemType": "EXTERNAL",
    "product": {
      "id": "ip15p",
      "name": "iPhone 15 pro",
      "description": "Apple iPhone 15 pro 128gb natural titanium",
      "sku": "testSku",
    },
    " tax": {
      "name": "STANDARD",
      "rate": 19,
      "grossValue": 1239,
      "netValue": 1041.18
    }
  }'
API Reference

How to add an external fee

For some cases, you might need to calculate and charge additional fees, for example for packaging, freight, or any additional reasons. The fees calculated externally can be added directly to the customer's cart.

1

To add a custom fee to the cart, you need to send the request to the Adding a product to cart endpoint. Provide the customer cart's ID in the cartId path parameter. Custom fee can be configured both for EXTERNAL and INTERNAL products, the payload should include the "itemType" : "EXTERNAL" or "itemType" : "INTERNAL" parameter. If the parameter is not provided, then "INTERNAL" is taken as default.

curl -i -X POST \
  'https://api.emporix.io/cart/{tenant}/carts/{cartId}/items?siteCode=string' 
  -H 'Authorization: Bearer <YOUR_TOKEN_HERE>' 
  -H 'Content-Type: application/json' 
  -d '{
    "itemYrn": "{productYrn}",
    "price": {
      "priceId": "{priceId}",
      "effectiveAmount": 0.3582,
      "originalAmount": 0.3582,
      "currency": "EUR"
    },
    "quantity": 6,
    "itemType": "EXTERNAL",
    "externalFees": [
      {
        "name": {
          "en": "Freight Fee"
        },
        "feeType": "ABSOLUTE",
        "feeAbsolute": {
          "amount": 2.13,
          "currency": "EUR"
        }
      }
    ]
  }'
API Reference

How to apply an external discount on an item level

Adding an external discount to an item in a cart is done with the cart.cart_manage_external_prices scope.

1

Use the externalDiscounts attribute when adding an item to the cart or updating an existing one.

curl -L \
  --request POST \
  --url 'https://api.emporix.io/cart/{tenant}/carts/{cartId}/items?siteCode=text' 
  --header 'Authorization: Bearer YOUR_SECRET_TOKEN' 
  --header 'Content-Type: application/json' 
  --data '{
    "externalDiscounts": [
        {
            "id": "ext-discount-001",
            "discountType": "PERCENT",
            "value": 15.00,
            "sequence": 1
        }
    ]
  }'
API Reference

How to pass externally calculated line price and line tax to items added or updated in the cart?

The Cart Service supports externally calculated pricing and tax amounts for cart items. This allows integrated systems to override cart's internal pricing logic with the values determined by external systems.

If you don’t want Emporix to calculate the line price by multiplying quantity × unit price, but instead want to provide the calculation from your ERP system, you can do so by supplying both linePrice and lineTax. These values are reflected in the line’s calculated price with calculated: EXTERNAL.

In the response, the lineTax will include the quantity information that was used in the add-to-cart request.

  • linePrice - externally calculated total price for the item line (unit price × quantity)

  • lineTax - externally calculated total tax for the item line, allowed only for external product type

The attributes are only allowed when itemType = EXTERNAL. If these values are provided, they are stored and returned unchanged in cart responses.

Payload example for Adding a product to cart:

{
    "itemYrn": "urn:yaas:saasag:caasproduct:product:b2b2cstage;samsung-galaxy-s24-gross",
    "keepAsSeparateLineItem": true,
    "itemType": "EXTERNAL",
    "price": {
        "effectiveAmount": 119.0,
        "originalAmount": 139.0,
        "currency": "EUR"
    },
    "tax": {
        "name": "STANDARD",
        "rate": 19,
        "grossValue": 119.0,
        "netValue": 100.0
    },
    "linePrice": {
        "effectiveAmount": 595.0,
        "originalAmount": 795.0,
        "currency": "EUR"
    },
    "lineTax": {
        "name": "STANDARD",
        "rate": 19,
        "grossValue": 595.0,
        "netValue": 500
    },
    "quantity": 5
}

Returned response example:

{
    "items": [{
        "itemType": "EXTERNAL",
        "price": { ... },
        "tax": { ... },
        "linePrice": { ... },
        "lineTax": { ... },
        "calculatedPrice": {
            "price": {
                "calculated": "EXTERNAL"
            }
        }
    }]
}

The price.calculated field indicates the source of the total price:

  • INTERNAL – for the price calculated by Emporix (unitPrice × quantity).

  • EXTERNAL – for the price taken directly from linePrice (authoritative).

Calculation behaviour with external line price and line tax

When you use linePrice and lineTax in cart operations, the following rules apply:

  • If lineTax is provided, these values take priority over internally calculated totals for calculatedPrice and finalPrice. If neither is provided, then cart service calculates totals internally based on the unit price and quantity.

  • For partial cart item updates (with partial=true), any existing linePrice or lineTax values are preserved if they are not provided in the update payload.

  • For full cart item updates, any previously set linePrice or lineTax values are cleared if they are not included in the update payload.

  • If the item’s quantity is updated after an external linePrice was set, the cart recalculates it internally (calculated = INTERNAL) and ignores the previous external value. To restore external pricing, a new linePrice must be provided that matches the new quantity.

    If the linePrice is provided, the quantity of the provided linePrice values has to much the quantity of items in the cart. Otherwise, the additional items are calculated internally.

  • In Retrieving all products added to a cart or Retrieving a cart item, any externally provided linePrice and lineTax are returned unchanged.

    A quantity field is included on lineTax in responses, reflecting the quantity used when the external tax was calculated.

For order entries, the calculated = INTERNAL/EXTERNAL flag is also returned - it indicates how the pricing was derived.

How is price calculated

To ensure that both net and gross prices are available, along with clear details on how these values are derived, the Cart Service includes the calculatedPrice field.

At the item level, there's a calculatedPrice attribute, which contains detailed price calculations for a specific item. Additionally, a calculatedPrice is also available at the cart level, summarizing the price calculations for all items in the cart.

This calculation method provides a comprehensive breakdown of prices, including net values, gross values, tax details, fees, and discounts, both at the cart level and for individual line items.

Pricing glossary - calculated price on item level

Term
Definition

price

A unit price from priceMatch, it's multiplied by item quantity.

{
  "calculatedPrice": {
    "price": {
      "netValue": 588.235,
      "grossValue": 700.0,
      "taxValue": 111.765,
      "taxCode": "STANDARD",
      "taxRate": 19.0
    }
  }
}

upliftValue

An additional amount authorized for payment to cover potential price adjustments during packing of weight-based products. There are two conditions to have this value for an item line:

  • The item has to be added to the cart with the "weightDependent":true attribute. It means that the quantity may vary during packaging, as some items, for example a case of bananas, cannot be divided to precisely match a given weight.

  • The tenant has to have the percentage uplift defined - authorizedAmountUplift, for example 0,1=10%. If the item price.netValue=12, the upliftValue.netValue=1,2 with the 10% uplift configured. If the upliftValue is not configured for an item, it's not returned in the response.

{
  "calculatedPrice": {
    "upliftValue" : {
        "netValue" : 30.0,
        "grossValue" : 33.0,
        "taxValue" : 3.0,
        "taxCode" : "STANDARD",
        "taxRate" : 10.0
      },
  }
}

discountedPrice

The price of the line item is calculated as unit price × quantity, with any applied discounts. If no discounts are applied to a given line item, this attribute is not included in the response. Depending on the site configuration, the includesTax attribute can be true or false. The discount is applied to price.grossValue when includesTax=true or price.netValue when includesTax=false. Based on this, the corresponding netValue or grossValue is recalculated using the taxRate. The calculation method that was used is indicated in totalDiscount.calculationType, which can be either ApplyDiscountAfterTax or ApplyDiscountBeforeTax.

{
  "calculatedPrice": {
    "discountedPrice" : {
      "netValue": 282.511,
      "grossValue": 336.188,
      "taxValue": 53.677,
      "taxCode": "STANDARD",
      "taxRate": 19.0,
      "appliedDiscounts": [
          {
              "id": "buy-2-get-1-free",
              "value": 280.000,
              "price": {
                  "netValue": 235.294,
                  "grossValue": 280.000,
                  "taxValue": 44.706,
                  "taxCode": "STANDARD",
                  "taxRate": 19.0
              },
              "discountType": "PERCENT",
              "origin": "EXTERNAL"
          },
          {
              "id": "LS100EUROTOTAL",
              "value": 83.812,
              "price": {
                  "netValue": 70.430,
                  "grossValue": 83.812,
                  "taxValue": 13.382,
                  "taxCode": "STANDARD",
                  "taxRate": 19.0
              },
              "discountType": "ABSOLUTE",
              "origin": "INTERNAL"
          }
      ]
    },
  }
}

fees

A list of fees applied to the line item. If there are no fees on the line item, it's not returned in the response.

  • Types of fees:

    • PERCENT - The fee percentage of the line item price.netValue - unit price x quantity.

    • ABSOLUTE - The absolute amount assigned to the item line.

    • ABSOLUTE_MULTIPLY_ITEMQUANTITY - Monetary amount multiplied by the item quantity and assigned to the item line.

  • Fees origin:

    • INTERNAL - Defined in commerce engine

    • EXTERNAL - Specified when an item is added to the cart.

  • netValue - Monetary amount of the fee. Depends on the fee type:

    • ABSOLUTE - The value of the defined fee's feeAbsolute.amount attribute.

    • ABSOLUTE_MULTIPLY_ITEMQUANTITY - The value of the defined fee's feeAbsolute.amount attribute multiplied by the quantity of the line item.

    • PERCENT - The defined fee level percentage (feePercentage attribute) of the line item price.netValue.

  • grossValue - Value calculated based on the taxCode and the taxRate if taxable=true. For a fee that is taxable=true and has a correct taxCode, the taxRate defined for that taxCode is used to calculate the grossValue. If the fee is not taxable, the netValue is equal to grossValue.

  • taxRate - If a fee is defined with the attribute taxable=true, the tax rate is calculated based on the provided taxCode at the fee level. A taxable fee must have a defined taxCode.

  • taxCode - Tax code defined on the fee level, for example STANDARD. The value should match the available tax codes in the system configuration.

{
  "calculatedPrice": {
    "fees" : [ {
        "id": "677d49ca3a421b451eab23f2",
        "type": "ABSOLUTE",
        "origin": "INTERNAL",
        "name": {
            "de": "Apple Picking Fee",
            "en": "Apple Picking Fee"
        },
        "price": {
            "netValue": 3.5,
            "grossValue": 3.745,
            "taxValue": 0.245,
            "taxCode": "REDUCED",
            "taxRate": 7.0
        },
        "discountedPrice": {
            "netValue": 3.081,
            "grossValue": 3.297,
            "taxValue": 0.216,
            "taxCode": "REDUCED",
            "taxRate": 7.0,
            "appliedDiscounts": [
                {
                    "id": "LS100EUROTOTAL",
                    "value": 0.448,
                    "price": {
                        "netValue": 0.419,
                        "grossValue": 0.448,
                        "taxValue": 0.029,
                        "taxCode": "REDUCED",
                        "taxRate": 7.0
                    },
                    "discountType": "ABSOLUTE",
                    "origin": "INTERNAL"
                }
            ]
        }
    } ],
  }
}

totalFee

Sum of all fees applied to the line item. It's calculated by summarizing fees[].discountedPrice if any discounts were applied to the fee, or fees[].price for a a not discounted fee.

{
  "calculatedPrice": {
    "totalFee" : {
        "netValue": 3.081,
        "grossValue": 3.297,
        "taxValue": 0.216,
        "taxCode": "REDUCED",
        "taxRate": 7.0,
        "appliedDiscounts": [
            {
                "id": "LS100EUROTOTAL",
                "value": 0.448,
                "price": {
                    "netValue": 0.419,
                    "grossValue": 0.448,
                    "taxValue": 0.029,
                    "taxCode": "REDUCED",
                    "taxRate": 7.0
                },
                "discountType": "ABSOLUTE",
                "origin": "INTERNAL"
            }
        ]
    },
  }
}

totalDiscount

A summary of all discounts applied to the line, including discounts on both the line item's price and its fees. If there are no discounts applied on the line item, it's not returned in the response.

{
  "calculatedPrice": {
    "totalDiscount" : {
        "calculationType": "ApplyDiscountAfterTax",
        "value": 364.26,
        "price": {
            "netValue": 306.143,
            "grossValue": 364.26,
            "taxValue": 58.117
        },
        "appliedDiscounts": [
            {
                "id": "buy-2-get-1-free",
                "value": 280.000,
                "price": {
                    "netValue": 235.294,
                    "grossValue": 280.000,
                    "taxValue": 44.706,
                    "taxCode": "STANDARD",
                    "taxRate": 19.0
                },
                "discountType": "PERCENT",
                "origin": "EXTERNAL"
            },
            {
                "id": "LS100EUROTOTAL",
                "value": 84.260,
                "price": {
                    "netValue": 70.849,
                    "grossValue": 84.260,
                    "taxValue": 13.411
                },
                "discountType": "ABSOLUTE",
                "origin": "INTERNAL"
            }
        ]
    },
  }
}

totalDiscount.calculationType

Indicates whether discounts were applied to net or gross values.

  • The discount is applied to either price.grossValue, when includesTax=true, or price.netValue, when includesTax=false. Based on this, the corresponding net or gross value is recalculated using the tax rate.

  • The calculation method used is indicated in totalDiscount.calculationType>, which can be either ApplyDiscountAfterTax or ApplyDiscountBeforeTax.

{
  "calculatedPrice": {
    "totalDiscount" : {
        "calculationType" : "ApplyDiscountAfterTax",
  }
}

finalPrice

The final price is the sum of the discountedPrice or the original price, depending on whether any discounts were applied to the line item, and the totalFee, which includes all fees applied to the line item.

{
  "calculatedPrice": {
    "finalPrice" : {
        "netValue": 285.592,
        "grossValue": 339.485,
        "taxValue": 53.893
    }
  }
}

Pricing glossary - calculated price on cart level

Term
Definition

price

A sum of all line item prices without discounts.

{
  "calculatedPrice": {
    "price" : {
        "netValue": 700.385,
        "grossValue": 820.0,
        "taxValue": 119.615
    },
  }
}

upliftValue

It's the sum of all uplift values from item lines. At item level, it's an additional amount authorized for payment to cover potential price adjustments during packing of weight-based products. There are two conditions to have this value for an item line:

  • The item has to be added to the cart with the "weightDependent":true attribute. It means that the quantity may vary during packaging, as some items, for example a case of bananas, cannot be divided to precisely match a given weight.

  • The tenant has to have the percentage uplift defined - authorizedAmountUplift, for example 0,1=10%. If the item price.netValue=12, the upliftValue.netValue=1,2 with the 10% uplift configured. If the upliftValue is not configured for an item, it's not returned in the response.

{
  "calculatedPrice": {
    "upliftValue" : {
        "netValue": 30.841,
        "grossValue": 33.0,
        "taxValue": 2.159,
        "taxCode": "REDUCED",
        "taxRate": 7.0
    },
  }
}

discountedPrice

The sum of all line item prices after discounts. This attribute is included in the response if at least one line item has a discounted price. It represents the total of discounted prices for line items with discounts applied, or the regular prices for line items without discounts. Ultimately, it reflects the total cost of all line items after discounts.

{
  "calculatedPrice": {
    "discountedPrice" : {
        "netValue": 381.233,
        "grossValue": 441.821,
        "taxValue": 60.588,
        "appliedDiscounts": [
            {
                "id": "buy-2-get-1-free",
                "value": 280.000,
                "price": {
                    "netValue": 235.294,
                    "grossValue": 280.000,
                    "taxValue": 44.706,
                    "taxCode": "STANDARD",
                    "taxRate": 19.0
                },
                "discountType": "PERCENT",
                "origin": "EXTERNAL"
            },
            {
                "id": "LS100EUROTOTAL",
                "value": 98.179,
                "price": {
                    "netValue": 83.857,
                    "grossValue": 98.179,
                    "taxValue": 14.322
                },
                "discountType": "ABSOLUTE",
                "origin": "INTERNAL"
            }
        ]
    },
  }
}

fees

It's a sum of all the fees of the line items in the cart - sum of all items[].calculatedPrice.fees.price. The fees are WITHOUT discounts.

{
  "calculatedPrice": {
    "fees": {
        "netValue": 7.0,
        "grossValue": 7.49,
        "taxValue": 0.49,
        "taxCode": "REDUCED",
        "taxRate": 7.0
    },
  }
}

totalFee

Sum of all fees applied on the line items. It's a sum of items[].calculatedPrice.totalFee, WITH applied discounts.

{
  "calculatedPrice": {
    "totalFee": {
        "netValue": 6.162,
        "grossValue": 6.594,
        "taxValue": 0.432,
        "taxCode": "REDUCED",
        "taxRate": 7.0,
        "appliedDiscounts": [
            {
                "id": "LS100EUROTOTAL",
                "value": 0.896,
                "price": {
                    "netValue": 0.838,
                    "grossValue": 0.896,
                    "taxValue": 0.058,
                    "taxCode": "REDUCED",
                    "taxRate": 7.0
                },
                "discountType": "ABSOLUTE",
                "origin": "INTERNAL"
            }
        ]
    },
  }
}

shipping

The calculated shipping cost. It takes the sum of items[].calculatedPrice.price.grossValue for shipping estimation. It's shipping cost WITHOUT applied discounts.

{
  "calculatedPrice": {
    "shipping": {
        "netValue": 7.22,
        "grossValue": 7.725,
        "taxValue": 0.505,
        "taxCode": "REDUCED",
        "taxRate": 7.0
    },
  }
}

totalShipping

The total shipping cost is calculated by summing items[].calculatedPrice.price.grossValue for shipping estimation. grossValue is used because, even for zero-tax items, it remains equal to netValue. It's a shipping cost WITH applied discounts.

{
  "calculatedPrice": {
    "totalShipping" : {
        "netValue": 6.355,
        "grossValue": 6.8,
        "taxValue": 0.445,
        "taxCode": "REDUCED",
        "taxRate": 7.0,
        "appliedDiscounts": [
            {
                "id": "LS100EUROTOTAL",
                "value": 0.925,
                "price": {
                    "netValue": 0.864,
                    "grossValue": 0.925,
                    "taxValue": 0.061,
                    "taxCode": "REDUCED",
                    "taxRate": 7.0
                },
                "discountType": "ABSOLUTE",
                "origin": "INTERNAL"
            }
        ]
    },
  }
}

totalDiscount

A summary of all discounts. It's the sum of all lines[].totalDiscount and shipping discounts. When discount is applied before tax the value equals price.netValue and price.grossValue for discount applied after tax.

{
  "calculatedPrice": {
     "totalDiscount" : {
          "calculationType": "ApplyDiscountAfterTax",
          "value": 380.0,
          "price": {
              "netValue": 320.853,
              "grossValue": 380.0,
              "taxValue": 59.147
          },
          "appliedDiscounts": [
              {
                  "id": "buy-2-get-1-free",
                  "value": 280.000,
                  "price": {
                      "netValue": 235.294,
                      "grossValue": 280.000,
                      "taxValue": 44.706,
                      "taxCode": "STANDARD",
                      "taxRate": 19.0
                  },
                  "discountType": "PERCENT",
                  "origin": "EXTERNAL"
              },
              {
                  "id": "LS100EUROTOTAL",
                  "value": 100.000,
                  "price": {
                      "netValue": 85.559,
                      "grossValue": 100.000,
                      "taxValue": 14.441
                  },
                  "discountType": "ABSOLUTE",
                  "origin": "INTERNAL"
              }
          ]
      } ]
    },
  }
}

finalPrice

The final price is the sum of items[].finalPrice, totalShipping.

{
  "calculatedPrice": {
    "finalPrice": {
            "netValue": 393.75,
            "grossValue": 455.215,
            "taxValue": 61.465,
            "taxAggregate": {
                "lines": [
                    {
                        "netValue": 111.239,
                        "grossValue": 119.027,
                        "taxValue": 7.788,
                        "taxCode": "REDUCED",
                        "taxRate": 7.0
                    },
                    {
                        "netValue": 282.511,
                        "grossValue": 336.188,
                        "taxValue": 53.677,
                        "taxCode": "STANDARD",
                        "taxRate": 19.0
                    }
                ]
            }
        }
    }
}

finalPrice.taxAggregate - lines

A list of tax values grouped by taxCode and taxRate. It includes the sum of item[].calculatedPrice.discountedPrice or item[].calculatedPrice.price, item[].calculatedPrice.fees[].discountedPrice or item[].calculatedPrice.fees[].price, calculatedPrice.totalShipping and calculatedPrice.paymentFees. If any of these values have the same taxRate but different taxCode, they are listed separately. The aggregation also includes items that do not have a taxRate or taxCode defined.

{
  "finalPrice": {
    "taxAggregate" : {
      "lines": [
          {
              "netValue": 111.239,
              "grossValue": 119.027,
              "taxValue": 7.788,
              "taxCode": "REDUCED",
              "taxRate": 7.0
          },
          {
              "netValue": 282.511,
              "grossValue": 336.188,
              "taxValue": 53.677,
              "taxCode": "STANDARD",
              "taxRate": 19.0
          } ]
      }
  }
}

See the sections below for shipping, payment fee, tax and discounts calculations.

How to calculate shipping cost at cart level

The shipping calculation depends on the stage at which it is done.

To get the shipping costs calculated and shown at the cart level, you need to update the cart with shipping information. That means, you have to set the shipping address with the countryCode and zipCode and then assign a valid shipping method to the cart so that it can trigger the shipping cost calculation.

1

Fetch available delivery windows for a cart by calling the Retrieving delivery windows by cart endpoint.

curl -L 
  --url 'https://api.emporix.io/shipping/{tenant}/actualDeliveryWindows/{cartId}' 
  --header 'Authorization: Bearer YOUR_OAUTH2_TOKEN' 
  --header 'Accept: */*'
2

Pick the delivery window you'd like to use and update the cart accordingly by calling the Updating a cart endpoint

curl -L 
  --request PUT 
  --url 'https://api.emporix.io/cart/{tenant}/carts/{cartId}' 
  --header 'Authorization: Bearer YOUR_OAUTH2_TOKEN' 
  --header 'Content-Type: application/json' 
  --data '{
        "countryCode": "DE",     
        "zipCode": "10115",
        "deliveryWindowId": "1234567890abcdef",    
        "deliveryWindow": {       
            "id": "1234567890abcdef",       
            "deliveryDate": "2025-07-25T10:00:00.000Z",       
            "slotId": "slot123"     
            }   
        }' 
3

Verify the results by retrieving the cart. Call the Retrieving cart details by ID endpoint.

curl -L \
  --url 'https://api.emporix.io/cart/{tenant}/carts/{cartId}'
  --header 'Authorization: Bearer YOUR_OAUTH2_TOKEN'
  --header 'Accept: */*'
API Reference

As a result, the response includes the shipping costs details:

{
    "calculatedPrice": {   
        "shipping": {     
            "amount": 20.00,     
            "currency": "EUR"   
        } 
    }
}

How to calculate a payment fee at cart level

At the cart level, only one additional fee is calculated, apart from the fees applied at the item level. The paymentFees is an additional, non-discountable amount that the customer must pay for using a given payment method.

The fee has a specific format, and there are two options for calculating it:

  • ABSOLUTE - the value of defined fee’s attribute feeAbsolute.amount, where the amount is treated as netValue.

  • PERCENT - the fee is calculated as a percentage of the total net value of all item lines' finalPrice.netValue, plus the cart’s calculatedPrice.totalShipping.netValue. The fee is specified by the feePercentage attribute.

If the fee is taxable and has a tax code, the gross value is calculated. Otherwise, the grossValue is equal to netValue.

How to determine a tax country at cart level

Since the shipping address is not set in the cart, you need to determine the country to find the taxRate for a fee that has a taxCode only. Ways to find the country data:

  • Use the country code that is set on the cart

  • If the cart has a customer, check the customer addresses, based on site’s setting taxDeterminationBasedOn:

    • SHIPPING_ADDRESS - use the address that is tagged with SHIPPING, select the default address or the first match.

    • BILLING_ADDRESS - use the address that is tagged with BILLING, select the default address or the first match. If the matching address is not found, return an error.

  • Get country code from site’s homeBase.address.country.

How to apply discounts at cart level

Discounts are known as coupons and, with the relevant settings that influence calculatedPrice, they can be applied to a cart.

Depending on the site configuration and the includesTax=true/false, the discount is applied to either the gross value - includesTax=true, or the net value - includesTax=false. Based on this setting, the corresponding netValue or grossValue is recalculated using the tax rate.

The information about which calculation method was used is available in the totalDiscount.calculationType=ApplyDiscountAfterTax/ApplyDiscountBeforeTax:

  • discountCalculationType:

    • SUBTOTAL - the discounts are applied on items[].calculatedPrice.price. The line item fees and shipping cost are NOT discounted.

    • TOTAL - the discounts are applied on items[].calculatedPrice.price, the line item fees and shipping cost.

  • discountType:

    • ABSOLUTE - a coupon that has a given type must have discountAbsolute attribute configured. It represents a monetary amount that should be discounted.

    Depending on the ApplyDiscountAfterTax/ApplyDiscountBeforeTax discount, the absolute amount is subtracted either from the grossValue or the netValue. The value of the discount on the cart level is divided across all the applicable cart prices, proportionally to the items[].calculatedPrice.price, items[].calculatedPrice.fees[].price and the calculated shipping cost. It's related to the difference between discountCalculationType:SUBTOTAL/TOTAL described above, to know which items are applicable.

    • PERCENT - it takes the value of discount’s discountPercentage attribute and calculates the percentage discount to the price.

    • FREE_SHIPPING - this type of a discount fully discounts the price of the calculatedPrice.totalShipping. It's applied before any other discount is applied.

  • categoryRestricted - the discount applies only to the line items that belong to a specific category. If the discountCalculationType=TOTAL, a fee of an item that fulfills the restriction is discounted. However, any other fees, or shipping are not part of the discounting.

  • segmentRestricted - the discount is applied only to the line items that belong to the given customer segment.

Since the system can be configured to allow more than one discount to a cart, it has a few implications:

  • The FREE_SHIPPING discount is applied on the shipping first.

  • The rest of the discounts are applied based on the order the discounts were applied to the cart.

  • Every PERCENT discount is calculated based on the original price, without applied discounts. Applying two coupons of 10% to 15.0 value results in 12.0 discounted price and two applied discounts of 1,5 value.

  • Every ABSOLUTE discount uses the not discounted values for the discount value spread. It means that if the given applicable item is already fully discounted, the remaining amount of the discount is spread proportionally on the discounts that still have some value left.

For some cases, you might need to calculate and charge additional fees, for example for packaging, freight, or any additional reasons. The fees calculated externally can be added directly to the customer's cart.

To achieve the communication between Commerce Engine and the fee management tool, you have to configure both systems accordingly. The steps required for such a case are described in the External Products, Pricing and Fees documentation. You need to generate a dedicated scope that serves as the authorization token for the API calls.

To add a custom fee to the cart, you need to send the request to the endpoint. Provide the customer cart's ID in the cartId path parameter. The payload has to include the "itemType" : "EXTERNAL" parameter - see the Adding a product to a cart documentation.

How to apply separation of the same line items in the cart

When you add an item to the cart, it's stored as a single line. If you add the same item multiple times, it remains a single line item, but the quantity attribute is updated to reflect the total amount, for example when you add 5 items they are stored as item1: productA, qty:5.

If you need to add the same item multiple times on separate lines in the cart, use the keepAsSeparateLineItem=true flag - it ensures each instance of the item appears as a distinct line item. This can be useful in a variety of scenarios, such as applying different discounts or fees to the same product, or handling separate delivery options.

A common use case is the Buy 2, Get 1 Free promotion. In this case, when a customer adds two of the same line items to the cart, the system can add a third instance as a separate line item marked as free.

Using the keepAsSeparateLineItem=true flag stores each addition of the product as an individual line, while the keepAsSeparateLineItem=false keeps them all in one.

By default, all items are grouped into a single line in the cart. This behavior is defined by keepAsSeparateLineItem=false. However, even if the keepAsSeparateLineItem flag is not explicitly included in the payload, the system assumes this default behavior. In other words, unless stated otherwise, keepAsSeparateLineItem=false is always applied.

Adding the keepAsSeparateLineItem":true flag to the payload example:

{
    "itemYrn": "urn:yaas:saasag:caasproduct:product:b2b2cstage;samsung-galaxy-s24-gross",
    "keepAsSeparateLineItem":true,
    "price": {
        "priceId": "679ca63dbcdefe5b380c98bc",
        "effectiveAmount": 550,
        "originalAmount": 550,
        "currency": "EUR"
    },
}

Usage examples

Adding multiple productA items with the keepAsSeparateLineItem=true flag

  • Adding the first productA item with keepAsSeparateLineItem=true results in:

item0: productA, qty:1, keepAsSeparateLineItem=true
  • Adding another productA item with keepAsSeparateLineItem=true results in:

item0: productA, qty:1, keepAsSeparateLineItem=true
item1: productA, qty:1, keepAsSeparateLineItem=true 

Adding multiple productA items with the keepAsSeparateLineItem=false flag

  • Adding the first productA item with keepAsSeparateLineItem=false results in:

item0: productA, qty:1, keepAsSeparateLineItem=false
  • Adding another productA item with keepAsSeparateLineItem=false results in:

item0: productA, qty:2, keepAsSeparateLineItem=false

Adding multiple productA items with the keepAsSeparateLineItem=true and keepAsSeparateLineItem=false flags

  • Adding the first productA item with two different flags results in:

item0: productA, qty:1, keepAsSeparateLineItem=true 
item2: productA, qty:1, keepAsSeparateLineItem=false 
  • Adding another two productA items with different flags results in:

item0: productA, qty:1, keepAsSeparateLineItem=true 
item1: productA, qty:1, keepAsSeparateLineItem=true 
item2: productA, qty:2, keepAsSeparateLineItem=false 

Products with external prices

You can add external prices for both custom products and products from the internal catalog. Line items for the same product can have different prices if they’re added separately with keepAsSeparateLineItem=true.

For example:

  • Adding the first productA item with priceX and keepAsSeparateLineItem=true results in

item0: productA, external, priceX, qty:1, keepAsSeparateLineItem=true 
  • Adding another productA item to it, but with priceY and keepAsSeparateLineItem=true results in:

item0: productA, external, priceX, qty:1, keepAsSeparateLineItem=true 
item1: productA, external, priceY, qty:1, keepAsSeparateLineItem=true 

Products with standard prices

When using internal prices, the priceId is the same across all line items - if the product uses a standard price from the catalog, all lines for that item are expected to have the same price.

For example:

  • Adding the first productA item with priceX and keepAsSeparateLineItem=true results in:

item0: productA, internal, priceX, qty:1, keepAsSeparateLineItem=true 
  • Adding another productA item with different priceY and keepAsSeparateLineItem=true results in:

    • If cartItemValidationSkipExistingItemsValidationOnAddToCart=false, the validation occurs, and an error is thrown due to the price mismatch.

    • If cartItemValidationSkipExistingItemsValidationOnAddToCart=true, the validation does not occur, and the cart accepts the new line item.

item0: productA, internal, priceX, qty:1, keepAsSeparateLineItem=true 
item1: productA, internal, priceY, qty:1, keepAsSeparateLineItem=true 

Adding products with internal and external pricing

When you add the same product first as an internal one and then as an external, the items are split into separate line items even if keepAsSeparateLineItem=false, or if the flag is not present.

  • Adding productA item, with internal priceX and keepAsSeparateLineItem=false results in:

  item0: productA, internal, priceX, qty:1, keepAsSeparateLineItem=false`
  • Adding productA item to it, with external priceY and keepAsSeparateLineItem=false results in:

  item0: productA, internal, priceX, qty:1, keepAsSeparateLineItem=false 
  item0: productA, external, priceY, qty:1, keepAsSeparateLineItem=false

Last updated

Was this helpful?