- Promotions, sale prices, and discounts
Promotions
Custom rule-based expressions for order promotions provide extensive flexibility to meet diverse business requirements. This implementation of Flexibility over Features enables developers to create customized if-then statements that solve more scenarios than fixed promotion types.
Promotion structure
Core components
Every promotion requires two expressions:
-
EligibleExpression: Evaluates order state- Returns true/false
- Determines promotion applicability
-
ValueExpression: Calculates discount- Returns monetary value
- Subtracts from order subtotal
Available properties
order: Matches Order model fromv1/orders- Includes extended properties (xp)
items: Provides collection functions
Collection functions
Line item operations
items.any(): True if any item matches filteritems.all(): True if all items match filteritems.quantity(): Sum of matching quantitiesitems.count(): Number of matching line itemsitems.total(): Dollar amount comparison
Product categorization
product.incategory(): Direct category assignmentproduct.inparentcategory(): Category or child assignment
Array operations
contains(): Value exists in arraycount(): Matching array itemsany(): Any array item matchesall(): All array items match
Property operations
in(): Value exists in list- Supports comma-delimited lists
Implementation examples
Array operations
Expression operators
Comparison operators
- Equal:
= - Less than:
< - Greater than:
> - Less/equal:
<= - Greater/equal:
>=
Logical operators
- And:
and - Or:
or - Not:
not
Mathematical operators
- Addition:
+ - Subtraction:
- - Multiplication:
* - Division:
/ - Modulo:
%
Helper functions
Minimum value
- Returns smaller argument
- Type conversion rules apply
- Integer vs decimal handling
Maximum value
- Returns larger argument
- Type conversion rules apply
- Integer vs decimal handling
Conditional logic
- Evaluates multiple conditions
- Returns matching value
- Last parameter is default
Rounding
- Rounds to specified decimals
- Supports expressions
- Precise control
Promotion limits
Line item promotions
Requires LineItemLevel: true
Item limit
ItemLimitPerOrder: Maximum items- Applies discount per item
- Excludes quantity limit
Quantity limit
QuantityLimitPerOrder: Maximum quantity- Applies discount per unit
- Excludes item limit
Sort order
ItemSortBy: Property-based sorting- Supports descending with
! - Includes extended properties
- Default:
DateAddedascending
Example configuration
30% off least expensive 3 items over $50:
Common scenarios
Order-level discounts
Product-specific discounts
Category discounts
Quantity-based discounts
BOGO (scales with quantity)
User-based discounts
Advanced scenarios
Implementation notes
Limitations
- Expression length: 400 characters
- Optimize for efficiency
- Evaluated at application and submit
Requirements
- Order history requires Premium Search
- Proper promotion assignments
- User access via
GET v1/me/promotions
Promotion enhancements
OrderCloud Promotions have been enhanced with new properties and endpoints to provide greater flexibility in promotion management and application.
New properties
AutoApply property
Default value: false
This property enables:
- Automatic promotion application
- Priority-based application order
- Controlled promotion sequencing
Active property
Default value: true
This property controls:
- Promotion evaluation status
- Buyer user access
- Historical record keeping
Behavior:
- Inactive promotions (
Active = false):- Not evaluated for
.../applypromotions - Not evaluated for
.../eligiblepromotions - Not returned from
v1/me/promotions - Removed from unsubmitted orders upon deactivation
- Remain accessible via administrative endpoints
- Available for future reactivation
- Not evaluated for
Priority property
Value type: Nullable
This property enables:
- Controlled promotion application order
- Flexible priority values
- Sequential promotion processing
Implementation notes:
- No strict sequencing rules
- Used by
applypromotionsandrefreshpromotions - Determines evaluation order
New endpoints
Eligible promotions endpoints
v1/orders/{direction}/{orderID}/eligiblepromotions and v1/cart/eligiblepromotions
These endpoints support:
- Listing eligible promotions for orders
- Displaying promo codes during checkout
- Enhanced promotion-based UI features
Refresh promotions endpoints
v1/orders/{direction}/{orderID}/refreshpromotions and v1/cart/refreshpromotions
These endpoints handle:
Automatic promotion application
- Applies eligible AutoApply promotions
- Sorts by Priority value
- Processes null Priority values last
- Limits to 100 promotions per API call
Promotion removal
- Removes ineligible applied promotions
- Handles CanCombine conflicts
- Processes Priority-based removals
Promotion recalculation
- Recalculates existing promotion discounts
- Updates order totals
- Maintains promotion integrity
Response details
Returns arrays of:
- PromosAdded: Newly applied promotions
- PromosRemoved: Removed promotions
Note: Prefer /refreshpromotions over /applypromotions for most use cases.
Apply promotions endpoints
v1/orders/{direction}/{orderID}/applypromotions and v1/cart/applypromotions
These endpoints provide:
Automatic application
- Processes eligible AutoApply promotions
- Sorts by Priority value
- Handles null Priority values last
- Limits to 100 promotions per call
Response format
Returns the complete Order object with:
- Applied promotions
- Updated totals
- Order details
Line item-level promotions
Promotions have become one of OrderCloud's more popular features, largely due to flexibility of rules-based expressions in determining both the eligibility and value of a promotion relative to an order. Today we're taking this capability a step farther by introducing the ability to associate a promotion directly with one or more line items on an order.
Benefits
Currently, all promotional discounts "live" at the order level. Expressions can make certain item-level assertions (e.g. items.any(...)) and calculations (e.g. items.total(...)), so you may be able to infer which line items triggered which discounts by referring back to the rule expressions, but we've heard multiple requests to break out discount amounts by the items they apply to. A couple use cases cited: making it easier to calculate item-level tax and partial returns. Who wants to reverse-engineer the rules engine to figure these out?
Implementation
To remove any ambiguity (a central theme of this feature), you must first declare whether a promotion applies at the order level or line item level. Do this by setting Promotion.LineItemLevel to true or false. There's also 2 new read-only fields on the LineItem model: LineSubtotal and PromotionDiscount. The existing LineTotal field is simply the former minus the latter. (Order.PromotionDiscount still reflects the total of all item-level and order-level discounts, not just the latter.) Also, the models you get back in a call to GET v1/orders/{direction}/{id}/promotions will contain a LineItemID field, which will be null in the case of order-level promos. Together, these enhancements should give you what you need to easily and unambiguously associate specific promotions and discount amounts with specific line items.
Expression syntax
The existing items functions aren't quite enough to determine which item(s) to associate with a promo. Simple example: buy product X and get product Y for free. You can imagine writing your EligibleExpression with a pair of items.any, and it'll work, but we won't know which of the 2 items to tie the discount to.
Enter the new item (singular) token. When used in an EligibleExpression, think of it as sort of a selector of the line item (or multiple line items) that you want the promo applied to. Any property of the full-blown LineItem model is valid on item in an expression, as is the incategory function. In the example above, the EligibleExpression would be:
Now the discount will be tied unambiguously to lines item(s) containing product Y, fulfilling the original intent. As you can see, items is still allowed in this context, but it's used to assert "other" parts of the order, not to identify the item(s) to tie the promo to. You could do order-level assertions here too, e.g. order.Total > 100.
For line item-level promos, item is required in EligibleExpression and optional in ValueExpression. For order-level promos, it's not allowed for either.
Kudos and bonus points if you already thought it through this far, but let's take our example over the finish line by specifying the ValueExpression. Here we can use our item token, which has already "selected" product Y, and just specify the price of one of them. Easy enough: