Skip to main content

Coupons

Coupons are discount codes that end users can apply during Stripe checkout. The admin Coupons view is the CRUD surface: create new codes, see redemption counts, and deactivate codes that should no longer be usable.

Where to find it

Admin sidebar → Coupons (/coupons).

Quick start

  1. Open Admin → Coupons.
  2. Click Create Coupon.
  3. Fill in a code (e.g. LAUNCH20), optional description, discount type (Percentage or Fixed Amount), value, optional max redemptions (leave blank for unlimited), and optional valid-until date.
  4. Click Create. The row appears in the list with an Active badge.
  5. To retire a code, click Deactivate on its row — existing subscriptions that used it keep their discount; no new redemptions are possible.

Detailed walkthrough

Coupons table

Columns:

  • Code — the code string users type at checkout (case sensitive).
  • Discount — formatted as 20% or $5.00 depending on discount type.
  • Redemptions — count of successful uses.
  • Valid Until — expiry timestamp or if unlimited.
  • StatusActive or Inactive badge.
  • ActionsDeactivate button (hidden for already-inactive coupons).

Create Coupon dialog (create-coupon-dialog.tsx)

Fields:

  • Code — e.g. LAUNCH20.
  • Description — optional free text.
  • Discount TypePercentage or Fixed Amount radio.
  • Discount Value — integer. For percentage it's 1–100; for fixed amount it's cents or minor units for the configured Stripe currency.
  • Max Redemptions — integer; leave blank for Unlimited.
  • Valid Until — optional date.

Create button triggers POST /api/coupons; while submitting the button shows "Creating…" and is disabled.

Deactivating

Deactivate sets the coupon's active flag to false without deleting the row. Existing redemptions remain valid via Stripe; new redemptions are rejected. To hard-delete, use the DELETE endpoint directly (no button in the UI).

Common scenarios

  • Launch promotion — create LAUNCH20 at 20% for the first 100 redemptions, expiry in 7 days.
  • Influencer code — percentage coupon with no expiry, unlimited redemptions.
  • Retire a leaked code — click Deactivate; existing paying customers keep their discount.
  • Stripe-level refund — not done here. Refunds are applied in the Stripe Dashboard against the invoice, not against the coupon.

Permissions

ActionPermission
View coupon list / detailcoupons:read
Create a couponcoupons:create
Edit / deactivate a couponcoupons:edit
Delete a coupon (hard delete)coupons:delete

Dashboard entry requires admin:access. System admins implicitly hold every coupons permission.

API

UI actionGraphQLREST
List couponsadminCouponsGET /v1/admin/coupons
Get couponadminCouponGET /v1/admin/coupons/\{id\}
Create couponadminCreateCouponPOST /v1/admin/coupons
Update couponadminUpdateCouponPUT /v1/admin/coupons/\{id\}
Deactivate couponadminDeactivateCouponPUT /v1/admin/coupons/\{id\} with { active: false }
Delete coupon (no UI)DELETE /v1/admin/coupons/\{id\}
End-user validate couponGET /v1/billing/validate-coupon?code=X

Tips & gotchas

  • Codes are case sensitive. LAUNCH20 and launch20 are different coupons — the UI does not normalise.
  • Deactivation is soft. It keeps redemption history intact. Delete only if the row is unused and you want it gone forever.
  • The discount value field is raw — percentage 20 means 20%, fixed amount 500 means 500 minor units (e.g. 5.00 USD). Document the convention in the description field for future admins.
  • Max redemptions is enforced at redemption time. Concurrent redemptions at the limit are a race — Stripe wins.
  • Billing — account-level subscription overview
  • Subscriptions — per-account subscription listing
  • Plans — plans the coupon can be applied against