> Portal Navigation:
> 
> - Append `.md` to any URL under `https://dev.wix.com/docs/` to get its markdown version.
> - Pages are either content pages (article or reference text) or menu pages (a list of links to child pages).
> - To get a menu page, truncate any URL to a parent path and append `.md` (e.g. `https://dev.wix.com/docs/sdk.md`, `https://dev.wix.com/docs/sdk/core-modules.md`).
> - Top-level index of all portals: https://dev.wix.com/docs/llms.txt
> - Full concatenated docs: https://dev.wix.com/docs/llms-full.txt

## Resource: Pricing: Create Coupon

## Article: Pricing: Create Coupon

## Article Link: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/skills/pricing-create-coupon.md

## Article Content:

# 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.md) — `POST /v2/coupons`
- [Update Coupon](https://dev.wix.com/docs/api-reference/business-solutions/coupons/coupons/update-a-coupon.md) — `PATCH /v2/coupons/{id}`
- [Query Coupons](https://dev.wix.com/docs/api-reference/business-solutions/coupons/coupons/query-coupons.md) — `POST /v2/coupons/query`
- [Delete Coupon](https://dev.wix.com/docs/api-reference/business-solutions/coupons/coupons/delete-a-coupon.md) — `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",
          "group": {
            "name": "product"
          }
        },
        "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.
- **% sanity** — > 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.md) → "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",
      "group": {
        "name": "product"
      }
    },
    "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",
      "group": {
        "name": "product"
      }
    },
    "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.name` | `group.entityId` |
|---|---|---|---|
| All store products | `"stores"` | `"product"` | Omit (applies to all) |
| Specific product | `"stores"` | `"product"` | Product UUID |
| Specific collection | `"stores"` | `"collection"` | 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", "group": { "name": "product" } }` (all products, no entityId) |
| `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", "group": { "name": "product" } }` for site-wide, 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.md)
- [Valid Scope Values](https://dev.wix.com/docs/api-reference/business-solutions/coupons/coupons/valid-scope-values.md)