All skills
wix avatar

/wix-manage

@4895cc9 official
by Wix.comwix/skills33 stars
33

REST recipes to configure and manage a Wix site's business solutions — stores, bookings, payments, CMS, and more. Open the matching recipe for the exact endpoint, method, and payload before calling — never guess a Wix API, never write Wix dashboard URL from memory. Routes to: stores, bookings, get-paid, CMS, contacts, forms, media, app-installation, pricing-plans, restaurants, ricos rich-content, sites, blog, calendar, domains, events, site-properties, ecommerce, marketing, google-ads, google-business-profile, analytics, accessibility, seo, dashboard-navigation.

Use this Skill: https://skilld.dev/gh/wix/skills/wix-manage

This session only. Nothing lands on disk.

referencesecommercepricing-promotionsecom-pricing-create-discount-rule.md

≈5k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Setup Discount Rules

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, values wrapper included. Never assume a simplified form. Each entry of discounts.values looks like:

{
  "targetType": "SPECIFIC_ITEMS",
  "specificItemsInfo": {
    "scopes": [
      {
        "id": "all_215238eb-22a5-4c36-9e7b-e7c08025e04e",
        "type": "CATALOG_ITEM",
        "catalogItemFilter": {
          "catalogAppId": "215238eb-22a5-4c36-9e7b-e7c08025e04e"
        }
      }
    ]
  },
  "discountType": "PERCENTAGE",
  "percentage": 20
}

When updating a rule, always reuse the discounts.values entries 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

Request — list all rules:

{
  "query": {
    "cursorPaging": {
      "limit": 100
    }
  }
}

Request — find by name (exact match):

{
  "query": {
    "filter": {
      "name": { "$eq": "Summer Sale" }
    },
    "cursorPaging": { "limit": 10 }
  }
}

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

Response:

{
  "discountRules": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "revision": "1",
      "name": "Summer Sale 10%",
      "active": true,
      "activeTimeInfo": {
        "start": "2026-06-01T00:00:00.000Z",
        "end": "2026-08-31T23:59:59.000Z"
      },
      "discounts": { "values": [
        {
          "targetType": "SPECIFIC_ITEMS",
          "specificItemsInfo": {
            "scopes": [
              {
                "id": "all_215238eb-22a5-4c36-9e7b-e7c08025e04e",
                "type": "CATALOG_ITEM",
                "catalogItemFilter": {
                  "catalogAppId": "215238eb-22a5-4c36-9e7b-e7c08025e04e"
                }
              }
            ]
          },
          "discountType": "PERCENTAGE",
          "percentage": 10
        }
      ] }
    }
  ],
  "pagingMetadata": {
    "cursors": {},
    "hasNext": false
  }
}

Note existing rules and their scopes to avoid stacking conflicts.


Guardrails — run before creating or updating any discount

These checks guard every discount creation (rule or coupon). Run them before the create/update calls below. User input overrides all caps — if the merchant explicitly asks for a value beyond a threshold, honor it and document the override in your reasoning.

Conflict / stacking (uses the Step 1 query of active rules; for coupons, also query active coupons):

  • Same-scope overlap — a new rule conflicts with an existing active rule when scopes overlap (both CATALOG; CATALOG vs COLLECTION; same COLLECTION/SPECIFIC_PRODUCTS id). Wix stacks automatic rules → warn and offer to deactivate the existing one.
  • Time overlap — overlapping activeTimeInfo on the same scope (existingStart < newEnd AND existingEnd > newStart) → warn about the overlap window.
  • Cross-mechanism (automatic + coupon) — automatic discounts and coupons both apply at checkout. If creating a rule, query active coupons on overlapping scope (and vice-versa); warn with the combined effective discount. (Only one coupon per checkout, but automatic rules are unlimited.)

Margin / sanity:

  • Global cap — default max discount 25%; flag anything higher (proceed only on explicit request).
  • Minimum margin — default floor 15%; if cost data is available, effective_margin = (price − cost − discount_amount) / price × 100 must stay ≥ 15% (block + explain otherwise).
  • % sanity — > 50% warn (show a $100 → $(100−pct) example); = 100% block unless confirmed ("makes the product free"); > 100% always block.
  • Stacking margin — when a new discount overlaps existing active ones, evaluate the combined discount against the cap and margin floor, not just the new one in isolation.
