# Promotions

> Create coupons, discounts, bundles and buy-X-get-Y offers, change them, pause them or end them by archiving.

These are the shop's own SellerSideKick promotions. They apply on the SellerSideKick store and in the chat bot. Marketplace promotions (Shopee, Lazada, TikTok) are not listed or changed here: manage them in each seller center.

| Job | Connector tool | API |
|---|---|---|
| List, find an id, check a code is free | `list_promotions` | `GET /promotions?type=&status=` |
| Create | `create_promotion` | `POST /promotions/{type}` |
| Change fields | `update_promotion` | `PATCH /promotions/{type}/{id}` |
| Pause, resume, end | `set_promotion_status` | `POST /promotions/{type}/{id}/status` |

Listing needs `catalog:read`; the other three need `promotions:write`.

## The four types

- **`coupon`**: a code the buyer enters. `discount_type` (`percentage` or `fixed`), `value`, `applies_to`; optional `min_order_amount`, `max_discount_amount` (a THB cap on a percentage) and `can_stack` (usable with other promotions).
- **`discount`**: the same fields as a coupon, without `can_stack`.
- **`bundle`**: buy these products together for less. `products` (2 or more, each `sku` and `quantity`) and `bundle_discount_type`: `fixed` with `bundle_discount` (THB) or `percentage` with `bundle_discount_percentage`.
- **`bogo`**: buy X, get Y. `products` with `role` `buy` or `get`, at least one of each.

Every type also has `code`, `name`, `starts_at` and `ends_at` (required on create), and optional `description`, `max_uses`, `max_uses_per_customer` and, on create, `status` (`active` by default, or `inactive`).

- `code`: letters, digits, `-` and `_`, up to 64 characters; lower case is upper-cased. Unique in the shop.
- `applies_to`: `{ "all_products": true }`, or any mix of `categories`, `brands` and `skus`, not both.
- Dates are ISO 8601. Send Thai time with its offset, e.g. `2026-11-01T00:00:00+07:00`. `ends_at` must be after `starts_at`.
- A percentage can't be more than 100. SKUs must be on your SellerSideKick store.

## Create

`POST /promotions/coupon`:

```json
{
  "code": "WELCOME10",
  "name": "ส่วนลด 10% สำหรับลูกค้าใหม่",
  "discount_type": "percentage",
  "value": 10,
  "max_discount_amount": 100,
  "applies_to": { "all_products": true },
  "starts_at": "2026-11-01T00:00:00+07:00",
  "ends_at": "2026-11-30T23:59:59+07:00",
  "max_uses_per_customer": 1
}
```

Confirm the code, dates, amount and products with the owner first. **Creating is not safe to retry**: if a call fails or times out, list the promotions to see whether it was created before sending it again. A code the shop already uses is refused.

## Change

Send only the fields that change, for example `{ "ends_at": "2026-12-15T23:59:59+07:00" }`. The type in the path must match the promotion's type. The change is checked against the promotion as it will be afterwards: the dates stay in order, a percentage stays at 100 or below, a BOGO keeps a buy and a get product, a bundle keeps 2 or more products. A code that another promotion of the shop uses is refused (`409`).

## Pause, resume or end

`{ "status": "inactive" }` pauses, `active` resumes, `archive` ends it for good. Nothing is deleted: an archived promotion stays in the history. Confirm with the owner before archiving.
