Discounts & coupons
A coupon is a reusable discount template. Apply it to a customer or a subscription and the discount flows through to invoices automatically.
Coupon shape
{ "code": "SUMMER25", "type": "percent", "amount_off": "25", "duration": "repeating", "duration_in_months": 3, "max_redemptions": 1000, "applies_to": { "plan_codes": ["pro-monthly-usd"] }, "valid_until": "2026-08-31T23:59:59Z"}| Field | Notes |
|---|---|
type | percent or amount. |
amount_off | Either a percentage (0–100) or a money amount string. |
duration | once, repeating, or forever. |
duration_in_months | Required when duration: repeating. |
max_redemptions | Optional cap across all customers. |
applies_to | Optional restriction by plan_codes or product_codes. |
valid_until | Optional expiry; redemptions after this date fail. |
Applying a coupon
To a subscription:
POST /v1/subscriptions/{id}/discounts{ "coupon_code": "SUMMER25" }Or at create time:
{ "customer_id": "cus_…", "plan_code": "pro-monthly-usd", "coupons": ["SUMMER25"]}To a customer (applies to every subscription they own):
POST /v1/customers/{id}/discounts{ "coupon_code": "PARTNER10" }Stacking
Multiple discounts apply in a fixed order:
- Customer-level coupons.
- Subscription-level coupons, in
created_atorder. - One-off invoice discounts (added directly to a draft invoice).
Each discount applies to the running subtotal after the previous
discount, never to the original. A 25% then 10% stack does not
equal 35% — it equals 32.5%.
Per-line vs invoice-level
By default, a discount applies to the whole invoice subtotal. To restrict
it to specific components, use applies_to.components:
{ "code": "SEATS50", "type": "percent", "amount_off": "50", "applies_to": { "plan_codes": ["pro-monthly-usd"], "components": ["seats"] }}The discount is allocated to the matching line items only; tax is recomputed against the discounted amount.
Currency handling
Coupons of type: amount carry an explicit currency. They are only valid
on invoices in that currency:
{ "code": "USD10OFF", "type": "amount", "amount_off": "10.00", "currency": "USD"}percent coupons are currency-agnostic.
Removing a discount
DELETE /v1/subscriptions/{id}/discounts/{discount_id}A removed discount stops applying from the next invoice. Already-issued invoices are not changed; if you need to remediate, issue a credit note.
Promo codes vs coupons
A promo code is a public-facing name (SUMMER25, WELCOME) that
maps to a coupon. The dashboard lets you create a coupon and one or more
promo codes that redeem it. Use promo codes when you want the same
discount on multiple campaigns; use a coupon directly when you’ll only
use it once.
Common pitfalls
- A coupon applied to a customer applies to every subscription they ever create. If you want it on one only, apply it at the subscription level.
duration: forevermeans forever for that subscription, not for that customer. Cancel-and-resubscribe loses it.applies_to.plan_codesmatches the plan in effect at invoice time. An upgrade to a non-matching plan ends the discount silently.
Webhook events
| Event | When |
|---|---|
coupon.created / coupon.updated / coupon.deleted | Coupon CRUD. |
discount.applied | A coupon redemption attached to a customer or subscription. |
discount.removed | A discount was detached. |
discount.expired | A repeating discount reached its last cycle. |