Scenario Action
Discount ≤ 25% and margin ≥ 15%, no scope overlap Proceed
Scope/time/cross-mechanism overlap Warn; offer to deactivate existing or confirm stacking
Discount 26–50% (no override) Warn, ask to confirm
Discount > 50% Warn with $ example, confirm
Discount = 100% Block unless confirmed
Discount > 100% Block always
Combined/stacked discount exceeds cap or margin floor Warn about cumulative effect
Any threshold, explicit user override Proceed, document the override in reasoning

When a discount isn't applying as expected, see Troubleshoot: Discount Not Applying.


Step 2: Create a percentage discount rule

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

Request — 20% off all products:

{
  "discountRule": {
    "name": "Flash Sale 20% Off",
    "active": true,
    "activeTimeInfo": {
      "start": "2026-05-01T00:00:00.000Z",
      "end": "2026-05-03T23:59:59.000Z"
    },
    "discounts": { "values": [
      {
        "targetType": "SPECIFIC_ITEMS",
        "specificItemsInfo": {
          "scopes": [
            {
              "id": "all_215238eb-22a5-4c36-9e7b-e7c08025e04e",
              "type": "CATALOG_ITEM",
              "catalogItemFilter": {
                "catalogAppId": "215238eb-22a5-4c36-9e7b-e7c08025e04e"
              }
            }
          ]
        },
        "discountType": "PERCENTAGE",
        "percentage": 20
      }
    ] }
  }
}

Request — 15% off a specific collection:

{
  "discountRule": {
    "name": "Summer Collection Sale",
    "active": true,
    "discounts": { "values": [
      {
        "targetType": "SPECIFIC_ITEMS",
        "specificItemsInfo": {
          "scopes": [
            {
              "id": "collections_215238eb-22a5-4c36-9e7b-e7c08025e04e",
              "type": "CUSTOM_FILTER",
              "customFilter": {
                "appId": "215238eb-22a5-4c36-9e7b-e7c08025e04e",
                "params": {
                  "collectionIds": ["collection-uuid-here"]
                }
              }
            }
          ]
        },
        "discountType": "PERCENTAGE",
        "percentage": 15
      }
    ] }
  }
}

Step 3: Create a fixed-amount discount rule

Request — $5 off specific products:

{
  "discountRule": {
    "name": "$5 Off Selected Items",
    "active": true,
    "discounts": { "values": [
      {
        "targetType": "SPECIFIC_ITEMS",
        "specificItemsInfo": {
          "scopes": [
            {
              "id": "specific_215238eb-22a5-4c36-9e7b-e7c08025e04e",
              "type": "CATALOG_ITEM",
              "catalogItemFilter": {
                "catalogAppId": "215238eb-22a5-4c36-9e7b-e7c08025e04e",
                "catalogItemIds": ["product-uuid-here"]
              }
            }
          ]
        },
        "discountType": "FIXED_AMOUNT",
        "fixedAmount": "5.00"
      }
    ] }
  }
}

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):

{
  "discountRule": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "revision": "1",
    "discounts": { "values": [
      {
        "targetType": "SPECIFIC_ITEMS",
        "specificItemsInfo": {
          "scopes": [
            {
              "id": "all_215238eb-22a5-4c36-9e7b-e7c08025e04e",
              "type": "CATALOG_ITEM",
              "catalogItemFilter": {
                "catalogAppId": "215238eb-22a5-4c36-9e7b-e7c08025e04e"
              }
            }
          ]
        },
        "discountType": "PERCENTAGE",
        "percentage": 25
      }
    ] }
  },
  "mask": { "paths": ["discounts"] }
}

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

{
  "discountRule": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "revision": "2",
    "active": false
  },
  "mask": { "paths": ["active"] }
}

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.values entries
  2. Modify only percentage on each entry, keeping all other fields intact
  3. PATCH with the modified discounts and mask: { paths: ["discounts"] }

Step 5a — Query by name:

POST https://www.wixapis.com/ecom/v1/discount-rules/query
{
  "query": {
    "filter": { "name": { "$eq": "My Rule Name" } },
    "cursorPaging": { "limit": 1 }
  }
}

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.values entries from the query response and update only percentage on each entry:

