Cost Price Promotion

API reference for creating and managing Cost Price promotions in Omnium OMS. Calculate selling prices dynamically from cost prices with configurable markup.

Cost Price Promotion API Reference

Table of Contents

  1. Overview
  2. How It Works
  3. API Endpoints
  4. Data Models
  5. Creating Promotions
  6. Examples
  7. Price Calculation Formula
  8. Best Practices
  9. Troubleshooting

Overview

Cost Price promotions allow you to dynamically calculate selling prices based on product cost prices from a linked price list, with a configurable markup percentage. This is ideal for cost-plus pricing strategies where the final price is derived from a product's cost rather than a fixed retail price.

Key Features

  • Cost-plus pricing: Automatically calculate selling prices from cost prices with a percentage markup
  • Price list integration: Link to a price list containing product cost prices
  • Tax-inclusive calculation: Tax rate from the price list is applied automatically
  • Automatic price generation: Product prices are updated in the catalog, visible on PLPs and PDPs
  • Product filtering: Target specific products using category, brand, season, and property filters

Common Use Cases

  • Outlet/clearance pricing where products are sold at cost + fixed margin
  • Wholesale pricing based on cost with standard markup
  • Dynamic pricing that automatically adjusts when cost prices change
  • Seasonal markdowns where you want to maintain a minimum margin above cost

Key Differences from Other Promotions

FeatureCost Price PromotionCategory/Brand PromotionPrice List Promotion
Price sourceCalculated from cost price + markupFixed discount on catalog priceDirect price from price list
Generates pricesYesYesYes
CombinableNo (exclusive)ConfigurableConfigurable
Requires price listYes (with cost prices)NoYes (with selling prices)

How It Works

Price Calculation Workflow

  1. Link a price list containing cost prices for your products
  2. Set a markup percentage (e.g., 25% margin above cost)
  3. Configure product filters to target specific products (optional)
  4. Omnium calculates the selling price using the formula: CostPrice x (1 + Markup%) x (1 + Tax%)
  5. Prices are generated on matching products and displayed in the catalog
  6. At checkout, the promotion discount is applied as the difference between the original catalog price and the calculated cost-based price

Example Calculation

Given:

  • Cost price: 100 NOK
  • Markup: 25%
  • Tax rate: 25%

Calculation:

CalculatedPrice = 100 x (1 + 25/100) x (1 + 25/100)
CalculatedPrice = 100 x 1.25 x 1.25
CalculatedPrice = 156.25 NOK

If the original catalog price was 299 NOK, the customer sees:

  • 299 NOK 156.25 NOK (47.7% off)

API Endpoints

Base URL

/api/promotions

Create Promotion

POST /api/promotions
Content-Type: application/json

Request Body: OmniumPromotionRequest

Update Promotion (Patch)

PATCH /api/promotions
Content-Type: application/json

Request Body: OmniumPromotionPatch

Get Promotions

GET /api/promotions

Delete Promotion

DELETE /api/promotions/{id}

Data Models

OmniumPromotionRequest

The main request model for creating a Cost Price promotion.

{
  "id": "string (Unique Id of the promotion, GUID will be generated if not provided)",
  "name": "Cost Price Outlet Sale",
  "title": "Outlet Prices - Cost + 25%",
  "activeFrom": "2026-01-01T00:00:00Z",
  "activeTo": "2026-12-31T23:59:59Z",
  "markets": ["NOR", "SWE"],
  "stores": [],
  "filterOnWarehouseStores": false,
  "customerGroups": [],
  "priority": 10,
  "couponCode": null,
  "canBeCombinedWithOtherPromotions": false,
  "alwaysApply": false,
  "customerClubMembersOnly": false,
  "isBonusPointsReward": false,
  "orderTypes": [],
  "tags": ["Outlet"],
  "promotionData": {
    "promotionType": "CostPricePromotion",
    "categoryAndBrandFilter": {},
    "priceListId": "your-price-list-id",
    "markupPercentage": 25.0
  }
}

CostPricePromotion Data

The promotion-specific configuration within promotionData.

{
  "promotionType": "CostPricePromotion",
  "categoryAndBrandFilter": {
    "categories": [],
    "brands": [],
    "products": []
  },
  "priceListId": "your-price-list-id",
  "markupPercentage": 25.0
}

Properties

PropertyTypeRequiredDescription
promotionTypestringYesMust be "CostPricePromotion". Note: unlike older promotion types that use numeric identifiers (e.g., 2 for MultiBuy), Cost Price promotions use a string-based type identifier
priceListIdstringYesThe ID of the price list containing cost prices for products
markupPercentagedecimalYesPercentage markup to add on top of cost price. E.g., 25 means 25% markup. Minimum value: 0
categoryAndBrandFilterobjectNoFilter to target specific products by category, brand, season, or properties. If omitted, applies to all products with cost prices in the linked price list
rewardobjectNoOptional reward configuration (inherited from order line promotion interface)

