← Files WixARCHIVED FILE

skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-create-coupon.md

12 KB · Oct 8, 2026 · 12:02 UTC

↓ Download file

See the change to this file →

---
name: "Pricing: Create Coupon"
description: "PREFERRED recipe for converting a COUPON recommendation (mechanism: COUPON) into a Wix coupon. Use THIS entry — NOT the legacy setup-coupons entry which is superseded. Maps scope/discountType/conditions to Coupons V2 API fields."
---
# Pricing: Create Coupon

> **This skill is the single source for coupon creation.** Do NOT load `…/skills/setup-coupons` — that legacy slug pre-dates the routing tree migration and its content has been merged into this file. If the WixREADME index surfaces it, ignore it.

## Prerequisites

- Wix Stores (or another eCommerce business solution) installed on the site

## Required APIs

- [Create Coupon](https://dev.wix.com/docs/api-reference/business-solutions/coupons/coupons/create-a-coupon) — `POST /v2/coupons`
- [Update Coupon](https://dev.wix.com/docs/api-reference/business-solutions/coupons/coupons/update-a-coupon) — `PATCH /v2/coupons/{id}`
- [Query Coupons](https://dev.wix.com/docs/api-reference/business-solutions/coupons/coupons/query-coupons) — `POST /v2/coupons/query`
- [Delete Coupon](https://dev.wix.com/docs/api-reference/business-solutions/coupons/coupons/delete-a-coupon) — `DELETE /v2/coupons/{id}`

---

## Step 1: Query existing coupons

Before creating a coupon, check for code conflicts and existing promotions on the same scope.

**Endpoint**: `POST https://www.wixapis.com/stores/v2/coupons/query`

**Request**:
```json
{
  "query": {
    "paging": {
      "limit": 100
    }
  }
}
```

**Response**:
```json
{
  "coupons": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "specification": {
        "name": "Summer Sale",
        "code": "SUMMER20",
        "percentOffRate": 20,
        "scope": {
          "namespace": "stores"
        },
        "startTime": 1717200000000,
        "expirationTime": 1719792000000,
        "usageLimit": 100,
        "limitPerCustomer": 1,
        "active": true
      },
      "numberOfUsages": 12,
      "expired": false
    }
  ]
}
```

Check for: duplicate codes, overlapping scopes with active coupons, and cross-mechanism stacking with active automatic discount rules.

### Guardrails — run before creating the coupon

- **Duplicate / conflicting code** — reject a code already in use.
- **Cross-mechanism stacking** — coupons stack with automatic discount rules at checkout. Query active discount rules on overlapping scope; if found, warn with the combined effective discount ("a 20% coupon during a 20% automatic sale = ~36% off"). Only one coupon applies per checkout, but automatic rules are unlimited.
- **% plausibility** — > 50% warn (show a $100 → $(100−pct) example); = 100% block unless confirmed; > 100% always block.
- **Margin** — if cost data is available, ensure the discount doesn't push price below cost; otherwise warn for > 40%.
- **User override** — explicit merchant values override these caps; document the override in your reasoning.

(The automatic-rule side of these checks lives in [Create Discount Rule](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/pricing-create-discount-rule) → "Guardrails".)

---

## Step 2: Create a percentage-off coupon

**Endpoint**: `POST https://www.wixapis.com/stores/v2/coupons`

**Request** — 15% off all store products:
```json
{
  "specification": {
    "name": "Spring Sale 15%",
    "code": "SPRING15",
    "percentOffRate": 15,
    "scope": {
      "namespace": "stores"
    },
    "startTime": 1714521600000,
    "usageLimit": 200,
    "limitPerCustomer": 1,
    "active": true
  }
}
```

**Response**:
```json
{
  "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
}
```

**Request** — 20% off a specific collection:
```json
{
  "specification": {
    "name": "Electronics Deal",
    "code": "ELEC20",
    "percentOffRate": 20,
    "scope": {
      "namespace": "stores",
      "group": {
        "name": "collection",
        "entityId": "collection-uuid-here"
      }
    },
    "startTime": 1714521600000,
    "expirationTime": 1717200000000,
    "usageLimit": 50,
    "limitPerCustomer": 1,
    "active": true
  }
}
```

**Request** — 10% off a specific product:
```json
{
  "specification": {
    "name": "VIP Product Discount",
    "code": "VIP10",
    "percentOffRate": 10,
    "scope": {
      "namespace": "stores",
      "group": {
        "name": "product",
        "entityId": "product-uuid-here"
      }
    },
    "startTime": 1714521600000,
    "limitPerCustomer": 1,
    "active": true
  }
}
```

---

## Step 3: Create a fixed-amount coupon

**Request** — $10 off all products:
```json
{
  "specification": {
    "name": "Save $10",
    "code": "SAVE10",
    "moneyOffAmount": 10,
    "scope": {
      "namespace": "stores"
    },
    "startTime": 1714521600000,
    "active": true
  }
}
```

---

## Step 4: Create a minimum subtotal coupon

Instead of targeting a scope, you can require a minimum cart subtotal. This is a **oneOf** with scope — you set EITHER `scope` OR `minimumSubtotal`, not both.

**Request** — 15% off orders over $100:
```json
{
  "specification": {
    "name": "Spend $100, Save 15%",
    "code": "SPEND100",
    "percentOffRate": 15,
    "minimumSubtotal": 100,
    "startTime": 1714521600000,
    "usageLimit": 500,
    "limitPerCustomer": 1,
    "active": true
  }
}
```

---

## Key field rules

| Field | Required | Notes |
|---|---|---|
| `name` | Yes | Display name shown to customers |
| `code` | Yes | Unique coupon code. Max 20 characters. Case-insensitive at checkout. |
| `startTime` | Yes | UNIX epoch in **milliseconds** (not seconds). E.g., `1714521600000` for 2024-05-01T00:00:00Z |
| `expirationTime` | No | UNIX epoch in milliseconds. Omit for no expiration. |
| `scope` OR `minimumSubtotal` | One required | **OneOf** — set scope to target items, OR minimumSubtotal for cart threshold. Cannot set both. Exception: freeShipping type ignores scope. |
| `usageLimit` | No | Total uses across all customers. Omit for unlimited. |
| `limitPerCustomer` | No | Max uses per customer. Omit for unlimited. |
| `limitedToOneItem` | No | If true, discount applies only to lowest-priced item when customer buys multiple. |
| `active` | No | Default `true`. Set `false` to create as draft. |

## Coupon types (oneOf — set exactly one)

| Type | Field | Value | Example |
|---|---|---|---|
| Percentage off | `percentOffRate` | Double (e.g., `15` for 15%) | `"percentOffRate": 15` |
| Fixed amount off | `moneyOffAmount` | Double (e.g., `10` for $10 off) | `"moneyOffAmount": 10` |
| Fixed price | `fixedPriceAmount` | Double (e.g., `29.99`) | `"fixedPriceAmount": 29.99` |
| Free shipping | `freeShipping` | Boolean `true` | `"freeShipping": true` |
| Buy X Get Y | `buyXGetY` | Object with `x` and `y` fields | `"buyXGetY": {"x": 2, "y": 1}` |

> **Note**: Free shipping as an **automatic discount rule** is NOT supported — use the `freeShipping` coupon type here, or configure a free-shipping rate via the Shipping Options API.

## Scope values for Wix Stores

| Scope target | `namespace` | `group` |
|---|---|---|
| All store products | `"stores"` | Omit the `group` field entirely — a present-but-empty `group: {}` is rejected the same as a populated one missing `entityId` |
| Specific product | `"stores"` | `{ "name": "product", "entityId": "<product UUID>" }` |
| Specific collection | `"stores"` | `{ "name": "collection", "entityId": "<collection UUID>" }` |

---

## Recommendation → Coupon API Mapping

When the recommendation output has `mechanism: "COUPON"`, use this mapping to convert it into a Coupons API payload.

### Scope mapping

| Recommendation `scope` | Coupon `scope` |
|---|---|
| `SITE` | `{ "namespace": "stores" }` (all products — omit `group` entirely) |
| `CATEGORY` | `{ "namespace": "stores", "group": { "name": "collection", "entityId": "<first categoryId>" } }` |
| `ITEMS` | `{ "namespace": "stores", "group": { "name": "product", "entityId": "<first productId>" } }` |

**Important limitation**: The Coupons API scope supports only **one entityId** (one product or one collection). If the recommendation targets multiple products or categories:
- For CATEGORY with multiple categoryIds: Create one coupon per collection, or pick the primary collection.
- For ITEMS with multiple productIds: Create one coupon per product, or use `minimumSubtotal` instead of `scope` if the intent is cart-level.

### Discount type mapping

| Recommendation `discountType` | Coupon field |
|---|---|
| `PERCENTAGE` | `"percentOffRate": <value>` |
| `FIXED_AMOUNT` | `"moneyOffAmount": <value>` |
| `FIXED_PRICE` | `"fixedPriceAmount": <value>` |

### Condition mapping

| Recommendation condition | Coupon approach |
|---|---|
| `minSubTotal > 0` | Use `minimumSubtotal` instead of `scope` (they are oneOf — cannot use both) |
| `minItemQuantity > 0` | **Not natively supported by Coupons API**. Mention in the coupon name (e.g., "Buy 3+, use code BUNDLE15") but the API cannot enforce item quantity. |
| `startDate` | Convert to UNIX epoch milliseconds: `Date.parse("2026-06-01") → 1748736000000`. Set as `startTime`. |
| `endDate` | Convert to UNIX epoch milliseconds. Set as `expirationTime`. |

### Code generation

| Recommendation field | Coupon field | Rules |
|---|---|---|
| `code` from recommendation | `specification.code` | Max 20 characters. Must be unique on the site. Suggest memorable, brand-relevant codes (e.g., `SUMMER25`, `SAVE15`, `VIP20`). |
| `usageLimit` from recommendation | `specification.usageLimit` | Total times the coupon can be used. `0` in recommendation → omit (unlimited). |
| `limitPerCustomer` from recommendation | `specification.limitPerCustomer` | Max per customer. `0` → omit (unlimited). Recommend setting to `1` for most campaigns. |

### Full mapping example

**Recommendation output**:
```json
{
  "mechanism": "COUPON",
  "scope": "CATEGORY",
  "categoryIds": ["electronics-collection-uuid"],
  "name": "Tech Insider Deal",
  "discountType": "PERCENTAGE",
  "discount": 20,
  "code": "TECH20",
  "usageLimit": 100,
  "limitPerCustomer": 1,
  "conditions": {
    "startDate": "2026-06-01",
    "endDate": "2026-06-30"
  }
}
```

**Coupon API request**:
```json
{
  "specification": {
    "name": "Tech Insider Deal",
    "code": "TECH20",
    "percentOffRate": 20,
    "scope": {
      "namespace": "stores",
      "group": {
        "name": "collection",
        "entityId": "electronics-collection-uuid"
      }
    },
    "startTime": 1748736000000,
    "expirationTime": 1751328000000,
    "usageLimit": 100,
    "limitPerCustomer": 1,
    "active": true
  }
}
```

### Key differences from Automatic Discounts

| Aspect | Automatic Discount (Discount Rules API) | Coupon (Coupons API) |
|---|---|---|
| Scope supports multiple items | Yes (multiple IDs in arrays) | No (one entityId per scope) |
| minSubTotal + scope together | Yes (scope + trigger) | No (oneOf — choose one) |
| minItemQuantity enforcement | Yes (ITEM_QUANTITY_RANGE trigger) | Not supported by API |
| Date format | ISO 8601 timestamps | UNIX epoch milliseconds |
| Created state | `active: false`, `status: PENDING` | `active: true` by default |
| Triggers/conditions | Separate trigger object with typed ranges | Only minimumSubtotal (simple threshold) |

---

## Error Handling

| Error | Cause | Fix |
|---|---|---|
| `"When scope or minimumSubtotal is not used - only FreeShipping coupon is allowed"` | Coupon sent without `scope` or `minimumSubtotal` | Add `scope: { "namespace": "stores" }` for site-wide (omit `group` — do not send `group: {}`, which is rejected identically), or set `minimumSubtotal` |
| Duplicate code | Another coupon uses the same code | Generate a different code |
| Invalid startTime | Value too low (must be epoch ms, not seconds) | Multiply by 1000 if in seconds |
| Both scope and minimumSubtotal set | These are oneOf — cannot use both | Choose scope OR minimumSubtotal |
| Code exceeds 20 characters | Code is too long | Shorten the code |

## References

- [Coupons API](https://dev.wix.com/docs/api-reference/business-solutions/coupons/coupons/create-a-coupon)
- [Valid Scope Values](https://dev.wix.com/docs/api-reference/business-solutions/coupons/coupons/valid-scope-values)

SHA-256: 12028332d6a3344b7cb9bacfe46158fc5e778f38277391b5c5c9b431b1ebf906