PATCH https://www.wixapis.com/ecom/v1/discount-rules/{id}
{
  "discountRule": {
    "id": "<id from query>",
    "revision": "<revision from query>",
    "discounts": { "values": [
      {
        "targetType": "SPECIFIC_ITEMS",
        "specificItemsInfo": { "<scopes unchanged from query response>" },
        "discountType": "PERCENTAGE",
        "percentage": 10
      }
    ] }
  },
  "mask": { "paths": ["discounts"] }
}

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


Step 6: Deactivate or delete a discount rule

To deactivate without deleting:

{
  "discountRule": {
    "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
    "revision": "2",
    "active": false
  },
  "mask": { "paths": ["active"] }
}

To delete permanently:

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


Key field rules

Field Required Notes
name Yes Internal name for the rule. Filterable in query.
active Yes Whether the rule is currently applied
activeTimeInfo.start No ISO 8601 start time. Omit for immediate activation
activeTimeInfo.end No ISO 8601 end time. Omit for no expiration
discounts.values[].targetType Yes Always "SPECIFIC_ITEMS" for standard rules
discounts.values[].specificItemsInfo.scopes[] Yes Array of scope objects — see Scope types below
discounts.values[].discountType Yes "PERCENTAGE" or "FIXED_AMOUNT" or "FIXED_PRICE" — at the entry root, not inside a discount object
discounts.values[].percentage If PERCENTAGE Number 0.1-100
discounts.values[].fixedAmount If FIXED_AMOUNT Decimal string (e.g., "5.00")
revision On update/delete Must match current value — fetch first
mask.paths[] On update Recommended — list fields being changed (e.g., ["discounts"], ["active"])

Scope types

Scope type id prefix When 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 scope API scope type Scope ID prefix How to build
SITE CATALOG_ITEM all_ Set catalogItemFilter.catalogAppId to the store catalog app ID. No item IDs.
ITEMS CATALOG_ITEM specific_ Set catalogItemFilter.catalogAppId + catalogItemFilter.catalogItemIds to the product UUIDs from productIds.
CATEGORY CUSTOM_FILTER collections_ Set customFilter.appId to the store catalog app ID + customFilter.params.collectionIds to the category UUIDs from categoryIds.

Example — SITE scope:

{
  "scope": {
    "id": "all_215238eb-22a5-4c36-9e7b-e7c08025e04e",
    "type": "CATALOG_ITEM",
    "catalogItemFilter": {
      "catalogAppId": "215238eb-22a5-4c36-9e7b-e7c08025e04e"
    }
  }
}

Example — ITEMS scope (with product IDs):

{
  "scope": {
    "id": "specific_215238eb-22a5-4c36-9e7b-e7c08025e04e",
    "type": "CATALOG_ITEM",
    "catalogItemFilter": {
      "catalogAppId": "215238eb-22a5-4c36-9e7b-e7c08025e04e",
      "catalogItemIds": ["product-uuid-1", "product-uuid-2"]
    }
  }
}

Example — CATEGORY scope (with collection IDs):

{
  "scope": {
    "id": "collections_215238eb-22a5-4c36-9e7b-e7c08025e04e",
    "type": "CUSTOM_FILTER",
    "customFilter": {
      "appId": "215238eb-22a5-4c36-9e7b-e7c08025e04e",
      "params": {
        "collectionIds": ["collection-uuid-1"]
      }
    }
  }
}

Discount type mapping

