Setup Discount Rules

Download skillThe skill is a reference md and part of wix-manage skill. You can use the following command to add the full wix-manage skill to your project:
Copy

Prerequisites

  • Wix Stores (or another eCommerce business solution) installed on the site
  • At least one product in the catalog

Required APIs


Critical: discounts structure

The API always returns the full normalized structure. Never assume a simplified form. Each discount entry looks like:

Copy

When updating a rule, always use the discounts array as returned from the query/get, modifying only the specific fields you need. Do not reconstruct from scratch unless creating a new rule.


Step 1: Query existing discount rules

Endpoint: POST https://www.wixapis.com/ecom/v1/discount-rules/query

Paging: This API uses cursor paging (cursorPaging), not offset paging. Using paging instead of cursorPaging will fail.

Request — list all rules:

Copy

Request — find by name (exact match):

Copy

Filterable fields: id, name, active, revision, created_date, updated_date, active_time_info.start, active_time_info.end

Response:

Copy

Note existing rules and their scopes to avoid stacking conflicts.


Step 2: Create a percentage discount rule

Endpoint: POST https://www.wixapis.com/ecom/v1/discount-rules

Request — 20% off all products:

Copy

Request — 15% off a specific collection:

Copy

Step 3: Create a fixed-amount discount rule

Request — $5 off specific products:

Copy

Step 4: Update a discount rule

Always fetch the rule first (via Get or Query), then modify only the fields you need. The mask field tells the API which fields to update — omit it to replace all writable fields.

Endpoint: PATCH https://www.wixapis.com/ecom/v1/discount-rules/{discountRule.id}

Required: discountRule.id, discountRule.revision (must match current revision)

Request — change percentage on an existing rule (full discounts replacement):

Copy

Request — change only active status (field mask for partial update):

Copy

Step 5: Find by name and update (complete pattern)

The safe pattern for "find a rule by name and update its percentage":

  1. Query with name filter → get the rule's id, revision, and discounts array
  2. Modify only the discount.percentage inside each discount entry, keeping all other fields intact
  3. PATCH with the modified discounts and mask: { paths: ["discounts"] }

Step 5a — Query by name:

Copy

Extract from response: discountRules[0].id, discountRules[0].revision, discountRules[0].discounts

Step 5b — Update percentage (modify the returned discounts in-place):

Take the discounts array from the query response and update only discount.percentage on each entry:

Copy

Important: Copy targetType, specificItemsInfo.scopes verbatim from the query response — do not reconstruct them. Only change discount.discountType and discount.percentage/discount.fixedAmount.


Step 6: Deactivate or delete a discount rule

To deactivate without deleting:

Copy

To delete permanently:

Endpoint: DELETE https://www.wixapis.com/ecom/v1/discount-rules/{discountRuleId}


Key field rules

FieldRequiredNotes
nameYesInternal name for the rule. Filterable in query.
activeYesWhether the rule is currently applied
activeTimeInfo.startNoISO 8601 start time. Omit for immediate activation
activeTimeInfo.endNoISO 8601 end time. Omit for no expiration
discounts[].targetTypeYesAlways "SPECIFIC_ITEMS" for standard rules
discounts[].specificItemsInfo.scopes[]YesArray of scope objects — see Scope types below
discounts[].discount.discountTypeYes"PERCENTAGE" or "FIXED_AMOUNT" or "FIXED_PRICE"
discounts[].discount.percentageIf PERCENTAGEInteger 1-100
discounts[].discount.fixedAmountIf FIXED_AMOUNTDecimal string (e.g., "5.00")
settings.appliesToYes on createAlways "ALL_ITEMS"
revisionOn update/deleteMust match current value — fetch first
mask.paths[]On updateRecommended — list fields being changed (e.g., ["discounts"], ["active"])

Scope types

Scopetypeid prefixWhen to use
All products"CATALOG_ITEM"all_<appId>catalogItemFilter.catalogAppId only, no catalogItemIds
Specific products"CATALOG_ITEM"specific_<appId>catalogItemFilter.catalogAppId + catalogItemFilter.catalogItemIds
Collection"CUSTOM_FILTER"collections_<appId>customFilter.appId + customFilter.params.collectionIds

