/coupon
Create, scope and debug a Store coupon (Store/Coupon at Admin/Coupons/{CODE}) β which PLAN it grants and for how long, where it may be redeemed, plus the redemption model and the traps that make a coupon look present while unlocking nothing. Use when issuing a coupon, seeding one for a test, or investigating a paywall that shows no redeem row.
- Instructions: # Coupons A coupon is a **typed node** at `Admin/Coupons/{CODE}` (`nodeType: Store/Coupon`, content `CouponContent`). The node id **is** the normalized (upper-cased) code β there is no separate code field to keep in step. ## Issue one ```json { "id": "WELCOME2026", "namespace": "Admin/Coupons", "name": "WELCOME2026", "nodeType": "Store/Coupon", "content": { "$type": "CouponContent", "tier": "personal", "tierDays": 90, "price": 0, "currency": "CHF", "plugins": ["AgenticPrimer"], "validUntil": "2026-12-31T23:59:59Z", "maxRedemptions": 100, "notes": "launch promo" } } ``` - π¨ **`tier`** β **REQUIRED. It is what the coupon gives.** A `PlanTiers` id (`personal`, `pro`, `dedicated`, `enterprise`); a coupon that names none is refused by `CouponRedemption.Validate` on every path, with *"This coupon does not grant a plan."* The coupon editor says the same thing in place, so a misconfigured coupon is visible where it is authored. - π¨ **`tierDays`** β how long the granted plan runs. **Blank = 90 days** (`DefaultTierDays`); `0` means a deliberately permanent grant, and must be typed. The term is clamped to the coupon's own `validUntil` β nothing a coupon issues outlives the coupon β and it EXTENDS a live plan without ever shortening one, so re-granting to a card subscriber cannot cancel what they are paying for. - **`price`** β `0`/null is a FREE unlock (redeemed straight on `{plugin}/Subscribe`); a positive number is the discounted price, applied inside an Order at checkout. A price is not a grant: a discount coupon still needs a tier. - **`validFrom` / `validUntil`** β the window. Outside it the code is refused. - **`maxRedemptions`** counts **unique viewers** (`RedeemedBy`), so a viewer never burns two, and an abandoned checkout never burns one (redemptions are counted at fulfilment). - **`Redemptions`** is the audit trail β one entry per viewer AND package unlocked. ## π¨ A coupon grants a PLAN, not packages This is theβ¦
- Auto mount: yes
- Launches sub thread: no