Recommendation discountType API field to set Value format
PERCENTAGE discounts.values[].percentage Integer (e.g., 15)
FIXED_AMOUNT discounts.values[].fixedAmount String (e.g., "5.00")
FIXED_PRICE discounts.values[].fixedPrice String (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.

Condition Trigger type How to build
minItemQuantity > 0 only ITEM_QUANTITY_RANGE Set itemQuantityRange.from to the value. No upper bound. Include the same scope as the discount target.
minSubTotal > 0 only SUBTOTAL_RANGE Set subtotalRange.from to the value as a string. No upper bound. Include the same scope.
Both conditions > 0 AND Combine both triggers in and.triggers[] array.
Neither condition No trigger Leave trigger field unset entirely.

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

{
  "trigger": {
    "triggerType": "SUBTOTAL_RANGE",
    "subtotalRange": {
      "from": "200",
      "scopes": [
        {
          "id": "all_215238eb-22a5-4c36-9e7b-e7c08025e04e",
          "type": "CATALOG_ITEM",
          "catalogItemFilter": {
            "catalogAppId": "215238eb-22a5-4c36-9e7b-e7c08025e04e"
          }
        }
      ]
    }
  }
}

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

{
  "trigger": {
    "triggerType": "ITEM_QUANTITY_RANGE",
    "itemQuantityRange": {
      "from": 3,
      "scopes": [
        {
          "id": "collections_215238eb-22a5-4c36-9e7b-e7c08025e04e",
          "type": "CUSTOM_FILTER",
          "customFilter": {
            "appId": "215238eb-22a5-4c36-9e7b-e7c08025e04e",
            "params": {
              "collectionIds": ["category-uuid"]
            }
          }
        }
      ]
    }
  }
}

Example — AND trigger (both conditions):

{
  "trigger": {
    "triggerType": "AND",
    "and": {
      "triggers": [
        {
          "triggerType": "ITEM_QUANTITY_RANGE",
          "itemQuantityRange": { "from": 2, "scopes": [/* same scope */] }
        },
        {
          "triggerType": "SUBTOTAL_RANGE",
          "subtotalRange": { "from": "100", "scopes": [/* same scope */] }
        }
      ]
    }
  }
}

Date handling

Recommendation field API 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 string Convert to ISO 8601 timestamp: activeTimeInfo.end
endDate is empty "" Omit activeTimeInfo.end — rule has no expiration

Error Handling

Error Cause Fix
DISCOUNT_RULE_NOT_FOUND The discount rule ID doesn't exist Re-query discount rules to get current IDs
REVISION_MISMATCH The revision doesn't match the current version Re-fetch the rule to get the latest revision, then retry
INVALID_DISCOUNT_TYPE Unsupported discount type Use PERCENTAGE or FIXED_AMOUNT
Expected an object (400) discounts sent as a bare array Wrap the entries — "discounts": { "values": [ … ] }
DISCOUNT_TYPE_AND_DISCOUNT_VALUE_MISMATCH discountType and the value field nested inside a discount object Move both to the discount entry root, alongside targetType
Both productIds and categoryIds set Scope mutual exclusivity violation Use only one: ITEMS with productIds OR CATEGORY with categoryIds
productIds empty when scope is ITEMS Missing required IDs Query products and provide at least 1 product UUID
categoryIds empty when scope is CATEGORY Missing required IDs Call getCategoryIds to convert category names to GUIDs

References

Source: SKILL.md on GitHub

1 warning1d4 checks · Risk SAFE
  • Gen Agent Trust Hub1d

    The wix-manage skill is an extensive collection of management recipes for Wix sites, covering business solutions such as eCommerce, Bookings, SEO, and site provisioning. It utilizes official Wix REST endpoints and incorporates robust safety patterns, including mandatory user confirmation for sensitive operations and careful validation of site data before mutation.

  • Socket1d

    No alerts

  • Snyk1d

    Risk: MEDIUM · 1 issue

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 4895cc9. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated yesterday
compatibility
Requires Wix REST API access (API key or OAuth).
  • wix
  • rest-api
  • ecommerce
  • bookings
  • cms
  • contacts
  • blog
  • domains
  • restaurants
  • site-configuration
  • api-integration

README badge

README badge for wix/skills/wix-manage

REST API operations for configuring Wix business solutions including stores, bookings, CMS, contacts, domains, and ecommerce. Routes to site setup, entity management (products, services, staff), bulk administrative operations, and server-to-server integrations across Wix's business app ecosystem.

Generated from the current SKILL.md.

Do I need API credentials to use these recipes?
Yes. The skill requires Wix REST API access via either an API key or OAuth token to execute any management operations.
Can I use these recipes to display data on my site frontend?
No. These recipes are for backend REST API operations only — site configuration, entity management, and administrative tasks. They do not cover frontend development or displaying data to users.
What business domains do these recipes cover?
The skill covers stores, bookings, payments, CMS, contacts, forms, media, apps, pricing plans, restaurants, rich content, sites, blogs, calendars, domains, and site properties.
Do these recipes handle OAuth authentication with external services like Google Calendar?
Yes. The external calendar integration recipe covers OAuth-based setup with Google Calendar, Microsoft Outlook, and Apple Calendar for bidirectional event sync.

Generated from the current SKILL.md. These answers refresh after source changes.