Skip to content

Coupons

Create discount codes customers can apply at checkout. Percentage or fixed-amount, time-limited or capped, one-time or recurring.

Coupons are managed in the builder’s Commerce panel > Products > Coupons sub-tab, or through the SDK at proyecta.commerce.coupons.

FieldNotes
codeThe promo code customers type at checkout (e.g. LAUNCH20)
percent_off or amount_offMutually exclusive. Percent is 1–100. Amount is in the smallest currency unit (cents).
currencyRequired for amount_off discounts (three-letter ISO code). Accepted on creation and forwarded to Stripe, but not stored or returned by the API afterward.
durationonce (first payment only), repeating (for duration_in_months), or forever
duration_in_monthsRequired when duration is repeating
max_redemptionsTotal cap across all customers
redeem_byExpiration date after which the coupon stops working
nameDisplay name shown to customers
activeToggle to enable/disable without deleting

From the Coupons sub-tab, click Add coupon and fill in the fields. Or via the SDK:

// 20% off forever
await proyecta.commerce.coupons.create({
code: 'LAUNCH20',
name: 'Launch discount',
percent_off: 20,
duration: 'forever',
});
// $10 off, single use, expires in 30 days
await proyecta.commerce.coupons.create({
code: 'WELCOME10',
amount_off: 1000,
currency: 'USD',
duration: 'once',
max_redemptions: 1,
redeem_by: new Date(Date.now() + 30 * 86400 * 1000).toISOString(),
});
// 50% off for the first 3 months of a subscription
await proyecta.commerce.coupons.create({
code: 'EARLY3',
percent_off: 50,
duration: 'repeating',
duration_in_months: 3,
});

Customers can enter the coupon code themselves on the Stripe-hosted checkout page — the promo code field is shown automatically.

await proyecta.commerce.checkout({
customer_id,
line_items: [{ variant_id: 'var_pro_monthly' }],
success_url: 'https://myapp.com/welcome',
});

Passing a coupon code programmatically in the checkout call is not yet supported.

// Browse every coupon (only lists coupons created via the SDK)
const { data } = await proyecta.commerce.coupons.list();
for (const coupon of data.data) {
console.log(coupon.code, coupon.times_redeemed, '/', coupon.max_redemptions);
}
// Paginate using data.has_more and the starting_after query parameter if needed.
// Disable a coupon (without deleting)
await proyecta.commerce.coupons.update({ couponId: 'coupon_123', active: false });

Note: coupons.list() only returns coupons created via the SDK. Coupons created in the builder Dashboard are not visible through coupons.list().

  • Codes and discount amounts are immutable. You can update the display name and toggle active, but not percent_off, amount_off, or code itself. Create a new coupon if you need different terms.
  • times_redeemed auto-increments and is read-only — useful for tracking campaign performance.
  • Coupons apply per customer, not per order — if a coupon is forever and a customer subscribes, every renewal gets the discount.