OmniumCategoryAndBrandFilter

Defines which products qualify for the promotion.

{
  "categories": [
    {
      "categoryId": "cat123",
      "categoryName": "Outlet"
    }
  ],
  "requiredCategories": [],
  "excludedCategories": [],
  "brands": ["Nike", "Adidas"],
  "excludedBrands": ["Premium Brand"],
  "products": [
    {
      "productId": "prod123",
      "productName": "Classic T-Shirt",
      "isSku": true
    }
  ],
  "excludedProducts": [],
  "seasons": ["SS24"],
  "excludedSeasons": [],
  "properties": [
    {
      "key": "Color",
      "value": "Red"
    }
  ],
  "excludedProperties": []
}

Filter Properties

PropertyTypeDescription
categoriesarrayInclude products in these categories
requiredCategoriesarrayProducts must be in these categories (AND logic)
excludedCategoriesarrayExclude products in these categories
brandsarrayInclude products from these brands (case-insensitive)
excludedBrandsarrayExclude products from these brands (case-insensitive)
productsarrayInclude specific products/SKUs
excludedProductsarrayExclude specific products/SKUs
seasonsarrayInclude products with these season values (case-insensitive)
excludedSeasonsarrayExclude products with these season values (case-insensitive)
propertiesarrayInclude products with these property key-value pairs (case-insensitive, AND logic)
excludedPropertiesarrayExclude products with any of these property key-value pairs (case-insensitive, OR logic)

Price List Requirements

The linked price list must contain cost prices for the products you want to apply the promotion to. Key fields on the price list:

PropertyTypeDescription
currencyCodestringCurrency of the price list (used for the calculated selling price)
taxRatedecimalTax percentage applied in the calculation formula
isExcludingTaxboolWhether prices in the list exclude tax
costCurrencyCodestringCurrency of the cost prices (if different from selling currency)
costCurrencyExchangeRatedecimalExchange rate for currency conversion

Each PriceListItem must have:

PropertyTypeDescription
skuIdstringSKU identifier for the product variant (preferred lookup key)
productIdstringProduct identifier (fallback if no SKU match)
costdecimalCost price in default currency
costInPriceListCurrencydecimalCost price in the price list currency (used if > 0, otherwise falls back to cost)

Creating Promotions

Basic Cost Price Promotion

Scenario: Apply cost + 25% markup to all products in the "Outlet" category

{
  "name": "Outlet Cost Plus 25%",
  "title": "Outlet Prices",
  "activeFrom": "2026-01-01T00:00:00Z",
  "activeTo": "2026-12-31T23:59:59Z",
  "markets": ["NOR"],
  "priority": 10,
  "promotionData": {
    "promotionType": "CostPricePromotion",
    "categoryAndBrandFilter": {
      "categories": [
        {
          "categoryId": "outlet",
          "categoryName": "Outlet"
        }
      ]
    },
    "priceListId": "cost-price-list-001",
    "markupPercentage": 25.0
  }
}

Brand-Specific Cost Pricing

Scenario: Apply cost + 15% markup to Nike products only

{
  "name": "Nike Cost Plus 15%",
  "title": "Nike Special Pricing",
  "activeFrom": "2026-01-01T00:00:00Z",
  "activeTo": "2026-06-30T23:59:59Z",
  "markets": ["NOR", "SWE"],
  "priority": 10,
  "promotionData": {
    "promotionType": "CostPricePromotion",
    "categoryAndBrandFilter": {
      "brands": ["Nike"]
    },
    "priceListId": "nike-cost-prices",
    "markupPercentage": 15.0
  }
}

Zero Markup (Sell at Cost)

Scenario: Sell specific clearance products at cost price (no markup)

{
  "name": "Clearance - At Cost",
  "title": "Final Clearance - At Cost!",
  "activeFrom": "2026-06-01T00:00:00Z",
  "activeTo": "2026-06-30T23:59:59Z",
  "markets": ["NOR"],
  "priority": 5,
  "promotionData": {
    "promotionType": "CostPricePromotion",
    "categoryAndBrandFilter": {
      "categories": [
        {
          "categoryId": "clearance",
          "categoryName": "Clearance"
        }
      ]
    },
    "priceListId": "main-cost-prices",
    "markupPercentage": 0
  }
}

Note: Setting markupPercentage to 0 means products are sold at cost price plus tax only.


Examples

Example 1: Multi-Market Cost Pricing

Scenario: Apply cost + 30% markup across Norwegian and Swedish markets

