Promotions are automatic discounts applied at checkout without a code. Each promotion takes a **percentage** or **fixed** amount off and can target specific products or collections, run over a date range, and be prioritized and stacked against other promotions.

## List Promotions

```
GET /api/v1/promotions
```

### Query Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `limit` | `number` | 20 | Promotions per page (1-100) |
| `offset` | `number` | 0 | Promotions to skip |
| `active` | `boolean` | – | Filter by active status |
| `includeExpired` | `boolean` | – | Include promotions whose end date has passed |

### Response

```json
{
  "data": [
    {
      "id": "0191abc0-1234-7def-8000-000000000001",
      "name": "Summer Sale",
      "description": "20% off swimwear",
      "discountType": "percentage",
      "discountValue": 20,
      "startDate": "2024-06-01T00:00:00.000Z",
      "endDate": "2024-08-31T23:59:59.000Z",
      "active": true,
      "priority": 1000,
      "stackable": true,
      "minQuantity": 1,
      "maxQuantity": null,
      "color": "#f5f5dc",
      "productIds": [],
      "collectionIds": ["0191abc0-0000-7000-8000-000000000100"],
      "currencyAmounts": {},
      "createdAt": "2024-05-20T10:30:00.000Z",
      "updatedAt": "2024-05-20T10:30:00.000Z"
    }
  ],
  "meta": {
    "count": 1,
    "offset": 0,
    "limit": 20
  }
}
```

---

## Create Promotion

```
POST /api/v1/promotions
```

Creates an automatic discount. `endDate` must be after `startDate`. For `fixed` promotions on multi-currency stores, supply per-currency amounts via `currencyAmounts`.

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | `string` | Yes | Promotion name |
| `description` | `string` | No | Optional description |
| `discountType` | `"percentage"` \| `"fixed"` | Yes | Discount type |
| `discountValue` | `number` | Yes | Percentage (e.g. `10` = 10%, max 100) or fixed amount in store currency |
| `startDate` | `string` | Yes | ISO 8601 datetime the promotion starts |
| `endDate` | `string` | Yes | ISO 8601 datetime the promotion ends |
| `active` | `boolean` | No | Whether the promotion is active (default `true`) |
| `priority` | `number` | No | Priority when multiple apply, lower wins (default `1000`) |
| `stackable` | `boolean` | No | Whether it stacks with other promotions (default `true`) |
| `minQuantity` | `number` | No | Minimum cart quantity to trigger (default `1`) |
| `maxQuantity` | `number` | No | Maximum quantity the promotion applies to |
| `products` | `string[]` | No | Product UUIDs the promotion targets |
| `collections` | `string[]` | No | Collection UUIDs the promotion targets |
| `color` | `string` | No | Badge color hex (default `#f5f5dc`) |
| `currencyAmounts` | `object` | No | Per-currency fixed amounts for multi-currency stores |

```bash
curl -X POST \
  -H "Authorization: Bearer your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"name": "Summer Sale", "discountType": "percentage", "discountValue": 20, "startDate": "2024-06-01T00:00:00.000Z", "endDate": "2024-08-31T23:59:59.000Z"}' \
  https://your-store.yns.store/api/v1/promotions
```

### Response (201)

```json
{
  "id": "0191abc0-1234-7def-8000-000000000001",
  "name": "Summer Sale",
  "description": null,
  "discountType": "percentage",
  "discountValue": 20,
  "startDate": "2024-06-01T00:00:00.000Z",
  "endDate": "2024-08-31T23:59:59.000Z",
  "active": true,
  "priority": 1000,
  "stackable": true,
  "minQuantity": 1,
  "maxQuantity": null,
  "color": "#f5f5dc",
  "productIds": [],
  "collectionIds": [],
  "currencyAmounts": {},
  "createdAt": "2024-06-15T10:30:00.000Z",
  "updatedAt": "2024-06-15T10:30:00.000Z"
}
```

---

## Get Promotion

```
GET /api/v1/promotions/:id
```

Returns a single promotion by UUID, including its targeted products and collections.

### Response

```json
{
  "id": "0191abc0-1234-7def-8000-000000000001",
  "name": "Summer Sale",
  "description": "20% off swimwear",
  "discountType": "percentage",
  "discountValue": 20,
  "startDate": "2024-06-01T00:00:00.000Z",
  "endDate": "2024-08-31T23:59:59.000Z",
  "active": true,
  "priority": 1000,
  "stackable": true,
  "minQuantity": 1,
  "maxQuantity": null,
  "color": "#f5f5dc",
  "productIds": [],
  "collectionIds": ["0191abc0-0000-7000-8000-000000000100"],
  "currencyAmounts": {},
  "createdAt": "2024-05-20T10:30:00.000Z",
  "updatedAt": "2024-05-20T10:30:00.000Z"
}
```

---

## Update Promotion

```
PATCH /api/v1/promotions/:id
```

Replaces the promotion's fields. Uses the same body as **Create Promotion**.

### Request Body

Same fields as [Create Promotion](#create-promotion).

```bash
curl -X PATCH \
  -H "Authorization: Bearer your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"name": "Summer Sale", "discountType": "percentage", "discountValue": 25, "startDate": "2024-06-01T00:00:00.000Z", "endDate": "2024-08-31T23:59:59.000Z"}' \
  https://your-store.yns.store/api/v1/promotions/0191abc0-1234-7def-8000-000000000001
```

### Response (200)

```json
{
  "id": "0191abc0-1234-7def-8000-000000000001",
  "name": "Summer Sale",
  "description": null,
  "discountType": "percentage",
  "discountValue": 25,
  "startDate": "2024-06-01T00:00:00.000Z",
  "endDate": "2024-08-31T23:59:59.000Z",
  "active": true,
  "priority": 1000,
  "stackable": true,
  "minQuantity": 1,
  "maxQuantity": null,
  "color": "#f5f5dc",
  "productIds": [],
  "collectionIds": [],
  "currencyAmounts": {},
  "createdAt": "2024-05-20T10:30:00.000Z",
  "updatedAt": "2024-06-15T11:00:00.000Z"
}
```

---

## Delete Promotion

```
DELETE /api/v1/promotions/:id
```

Hard-deletes the promotion by UUID.

```bash
curl -X DELETE \
  -H "Authorization: Bearer your_api_key" \
  https://your-store.yns.store/api/v1/promotions/0191abc0-1234-7def-8000-000000000001
```

### Response

```json
{
  "ok": true,
  "deleted": 1
}
```