Store catalog app ID (required in all scopes): 215238eb-22a5-4c36-9e7b-e7c08025e04e

Recommendation → API Mapping

When creating a discount rule from a recommendation output, use this mapping to convert the recommendation's simplified JSON into the actual Discount Rules API payload.

Constants

  • Store catalog app ID: 215238eb-22a5-4c36-9e7b-e7c08025e04e — used in all scope constructions below.
  • Initial state: Recommendations create rules as active: false with status: "PENDING". The merchant must approve before the rule goes live.

Scope mapping

The recommendation's scope field maps to the API's internal scope structure. The scope ID uses a prefix convention:

Recommendation scopeAPI scope typeScope ID prefixHow to build
SITECATALOG_ITEMall_Set catalogItemFilter.catalogAppId to the store catalog app ID. No item IDs.
ITEMSCATALOG_ITEMspecific_Set catalogItemFilter.catalogAppId + catalogItemFilter.catalogItemIds to the product UUIDs from productIds.
CATEGORYCUSTOM_FILTERcollections_Set customFilter.appId to the store catalog app ID + customFilter.params.collectionIds to the category UUIDs from categoryIds.

Example — SITE scope:

Copy

Example — ITEMS scope (with product IDs):

Copy

Example — CATEGORY scope (with collection IDs):

Copy

Discount type mapping

Recommendation discountTypeAPI field to setValue format
PERCENTAGEdiscount.percentageInteger (e.g., 15)
FIXED_AMOUNTdiscount.fixedAmountString (e.g., "5.00")
FIXED_PRICEdiscount.fixedPriceString (e.g., "29.99")

All discount entries use targetType: "SPECIFIC_ITEMS" with the scope wrapped in specificItemsInfo.scopes[].

Trigger mapping (conditions)

Triggers determine WHEN the discount activates. They are built from the recommendation's conditions fields. If no conditions exist (both minSubTotal and minItemQuantity are 0), do NOT set a trigger — the discount applies unconditionally.

ConditionTrigger typeHow to build
minItemQuantity > 0 onlyITEM_QUANTITY_RANGESet itemQuantityRange.from to the value. No upper bound. Include the same scope as the discount target.
minSubTotal > 0 onlySUBTOTAL_RANGESet subtotalRange.from to the value as a string. No upper bound. Include the same scope.
Both conditions > 0ANDCombine both triggers in and.triggers[] array.
Neither conditionNo triggerLeave trigger field unset entirely.

Example — minSubTotal trigger (upsell boost: spend $200+):

Copy

Example — minItemQuantity trigger (bundle: buy 3+):

Copy

Example — AND trigger (both conditions):

Copy

Date handling

Recommendation fieldAPI mapping
startDate is a date string (e.g., "2026-06-01")Convert to ISO 8601 timestamp: activeTimeInfo.start
startDate is empty ""Default to current time (now)
endDate is a date stringConvert to ISO 8601 timestamp: activeTimeInfo.end
endDate is empty ""Omit activeTimeInfo.end — rule has no expiration

Settings

All recommendation-created rules use these fixed settings:

Copy

Error Handling

ErrorCauseFix
DISCOUNT_RULE_NOT_FOUNDThe discount rule ID doesn't existRe-query discount rules to get current IDs
REVISION_MISMATCHThe revision doesn't match the current versionRe-fetch the rule to get the latest revision, then retry
INVALID_DISCOUNT_TYPEUnsupported discount typeUse PERCENTAGE or FIXED_AMOUNT
Both productIds and categoryIds setScope mutual exclusivity violationUse only one: ITEMS with productIds OR CATEGORY with categoryIds
productIds empty when scope is ITEMSMissing required IDsQuery products and provide at least 1 product UUID
categoryIds empty when scope is CATEGORYMissing required IDsCall getCategoryIds to convert category names to GUIDs

References

Did this help?