{
  "name": "Cost Plus 30% - NOR/SWE",
  "title": "Special Outlet Pricing",
  "activeFrom": "2026-01-01T00:00:00Z",
  "activeTo": "2026-12-31T23:59:59Z",
  "markets": ["NOR", "SWE"],
  "priority": 10,
  "promotionData": {
    "promotionType": "CostPricePromotion",
    "categoryAndBrandFilter": {
      "categories": [
        {
          "categoryId": "outlet",
          "categoryName": "Outlet"
        }
      ]
    },
    "priceListId": "multi-market-cost-prices",
    "markupPercentage": 30.0
  }
}

Note: The price list's currencyCode and taxRate are used for the calculation. Ensure your price list has correct values for the target markets.

Example 2: Season-Based Cost Pricing

Scenario: Mark down last season's products to cost + 10%

{
  "name": "Last Season Clearance",
  "title": "Last Season - Cost + 10%",
  "activeFrom": "2026-03-01T00:00:00Z",
  "activeTo": "2026-05-31T23:59:59Z",
  "markets": ["NOR"],
  "priority": 5,
  "promotionData": {
    "promotionType": "CostPricePromotion",
    "categoryAndBrandFilter": {
      "seasons": ["AW25"],
      "excludedBrands": ["Premium Brand"]
    },
    "priceListId": "aw25-cost-prices",
    "markupPercentage": 10.0
  }
}

Example 3: Customer Group Exclusive

Scenario: VIP members get cost + 20% on all products

{
  "name": "VIP Cost Pricing",
  "title": "VIP Member Exclusive Pricing",
  "activeFrom": "2026-01-01T00:00:00Z",
  "activeTo": "2026-12-31T23:59:59Z",
  "markets": ["NOR"],
  "customerGroups": [
    {
      "customerGroupId": "vip-members",
      "customerGroupName": "VIP Members"
    }
  ],
  "priority": 5,
  "promotionData": {
    "promotionType": "CostPricePromotion",
    "priceListId": "main-cost-prices",
    "markupPercentage": 20.0
  }
}

Example 4: Specific Products Only

Scenario: Apply cost + 5% to specific SKUs

{
  "name": "Selected SKU Cost Pricing",
  "title": "Special Deal",
  "activeFrom": "2026-01-01T00:00:00Z",
  "activeTo": "2026-03-31T23:59:59Z",
  "markets": ["NOR"],
  "priority": 10,
  "promotionData": {
    "promotionType": "CostPricePromotion",
    "categoryAndBrandFilter": {
      "products": [
        {
          "productId": "SKU-001",
          "productName": "Product A",
          "isSku": true
        },
        {
          "productId": "SKU-002",
          "productName": "Product B",
          "isSku": true
        }
      ]
    },
    "priceListId": "main-cost-prices",
    "markupPercentage": 5.0
  }
}

Example 5: Category with Property Filtering

Scenario: Apply cost + 20% to red clothing items, excluding small sizes

{
  "name": "Red Clothing Cost Pricing",
  "title": "Red Collection - Special Price",
  "activeFrom": "2026-01-01T00:00:00Z",
  "activeTo": "2026-06-30T23:59:59Z",
  "markets": ["NOR"],
  "priority": 10,
  "promotionData": {
    "promotionType": "CostPricePromotion",
    "categoryAndBrandFilter": {
      "categories": [
        {
          "categoryId": "clothing",
          "categoryName": "Clothing"
        }
      ],
      "properties": [
        {
          "key": "Color",
          "value": "Red"
        }
      ],
      "excludedProperties": [
        {
          "key": "Size",
          "value": "Small"
        }
      ]
    },
    "priceListId": "main-cost-prices",
    "markupPercentage": 20.0
  }
}

Price Calculation Formula

Formula

CalculatedPrice = CostPrice x MarkupMultiplier x TaxMultiplier

Where:

MarkupMultiplier = 1 + (MarkupPercentage / 100)
TaxMultiplier = 1 + (TaxRate / 100)

Calculation Examples

Cost PriceMarkup %Tax Rate %Markup MultiplierTax MultiplierCalculated Price
10025251.251.25156.25
20050251.501.25375.00
1500251.001.25187.50
8010121.101.1298.56

Cost Price Selection

When looking up cost prices from the price list, the system uses this priority:

  1. costInPriceListCurrency - Used if greater than 0 (preferred, avoids currency conversion)
  2. cost - Fallback if costInPriceListCurrency is 0 or not set

SKU Lookup Priority

When matching products to cost prices in the price list:

  1. By SKU ID - Exact match on variant SKU (preferred)
  2. By Product ID - Fallback if no SKU match found

Discount Calculation

The discount shown to the customer is calculated as:

DiscountAmount = OriginalCatalogPrice - CalculatedPrice
DiscountPercent = (DiscountAmount / OriginalCatalogPrice) x 100

Note: A discount is only applied if the calculated price is lower than the original catalog price. If the cost-based price would be higher than the existing price, no discount is created.

