# Pricing and discounts APIs overview

**How to work with the APIs for product pricing and discounts.**

This page describes rules that apply across the pricing and discounts APIs. For what Prices and Discounts are and how they behave, see the [Pricing and discounts overview](/api/pricing-and-discounts-overview.md).

## APIs in this topic

| Resource | Purpose | Reference |
| --- | --- | --- |
| Standalone Prices | Store your product prices as standalone resources, especially with a large number of prices. | [Standalone Prices](/api/projects/standalone-prices.md) |
| Product Discounts | Reduce certain Product Prices. | [Product Discounts](/api/projects/productDiscounts.md) |
| Cart Discounts | Change the Prices of different elements within a Cart. | [Cart Discounts](/api/projects/cartDiscounts.md) |
| Discount Codes | Give specific Cart Discounts to eligible Customers. | [Discount Codes](/api/projects/discountCodes.md) |
| Discount Groups | Group Cart Discounts and apply the best discount from the group to a Cart. | [Discount Groups](/api/projects/discount-groups.md) |

## Data model

- For Embedded Prices, the discounted value is stored in the [Price](/search.md?urn=ctp:api:type:Price) `discounted` field.
- For Standalone Prices, the discounted value is stored in the [StandalonePrice](/search.md?urn=ctp:api:type:StandalonePrice) and [StagedStandalonePrice](/api/projects/standalone-prices.md#stagedstandaloneprice) `discounted` fields.

## Working with the APIs

### Price modes

The [Product](/search.md?urn=ctp:api:type:Product) `priceMode` determines the type of Price used for a Product Variant. If the `priceMode` is not set, as a default, Product Variants use Embedded Prices.

- For existing Products using Embedded Prices, use the [Set PriceMode](/api/projects/products.md#set-pricemode) update action to change the price mode.
- For new Products, [create a Product](/search.md?urn=ctp:api:endpoint:/{projectKey}/products:POST) with `priceMode` as `Standalone`.

### Embedded Prices

Embedded Prices are stored within a [ProductVariant](/search.md?urn=ctp:api:type:ProductVariant), and are associated to it through its `prices` field.

Embedded Prices are managed and queried using the [Products API](/api/projects/products.md). You can add Prices when [creating a Product](/search.md?urn=ctp:api:endpoint:/{projectKey}/products:POST), or manage Prices of an existing Product using the [Add Price](/api/projects/products.md#add-price), [Set Prices](/api/projects/products.md#set-prices), [Change Price](/api/projects/products.md#change-price), or [Remove Price](/api/projects/products.md#remove-price) update actions.

### Standalone Prices

Standalone Prices are managed and queried using the [Standalone Prices API](/api/projects/standalone-prices.md), independent from your Products, thus contributing to better query performance.

### External Prices

Since external prices are not part of the product catalog, they are not available on the [Product Search API](/api/projects/product-search.md) as well as the [Product Projection Search API](/api/projects/product-projection-search.md) for filtering, faceting, or sorting products by price.

You can set an external price for the Line Item when [creating](/search.md?urn=ctp:api:endpoint:/{projectKey}/carts:POST) or updating a Cart using the following actions: [Add LineItem](/api/projects/carts.md#add-lineitem), [Remove LineItem](/api/projects/carts.md#remove-lineitem), [Change LineItem Quantity](/api/projects/carts.md#change-lineitem-quantity), [Set LineItem Price](/api/projects/carts.md#set-lineitem-price), or [Set LineItem TotalPrice](/api/projects/carts.md#set-lineitem-totalprice).

If the LineItem's `priceMode` is `ExternalPrice`, set the `externalPrice` value. The `totalPrice` of the LineItem is automatically calculated by multiplying the `externalPrice` by the quantity.

If the LineItem's `priceMode` is `ExternalTotal`, set the `externalTotalPrice` value (unit price multiplied by the quantity). The `totalPrice` of the LineItem is set from the value defined in `externalTotalPrice`.

> Your code should be able to find the correct prices to display on your storefront and set the Line Item price when it's added to a Cart.

### Tiered pricing

When the [PriceTier](/api/types.md#pricetier) `minimumQuantity` is reached, the Price tier is applied for the entire quantity of a Product Variant [added as Line Item](/api/projects/carts.md#add-lineitem) to a Cart.

### Price selection in API responses

Both types of price selection add the additional `price` field to the [ProductVariant](/search.md?urn=ctp:api:type:ProductVariant) and [LineItem](/search.md?urn=ctp:api:type:LineItem) respectively in API responses. The `price` field is not populated for [ShoppingListLineItem](/search.md?urn=ctp:api:type:ShoppingListLineItem) because price selection is not supported in the Shopping List context.

The returned [ProductVariant](/search.md?urn=ctp:api:type:ProductVariant) `price` field—added in API responses—contains the Price that matches most of the Price-selection parameters.

> The price is shown only when the timestamp of the request is within `validFrom` and `validUntil` range of [Embedded Price](/api/types.md#price) or [StandalonePrice](/search.md?urn=ctp:api:type:StandalonePrice).

- **Line Item price selection**: When you [create a Cart](/search.md?urn=ctp:api:endpoint:/{projectKey}/carts:POST) or [add a LineItem to a Cart](/api/projects/carts.md#add-lineitem), the `price` is determined by the Carts API based on the following parameters:

  - [Cart](/search.md?urn=ctp:api:type:Cart) `currency`: maps to `value.currencyCode` of [Price](/api/types.md#price) or [StandalonePrice](/search.md?urn=ctp:api:type:StandalonePrice)
  - Cart `customerGroup`: maps to `customerGroup` of Price or StandalonePrice
  - [LineItemDraft](/search.md?urn=ctp:api:type:LineItemDraft) `distributionChannel`: maps to `channel` of Price or StandalonePrice
  - Cart `country`: maps to `country` of Price or StandalonePrice
  - [Customer](/api/projects/customers.md) `customerGroupAssignments`: maps to `customerGroup` of Price or StandalonePrice. For more information, see [Fallback logic for multiple Customer Groups](/api/pricing-and-discounts-overview.md#fallback-logic-for-multiple-customer-groups).
  - [Business Unit](/api/projects/business-units.md) `customerGroupAssignments`: maps to `customerGroup` of Price or StandalonePrice. For more information, see [Fallback logic for multiple Customer Groups](/api/pricing-and-discounts-overview.md#fallback-logic-for-multiple-customer-groups).

    > Both `businessUnit.customerGroupAssignments` and `cart.businessUnit` fields must be defined (non-null) for B2B-specific prices to apply on the cart; otherwise, the platform selects B2C-specific prices.

    - If the Business Unit `customerGroupAssignments` field is an empty list (`[]`), the base price applies as no Customer Group-specific prices are available.
    - If the Business Unit `customerGroupAssignments` field is not set, the Cart `customerGroup` and Customer `customerGroupAssignments` fields are used (as a fallback) to determine eligible Customer Groups, provided the Cart has a `customerId`. If no `customerId` is set, the base price applies.

### Scoped Price search

> Scoped Price search—that includes [filter](/api/projects/product-projection-search.md#filter-by-scoped-price), [facet](/api/projects/product-projection-search.md#facets), and [sort](/api/projects/product-projection-search.md#sort-by-scoped-price) options—only works with [Embedded Prices](/api/pricing-and-discounts-overview.md#embedded-prices). Using these options on Products with `Standalone` [ProductPriceMode](/api/projects/products.md#productpricemode) yields inconsistent results, as only Embedded Prices are taken into account.

In case of a full match—where a Price matching all Price-selection parameters provided with the search request exists—the [ProductVariants](/api/projects/products.md#productvariant) returned with the search result contains the `scopedPrice` field. In case of a partial match, this field is not present.

> Scoped Price search does not have a fallback behavior, and does not take the Price validity dates into consideration. To ensure only Products with valid Prices are returned, [remove Prices](/api/projects/products.md#remove-price) that are no longer valid. For Prices to become valid at a later time, do not [publish](/api/projects/products.md#publish) them before their `validFrom` date, and [search](/api/projects/product-projection-search.md#product-projection-search) for the [current](/api/projects/productProjections.md#current--staged) Product Projection.

For worked examples of Scoped Price search, see [Product Projection Search](/api/projects/product-projection-search.md#scoped-price-search).

### Product Discounts

If multiple active Product Discounts match a Price, then the [ProductDiscount](/search.md?urn=ctp:api:type:ProductDiscount) `sortOrder` determines which one applies.

Product Discounts are managed and queried using the [Product Discounts API](/api/projects/productDiscounts.md).

To use external discounts, set the [ProductDiscountDraft](/search.md?urn=ctp:api:type:ProductDiscountDraft) `value` to `external`.

### Cart Discounts

Cart Discounts can be used to discount different elements of a Cart, some of which include:

- A discount on any item in a cart with [CartDiscountLineItemsTarget](/search.md?urn=ctp:api:type:CartDiscountLineItemsTarget) or [CartDiscountCustomLineItemsTarget](/search.md?urn=ctp:api:type:CartDiscountCustomLineItemsTarget)
- A discount on the shipping cost of a cart with [CartDiscountShippingCostTarget](/search.md?urn=ctp:api:type:CartDiscountShippingCostTarget)
- A discount on a cart's total with [CartDiscountTotalPriceTarget](/search.md?urn=ctp:api:type:CartDiscountTotalPriceTarget)
- A 'Buy X, get Y free' discount with [CartDiscountValueGiftLineItemDraft](/search.md?urn=ctp:api:type:CartDiscountValueGiftLineItemDraft)
- A 'Buy X items, get Y of them at a discounted rate' discount with [MultiBuyLineItemsTarget](/search.md?urn=ctp:api:type:MultiBuyLineItemsTarget) or [MultiBuyCustomLineItemsTarget](/search.md?urn=ctp:api:type:MultiBuyCustomLineItemsTarget). Note that you can only apply a percentage-off discount on eligible items.
  You can also use [CartDiscountPatternTarget](/search.md?urn=ctp:api:type:CartDiscountPatternTarget). It is a more powerful option and lets you apply an amount, a fixed price, or percentage discount to eligible items.

> Gift Line Items are ignored by [MultiBuyLineItemsTarget](/search.md?urn=ctp:api:type:MultiBuyLineItemsTarget) and [CartDiscountPatternTarget](/search.md?urn=ctp:api:type:CartDiscountPatternTarget) discounts.

Cart Discounts can be defined globally for a Project, or be specific to one or more Stores in a Project. In the latter case, the Discount is only applied to [Carts](/api/projects/carts.md#cart) that belong to one of the Stores referenced in the [CartDiscount](/search.md?urn=ctp:api:type:CartDiscount) `stores` array. If the array is empty or unspecified, the Discount applies (globally) to all Carts.

You can avoid applying further Cart Discounts to the Cart by setting the `stackingMode` to `StopAfterThisDiscount` on the [CartDiscount](/search.md?urn=ctp:api:type:CartDiscount) that must be applied last.

> The stacking mode does not control free shipping as defined via `freeAbove` on a [ShippingRate](/search.md?urn=ctp:api:type:ShippingRate). To avoid unwanted scenarios, we highly recommend not using Cart Discounts on `shipping` target and `freeAbove` together.

Cart Discounts are managed and queried using the [Cart Discounts API](/api/projects/cartDiscounts.md).

Cart Discounts are recalculated every time a [Discount Code](/api/projects/discountCodes.md), [LineItem](/search.md?urn=ctp:api:type:LineItem), or [CustomLineItem](/search.md?urn=ctp:api:type:CustomLineItem) is added or removed from a [Cart](/search.md?urn=ctp:api:type:Cart), or when an [Order is created from a Cart](/search.md?urn=ctp:api:endpoint:/{projectKey}/orders:POST).

### Discount Codes

Discount Codes are managed and queried using the [Discount Codes API](/api/projects/discountCodes.md).

### Discount Groups

You can only group Cart Discounts if they are not specific to a Store and they target Line Items (that is, CartDiscounts with `target` as `lineItems`, `customLineItems`, `multiBuyLineItems`, `multiBuyCustomLineItems`, or `pattern`).

To remove a Cart Discount from a Discount Group, use the [Set DiscountGroup](/api/projects/cartDiscounts.md#set-discountgroup) action and set the sort order for the Cart Discount again.

Discounts Groups are managed and queried using the [Discount Groups API](/api/projects/discount-groups.md).

### Direct Discounts

Direct Discounts are always active and valid, use the default [StackingMode](/search.md?urn=ctp:api:type:StackingMode) `Stacking`, and do not have a sorting order. They apply in the order listed in the `directDiscounts` array of the Cart or Order.

For all three discount types to coexist, `directDiscountsIgnoreCartDiscounts` must be `false` on the Cart.

To avoid losing a negotiated reduction, `participateInBestDealSelection` must be set to `false` on the [DirectDiscountDraft](/search.md?urn=ctp:api:type:DirectDiscountDraft).

To update or add Direct Discounts to an Order, use the [Set DirectDiscounts](/search.md?urn=ctp:api:type:StagedOrderSetDirectDiscountsAction) update action.

### Discount combination mode

In the `BestDeal` [DiscountCombinationMode](/search.md?urn=ctp:api:type:DiscountCombinationMode), Product Discounts and Cart Discounts can both be present on the same Cart, but only one discount type applies per Line Item.

The discount combination mode for a [Cart](/search.md?urn=ctp:api:type:Cart) and for an [Order](/search.md?urn=ctp:api:type:Order) is indicated in the `discountTypeCombination` field.

## Eventual consistency

> When you create, update, or delete a Product Discount, the Prices are updated in an [eventually consistent](/api/general-concepts.md#eventual-consistency) manner. Both [Embedded Prices](/api/types.md#price) and [StandalonePrices](/api/projects/standalone-prices.md#standaloneprice) associated to a [ProductVariant](/search.md?urn=ctp:api:type:ProductVariant) are updated, regardless of the Product's [priceMode](/api/projects/products.md#product) value.
>
> The time to update can vary—between a fraction of a second to several hours—depending on the following factors:
>
> - The number of Products and their size
> - The number of Products affected by Discount predicates
> - The number of Prices to be updated

## Limits

With Embedded Prices, you can store up to 100 Prices for each Product Variant. For more flexibility with pricing your products with higher limits, see [Standalone Prices](/api/pricing-and-discounts-overview.md#standalone-prices).

When using Embedded Prices, keep the JSON document size in mind. A Product and all its Prices are stored in a single JSON document. As Price count and Product Type complexity grow, you may approach the document size limit.

A maximum number of **50000** Standalone Prices can be specified per [ProductVariant](/search.md?urn=ctp:api:type:ProductVariant). This is a soft limit that can be increased per Project after a performance impact review. See [Limit increase guidance](/api/limit-increase-guidance.md#product-and-pricing-model-limits).

Product Discounts are subject to a [limit](/api/limits.md#product-discounts) in a Project.

Cart Discounts are subject to a [limit](/api/limits.md#cart-discounts) in a Project.

A [DiscountCode](/search.md?urn=ctp:api:type:DiscountCode) can apply up to **10** [CartDiscounts](/api/projects/cartDiscounts.md#cartdiscount).

Discount Groups are subject to a [limit](/api/limits.md#discount-groups) in a Project.

Discount Codes are subject to a [limit](/api/limits.md#discount-codes) in a Project.

## Related pages

- [Area overview page with navigation](/api.md)
- [Previous page: Overview](/api/pricing-and-discounts-overview.md)
- [Next page: Standalone Prices](/api/projects/standalone-prices.md)
- [Search documentation and API specs](/search.md)