Skip to content

Apply a discount

Coupons let you apply a percentage or fixed-amount discount, with duration and scope rules. See Discounts & coupons for the full model.

1. Create the coupon

POST /v1/coupons
Idempotency-Key: <uuid>
{
"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"
}

Most coupons are reusable templates. Once created, apply them to as many subscriptions / customers as the max_redemptions cap allows.

2. Apply to a subscription

At create time:

{
"customer_id": "cus_…",
"plan_code": "pro-monthly-usd",
"coupons": ["SUMMER25"]
}

After the fact:

POST /v1/subscriptions/{id}/discounts
{ "coupon_code": "SUMMER25" }

The discount applies starting with the next invoice (or the upcoming one if it’s still in draft). repeating discounts count down on each invoice; on the last cycle, the discount auto-expires and emits discount.expired.

Apply to a customer

A customer-level discount applies to every subscription that customer has, including future ones:

POST /v1/customers/{id}/discounts
{ "coupon_code": "PARTNER10" }

Use sparingly — it’s easy to forget that the partner discount is silently applying to every subsequent purchase.

Apply to a one-off invoice

POST /v1/invoices/{id}/discounts
{ "coupon_code": "GOODWILL_50" }

Only allowed while the invoice is draft. Once finalised, you’d issue a credit note instead.

Promo codes

For customer-facing redemption, set up a promo code that maps to a coupon:

POST /v1/promotion-codes
{
"code": "SUMMER25",
"coupon_code": "summer25-internal",
"active": true,
"max_redemptions": 1000,
"first_time_transaction": true,
"minimum_amount": "20.00",
"currency": "USD"
}

The same coupon can have multiple promo codes (SUMMER, SUMMER25, AUGUST) for different campaigns. Use the dashboard’s redemption analytics to see which campaign drove what.

To enable code entry on hosted checkout:

{ "allow_promotion_codes": true }

Removing a discount

DELETE /v1/subscriptions/{id}/discounts/{discount_id}

A removed discount stops applying on the next invoice. Already-issued invoices are untouched.

Listing applied discounts

GET /v1/subscriptions/{id}/discounts

Returns every discount currently in effect, with cycles remaining and projected savings on the next invoice.

Common pitfalls

  • Coupon code collisions. Two coupons with similar codes (SAVE10 vs SAVE_10) are easy for support to mis-apply. Pick a naming convention and stick to it.
  • amount coupons in the wrong currency. A USD coupon does not apply to an EUR invoice. Either create a per-currency variant or use a percent coupon.
  • Discounts on annual plans applied as duration: repeating, duration_in_months: 3 — applies for one invoice (annual = 1 invoice = 1 cycle). Use once for annual.

Webhook events

EventWhen
coupon.created / coupon.updatedCoupon CRUD.
discount.appliedCoupon attached to a customer / subscription / invoice.
discount.removedDetached.
discount.expiredA repeating discount used its last cycle.
promotion_code.redeemedA customer used a public promo code.