Rounding: If a rounding policy is configured on the promotion, the final calculated price is rounded accordingly (e.g., to nearest whole number or nearest .90). The discount amount and percentage are recalculated after rounding.


Best Practices

1. Ensure Cost Prices Exist

Before creating the promotion, verify that the linked price list contains cost prices for all target products. Products without matching cost prices in the price list will not be affected by the promotion.

2. Set Appropriate Priorities

Cost Price promotions cannot be combined with other promotions (canBeCombinedWithOtherPromotions is always false). Use priority values to control which promotion takes precedence:

  • Cost price promotions for clearance: Priority 0-5
  • Standard cost pricing: Priority 10-20
  • Use alwaysApply: true only if this promotion should override all others

3. Verify Tax Rate Configuration

The tax rate comes from the linked price list, not the promotion itself. Ensure the price list has the correct taxRate configured for your market.

4. Use Descriptive Names

Internal names should clearly indicate the pricing strategy:

  • Good: "CostPlus25_Outlet_NOR"
  • Bad: "Promo1"

5. Test Calculations Before Activation

Verify the formula produces expected prices:

  • Check a sample of products with known cost prices
  • Verify the tax rate is applied correctly
  • Ensure the calculated price is lower than the original catalog price

6. Consider Multi-Currency Scenarios

If your price list uses costInPriceListCurrency, ensure values are populated for the correct currency. The system prefers costInPriceListCurrency over cost when available.

7. Monitor Price Updates

After creating or modifying a Cost Price promotion, the system asynchronously updates product prices in the catalog. The totalHits and lastPriceUpdate fields on the promotion track the progress of this update.

8. Set Realistic Date Ranges

Always set activeTo dates to avoid promotions running indefinitely. For seasonal clearance, use precise date ranges.


Troubleshooting

Promotion Not Generating Prices

Check:

  1. Is the promotion within its activeFrom and activeTo dates?
  2. Is priceListId set and pointing to a valid price list?
  3. Does the price list contain cost prices for the target products?
  4. Do the cost prices have values greater than 0?
  5. Are markets specified on the promotion?
  6. If using orderTypes, note that promotions with order types do not generate product prices automatically

Solution: Verify the price list contains PriceListItems with matching skuId or productId values. Check that cost or costInPriceListCurrency is greater than 0.

Calculated Price Higher Than Original

Problem: No discount appears because the cost-based price exceeds the catalog price.

Check:

  1. Is the markup percentage too high for the product's cost-to-retail ratio?
  2. Is the tax rate in the price list correct?
  3. Is the cost price in the correct currency?

Solution: The promotion only applies a discount when the calculated price is lower than the original catalog price. Adjust the markup percentage or verify cost prices.

Discount Not Applied at Checkout

Check:

  1. Does the order line have isExcludedFromPromotions set to true?
  2. Is another non-combinable promotion already applied to the same product?
  3. Does the product's SKU match a skuId in the price list?
  4. Is the order's market included in the promotion's markets list?

Solution: Cost Price promotions cannot be combined with other promotions. If another promotion has already been applied, the Cost Price promotion will not stack. Use alwaysApply: true if this promotion should override combination rules.

Products Not Matching Filters

Check:

  1. Verify products are in the specified categories
  2. Ensure brand names match (case-insensitive)
  3. For property filters, confirm products have the expected property key-value pairs
  4. Check that products are not excluded by excludedCategories, excludedBrands, excludedProducts, or excludedProperties
  5. Verify products have excludeFromPromotions set to false

Price List Currency Mismatch

Problem: Calculated prices seem incorrect or unexpected.

Check:

  1. Verify the price list's currencyCode matches the market currency
  2. If using costCurrencyCode, check the costCurrencyExchangeRate is correct
  3. Verify whether costInPriceListCurrency or cost is being used (system prefers costInPriceListCurrency when > 0)

API Response Models

Success Response (Create)

{
  "message": "Promotion 7f8d9e1a-3b4c-5d6e-8f0a-1b2c3d4e5f6a added, prices updated: 150",
  "statusCode": 200
}

Error Response

{
  "error": "Validation error message",
  "statusCode": 400
}

Additional Resources

  • Promotion Types Overview: See the Promotions Overview for a summary of all promotion types
  • Price Lists: Cost Price promotions require a price list with cost prices. Ensure your price list is configured before creating the promotion
  • Category/Brand Filters: The same filter model is used across all order line promotion types. See MultiBuy API Reference for detailed filter documentation
  • Date Formats: Use ISO 8601 format (e.g., 2026-01-01T00:00:00Z)

Support

For questions or issues:

  1. Check this documentation
  2. Review the troubleshooting section
  3. Examine API error messages for validation details
  4. Contact your Omnium support team

Document Version: 1.0 Last Updated: 2026 API Version: Compatible with Omnium OMS .NET 10.0+

On this page