Coupons
Endpoint
POST /api/v1/coupons/validate
{ "code": "SPRING25" }The endpoint normalizes the code (uppercase, trim) and returns either the matched coupon's discount or a structured error (expired, already_used, min_amount_not_met, plan_not_allowed).
What admins issue
Coupons are issued from Coupons Admin. Field reference (truncated):
typescript
{
code: string, // 2–40 chars, uppercase, unique
kind: "percent" | "fixed" | "trial_extension",
value: number,
currency: "TRY" | "USD" | null,
applies_to: ("new" | "renewal" | "upgrade")[], // default ["new", "upgrade"]
allowed_plans: string[], // empty = all
usage_limit: number, // 0 = unlimited
single_use_per_user: boolean, // default true
valid_from: Date | null,
valid_until: Date | null,
is_active: boolean,
}Stacking
Sosyabot does not stack coupons today — one code per checkout. Use trial_extension codes for non-monetary perks alongside paid promotions issued separately.